Annotation of embedaddon/curl/lib/tftp.c, revision 1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>