Loading CHANGES +4 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,10 @@ Changelog Daniel (8 May 2006) - Fixed known bug #28. The TFTP code no longer assumes a packed struct and thus works reliably on more platforms. Daniel (5 May 2006) - Roland Blom filed bug report #1481217 (http://curl.haxx.se/bug/view.cgi?id=1481217), with follow-ups by Michele Loading RELEASE-NOTES +1 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ This release includes the following changes: This release includes the following bugfixes: o TFTP works in a more portable fashion (== on more platforms) o WSAGetLastError() is now used (better) on Windows o GnuTLS non-block case that could cause data trashing o deflate code survives lack of zlib header Loading docs/KNOWN_BUGS +0 −2 Original line number Diff line number Diff line Loading @@ -33,8 +33,6 @@ may have been fixed since this was written! See http://curl.haxx.se/bug/view.cgi?id=1371118 28. The TFTP code is not portable and will fail on some architectures. 26. NTLM authentication using SSPI (on Windows) when (lib)curl is running in "system context" will make it use wrong(?) user name - at least when compared to what winhttp does. See http://curl.haxx.se/bug/view.cgi?id=1281867 Loading lib/tftp.c +52 −59 Original line number Diff line number Diff line Loading @@ -122,23 +122,7 @@ typedef enum { } tftp_error_t; typedef struct tftp_packet { unsigned short event; union { struct { unsigned char data[512]; } request; struct { unsigned short block; unsigned char data[512]; } data; struct { unsigned short block; } ack; struct { unsigned short code; unsigned char data[512]; } error; } u; unsigned char data[516]; } tftp_packet_t; typedef struct tftp_state_data { Loading Loading @@ -199,7 +183,8 @@ void tftp_set_timeouts(tftp_state_data_t *state) /* Compute the re-start interval to suit the timeout */ state->retry_time = timeout/state->retry_max; if(state->retry_time<1) state->retry_time=1; if(state->retry_time<1) state->retry_time=1; } else { Loading @@ -215,12 +200,16 @@ void tftp_set_timeouts(tftp_state_data_t *state) state->retry_max = timeout/15; } /* But bound the total number */ if(state->retry_max<3) state->retry_max=3; if(state->retry_max>50) state->retry_max=50; if(state->retry_max<3) state->retry_max=3; if(state->retry_max>50) state->retry_max=50; /* Compute the re-ACK interval to suit the timeout */ state->retry_time = timeout/state->retry_max; if(state->retry_time<1) state->retry_time=1; if(state->retry_time<1) state->retry_time=1; infof(data, "set timeouts for state %d; Total %d, retry %d maxtry %d\n", state->state, (state->max_time-state->start_time), Loading @@ -235,6 +224,29 @@ void tftp_set_timeouts(tftp_state_data_t *state) * **********************************************************/ static void setpacketevent(tftp_packet_t *packet, unsigned short num) { packet->data[0] = (num >> 8); packet->data[1] = (num & 0xff); } static void setpacketblock(tftp_packet_t *packet, unsigned short num) { packet->data[2] = (num >> 8); packet->data[3] = (num & 0xff); } static unsigned short getrpacketevent(tftp_packet_t *packet) { return (packet->data[0] << 8) | packet->data[1]; } static unsigned short getrpacketblock(tftp_packet_t *packet) { return (packet->data[2] << 8) | packet->data[3]; } static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event) { int sbytes; Loading @@ -260,18 +272,18 @@ static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(data->set.upload) { /* If we are uploading, send an WRQ */ state->spacket.event = htons(TFTP_EVENT_WRQ); setpacketevent(&state->spacket, TFTP_EVENT_WRQ); filename = curl_easy_unescape(data, filename, 0, NULL); state->conn->upload_fromhere = (char *)state->spacket.u.data.data; state->conn->upload_fromhere = (char *)&state->spacket.data[2]; if(data->set.infilesize != -1) Curl_pgrsSetUploadSize(data, data->set.infilesize); } else { /* If we are downloading, send an RRQ */ state->spacket.event = htons(TFTP_EVENT_RRQ); setpacketevent(&state->spacket, TFTP_EVENT_RRQ); } snprintf((char *)state->spacket.u.request.data, sizeof(state->spacket.u.request.data), snprintf((char *)&state->spacket.data[2], 512, "%s%c%s%c", filename, '\0', mode, '\0'); sbytes = 4 + (int)strlen(filename) + (int)strlen(mode); sbytes = sendto(state->sockfd, (void *)&state->spacket, Loading Loading @@ -325,7 +337,7 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) case TFTP_EVENT_DATA: /* Is this the block we expect? */ rblock = ntohs(state->rpacket.u.data.block); rblock = getrpacketblock(&state->rpacket); if ((state->block+1) != rblock) { /* No, log it, up the retry count and fail if over the limit */ infof(data, Loading @@ -340,9 +352,9 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) /* This is the expected block. Reset counters and ACK it. */ state->block = rblock; state->retries = 0; state->spacket.event = htons(TFTP_EVENT_ACK); state->spacket.u.ack.block = htons(state->block); sbytes = sendto(state->sockfd, (void *)&state->spacket, setpacketevent(&state->spacket, TFTP_EVENT_ACK); setpacketblock(&state->spacket, state->block); sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); Loading Loading @@ -409,7 +421,7 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) case TFTP_EVENT_ACK: /* Ack the packet */ rblock = ntohs(state->rpacket.u.data.block); rblock = getrpacketblock(&state->rpacket); if(rblock != state->block) { /* This isn't the expected block. Log it and up the retry counter */ Loading @@ -428,14 +440,14 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) block */ state->block++; state->retries = 0; state->spacket.event = htons(TFTP_EVENT_DATA); state->spacket.u.ack.block = htons(state->block); setpacketevent(&state->spacket, TFTP_EVENT_DATA); setpacketblock(&state->spacket, state->block); if(state->block > 1 && state->sbytes < 512) { state->state = TFTP_STATE_FIN; return; } Curl_fillreadbuffer(state->conn, 512, &state->sbytes); sbytes = sendto(state->sockfd, (void *)&state->spacket, sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4+state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); Loading Loading @@ -529,28 +541,9 @@ CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) tftp_state_data_t *state; int rc; /* * The TFTP code is not portable because it sends C structs directly over * the wire. Since C gives compiler writers a wide latitude in padding and * aligning structs, this fails on many architectures (e.g. ARM). * * The only portable way to fix this is to copy each struct item into a * flat buffer and send the flat buffer instead of the struct. The * alternative, trying to get the compiler to eliminate padding bytes * within the struct, is a nightmare to maintain (each compiler does it * differently), and is still not guaranteed to work because some * architectures can't handle the resulting alignment. * * This check can be removed once the code has been fixed. */ if(sizeof(struct tftp_packet) != 516) { failf(conn->data, "tftp not supported on this architecture"); return CURLE_FAILED_INIT; } if((state = conn->proto.tftp = calloc(sizeof(tftp_state_data_t), 1))==NULL) { state = conn->proto.tftp = calloc(sizeof(tftp_state_data_t), 1); if(!state) return CURLE_OUT_OF_MEMORY; } state->conn = conn; state->sockfd = state->conn->sock[FIRSTSOCKET]; Loading Loading @@ -678,17 +671,17 @@ CURLcode Curl_tftp(struct connectdata *conn, bool *done) } else { /* The event is given by the TFTP packet time */ event = (tftp_event_t)ntohs(state->rpacket.event); event = (tftp_event_t)getrpacketevent(&state->rpacket); switch(event) { case TFTP_EVENT_DATA: if (state->rbytes > 4) Curl_client_write(data, CLIENTWRITE_BODY, (char *)state->rpacket.u.data.data, state->rbytes-4); (char *)&state->rpacket.data[4], state->rbytes-4); break; case TFTP_EVENT_ERROR: state->error = (tftp_error_t)ntohs(state->rpacket.u.error.code); infof(conn->data, "%s\n", (char *)state->rpacket.u.error.data); state->error = (tftp_error_t)getrpacketblock(&state->rpacket); infof(conn->data, "%s\n", (char *)&state->rpacket.data[4]); break; case TFTP_EVENT_ACK: break; Loading Loading
CHANGES +4 −0 Original line number Diff line number Diff line Loading @@ -6,6 +6,10 @@ Changelog Daniel (8 May 2006) - Fixed known bug #28. The TFTP code no longer assumes a packed struct and thus works reliably on more platforms. Daniel (5 May 2006) - Roland Blom filed bug report #1481217 (http://curl.haxx.se/bug/view.cgi?id=1481217), with follow-ups by Michele Loading
RELEASE-NOTES +1 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ This release includes the following changes: This release includes the following bugfixes: o TFTP works in a more portable fashion (== on more platforms) o WSAGetLastError() is now used (better) on Windows o GnuTLS non-block case that could cause data trashing o deflate code survives lack of zlib header Loading
docs/KNOWN_BUGS +0 −2 Original line number Diff line number Diff line Loading @@ -33,8 +33,6 @@ may have been fixed since this was written! See http://curl.haxx.se/bug/view.cgi?id=1371118 28. The TFTP code is not portable and will fail on some architectures. 26. NTLM authentication using SSPI (on Windows) when (lib)curl is running in "system context" will make it use wrong(?) user name - at least when compared to what winhttp does. See http://curl.haxx.se/bug/view.cgi?id=1281867 Loading
lib/tftp.c +52 −59 Original line number Diff line number Diff line Loading @@ -122,23 +122,7 @@ typedef enum { } tftp_error_t; typedef struct tftp_packet { unsigned short event; union { struct { unsigned char data[512]; } request; struct { unsigned short block; unsigned char data[512]; } data; struct { unsigned short block; } ack; struct { unsigned short code; unsigned char data[512]; } error; } u; unsigned char data[516]; } tftp_packet_t; typedef struct tftp_state_data { Loading Loading @@ -199,7 +183,8 @@ void tftp_set_timeouts(tftp_state_data_t *state) /* Compute the re-start interval to suit the timeout */ state->retry_time = timeout/state->retry_max; if(state->retry_time<1) state->retry_time=1; if(state->retry_time<1) state->retry_time=1; } else { Loading @@ -215,12 +200,16 @@ void tftp_set_timeouts(tftp_state_data_t *state) state->retry_max = timeout/15; } /* But bound the total number */ if(state->retry_max<3) state->retry_max=3; if(state->retry_max>50) state->retry_max=50; if(state->retry_max<3) state->retry_max=3; if(state->retry_max>50) state->retry_max=50; /* Compute the re-ACK interval to suit the timeout */ state->retry_time = timeout/state->retry_max; if(state->retry_time<1) state->retry_time=1; if(state->retry_time<1) state->retry_time=1; infof(data, "set timeouts for state %d; Total %d, retry %d maxtry %d\n", state->state, (state->max_time-state->start_time), Loading @@ -235,6 +224,29 @@ void tftp_set_timeouts(tftp_state_data_t *state) * **********************************************************/ static void setpacketevent(tftp_packet_t *packet, unsigned short num) { packet->data[0] = (num >> 8); packet->data[1] = (num & 0xff); } static void setpacketblock(tftp_packet_t *packet, unsigned short num) { packet->data[2] = (num >> 8); packet->data[3] = (num & 0xff); } static unsigned short getrpacketevent(tftp_packet_t *packet) { return (packet->data[0] << 8) | packet->data[1]; } static unsigned short getrpacketblock(tftp_packet_t *packet) { return (packet->data[2] << 8) | packet->data[3]; } static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event) { int sbytes; Loading @@ -260,18 +272,18 @@ static void tftp_send_first(tftp_state_data_t *state, tftp_event_t event) if(data->set.upload) { /* If we are uploading, send an WRQ */ state->spacket.event = htons(TFTP_EVENT_WRQ); setpacketevent(&state->spacket, TFTP_EVENT_WRQ); filename = curl_easy_unescape(data, filename, 0, NULL); state->conn->upload_fromhere = (char *)state->spacket.u.data.data; state->conn->upload_fromhere = (char *)&state->spacket.data[2]; if(data->set.infilesize != -1) Curl_pgrsSetUploadSize(data, data->set.infilesize); } else { /* If we are downloading, send an RRQ */ state->spacket.event = htons(TFTP_EVENT_RRQ); setpacketevent(&state->spacket, TFTP_EVENT_RRQ); } snprintf((char *)state->spacket.u.request.data, sizeof(state->spacket.u.request.data), snprintf((char *)&state->spacket.data[2], 512, "%s%c%s%c", filename, '\0', mode, '\0'); sbytes = 4 + (int)strlen(filename) + (int)strlen(mode); sbytes = sendto(state->sockfd, (void *)&state->spacket, Loading Loading @@ -325,7 +337,7 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) case TFTP_EVENT_DATA: /* Is this the block we expect? */ rblock = ntohs(state->rpacket.u.data.block); rblock = getrpacketblock(&state->rpacket); if ((state->block+1) != rblock) { /* No, log it, up the retry count and fail if over the limit */ infof(data, Loading @@ -340,9 +352,9 @@ static void tftp_rx(tftp_state_data_t *state, tftp_event_t event) /* This is the expected block. Reset counters and ACK it. */ state->block = rblock; state->retries = 0; state->spacket.event = htons(TFTP_EVENT_ACK); state->spacket.u.ack.block = htons(state->block); sbytes = sendto(state->sockfd, (void *)&state->spacket, setpacketevent(&state->spacket, TFTP_EVENT_ACK); setpacketblock(&state->spacket, state->block); sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); Loading Loading @@ -409,7 +421,7 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) case TFTP_EVENT_ACK: /* Ack the packet */ rblock = ntohs(state->rpacket.u.data.block); rblock = getrpacketblock(&state->rpacket); if(rblock != state->block) { /* This isn't the expected block. Log it and up the retry counter */ Loading @@ -428,14 +440,14 @@ static void tftp_tx(tftp_state_data_t *state, tftp_event_t event) block */ state->block++; state->retries = 0; state->spacket.event = htons(TFTP_EVENT_DATA); state->spacket.u.ack.block = htons(state->block); setpacketevent(&state->spacket, TFTP_EVENT_DATA); setpacketblock(&state->spacket, state->block); if(state->block > 1 && state->sbytes < 512) { state->state = TFTP_STATE_FIN; return; } Curl_fillreadbuffer(state->conn, 512, &state->sbytes); sbytes = sendto(state->sockfd, (void *)&state->spacket, sbytes = sendto(state->sockfd, (void *)state->spacket.data, 4+state->sbytes, SEND_4TH_ARG, (struct sockaddr *)&state->remote_addr, state->remote_addrlen); Loading Loading @@ -529,28 +541,9 @@ CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) tftp_state_data_t *state; int rc; /* * The TFTP code is not portable because it sends C structs directly over * the wire. Since C gives compiler writers a wide latitude in padding and * aligning structs, this fails on many architectures (e.g. ARM). * * The only portable way to fix this is to copy each struct item into a * flat buffer and send the flat buffer instead of the struct. The * alternative, trying to get the compiler to eliminate padding bytes * within the struct, is a nightmare to maintain (each compiler does it * differently), and is still not guaranteed to work because some * architectures can't handle the resulting alignment. * * This check can be removed once the code has been fixed. */ if(sizeof(struct tftp_packet) != 516) { failf(conn->data, "tftp not supported on this architecture"); return CURLE_FAILED_INIT; } if((state = conn->proto.tftp = calloc(sizeof(tftp_state_data_t), 1))==NULL) { state = conn->proto.tftp = calloc(sizeof(tftp_state_data_t), 1); if(!state) return CURLE_OUT_OF_MEMORY; } state->conn = conn; state->sockfd = state->conn->sock[FIRSTSOCKET]; Loading Loading @@ -678,17 +671,17 @@ CURLcode Curl_tftp(struct connectdata *conn, bool *done) } else { /* The event is given by the TFTP packet time */ event = (tftp_event_t)ntohs(state->rpacket.event); event = (tftp_event_t)getrpacketevent(&state->rpacket); switch(event) { case TFTP_EVENT_DATA: if (state->rbytes > 4) Curl_client_write(data, CLIENTWRITE_BODY, (char *)state->rpacket.u.data.data, state->rbytes-4); (char *)&state->rpacket.data[4], state->rbytes-4); break; case TFTP_EVENT_ERROR: state->error = (tftp_error_t)ntohs(state->rpacket.u.error.code); infof(conn->data, "%s\n", (char *)state->rpacket.u.error.data); state->error = (tftp_error_t)getrpacketblock(&state->rpacket); infof(conn->data, "%s\n", (char *)&state->rpacket.data[4]); break; case TFTP_EVENT_ACK: break; Loading