quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

tftp.c (41954B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
      9  *
     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.se/docs/copyright.html.
     13  *
     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.
     17  *
     18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
     19  * KIND, either express or implied.
     20  *
     21  * SPDX-License-Identifier: curl
     22  *
     23  ***************************************************************************/
     24 
     25 #include "curl_setup.h"
     26 
     27 #ifndef CURL_DISABLE_TFTP
     28 
     29 #ifdef HAVE_NETINET_IN_H
     30 #include <netinet/in.h>
     31 #endif
     32 #ifdef HAVE_NETDB_H
     33 #include <netdb.h>
     34 #endif
     35 #ifdef HAVE_ARPA_INET_H
     36 #include <arpa/inet.h>
     37 #endif
     38 #ifdef HAVE_NET_IF_H
     39 #include <net/if.h>
     40 #endif
     41 #ifdef HAVE_SYS_IOCTL_H
     42 #include <sys/ioctl.h>
     43 #endif
     44 
     45 #ifdef HAVE_SYS_PARAM_H
     46 #include <sys/param.h>
     47 #endif
     48 
     49 #include "urldata.h"
     50 #include <curl/curl.h>
     51 #include "cfilters.h"
     52 #include "cf-socket.h"
     53 #include "transfer.h"
     54 #include "sendf.h"
     55 #include "tftp.h"
     56 #include "progress.h"
     57 #include "connect.h"
     58 #include "strerror.h"
     59 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
     60 #include "multiif.h"
     61 #include "url.h"
     62 #include "strcase.h"
     63 #include "speedcheck.h"
     64 #include "select.h"
     65 #include "escape.h"
     66 #include "curlx/strparse.h"
     67 
     68 /* The last 3 #include files should be in this order */
     69 #include "curl_printf.h"
     70 #include "curl_memory.h"
     71 #include "memdebug.h"
     72 
     73 /* RFC2348 allows the block size to be negotiated */
     74 #define TFTP_BLKSIZE_DEFAULT 512
     75 #define TFTP_OPTION_BLKSIZE "blksize"
     76 
     77 /* from RFC2349: */
     78 #define TFTP_OPTION_TSIZE    "tsize"
     79 #define TFTP_OPTION_INTERVAL "timeout"
     80 
     81 typedef enum {
     82   TFTP_MODE_NETASCII = 0,
     83   TFTP_MODE_OCTET
     84 } tftp_mode_t;
     85 
     86 typedef enum {
     87   TFTP_STATE_START = 0,
     88   TFTP_STATE_RX,
     89   TFTP_STATE_TX,
     90   TFTP_STATE_FIN
     91 } tftp_state_t;
     92 
     93 typedef enum {
     94   TFTP_EVENT_NONE = -1,
     95   TFTP_EVENT_INIT = 0,
     96   TFTP_EVENT_RRQ = 1,
     97   TFTP_EVENT_WRQ = 2,
     98   TFTP_EVENT_DATA = 3,
     99   TFTP_EVENT_ACK = 4,
    100   TFTP_EVENT_ERROR = 5,
    101   TFTP_EVENT_OACK = 6,
    102   TFTP_EVENT_TIMEOUT
    103 } tftp_event_t;
    104 
    105 typedef enum {
    106   TFTP_ERR_UNDEF = 0,
    107   TFTP_ERR_NOTFOUND,
    108   TFTP_ERR_PERM,
    109   TFTP_ERR_DISKFULL,
    110   TFTP_ERR_ILLEGAL,
    111   TFTP_ERR_UNKNOWNID,
    112   TFTP_ERR_EXISTS,
    113   TFTP_ERR_NOSUCHUSER,  /* This will never be triggered by this code */
    114 
    115   /* The remaining error codes are internal to curl */
    116   TFTP_ERR_NONE = -100,
    117   TFTP_ERR_TIMEOUT,
    118   TFTP_ERR_NORESPONSE
    119 } tftp_error_t;
    120 
    121 struct tftp_packet {
    122   unsigned char *data;
    123 };
    124 
    125 /* meta key for storing protocol meta at connection */
    126 #define CURL_META_TFTP_CONN   "meta:proto:tftp:conn"
    127 
    128 struct tftp_conn {
    129   tftp_state_t    state;
    130   tftp_mode_t     mode;
    131   tftp_error_t    error;
    132   tftp_event_t    event;
    133   struct Curl_easy *data;
    134   curl_socket_t   sockfd;
    135   int             retries;
    136   int             retry_time;
    137   int             retry_max;
    138   time_t          rx_time;
    139   struct Curl_sockaddr_storage   local_addr;
    140   struct Curl_sockaddr_storage   remote_addr;
    141   curl_socklen_t  remote_addrlen;
    142   int             rbytes;
    143   size_t          sbytes;
    144   unsigned int    blksize;
    145   unsigned int    requested_blksize;
    146   unsigned short  block;
    147   struct tftp_packet rpacket;
    148   struct tftp_packet spacket;
    149 };
    150 
    151 
    152 /* Forward declarations */
    153 static CURLcode tftp_rx(struct tftp_conn *state, tftp_event_t event);
    154 static CURLcode tftp_tx(struct tftp_conn *state, tftp_event_t event);
    155 static CURLcode tftp_connect(struct Curl_easy *data, bool *done);
    156 static CURLcode tftp_do(struct Curl_easy *data, bool *done);
    157 static CURLcode tftp_done(struct Curl_easy *data,
    158                           CURLcode, bool premature);
    159 static CURLcode tftp_setup_connection(struct Curl_easy *data,
    160                                       struct connectdata *conn);
    161 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done);
    162 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done);
    163 static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn,
    164                         curl_socket_t *socks);
    165 static CURLcode tftp_translate_code(tftp_error_t error);
    166 
    167 
    168 /*
    169  * TFTP protocol handler.
    170  */
    171 
    172 const struct Curl_handler Curl_handler_tftp = {
    173   "tftp",                               /* scheme */
    174   tftp_setup_connection,                /* setup_connection */
    175   tftp_do,                              /* do_it */
    176   tftp_done,                            /* done */
    177   ZERO_NULL,                            /* do_more */
    178   tftp_connect,                         /* connect_it */
    179   tftp_multi_statemach,                 /* connecting */
    180   tftp_doing,                           /* doing */
    181   tftp_getsock,                         /* proto_getsock */
    182   tftp_getsock,                         /* doing_getsock */
    183   ZERO_NULL,                            /* domore_getsock */
    184   ZERO_NULL,                            /* perform_getsock */
    185   ZERO_NULL,                            /* disconnect */
    186   ZERO_NULL,                            /* write_resp */
    187   ZERO_NULL,                            /* write_resp_hd */
    188   ZERO_NULL,                            /* connection_check */
    189   ZERO_NULL,                            /* attach connection */
    190   ZERO_NULL,                            /* follow */
    191   PORT_TFTP,                            /* defport */
    192   CURLPROTO_TFTP,                       /* protocol */
    193   CURLPROTO_TFTP,                       /* family */
    194   PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
    195 };
    196 
    197 /**********************************************************
    198  *
    199  * tftp_set_timeouts -
    200  *
    201  * Set timeouts based on state machine state.
    202  * Use user provided connect timeouts until DATA or ACK
    203  * packet is received, then use user-provided transfer timeouts
    204  *
    205  *
    206  **********************************************************/
    207 static CURLcode tftp_set_timeouts(struct tftp_conn *state)
    208 {
    209   time_t maxtime, timeout;
    210   timediff_t timeout_ms;
    211   bool start = (state->state == TFTP_STATE_START);
    212 
    213   /* Compute drop-dead time */
    214   timeout_ms = Curl_timeleft(state->data, NULL, start);
    215 
    216   if(timeout_ms < 0) {
    217     /* time-out, bail out, go home */
    218     failf(state->data, "Connection time-out");
    219     return CURLE_OPERATION_TIMEDOUT;
    220   }
    221 
    222   if(timeout_ms > 0)
    223     maxtime = (time_t)(timeout_ms + 500) / 1000;
    224   else
    225     maxtime = 3600; /* use for calculating block timeouts */
    226 
    227   /* Set per-block timeout to total */
    228   timeout = maxtime;
    229 
    230   /* Average reposting an ACK after 5 seconds */
    231   state->retry_max = (int)timeout/5;
    232 
    233   /* But bound the total number */
    234   if(state->retry_max < 3)
    235     state->retry_max = 3;
    236 
    237   if(state->retry_max > 50)
    238     state->retry_max = 50;
    239 
    240   /* Compute the re-ACK interval to suit the timeout */
    241   state->retry_time = (int)(timeout/state->retry_max);
    242   if(state->retry_time < 1)
    243     state->retry_time = 1;
    244 
    245   infof(state->data,
    246         "set timeouts for state %d; Total % " FMT_OFF_T ", retry %d maxtry %d",
    247         (int)state->state, timeout_ms, state->retry_time, state->retry_max);
    248 
    249   /* init RX time */
    250   state->rx_time = time(NULL);
    251 
    252   return CURLE_OK;
    253 }
    254 
    255 /**********************************************************
    256  *
    257  * tftp_set_send_first
    258  *
    259  * Event handler for the START state
    260  *
    261  **********************************************************/
    262 
    263 static void setpacketevent(struct tftp_packet *packet, unsigned short num)
    264 {
    265   packet->data[0] = (unsigned char)(num >> 8);
    266   packet->data[1] = (unsigned char)(num & 0xff);
    267 }
    268 
    269 
    270 static void setpacketblock(struct tftp_packet *packet, unsigned short num)
    271 {
    272   packet->data[2] = (unsigned char)(num >> 8);
    273   packet->data[3] = (unsigned char)(num & 0xff);
    274 }
    275 
    276 static unsigned short getrpacketevent(const struct tftp_packet *packet)
    277 {
    278   return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
    279 }
    280 
    281 static unsigned short getrpacketblock(const struct tftp_packet *packet)
    282 {
    283   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
    284 }
    285 
    286 static size_t tftp_strnlen(const char *string, size_t maxlen)
    287 {
    288   const char *end = memchr(string, '\0', maxlen);
    289   return end ? (size_t) (end - string) : maxlen;
    290 }
    291 
    292 static const char *tftp_option_get(const char *buf, size_t len,
    293                                    const char **option, const char **value)
    294 {
    295   size_t loc;
    296 
    297   loc = tftp_strnlen(buf, len);
    298   loc++; /* NULL term */
    299 
    300   if(loc >= len)
    301     return NULL;
    302   *option = buf;
    303 
    304   loc += tftp_strnlen(buf + loc, len-loc);
    305   loc++; /* NULL term */
    306 
    307   if(loc > len)
    308     return NULL;
    309   *value = &buf[strlen(*option) + 1];
    310 
    311   return &buf[loc];
    312 }
    313 
    314 static CURLcode tftp_parse_option_ack(struct tftp_conn *state,
    315                                       const char *ptr, int len)
    316 {
    317   const char *tmp = ptr;
    318   struct Curl_easy *data = state->data;
    319 
    320   /* if OACK does not contain blksize option, the default (512) must be used */
    321   state->blksize = TFTP_BLKSIZE_DEFAULT;
    322 
    323   while(tmp < ptr + len) {
    324     const char *option, *value;
    325 
    326     tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
    327     if(!tmp) {
    328       failf(data, "Malformed ACK packet, rejecting");
    329       return CURLE_TFTP_ILLEGAL;
    330     }
    331 
    332     infof(data, "got option=(%s) value=(%s)", option, value);
    333 
    334     if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
    335       curl_off_t blksize;
    336       if(curlx_str_number(&value, &blksize, TFTP_BLKSIZE_MAX)) {
    337         failf(data, "%s (%d)", "blksize is larger than max supported",
    338               TFTP_BLKSIZE_MAX);
    339         return CURLE_TFTP_ILLEGAL;
    340       }
    341       if(!blksize) {
    342         failf(data, "invalid blocksize value in OACK packet");
    343         return CURLE_TFTP_ILLEGAL;
    344       }
    345       else if(blksize < TFTP_BLKSIZE_MIN) {
    346         failf(data, "%s (%d)", "blksize is smaller than min supported",
    347               TFTP_BLKSIZE_MIN);
    348         return CURLE_TFTP_ILLEGAL;
    349       }
    350       else if(blksize > state->requested_blksize) {
    351         /* could realloc pkt buffers here, but the spec does not call out
    352          * support for the server requesting a bigger blksize than the client
    353          * requests */
    354         failf(data, "server requested blksize larger than allocated (%"
    355               CURL_FORMAT_CURL_OFF_T ")", blksize);
    356         return CURLE_TFTP_ILLEGAL;
    357       }
    358 
    359       state->blksize = (int)blksize;
    360       infof(data, "blksize parsed from OACK (%d) requested (%d)",
    361             state->blksize, state->requested_blksize);
    362     }
    363     else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
    364       curl_off_t tsize = 0;
    365       /* tsize should be ignored on upload: Who cares about the size of the
    366          remote file? */
    367       if(!data->state.upload &&
    368          !curlx_str_number(&value, &tsize, CURL_OFF_T_MAX)) {
    369         if(!tsize) {
    370           failf(data, "invalid tsize -:%s:- value in OACK packet", value);
    371           return CURLE_TFTP_ILLEGAL;
    372         }
    373         infof(data, "tsize parsed from OACK (%" CURL_FORMAT_CURL_OFF_T ")",
    374               tsize);
    375         Curl_pgrsSetDownloadSize(data, tsize);
    376       }
    377     }
    378   }
    379 
    380   return CURLE_OK;
    381 }
    382 
    383 static CURLcode tftp_option_add(struct tftp_conn *state, size_t *csize,
    384                                 char *buf, const char *option)
    385 {
    386   if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
    387     return CURLE_TFTP_ILLEGAL;
    388   strcpy(buf, option);
    389   *csize += strlen(option) + 1;
    390   return CURLE_OK;
    391 }
    392 
    393 static CURLcode tftp_connect_for_tx(struct tftp_conn *state,
    394                                     tftp_event_t event)
    395 {
    396   CURLcode result;
    397 #ifndef CURL_DISABLE_VERBOSE_STRINGS
    398   struct Curl_easy *data = state->data;
    399 
    400   infof(data, "%s", "Connected for transmit");
    401 #endif
    402   state->state = TFTP_STATE_TX;
    403   result = tftp_set_timeouts(state);
    404   if(result)
    405     return result;
    406   return tftp_tx(state, event);
    407 }
    408 
    409 static CURLcode tftp_connect_for_rx(struct tftp_conn *state,
    410                                     tftp_event_t event)
    411 {
    412   CURLcode result;
    413 #ifndef CURL_DISABLE_VERBOSE_STRINGS
    414   struct Curl_easy *data = state->data;
    415 
    416   infof(data, "%s", "Connected for receive");
    417 #endif
    418   state->state = TFTP_STATE_RX;
    419   result = tftp_set_timeouts(state);
    420   if(result)
    421     return result;
    422   return tftp_rx(state, event);
    423 }
    424 
    425 static CURLcode tftp_send_first(struct tftp_conn *state,
    426                                 tftp_event_t event)
    427 {
    428   size_t sbytes;
    429   ssize_t senddata;
    430   const char *mode = "octet";
    431   char *filename;
    432   struct Curl_easy *data = state->data;
    433   const struct Curl_sockaddr_ex *remote_addr = NULL;
    434   CURLcode result = CURLE_OK;
    435 
    436   /* Set ASCII mode if -B flag was used */
    437   if(data->state.prefer_ascii)
    438     mode = "netascii";
    439 
    440   switch(event) {
    441 
    442   case TFTP_EVENT_INIT:    /* Send the first packet out */
    443   case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
    444     /* Increment the retry counter, quit if over the limit */
    445     state->retries++;
    446     if(state->retries > state->retry_max) {
    447       state->error = TFTP_ERR_NORESPONSE;
    448       state->state = TFTP_STATE_FIN;
    449       return result;
    450     }
    451 
    452     if(data->state.upload) {
    453       /* If we are uploading, send an WRQ */
    454       setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
    455       if(data->state.infilesize != -1)
    456         Curl_pgrsSetUploadSize(data, data->state.infilesize);
    457     }
    458     else {
    459       /* If we are downloading, send an RRQ */
    460       setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
    461     }
    462     /* As RFC3617 describes the separator slash is not actually part of the
    463        filename so we skip the always-present first letter of the path
    464        string. */
    465     result = Curl_urldecode(&state->data->state.up.path[1], 0,
    466                             &filename, NULL, REJECT_ZERO);
    467     if(result)
    468       return result;
    469 
    470     if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
    471       failf(data, "TFTP filename too long");
    472       free(filename);
    473       return CURLE_TFTP_ILLEGAL; /* too long filename field */
    474     }
    475 
    476     msnprintf((char *)state->spacket.data + 2,
    477               state->blksize,
    478               "%s%c%s%c", filename, '\0',  mode, '\0');
    479     sbytes = 4 + strlen(filename) + strlen(mode);
    480 
    481     /* optional addition of TFTP options */
    482     if(!data->set.tftp_no_options) {
    483       char buf[64];
    484       /* add tsize option */
    485       msnprintf(buf, sizeof(buf), "%" FMT_OFF_T,
    486                 data->state.upload && (data->state.infilesize != -1) ?
    487                 data->state.infilesize : 0);
    488 
    489       result = tftp_option_add(state, &sbytes,
    490                                (char *)state->spacket.data + sbytes,
    491                                TFTP_OPTION_TSIZE);
    492       if(result == CURLE_OK)
    493         result = tftp_option_add(state, &sbytes,
    494                                  (char *)state->spacket.data + sbytes, buf);
    495 
    496       /* add blksize option */
    497       msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
    498       if(result == CURLE_OK)
    499         result = tftp_option_add(state, &sbytes,
    500                                  (char *)state->spacket.data + sbytes,
    501                                  TFTP_OPTION_BLKSIZE);
    502       if(result == CURLE_OK)
    503         result = tftp_option_add(state, &sbytes,
    504                                  (char *)state->spacket.data + sbytes, buf);
    505 
    506       /* add timeout option */
    507       msnprintf(buf, sizeof(buf), "%d", state->retry_time);
    508       if(result == CURLE_OK)
    509         result = tftp_option_add(state, &sbytes,
    510                                  (char *)state->spacket.data + sbytes,
    511                                  TFTP_OPTION_INTERVAL);
    512       if(result == CURLE_OK)
    513         result = tftp_option_add(state, &sbytes,
    514                                  (char *)state->spacket.data + sbytes, buf);
    515 
    516       if(result != CURLE_OK) {
    517         failf(data, "TFTP buffer too small for options");
    518         free(filename);
    519         return CURLE_TFTP_ILLEGAL;
    520       }
    521     }
    522 
    523     /* the typecase for the 3rd argument is mostly for systems that do
    524        not have a size_t argument, like older unixes that want an 'int' */
    525 #ifdef __AMIGA__
    526 #define CURL_SENDTO_ARG5(x) CURL_UNCONST(x)
    527 #else
    528 #define CURL_SENDTO_ARG5(x) (x)
    529 #endif
    530     remote_addr = Curl_conn_get_remote_addr(data, FIRSTSOCKET);
    531     if(!remote_addr)
    532       return CURLE_FAILED_INIT;
    533 
    534     senddata = sendto(state->sockfd, (void *)state->spacket.data,
    535                       (SEND_TYPE_ARG3)sbytes, 0,
    536                       CURL_SENDTO_ARG5(&remote_addr->curl_sa_addr),
    537                       (curl_socklen_t)remote_addr->addrlen);
    538     if(senddata != (ssize_t)sbytes) {
    539       char buffer[STRERROR_LEN];
    540       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
    541     }
    542     free(filename);
    543     break;
    544 
    545   case TFTP_EVENT_OACK:
    546     if(data->state.upload) {
    547       result = tftp_connect_for_tx(state, event);
    548     }
    549     else {
    550       result = tftp_connect_for_rx(state, event);
    551     }
    552     break;
    553 
    554   case TFTP_EVENT_ACK: /* Connected for transmit */
    555     result = tftp_connect_for_tx(state, event);
    556     break;
    557 
    558   case TFTP_EVENT_DATA: /* Connected for receive */
    559     result = tftp_connect_for_rx(state, event);
    560     break;
    561 
    562   case TFTP_EVENT_ERROR:
    563     state->state = TFTP_STATE_FIN;
    564     break;
    565 
    566   default:
    567     failf(state->data, "tftp_send_first: internal error");
    568     break;
    569   }
    570 
    571   return result;
    572 }
    573 
    574 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
    575    boundary */
    576 #define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
    577 
    578 /**********************************************************
    579  *
    580  * tftp_rx
    581  *
    582  * Event handler for the RX state
    583  *
    584  **********************************************************/
    585 static CURLcode tftp_rx(struct tftp_conn *state, tftp_event_t event)
    586 {
    587   ssize_t sbytes;
    588   int rblock;
    589   struct Curl_easy *data = state->data;
    590   char buffer[STRERROR_LEN];
    591 
    592   switch(event) {
    593 
    594   case TFTP_EVENT_DATA:
    595     /* Is this the block we expect? */
    596     rblock = getrpacketblock(&state->rpacket);
    597     if(NEXT_BLOCKNUM(state->block) == rblock) {
    598       /* This is the expected block. Reset counters and ACK it. */
    599       state->retries = 0;
    600     }
    601     else if(state->block == rblock) {
    602       /* This is the last recently received block again. Log it and ACK it
    603          again. */
    604       infof(data, "Received last DATA packet block %d again.", rblock);
    605     }
    606     else {
    607       /* totally unexpected, just log it */
    608       infof(data,
    609             "Received unexpected DATA packet block %d, expecting block %d",
    610             rblock, NEXT_BLOCKNUM(state->block));
    611       break;
    612     }
    613 
    614     /* ACK this block. */
    615     state->block = (unsigned short)rblock;
    616     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
    617     setpacketblock(&state->spacket, state->block);
    618     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
    619                     4, SEND_4TH_ARG,
    620                     (struct sockaddr *)&state->remote_addr,
    621                     state->remote_addrlen);
    622     if(sbytes < 0) {
    623       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
    624       return CURLE_SEND_ERROR;
    625     }
    626 
    627     /* Check if completed (That is, a less than full packet is received) */
    628     if(state->rbytes < (ssize_t)state->blksize + 4) {
    629       state->state = TFTP_STATE_FIN;
    630     }
    631     else {
    632       state->state = TFTP_STATE_RX;
    633     }
    634     state->rx_time = time(NULL);
    635     break;
    636 
    637   case TFTP_EVENT_OACK:
    638     /* ACK option acknowledgement so we can move on to data */
    639     state->block = 0;
    640     state->retries = 0;
    641     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
    642     setpacketblock(&state->spacket, state->block);
    643     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
    644                     4, SEND_4TH_ARG,
    645                     (struct sockaddr *)&state->remote_addr,
    646                     state->remote_addrlen);
    647     if(sbytes < 0) {
    648       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
    649       return CURLE_SEND_ERROR;
    650     }
    651 
    652     /* we are ready to RX data */
    653     state->state = TFTP_STATE_RX;
    654     state->rx_time = time(NULL);
    655     break;
    656 
    657   case TFTP_EVENT_TIMEOUT:
    658     /* Increment the retry count and fail if over the limit */
    659     state->retries++;
    660     infof(data,
    661           "Timeout waiting for block %d ACK. Retries = %d",
    662           NEXT_BLOCKNUM(state->block), state->retries);
    663     if(state->retries > state->retry_max) {
    664       state->error = TFTP_ERR_TIMEOUT;
    665       state->state = TFTP_STATE_FIN;
    666     }
    667     else {
    668       /* Resend the previous ACK */
    669       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
    670                       4, SEND_4TH_ARG,
    671                       (struct sockaddr *)&state->remote_addr,
    672                       state->remote_addrlen);
    673       if(sbytes < 0) {
    674         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
    675         return CURLE_SEND_ERROR;
    676       }
    677     }
    678     break;
    679 
    680   case TFTP_EVENT_ERROR:
    681     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
    682     setpacketblock(&state->spacket, state->block);
    683     (void)sendto(state->sockfd, (void *)state->spacket.data,
    684                  4, SEND_4TH_ARG,
    685                  (struct sockaddr *)&state->remote_addr,
    686                  state->remote_addrlen);
    687     /* do not bother with the return code, but if the socket is still up we
    688      * should be a good TFTP client and let the server know we are done */
    689     state->state = TFTP_STATE_FIN;
    690     break;
    691 
    692   default:
    693     failf(data, "%s", "tftp_rx: internal error");
    694     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
    695                                   this */
    696   }
    697   return CURLE_OK;
    698 }
    699 
    700 /**********************************************************
    701  *
    702  * tftp_tx
    703  *
    704  * Event handler for the TX state
    705  *
    706  **********************************************************/
    707 static CURLcode tftp_tx(struct tftp_conn *state, tftp_event_t event)
    708 {
    709   struct Curl_easy *data = state->data;
    710   ssize_t sbytes;
    711   CURLcode result = CURLE_OK;
    712   struct SingleRequest *k = &data->req;
    713   size_t cb; /* Bytes currently read */
    714   char buffer[STRERROR_LEN];
    715   char *bufptr;
    716   bool eos;
    717 
    718   switch(event) {
    719 
    720   case TFTP_EVENT_ACK:
    721   case TFTP_EVENT_OACK:
    722     if(event == TFTP_EVENT_ACK) {
    723       /* Ack the packet */
    724       int rblock = getrpacketblock(&state->rpacket);
    725 
    726       if(rblock != state->block &&
    727          /* There is a bug in tftpd-hpa that causes it to send us an ack for
    728           * 65535 when the block number wraps to 0. So when we are expecting
    729           * 0, also accept 65535. See
    730           * https://www.syslinux.org/archives/2010-September/015612.html
    731           * */
    732          !(state->block == 0 && rblock == 65535)) {
    733         /* This is not the expected block. Log it and up the retry counter */
    734         infof(data, "Received ACK for block %d, expecting %d",
    735               rblock, state->block);
    736         state->retries++;
    737         /* Bail out if over the maximum */
    738         if(state->retries > state->retry_max) {
    739           failf(data, "tftp_tx: giving up waiting for block %d ack",
    740                 state->block);
    741           result = CURLE_SEND_ERROR;
    742         }
    743         else {
    744           /* Re-send the data packet */
    745           sbytes = sendto(state->sockfd, (void *)state->spacket.data,
    746                           4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
    747                           (struct sockaddr *)&state->remote_addr,
    748                           state->remote_addrlen);
    749           /* Check all sbytes were sent */
    750           if(sbytes < 0) {
    751             failf(data, "%s", Curl_strerror(SOCKERRNO,
    752                                             buffer, sizeof(buffer)));
    753             result = CURLE_SEND_ERROR;
    754           }
    755         }
    756 
    757         return result;
    758       }
    759       /* This is the expected packet. Reset the counters and send the next
    760          block */
    761       state->rx_time = time(NULL);
    762       state->block++;
    763     }
    764     else
    765       state->block = 1; /* first data block is 1 when using OACK */
    766 
    767     state->retries = 0;
    768     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
    769     setpacketblock(&state->spacket, state->block);
    770     if(state->block > 1 && state->sbytes < state->blksize) {
    771       state->state = TFTP_STATE_FIN;
    772       return CURLE_OK;
    773     }
    774 
    775     /* TFTP considers data block size < 512 bytes as an end of session. So
    776      * in some cases we must wait for additional data to build full (512 bytes)
    777      * data block.
    778      * */
    779     state->sbytes = 0;
    780     bufptr = (char *)state->spacket.data + 4;
    781     do {
    782       result = Curl_client_read(data, bufptr, state->blksize - state->sbytes,
    783                                 &cb, &eos);
    784       if(result)
    785         return result;
    786       state->sbytes += cb;
    787       bufptr += cb;
    788     } while(state->sbytes < state->blksize && cb);
    789 
    790     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
    791                     4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
    792                     (struct sockaddr *)&state->remote_addr,
    793                     state->remote_addrlen);
    794     /* Check all sbytes were sent */
    795     if(sbytes < 0) {
    796       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
    797       return CURLE_SEND_ERROR;
    798     }
    799     /* Update the progress meter */
    800     k->writebytecount += state->sbytes;
    801     Curl_pgrsSetUploadCounter(data, k->writebytecount);
    802     break;
    803 
    804   case TFTP_EVENT_TIMEOUT:
    805     /* Increment the retry counter and log the timeout */
    806     state->retries++;
    807     infof(data, "Timeout waiting for block %d ACK. "
    808           " Retries = %d", NEXT_BLOCKNUM(state->block), state->retries);
    809     /* Decide if we have had enough */
    810     if(state->retries > state->retry_max) {
    811       state->error = TFTP_ERR_TIMEOUT;
    812       state->state = TFTP_STATE_FIN;
    813     }
    814     else {
    815       /* Re-send the data packet */
    816       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
    817                       4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
    818                       (struct sockaddr *)&state->remote_addr,
    819                       state->remote_addrlen);
    820       /* Check all sbytes were sent */
    821       if(sbytes < 0) {
    822         failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
    823         return CURLE_SEND_ERROR;
    824       }
    825       /* since this was a re-send, we remain at the still byte position */
    826       Curl_pgrsSetUploadCounter(data, k->writebytecount);
    827     }
    828     break;
    829 
    830   case TFTP_EVENT_ERROR:
    831     state->state = TFTP_STATE_FIN;
    832     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
    833     setpacketblock(&state->spacket, state->block);
    834     (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
    835                  (struct sockaddr *)&state->remote_addr,
    836                  state->remote_addrlen);
    837     /* do not bother with the return code, but if the socket is still up we
    838      * should be a good TFTP client and let the server know we are done */
    839     state->state = TFTP_STATE_FIN;
    840     break;
    841 
    842   default:
    843     failf(data, "tftp_tx: internal error, event: %i", (int)(event));
    844     break;
    845   }
    846 
    847   return result;
    848 }
    849 
    850 /**********************************************************
    851  *
    852  * tftp_translate_code
    853  *
    854  * Translate internal error codes to CURL error codes
    855  *
    856  **********************************************************/
    857 static CURLcode tftp_translate_code(tftp_error_t error)
    858 {
    859   CURLcode result = CURLE_OK;
    860 
    861   if(error != TFTP_ERR_NONE) {
    862     switch(error) {
    863     case TFTP_ERR_NOTFOUND:
    864       result = CURLE_TFTP_NOTFOUND;
    865       break;
    866     case TFTP_ERR_PERM:
    867       result = CURLE_TFTP_PERM;
    868       break;
    869     case TFTP_ERR_DISKFULL:
    870       result = CURLE_REMOTE_DISK_FULL;
    871       break;
    872     case TFTP_ERR_UNDEF:
    873     case TFTP_ERR_ILLEGAL:
    874       result = CURLE_TFTP_ILLEGAL;
    875       break;
    876     case TFTP_ERR_UNKNOWNID:
    877       result = CURLE_TFTP_UNKNOWNID;
    878       break;
    879     case TFTP_ERR_EXISTS:
    880       result = CURLE_REMOTE_FILE_EXISTS;
    881       break;
    882     case TFTP_ERR_NOSUCHUSER:
    883       result = CURLE_TFTP_NOSUCHUSER;
    884       break;
    885     case TFTP_ERR_TIMEOUT:
    886       result = CURLE_OPERATION_TIMEDOUT;
    887       break;
    888     case TFTP_ERR_NORESPONSE:
    889       result = CURLE_COULDNT_CONNECT;
    890       break;
    891     default:
    892       result = CURLE_ABORTED_BY_CALLBACK;
    893       break;
    894     }
    895   }
    896   else
    897     result = CURLE_OK;
    898 
    899   return result;
    900 }
    901 
    902 /**********************************************************
    903  *
    904  * tftp_state_machine
    905  *
    906  * The tftp state machine event dispatcher
    907  *
    908  **********************************************************/
    909 static CURLcode tftp_state_machine(struct tftp_conn *state,
    910                                    tftp_event_t event)
    911 {
    912   CURLcode result = CURLE_OK;
    913   struct Curl_easy *data = state->data;
    914 
    915   switch(state->state) {
    916   case TFTP_STATE_START:
    917     DEBUGF(infof(data, "TFTP_STATE_START"));
    918     result = tftp_send_first(state, event);
    919     break;
    920   case TFTP_STATE_RX:
    921     DEBUGF(infof(data, "TFTP_STATE_RX"));
    922     result = tftp_rx(state, event);
    923     break;
    924   case TFTP_STATE_TX:
    925     DEBUGF(infof(data, "TFTP_STATE_TX"));
    926     result = tftp_tx(state, event);
    927     break;
    928   case TFTP_STATE_FIN:
    929     infof(data, "%s", "TFTP finished");
    930     break;
    931   default:
    932     DEBUGF(infof(data, "STATE: %d", state->state));
    933     failf(data, "%s", "Internal state machine error");
    934     result = CURLE_TFTP_ILLEGAL;
    935     break;
    936   }
    937 
    938   return result;
    939 }
    940 
    941 static void tftp_conn_dtor(void *key, size_t klen, void *entry)
    942 {
    943   struct tftp_conn *state = entry;
    944   (void)key;
    945   (void)klen;
    946   Curl_safefree(state->rpacket.data);
    947   Curl_safefree(state->spacket.data);
    948   free(state);
    949 }
    950 
    951 /**********************************************************
    952  *
    953  * tftp_connect
    954  *
    955  * The connect callback
    956  *
    957  **********************************************************/
    958 static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
    959 {
    960   struct tftp_conn *state;
    961   int blksize;
    962   int need_blksize;
    963   struct connectdata *conn = data->conn;
    964   const struct Curl_sockaddr_ex *remote_addr = NULL;
    965 
    966   blksize = TFTP_BLKSIZE_DEFAULT;
    967 
    968   state = calloc(1, sizeof(*state));
    969   if(!state ||
    970      Curl_conn_meta_set(conn, CURL_META_TFTP_CONN, state, tftp_conn_dtor))
    971     return CURLE_OUT_OF_MEMORY;
    972 
    973   /* alloc pkt buffers based on specified blksize */
    974   if(data->set.tftp_blksize)
    975     /* range checked when set */
    976     blksize = (int)data->set.tftp_blksize;
    977 
    978   need_blksize = blksize;
    979   /* default size is the fallback when no OACK is received */
    980   if(need_blksize < TFTP_BLKSIZE_DEFAULT)
    981     need_blksize = TFTP_BLKSIZE_DEFAULT;
    982 
    983   if(!state->rpacket.data) {
    984     state->rpacket.data = calloc(1, need_blksize + 2 + 2);
    985 
    986     if(!state->rpacket.data)
    987       return CURLE_OUT_OF_MEMORY;
    988   }
    989 
    990   if(!state->spacket.data) {
    991     state->spacket.data = calloc(1, need_blksize + 2 + 2);
    992 
    993     if(!state->spacket.data)
    994       return CURLE_OUT_OF_MEMORY;
    995   }
    996 
    997   /* we do not keep TFTP connections up basically because there is none or
    998    * little gain for UDP */
    999   connclose(conn, "TFTP");
   1000 
   1001   state->data = data;
   1002   state->sockfd = conn->sock[FIRSTSOCKET];
   1003   state->state = TFTP_STATE_START;
   1004   state->error = TFTP_ERR_NONE;
   1005   state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
   1006   state->requested_blksize = blksize;
   1007 
   1008   remote_addr = Curl_conn_get_remote_addr(data, FIRSTSOCKET);
   1009   DEBUGASSERT(remote_addr);
   1010   if(!remote_addr)
   1011     return CURLE_FAILED_INIT;
   1012 
   1013   ((struct sockaddr *)&state->local_addr)->sa_family =
   1014     (CURL_SA_FAMILY_T)(remote_addr->family);
   1015 
   1016   tftp_set_timeouts(state);
   1017 
   1018   if(!conn->bits.bound) {
   1019     /* If not already bound, bind to any interface, random UDP port. If it is
   1020      * reused or a custom local port was desired, this has already been done!
   1021      *
   1022      * We once used the size of the local_addr struct as the third argument
   1023      * for bind() to better work with IPv6 or whatever size the struct could
   1024      * have, but we learned that at least Tru64, AIX and IRIX *requires* the
   1025      * size of that argument to match the exact size of a 'sockaddr_in' struct
   1026      * when running IPv4-only.
   1027      *
   1028      * Therefore we use the size from the address we connected to, which we
   1029      * assume uses the same IP version and thus hopefully this works for both
   1030      * IPv4 and IPv6...
   1031      */
   1032     int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
   1033                   (curl_socklen_t)remote_addr->addrlen);
   1034     if(rc) {
   1035       char buffer[STRERROR_LEN];
   1036       failf(data, "bind() failed; %s",
   1037             Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
   1038       return CURLE_COULDNT_CONNECT;
   1039     }
   1040     conn->bits.bound = TRUE;
   1041   }
   1042 
   1043   Curl_pgrsStartNow(data);
   1044 
   1045   *done = TRUE;
   1046 
   1047   return CURLE_OK;
   1048 }
   1049 
   1050 /**********************************************************
   1051  *
   1052  * tftp_done
   1053  *
   1054  * The done callback
   1055  *
   1056  **********************************************************/
   1057 static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
   1058                           bool premature)
   1059 {
   1060   CURLcode result = CURLE_OK;
   1061   struct connectdata *conn = data->conn;
   1062   struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
   1063 
   1064   (void)status; /* unused */
   1065   (void)premature; /* not used */
   1066 
   1067   if(Curl_pgrsDone(data))
   1068     return CURLE_ABORTED_BY_CALLBACK;
   1069 
   1070   /* If we have encountered an error */
   1071   if(state)
   1072     result = tftp_translate_code(state->error);
   1073 
   1074   return result;
   1075 }
   1076 
   1077 /**********************************************************
   1078  *
   1079  * tftp_getsock
   1080  *
   1081  * The getsock callback
   1082  *
   1083  **********************************************************/
   1084 static int tftp_getsock(struct Curl_easy *data,
   1085                         struct connectdata *conn, curl_socket_t *socks)
   1086 {
   1087   (void)data;
   1088   socks[0] = conn->sock[FIRSTSOCKET];
   1089   return GETSOCK_READSOCK(0);
   1090 }
   1091 
   1092 /**********************************************************
   1093  *
   1094  * tftp_receive_packet
   1095  *
   1096  * Called once select fires and data is ready on the socket
   1097  *
   1098  **********************************************************/
   1099 static CURLcode tftp_receive_packet(struct Curl_easy *data,
   1100                                     struct tftp_conn *state)
   1101 {
   1102   curl_socklen_t        fromlen;
   1103   CURLcode              result = CURLE_OK;
   1104 
   1105   /* Receive the packet */
   1106   fromlen = sizeof(state->remote_addr);
   1107   state->rbytes = (int)recvfrom(state->sockfd,
   1108                                 (void *)state->rpacket.data,
   1109                                 (RECV_TYPE_ARG3)state->blksize + 4,
   1110                                 0,
   1111                                 (struct sockaddr *)&state->remote_addr,
   1112                                 &fromlen);
   1113   state->remote_addrlen = fromlen;
   1114 
   1115   /* Sanity check packet length */
   1116   if(state->rbytes < 4) {
   1117     failf(data, "Received too short packet");
   1118     /* Not a timeout, but how best to handle it? */
   1119     state->event = TFTP_EVENT_TIMEOUT;
   1120   }
   1121   else {
   1122     /* The event is given by the TFTP packet time */
   1123     unsigned short event = getrpacketevent(&state->rpacket);
   1124     state->event = (tftp_event_t)event;
   1125 
   1126     switch(state->event) {
   1127     case TFTP_EVENT_DATA:
   1128       /* Do not pass to the client empty or retransmitted packets */
   1129       if(state->rbytes > 4 &&
   1130          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
   1131         result = Curl_client_write(data, CLIENTWRITE_BODY,
   1132                                    (char *)state->rpacket.data + 4,
   1133                                    state->rbytes-4);
   1134         if(result) {
   1135           tftp_state_machine(state, TFTP_EVENT_ERROR);
   1136           return result;
   1137         }
   1138       }
   1139       break;
   1140     case TFTP_EVENT_ERROR:
   1141     {
   1142       unsigned short error = getrpacketblock(&state->rpacket);
   1143       char *str = (char *)state->rpacket.data + 4;
   1144       size_t strn = state->rbytes - 4;
   1145       state->error = (tftp_error_t)error;
   1146       if(tftp_strnlen(str, strn) < strn)
   1147         infof(data, "TFTP error: %s", str);
   1148       break;
   1149     }
   1150     case TFTP_EVENT_ACK:
   1151       break;
   1152     case TFTP_EVENT_OACK:
   1153       result = tftp_parse_option_ack(state,
   1154                                      (const char *)state->rpacket.data + 2,
   1155                                      state->rbytes-2);
   1156       if(result)
   1157         return result;
   1158       break;
   1159     case TFTP_EVENT_RRQ:
   1160     case TFTP_EVENT_WRQ:
   1161     default:
   1162       failf(data, "%s", "Internal error: Unexpected packet");
   1163       break;
   1164     }
   1165 
   1166     /* Update the progress meter */
   1167     if(Curl_pgrsUpdate(data)) {
   1168       tftp_state_machine(state, TFTP_EVENT_ERROR);
   1169       return CURLE_ABORTED_BY_CALLBACK;
   1170     }
   1171   }
   1172   return result;
   1173 }
   1174 
   1175 /**********************************************************
   1176  *
   1177  * tftp_state_timeout
   1178  *
   1179  * Check if timeouts have been reached
   1180  *
   1181  **********************************************************/
   1182 static timediff_t tftp_state_timeout(struct tftp_conn *state,
   1183                                      tftp_event_t *event)
   1184 {
   1185   time_t current;
   1186   timediff_t timeout_ms;
   1187 
   1188   if(event)
   1189     *event = TFTP_EVENT_NONE;
   1190 
   1191   timeout_ms = Curl_timeleft(state->data, NULL,
   1192                              (state->state == TFTP_STATE_START));
   1193   if(timeout_ms < 0) {
   1194     state->error = TFTP_ERR_TIMEOUT;
   1195     state->state = TFTP_STATE_FIN;
   1196     return 0;
   1197   }
   1198   current = time(NULL);
   1199   if(current > state->rx_time + state->retry_time) {
   1200     if(event)
   1201       *event = TFTP_EVENT_TIMEOUT;
   1202     state->rx_time = time(NULL); /* update even though we received nothing */
   1203   }
   1204 
   1205   return timeout_ms;
   1206 }
   1207 
   1208 /**********************************************************
   1209  *
   1210  * tftp_multi_statemach
   1211  *
   1212  * Handle single RX socket event and return
   1213  *
   1214  **********************************************************/
   1215 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
   1216 {
   1217   tftp_event_t event;
   1218   CURLcode result = CURLE_OK;
   1219   struct connectdata *conn = data->conn;
   1220   struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
   1221   timediff_t timeout_ms;
   1222 
   1223   *done = FALSE;
   1224   if(!state)
   1225     return CURLE_FAILED_INIT;
   1226 
   1227   timeout_ms = tftp_state_timeout(state, &event);
   1228   if(timeout_ms < 0) {
   1229     failf(data, "TFTP response timeout");
   1230     return CURLE_OPERATION_TIMEDOUT;
   1231   }
   1232   if(event != TFTP_EVENT_NONE) {
   1233     result = tftp_state_machine(state, event);
   1234     if(result)
   1235       return result;
   1236     *done = (state->state == TFTP_STATE_FIN);
   1237     if(*done)
   1238       /* Tell curl we are done */
   1239       Curl_xfer_setup_nop(data);
   1240   }
   1241   else {
   1242     /* no timeouts to handle, check our socket */
   1243     int rc = SOCKET_READABLE(state->sockfd, 0);
   1244 
   1245     if(rc == -1) {
   1246       /* bail out */
   1247       int error = SOCKERRNO;
   1248       char buffer[STRERROR_LEN];
   1249       failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
   1250       state->event = TFTP_EVENT_ERROR;
   1251     }
   1252     else if(rc) {
   1253       result = tftp_receive_packet(data, state);
   1254       if(result)
   1255         return result;
   1256       result = tftp_state_machine(state, state->event);
   1257       if(result)
   1258         return result;
   1259       *done = (state->state == TFTP_STATE_FIN);
   1260       if(*done)
   1261         /* Tell curl we are done */
   1262         Curl_xfer_setup_nop(data);
   1263     }
   1264     /* if rc == 0, then select() timed out */
   1265   }
   1266 
   1267   return result;
   1268 }
   1269 
   1270 /**********************************************************
   1271  *
   1272  * tftp_doing
   1273  *
   1274  * Called from multi.c while DOing
   1275  *
   1276  **********************************************************/
   1277 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
   1278 {
   1279   CURLcode result;
   1280   result = tftp_multi_statemach(data, dophase_done);
   1281 
   1282   if(*dophase_done) {
   1283     DEBUGF(infof(data, "DO phase is complete"));
   1284   }
   1285   else if(!result) {
   1286     /* The multi code does not have this logic for the DOING state so we
   1287        provide it for TFTP since it may do the entire transfer in this
   1288        state. */
   1289     if(Curl_pgrsUpdate(data))
   1290       result = CURLE_ABORTED_BY_CALLBACK;
   1291     else
   1292       result = Curl_speedcheck(data, curlx_now());
   1293   }
   1294   return result;
   1295 }
   1296 
   1297 /**********************************************************
   1298  *
   1299  * tftp_perform
   1300  *
   1301  * Entry point for transfer from tftp_do, starts state mach
   1302  *
   1303  **********************************************************/
   1304 static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
   1305 {
   1306   CURLcode result = CURLE_OK;
   1307   struct connectdata *conn = data->conn;
   1308   struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
   1309 
   1310   *dophase_done = FALSE;
   1311   if(!state)
   1312     return CURLE_FAILED_INIT;
   1313 
   1314   result = tftp_state_machine(state, TFTP_EVENT_INIT);
   1315 
   1316   if((state->state == TFTP_STATE_FIN) || result)
   1317     return result;
   1318 
   1319   tftp_multi_statemach(data, dophase_done);
   1320 
   1321   if(*dophase_done)
   1322     DEBUGF(infof(data, "DO phase is complete"));
   1323 
   1324   return result;
   1325 }
   1326 
   1327 
   1328 /**********************************************************
   1329  *
   1330  * tftp_do
   1331  *
   1332  * The do callback
   1333  *
   1334  * This callback initiates the TFTP transfer
   1335  *
   1336  **********************************************************/
   1337 
   1338 static CURLcode tftp_do(struct Curl_easy *data, bool *done)
   1339 {
   1340   struct connectdata *conn = data->conn;
   1341   struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
   1342   CURLcode result;
   1343 
   1344   *done = FALSE;
   1345 
   1346   if(!state) {
   1347     result = tftp_connect(data, done);
   1348     if(result)
   1349       return result;
   1350 
   1351     state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
   1352     if(!state)
   1353       return CURLE_TFTP_ILLEGAL;
   1354   }
   1355 
   1356   result = tftp_perform(data, done);
   1357 
   1358   /* If tftp_perform() returned an error, use that for return code. If it
   1359      was OK, see if tftp_translate_code() has an error. */
   1360   if(!result)
   1361     /* If we have encountered an internal tftp error, translate it. */
   1362     result = tftp_translate_code(state->error);
   1363 
   1364   return result;
   1365 }
   1366 
   1367 static CURLcode tftp_setup_connection(struct Curl_easy *data,
   1368                                       struct connectdata *conn)
   1369 {
   1370   char *type;
   1371 
   1372   conn->transport_wanted = TRNSPRT_UDP;
   1373 
   1374   /* TFTP URLs support an extension like ";mode=<typecode>" that
   1375    * we will try to get now! */
   1376   type = strstr(data->state.up.path, ";mode=");
   1377 
   1378   if(!type)
   1379     type = strstr(conn->host.rawalloc, ";mode=");
   1380 
   1381   if(type) {
   1382     char command;
   1383     *type = 0;                   /* it was in the middle of the hostname */
   1384     command = Curl_raw_toupper(type[6]);
   1385 
   1386     switch(command) {
   1387     case 'A': /* ASCII mode */
   1388     case 'N': /* NETASCII mode */
   1389       data->state.prefer_ascii = TRUE;
   1390       break;
   1391 
   1392     case 'O': /* octet mode */
   1393     case 'I': /* binary mode */
   1394     default:
   1395       /* switch off ASCII */
   1396       data->state.prefer_ascii = FALSE;
   1397       break;
   1398     }
   1399   }
   1400 
   1401   return CURLE_OK;
   1402 }
   1403 #endif