1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_setup.h"
25 #ifndef CURL_DISABLE_TFTP
27 #ifdef HAVE_NETINET_IN_H
28 #include <netinet/in.h>
33 #ifdef HAVE_ARPA_INET_H
34 #include <arpa/inet.h>
39 #ifdef HAVE_SYS_IOCTL_H
40 #include <sys/ioctl.h>
43 #ifdef HAVE_SYS_PARAM_H
44 #include <sys/param.h>
48 #include <curl/curl.h>
55 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
59 #include "speedcheck.h"
63 /* The last 3 #include files should be in this order */
64 #include "curl_printf.h"
65 #include "curl_memory.h"
68 /* RFC2348 allows the block size to be negotiated */
69 #define TFTP_BLKSIZE_DEFAULT 512
70 #define TFTP_BLKSIZE_MIN 8
71 #define TFTP_BLKSIZE_MAX 65464
72 #define TFTP_OPTION_BLKSIZE "blksize"
75 #define TFTP_OPTION_TSIZE "tsize"
76 #define TFTP_OPTION_INTERVAL "timeout"
110 TFTP_ERR_NOSUCHUSER, /* This will never be triggered by this code */
112 /* The remaining error codes are internal to curl */
113 TFTP_ERR_NONE = -100,
118 typedef struct tftp_packet {
122 typedef struct tftp_state_data {
127 struct connectdata *conn;
128 curl_socket_t sockfd;
135 unsigned short block;
136 struct Curl_sockaddr_storage local_addr;
137 struct Curl_sockaddr_storage remote_addr;
138 curl_socklen_t remote_addrlen;
142 int requested_blksize;
143 tftp_packet_t rpacket;
144 tftp_packet_t spacket;
148 /* Forward declarations */
149 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event);
150 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event);
151 static CURLcode tftp_connect(struct connectdata *conn, bool *done);
152 static CURLcode tftp_disconnect(struct connectdata *conn,
153 bool dead_connection);
154 static CURLcode tftp_do(struct connectdata *conn, bool *done);
155 static CURLcode tftp_done(struct connectdata *conn,
156 CURLcode, bool premature);
157 static CURLcode tftp_setup_connection(struct connectdata * conn);
158 static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
159 static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
160 static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
162 static CURLcode tftp_translate_code(tftp_error_t error);
166 * TFTP protocol handler.
169 const struct Curl_handler Curl_handler_tftp = {
171 tftp_setup_connection, /* setup_connection */
173 tftp_done, /* done */
174 ZERO_NULL, /* do_more */
175 tftp_connect, /* connect_it */
176 tftp_multi_statemach, /* connecting */
177 tftp_doing, /* doing */
178 tftp_getsock, /* proto_getsock */
179 tftp_getsock, /* doing_getsock */
180 ZERO_NULL, /* domore_getsock */
181 ZERO_NULL, /* perform_getsock */
182 tftp_disconnect, /* disconnect */
183 ZERO_NULL, /* readwrite */
184 PORT_TFTP, /* defport */
185 CURLPROTO_TFTP, /* protocol */
186 PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
189 /**********************************************************
191 * tftp_set_timeouts -
193 * Set timeouts based on state machine state.
194 * Use user provided connect timeouts until DATA or ACK
195 * packet is received, then use user-provided transfer timeouts
198 **********************************************************/
199 static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
201 time_t maxtime, timeout;
203 bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
205 time(&state->start_time);
207 /* Compute drop-dead time */
208 timeout_ms = Curl_timeleft(state->conn->data, NULL, start);
211 /* time-out, bail out, go home */
212 failf(state->conn->data, "Connection time-out");
213 return CURLE_OPERATION_TIMEDOUT;
218 maxtime = (time_t)(timeout_ms + 500) / 1000;
219 state->max_time = state->start_time+maxtime;
221 /* Set per-block timeout to total */
224 /* Average restart after 5 seconds */
225 state->retry_max = (int)timeout/5;
227 if(state->retry_max < 1)
228 /* avoid division by zero below */
229 state->retry_max = 1;
231 /* Compute the re-start interval to suit the timeout */
232 state->retry_time = (int)timeout/state->retry_max;
233 if(state->retry_time<1)
239 maxtime = (time_t)(timeout_ms + 500) / 1000;
243 state->max_time = state->start_time+maxtime;
245 /* Set per-block timeout to total */
248 /* Average reposting an ACK after 5 seconds */
249 state->retry_max = (int)timeout/5;
251 /* But bound the total number */
252 if(state->retry_max<3)
255 if(state->retry_max>50)
258 /* Compute the re-ACK interval to suit the timeout */
259 state->retry_time = (int)(timeout/state->retry_max);
260 if(state->retry_time<1)
263 infof(state->conn->data,
264 "set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
265 (int)state->state, (long)(state->max_time-state->start_time),
266 state->retry_time, state->retry_max);
269 time(&state->rx_time);
274 /**********************************************************
276 * tftp_set_send_first
278 * Event handler for the START state
280 **********************************************************/
282 static void setpacketevent(tftp_packet_t *packet, unsigned short num)
284 packet->data[0] = (unsigned char)(num >> 8);
285 packet->data[1] = (unsigned char)(num & 0xff);
289 static void setpacketblock(tftp_packet_t *packet, unsigned short num)
291 packet->data[2] = (unsigned char)(num >> 8);
292 packet->data[3] = (unsigned char)(num & 0xff);
295 static unsigned short getrpacketevent(const tftp_packet_t *packet)
297 return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
300 static unsigned short getrpacketblock(const tftp_packet_t *packet)
302 return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
305 static size_t Curl_strnlen(const char *string, size_t maxlen)
307 const char *end = memchr(string, '\0', maxlen);
308 return end ? (size_t) (end - string) : maxlen;
311 static const char *tftp_option_get(const char *buf, size_t len,
312 const char **option, const char **value)
316 loc = Curl_strnlen(buf, len);
317 loc++; /* NULL term */
323 loc += Curl_strnlen(buf+loc, len-loc);
324 loc++; /* NULL term */
328 *value = &buf[strlen(*option) + 1];
333 static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
334 const char *ptr, int len)
336 const char *tmp = ptr;
337 struct Curl_easy *data = state->conn->data;
339 /* if OACK doesn't contain blksize option, the default (512) must be used */
340 state->blksize = TFTP_BLKSIZE_DEFAULT;
342 while(tmp < ptr + len) {
343 const char *option, *value;
345 tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
347 failf(data, "Malformed ACK packet, rejecting");
348 return CURLE_TFTP_ILLEGAL;
351 infof(data, "got option=(%s) value=(%s)\n", option, value);
353 if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
356 blksize = strtol(value, NULL, 10);
359 failf(data, "invalid blocksize value in OACK packet");
360 return CURLE_TFTP_ILLEGAL;
362 else if(blksize > TFTP_BLKSIZE_MAX) {
363 failf(data, "%s (%d)", "blksize is larger than max supported",
365 return CURLE_TFTP_ILLEGAL;
367 else if(blksize < TFTP_BLKSIZE_MIN) {
368 failf(data, "%s (%d)", "blksize is smaller than min supported",
370 return CURLE_TFTP_ILLEGAL;
372 else if(blksize > state->requested_blksize) {
373 /* could realloc pkt buffers here, but the spec doesn't call out
374 * support for the server requesting a bigger blksize than the client
376 failf(data, "%s (%ld)",
377 "server requested blksize larger than allocated", blksize);
378 return CURLE_TFTP_ILLEGAL;
381 state->blksize = (int)blksize;
382 infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
383 state->blksize, "requested", state->requested_blksize);
385 else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
388 tsize = strtol(value, NULL, 10);
389 infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
391 /* tsize should be ignored on upload: Who cares about the size of the
393 if(!data->set.upload) {
395 failf(data, "invalid tsize -:%s:- value in OACK packet", value);
396 return CURLE_TFTP_ILLEGAL;
398 Curl_pgrsSetDownloadSize(data, tsize);
406 static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
407 char *buf, const char *option)
409 if(( strlen(option) + csize + 1) > (size_t)state->blksize)
412 return strlen(option) + 1;
415 static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
419 #ifndef CURL_DISABLE_VERBOSE_STRINGS
420 struct Curl_easy *data = state->conn->data;
422 infof(data, "%s\n", "Connected for transmit");
424 state->state = TFTP_STATE_TX;
425 result = tftp_set_timeouts(state);
428 return tftp_tx(state, event);
431 static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
435 #ifndef CURL_DISABLE_VERBOSE_STRINGS
436 struct Curl_easy *data = state->conn->data;
438 infof(data, "%s\n", "Connected for receive");
440 state->state = TFTP_STATE_RX;
441 result = tftp_set_timeouts(state);
444 return tftp_rx(state, event);
447 static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
451 const char *mode = "octet";
454 struct Curl_easy *data = state->conn->data;
455 CURLcode result = CURLE_OK;
457 /* Set ascii mode if -B flag was used */
458 if(data->set.prefer_ascii)
463 case TFTP_EVENT_INIT: /* Send the first packet out */
464 case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
465 /* Increment the retry counter, quit if over the limit */
467 if(state->retries>state->retry_max) {
468 state->error = TFTP_ERR_NORESPONSE;
469 state->state = TFTP_STATE_FIN;
473 if(data->set.upload) {
474 /* If we are uploading, send an WRQ */
475 setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
476 state->conn->data->req.upload_fromhere =
477 (char *)state->spacket.data+4;
478 if(data->state.infilesize != -1)
479 Curl_pgrsSetUploadSize(data, data->state.infilesize);
482 /* If we are downloading, send an RRQ */
483 setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
485 /* As RFC3617 describes the separator slash is not actually part of the
486 file name so we skip the always-present first letter of the path
488 result = Curl_urldecode(data, &state->conn->data->state.path[1], 0,
489 &filename, NULL, FALSE);
493 snprintf((char *)state->spacket.data+2,
495 "%s%c%s%c", filename, '\0', mode, '\0');
496 sbytes = 4 + strlen(filename) + strlen(mode);
498 /* optional addition of TFTP options */
499 if(!data->set.tftp_no_options) {
500 /* add tsize option */
501 if(data->set.upload && (data->state.infilesize != -1))
502 snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
503 data->state.infilesize);
505 strcpy(buf, "0"); /* the destination is large enough */
507 sbytes += tftp_option_add(state, sbytes,
508 (char *)state->spacket.data+sbytes,
510 sbytes += tftp_option_add(state, sbytes,
511 (char *)state->spacket.data+sbytes, buf);
512 /* add blksize option */
513 snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
514 sbytes += tftp_option_add(state, sbytes,
515 (char *)state->spacket.data+sbytes,
516 TFTP_OPTION_BLKSIZE);
517 sbytes += tftp_option_add(state, sbytes,
518 (char *)state->spacket.data+sbytes, buf);
520 /* add timeout option */
521 snprintf(buf, sizeof(buf), "%d", state->retry_time);
522 sbytes += tftp_option_add(state, sbytes,
523 (char *)state->spacket.data+sbytes,
524 TFTP_OPTION_INTERVAL);
525 sbytes += tftp_option_add(state, sbytes,
526 (char *)state->spacket.data+sbytes, buf);
529 /* the typecase for the 3rd argument is mostly for systems that do
530 not have a size_t argument, like older unixes that want an 'int' */
531 senddata = sendto(state->sockfd, (void *)state->spacket.data,
532 (SEND_TYPE_ARG3)sbytes, 0,
533 state->conn->ip_addr->ai_addr,
534 state->conn->ip_addr->ai_addrlen);
535 if(senddata != (ssize_t)sbytes) {
536 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
541 case TFTP_EVENT_OACK:
542 if(data->set.upload) {
543 result = tftp_connect_for_tx(state, event);
546 result = tftp_connect_for_rx(state, event);
550 case TFTP_EVENT_ACK: /* Connected for transmit */
551 result = tftp_connect_for_tx(state, event);
554 case TFTP_EVENT_DATA: /* Connected for receive */
555 result = tftp_connect_for_rx(state, event);
558 case TFTP_EVENT_ERROR:
559 state->state = TFTP_STATE_FIN;
563 failf(state->conn->data, "tftp_send_first: internal error");
570 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
572 #define NEXT_BLOCKNUM(x) (((x)+1)&0xffff)
574 /**********************************************************
578 * Event handler for the RX state
580 **********************************************************/
581 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
585 struct Curl_easy *data = state->conn->data;
589 case TFTP_EVENT_DATA:
590 /* Is this the block we expect? */
591 rblock = getrpacketblock(&state->rpacket);
592 if(NEXT_BLOCKNUM(state->block) == rblock) {
593 /* This is the expected block. Reset counters and ACK it. */
596 else if(state->block == rblock) {
597 /* This is the last recently received block again. Log it and ACK it
599 infof(data, "Received last DATA packet block %d again.\n", rblock);
602 /* totally unexpected, just log it */
604 "Received unexpected DATA packet block %d, expecting block %d\n",
605 rblock, NEXT_BLOCKNUM(state->block));
609 /* ACK this block. */
610 state->block = (unsigned short)rblock;
611 setpacketevent(&state->spacket, TFTP_EVENT_ACK);
612 setpacketblock(&state->spacket, state->block);
613 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
615 (struct sockaddr *)&state->remote_addr,
616 state->remote_addrlen);
618 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
619 return CURLE_SEND_ERROR;
622 /* Check if completed (That is, a less than full packet is received) */
623 if(state->rbytes < (ssize_t)state->blksize+4) {
624 state->state = TFTP_STATE_FIN;
627 state->state = TFTP_STATE_RX;
629 time(&state->rx_time);
632 case TFTP_EVENT_OACK:
633 /* ACK option acknowledgement so we can move on to data */
636 setpacketevent(&state->spacket, TFTP_EVENT_ACK);
637 setpacketblock(&state->spacket, state->block);
638 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
640 (struct sockaddr *)&state->remote_addr,
641 state->remote_addrlen);
643 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
644 return CURLE_SEND_ERROR;
647 /* we're ready to RX data */
648 state->state = TFTP_STATE_RX;
649 time(&state->rx_time);
652 case TFTP_EVENT_TIMEOUT:
653 /* Increment the retry count and fail if over the limit */
656 "Timeout waiting for block %d ACK. Retries = %d\n",
657 NEXT_BLOCKNUM(state->block), state->retries);
658 if(state->retries > state->retry_max) {
659 state->error = TFTP_ERR_TIMEOUT;
660 state->state = TFTP_STATE_FIN;
663 /* Resend the previous ACK */
664 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
666 (struct sockaddr *)&state->remote_addr,
667 state->remote_addrlen);
669 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
670 return CURLE_SEND_ERROR;
675 case TFTP_EVENT_ERROR:
676 setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
677 setpacketblock(&state->spacket, state->block);
678 (void)sendto(state->sockfd, (void *)state->spacket.data,
680 (struct sockaddr *)&state->remote_addr,
681 state->remote_addrlen);
682 /* don't bother with the return code, but if the socket is still up we
683 * should be a good TFTP client and let the server know we're done */
684 state->state = TFTP_STATE_FIN;
688 failf(data, "%s", "tftp_rx: internal error");
689 return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
695 /**********************************************************
699 * Event handler for the TX state
701 **********************************************************/
702 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
704 struct Curl_easy *data = state->conn->data;
707 CURLcode result = CURLE_OK;
708 struct SingleRequest *k = &data->req;
709 int cb; /* Bytes currently read */
714 case TFTP_EVENT_OACK:
715 if(event == TFTP_EVENT_ACK) {
717 rblock = getrpacketblock(&state->rpacket);
719 if(rblock != state->block &&
720 /* There's a bug in tftpd-hpa that causes it to send us an ack for
721 * 65535 when the block number wraps to 0. So when we're expecting
722 * 0, also accept 65535. See
723 * http://syslinux.zytor.com/archives/2010-September/015253.html
725 !(state->block == 0 && rblock == 65535)) {
726 /* This isn't the expected block. Log it and up the retry counter */
727 infof(data, "Received ACK for block %d, expecting %d\n",
728 rblock, state->block);
730 /* Bail out if over the maximum */
731 if(state->retries>state->retry_max) {
732 failf(data, "tftp_tx: giving up waiting for block %d ack",
734 result = CURLE_SEND_ERROR;
737 /* Re-send the data packet */
738 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
739 4+state->sbytes, SEND_4TH_ARG,
740 (struct sockaddr *)&state->remote_addr,
741 state->remote_addrlen);
742 /* Check all sbytes were sent */
744 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
745 result = CURLE_SEND_ERROR;
751 /* This is the expected packet. Reset the counters and send the next
753 time(&state->rx_time);
757 state->block = 1; /* first data block is 1 when using OACK */
760 setpacketevent(&state->spacket, TFTP_EVENT_DATA);
761 setpacketblock(&state->spacket, state->block);
762 if(state->block > 1 && state->sbytes < (int)state->blksize) {
763 state->state = TFTP_STATE_FIN;
767 /* TFTP considers data block size < 512 bytes as an end of session. So
768 * in some cases we must wait for additional data to build full (512 bytes)
772 state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4;
774 result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes,
779 state->conn->data->req.upload_fromhere += cb;
780 } while(state->sbytes < state->blksize && cb != 0);
782 sbytes = sendto(state->sockfd, (void *) state->spacket.data,
783 4 + state->sbytes, SEND_4TH_ARG,
784 (struct sockaddr *)&state->remote_addr,
785 state->remote_addrlen);
786 /* Check all sbytes were sent */
788 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
789 return CURLE_SEND_ERROR;
791 /* Update the progress meter */
792 k->writebytecount += state->sbytes;
793 Curl_pgrsSetUploadCounter(data, k->writebytecount);
796 case TFTP_EVENT_TIMEOUT:
797 /* Increment the retry counter and log the timeout */
799 infof(data, "Timeout waiting for block %d ACK. "
800 " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries);
801 /* Decide if we've had enough */
802 if(state->retries > state->retry_max) {
803 state->error = TFTP_ERR_TIMEOUT;
804 state->state = TFTP_STATE_FIN;
807 /* Re-send the data packet */
808 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
809 4+state->sbytes, SEND_4TH_ARG,
810 (struct sockaddr *)&state->remote_addr,
811 state->remote_addrlen);
812 /* Check all sbytes were sent */
814 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
815 return CURLE_SEND_ERROR;
817 /* since this was a re-send, we remain at the still byte position */
818 Curl_pgrsSetUploadCounter(data, k->writebytecount);
822 case TFTP_EVENT_ERROR:
823 state->state = TFTP_STATE_FIN;
824 setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
825 setpacketblock(&state->spacket, state->block);
826 (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
827 (struct sockaddr *)&state->remote_addr,
828 state->remote_addrlen);
829 /* don't bother with the return code, but if the socket is still up we
830 * should be a good TFTP client and let the server know we're done */
831 state->state = TFTP_STATE_FIN;
835 failf(data, "tftp_tx: internal error, event: %i", (int)(event));
842 /**********************************************************
844 * tftp_translate_code
846 * Translate internal error codes to CURL error codes
848 **********************************************************/
849 static CURLcode tftp_translate_code(tftp_error_t error)
851 CURLcode result = CURLE_OK;
853 if(error != TFTP_ERR_NONE) {
855 case TFTP_ERR_NOTFOUND:
856 result = CURLE_TFTP_NOTFOUND;
859 result = CURLE_TFTP_PERM;
861 case TFTP_ERR_DISKFULL:
862 result = CURLE_REMOTE_DISK_FULL;
865 case TFTP_ERR_ILLEGAL:
866 result = CURLE_TFTP_ILLEGAL;
868 case TFTP_ERR_UNKNOWNID:
869 result = CURLE_TFTP_UNKNOWNID;
871 case TFTP_ERR_EXISTS:
872 result = CURLE_REMOTE_FILE_EXISTS;
874 case TFTP_ERR_NOSUCHUSER:
875 result = CURLE_TFTP_NOSUCHUSER;
877 case TFTP_ERR_TIMEOUT:
878 result = CURLE_OPERATION_TIMEDOUT;
880 case TFTP_ERR_NORESPONSE:
881 result = CURLE_COULDNT_CONNECT;
884 result = CURLE_ABORTED_BY_CALLBACK;
894 /**********************************************************
898 * The tftp state machine event dispatcher
900 **********************************************************/
901 static CURLcode tftp_state_machine(tftp_state_data_t *state,
904 CURLcode result = CURLE_OK;
905 struct Curl_easy *data = state->conn->data;
907 switch(state->state) {
908 case TFTP_STATE_START:
909 DEBUGF(infof(data, "TFTP_STATE_START\n"));
910 result = tftp_send_first(state, event);
913 DEBUGF(infof(data, "TFTP_STATE_RX\n"));
914 result = tftp_rx(state, event);
917 DEBUGF(infof(data, "TFTP_STATE_TX\n"));
918 result = tftp_tx(state, event);
921 infof(data, "%s\n", "TFTP finished");
924 DEBUGF(infof(data, "STATE: %d\n", state->state));
925 failf(data, "%s", "Internal state machine error");
926 result = CURLE_TFTP_ILLEGAL;
933 /**********************************************************
937 * The disconnect callback
939 **********************************************************/
940 static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
942 tftp_state_data_t *state = conn->proto.tftpc;
943 (void) dead_connection;
945 /* done, free dynamically allocated pkt buffers */
947 Curl_safefree(state->rpacket.data);
948 Curl_safefree(state->spacket.data);
955 /**********************************************************
959 * The connect callback
961 **********************************************************/
962 static CURLcode tftp_connect(struct connectdata *conn, bool *done)
964 tftp_state_data_t *state;
967 blksize = TFTP_BLKSIZE_DEFAULT;
969 state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
971 return CURLE_OUT_OF_MEMORY;
973 /* alloc pkt buffers based on specified blksize */
974 if(conn->data->set.tftp_blksize) {
975 blksize = (int)conn->data->set.tftp_blksize;
976 if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
977 return CURLE_TFTP_ILLEGAL;
980 if(!state->rpacket.data) {
981 state->rpacket.data = calloc(1, blksize + 2 + 2);
983 if(!state->rpacket.data)
984 return CURLE_OUT_OF_MEMORY;
987 if(!state->spacket.data) {
988 state->spacket.data = calloc(1, blksize + 2 + 2);
990 if(!state->spacket.data)
991 return CURLE_OUT_OF_MEMORY;
994 /* we don't keep TFTP connections up basically because there's none or very
995 * little gain for UDP */
996 connclose(conn, "TFTP");
999 state->sockfd = state->conn->sock[FIRSTSOCKET];
1000 state->state = TFTP_STATE_START;
1001 state->error = TFTP_ERR_NONE;
1002 state->blksize = TFTP_BLKSIZE_DEFAULT;
1003 state->requested_blksize = blksize;
1005 ((struct sockaddr *)&state->local_addr)->sa_family =
1006 (unsigned short)(conn->ip_addr->ai_family);
1008 tftp_set_timeouts(state);
1010 if(!conn->bits.bound) {
1011 /* If not already bound, bind to any interface, random UDP port. If it is
1012 * reused or a custom local port was desired, this has already been done!
1014 * We once used the size of the local_addr struct as the third argument
1015 * for bind() to better work with IPv6 or whatever size the struct could
1016 * have, but we learned that at least Tru64, AIX and IRIX *requires* the
1017 * size of that argument to match the exact size of a 'sockaddr_in' struct
1018 * when running IPv4-only.
1020 * Therefore we use the size from the address we connected to, which we
1021 * assume uses the same IP version and thus hopefully this works for both
1024 rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
1025 conn->ip_addr->ai_addrlen);
1027 failf(conn->data, "bind() failed; %s",
1028 Curl_strerror(conn, SOCKERRNO));
1029 return CURLE_COULDNT_CONNECT;
1031 conn->bits.bound = TRUE;
1034 Curl_pgrsStartNow(conn->data);
1041 /**********************************************************
1047 **********************************************************/
1048 static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
1051 CURLcode result = CURLE_OK;
1052 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
1054 (void)status; /* unused */
1055 (void)premature; /* not used */
1057 if(Curl_pgrsDone(conn))
1058 return CURLE_ABORTED_BY_CALLBACK;
1060 /* If we have encountered an error */
1062 result = tftp_translate_code(state->error);
1067 /**********************************************************
1071 * The getsock callback
1073 **********************************************************/
1074 static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
1078 return GETSOCK_BLANK;
1080 socks[0] = conn->sock[FIRSTSOCKET];
1082 return GETSOCK_READSOCK(0);
1085 /**********************************************************
1087 * tftp_receive_packet
1089 * Called once select fires and data is ready on the socket
1091 **********************************************************/
1092 static CURLcode tftp_receive_packet(struct connectdata *conn)
1094 struct Curl_sockaddr_storage fromaddr;
1095 curl_socklen_t fromlen;
1096 CURLcode result = CURLE_OK;
1097 struct Curl_easy *data = conn->data;
1098 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
1099 struct SingleRequest *k = &data->req;
1101 /* Receive the packet */
1102 fromlen = sizeof(fromaddr);
1103 state->rbytes = (int)recvfrom(state->sockfd,
1104 (void *)state->rpacket.data,
1107 (struct sockaddr *)&fromaddr,
1109 if(state->remote_addrlen==0) {
1110 memcpy(&state->remote_addr, &fromaddr, fromlen);
1111 state->remote_addrlen = fromlen;
1114 /* Sanity check packet length */
1115 if(state->rbytes < 4) {
1116 failf(data, "Received too short packet");
1117 /* Not a timeout, but how best to handle it? */
1118 state->event = TFTP_EVENT_TIMEOUT;
1121 /* The event is given by the TFTP packet time */
1122 state->event = (tftp_event_t)getrpacketevent(&state->rpacket);
1124 switch(state->event) {
1125 case TFTP_EVENT_DATA:
1126 /* Don't pass to the client empty or retransmitted packets */
1127 if(state->rbytes > 4 &&
1128 (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
1129 result = Curl_client_write(conn, CLIENTWRITE_BODY,
1130 (char *)state->rpacket.data+4,
1133 tftp_state_machine(state, TFTP_EVENT_ERROR);
1136 k->bytecount += state->rbytes-4;
1137 Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
1140 case TFTP_EVENT_ERROR:
1141 state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
1142 infof(data, "%s\n", (const char *)state->rpacket.data+4);
1144 case TFTP_EVENT_ACK:
1146 case TFTP_EVENT_OACK:
1147 result = tftp_parse_option_ack(state,
1148 (const char *)state->rpacket.data+2,
1153 case TFTP_EVENT_RRQ:
1154 case TFTP_EVENT_WRQ:
1156 failf(data, "%s", "Internal error: Unexpected packet");
1160 /* Update the progress meter */
1161 if(Curl_pgrsUpdate(conn)) {
1162 tftp_state_machine(state, TFTP_EVENT_ERROR);
1163 return CURLE_ABORTED_BY_CALLBACK;
1169 /**********************************************************
1171 * tftp_state_timeout
1173 * Check if timeouts have been reached
1175 **********************************************************/
1176 static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
1179 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
1182 *event = TFTP_EVENT_NONE;
1185 if(current > state->max_time) {
1186 DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
1187 (long)current, (long)state->max_time));
1188 state->error = TFTP_ERR_TIMEOUT;
1189 state->state = TFTP_STATE_FIN;
1192 else if(current > state->rx_time+state->retry_time) {
1194 *event = TFTP_EVENT_TIMEOUT;
1195 time(&state->rx_time); /* update even though we received nothing */
1198 /* there's a typecast below here since 'time_t' may in fact be larger than
1199 'long', but we estimate that a 'long' will still be able to hold number
1200 of seconds even if "only" 32 bit */
1201 return (long)(state->max_time - current);
1204 /**********************************************************
1206 * tftp_multi_statemach
1208 * Handle single RX socket event and return
1210 **********************************************************/
1211 static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
1215 CURLcode result = CURLE_OK;
1216 struct Curl_easy *data = conn->data;
1217 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
1218 long timeout_ms = tftp_state_timeout(conn, &event);
1222 if(timeout_ms <= 0) {
1223 failf(data, "TFTP response timeout");
1224 return CURLE_OPERATION_TIMEDOUT;
1226 else if(event != TFTP_EVENT_NONE) {
1227 result = tftp_state_machine(state, event);
1230 *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
1232 /* Tell curl we're done */
1233 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1236 /* no timeouts to handle, check our socket */
1237 rc = SOCKET_READABLE(state->sockfd, 0);
1241 int error = SOCKERRNO;
1242 failf(data, "%s", Curl_strerror(conn, error));
1243 state->event = TFTP_EVENT_ERROR;
1246 result = tftp_receive_packet(conn);
1249 result = tftp_state_machine(state, state->event);
1252 *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
1254 /* Tell curl we're done */
1255 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1257 /* if rc == 0, then select() timed out */
1263 /**********************************************************
1267 * Called from multi.c while DOing
1269 **********************************************************/
1270 static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
1273 result = tftp_multi_statemach(conn, dophase_done);
1276 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1279 /* The multi code doesn't have this logic for the DOING state so we
1280 provide it for TFTP since it may do the entire transfer in this
1282 if(Curl_pgrsUpdate(conn))
1283 result = CURLE_ABORTED_BY_CALLBACK;
1285 result = Curl_speedcheck(conn->data, Curl_tvnow());
1290 /**********************************************************
1294 * Entry point for transfer from tftp_do, sarts state mach
1296 **********************************************************/
1297 static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
1299 CURLcode result = CURLE_OK;
1300 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
1302 *dophase_done = FALSE;
1304 result = tftp_state_machine(state, TFTP_EVENT_INIT);
1306 if((state->state == TFTP_STATE_FIN) || result)
1309 tftp_multi_statemach(conn, dophase_done);
1312 DEBUGF(infof(conn->data, "DO phase is complete\n"));
1318 /**********************************************************
1324 * This callback initiates the TFTP transfer
1326 **********************************************************/
1328 static CURLcode tftp_do(struct connectdata *conn, bool *done)
1330 tftp_state_data_t *state;
1335 if(!conn->proto.tftpc) {
1336 result = tftp_connect(conn, done);
1341 state = (tftp_state_data_t *)conn->proto.tftpc;
1343 return CURLE_BAD_CALLING_ORDER;
1345 result = tftp_perform(conn, done);
1347 /* If tftp_perform() returned an error, use that for return code. If it
1348 was OK, see if tftp_translate_code() has an error. */
1350 /* If we have encountered an internal tftp error, translate it. */
1351 result = tftp_translate_code(state->error);
1356 static CURLcode tftp_setup_connection(struct connectdata * conn)
1358 struct Curl_easy *data = conn->data;
1362 conn->socktype = SOCK_DGRAM; /* UDP datagram based */
1364 /* TFTP URLs support an extension like ";mode=<typecode>" that
1365 * we'll try to get now! */
1366 type = strstr(data->state.path, ";mode=");
1369 type = strstr(conn->host.rawalloc, ";mode=");
1372 *type = 0; /* it was in the middle of the hostname */
1373 command = Curl_raw_toupper(type[6]);
1376 case 'A': /* ASCII mode */
1377 case 'N': /* NETASCII mode */
1378 data->set.prefer_ascii = TRUE;
1381 case 'O': /* octet mode */
1382 case 'I': /* binary mode */
1384 /* switch off ASCII */
1385 data->set.prefer_ascii = FALSE;