tftp.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #ifndef CURL_DISABLE_TFTP
00026 
00027 #ifdef HAVE_NETINET_IN_H
00028 #include <netinet/in.h>
00029 #endif
00030 #ifdef HAVE_NETDB_H
00031 #include <netdb.h>
00032 #endif
00033 #ifdef HAVE_ARPA_INET_H
00034 #include <arpa/inet.h>
00035 #endif
00036 #ifdef HAVE_NET_IF_H
00037 #include <net/if.h>
00038 #endif
00039 #ifdef HAVE_SYS_IOCTL_H
00040 #include <sys/ioctl.h>
00041 #endif
00042 
00043 #ifdef HAVE_SYS_PARAM_H
00044 #include <sys/param.h>
00045 #endif
00046 
00047 #include "urldata.h"
00048 #include <curl/curl.h>
00049 #include "transfer.h"
00050 #include "sendf.h"
00051 #include "tftp.h"
00052 #include "progress.h"
00053 #include "connect.h"
00054 #include "strerror.h"
00055 #include "sockaddr.h" /* required for Curl_sockaddr_storage */
00056 #include "multiif.h"
00057 #include "url.h"
00058 #include "strcase.h"
00059 #include "speedcheck.h"
00060 #include "select.h"
00061 #include "escape.h"
00062 
00063 /* The last 3 #include files should be in this order */
00064 #include "curl_printf.h"
00065 #include "curl_memory.h"
00066 #include "memdebug.h"
00067 
00068 /* RFC2348 allows the block size to be negotiated */
00069 #define TFTP_BLKSIZE_DEFAULT 512
00070 #define TFTP_BLKSIZE_MIN 8
00071 #define TFTP_BLKSIZE_MAX 65464
00072 #define TFTP_OPTION_BLKSIZE "blksize"
00073 
00074 /* from RFC2349: */
00075 #define TFTP_OPTION_TSIZE    "tsize"
00076 #define TFTP_OPTION_INTERVAL "timeout"
00077 
00078 typedef enum {
00079   TFTP_MODE_NETASCII=0,
00080   TFTP_MODE_OCTET
00081 } tftp_mode_t;
00082 
00083 typedef enum {
00084   TFTP_STATE_START=0,
00085   TFTP_STATE_RX,
00086   TFTP_STATE_TX,
00087   TFTP_STATE_FIN
00088 } tftp_state_t;
00089 
00090 typedef enum {
00091   TFTP_EVENT_NONE = -1,
00092   TFTP_EVENT_INIT = 0,
00093   TFTP_EVENT_RRQ = 1,
00094   TFTP_EVENT_WRQ = 2,
00095   TFTP_EVENT_DATA = 3,
00096   TFTP_EVENT_ACK = 4,
00097   TFTP_EVENT_ERROR = 5,
00098   TFTP_EVENT_OACK = 6,
00099   TFTP_EVENT_TIMEOUT
00100 } tftp_event_t;
00101 
00102 typedef enum {
00103   TFTP_ERR_UNDEF=0,
00104   TFTP_ERR_NOTFOUND,
00105   TFTP_ERR_PERM,
00106   TFTP_ERR_DISKFULL,
00107   TFTP_ERR_ILLEGAL,
00108   TFTP_ERR_UNKNOWNID,
00109   TFTP_ERR_EXISTS,
00110   TFTP_ERR_NOSUCHUSER,  /* This will never be triggered by this code */
00111 
00112   /* The remaining error codes are internal to curl */
00113   TFTP_ERR_NONE = -100,
00114   TFTP_ERR_TIMEOUT,
00115   TFTP_ERR_NORESPONSE
00116 } tftp_error_t;
00117 
00118 typedef struct tftp_packet {
00119   unsigned char *data;
00120 } tftp_packet_t;
00121 
00122 typedef struct tftp_state_data {
00123   tftp_state_t    state;
00124   tftp_mode_t     mode;
00125   tftp_error_t    error;
00126   tftp_event_t    event;
00127   struct connectdata      *conn;
00128   curl_socket_t   sockfd;
00129   int             retries;
00130   int             retry_time;
00131   int             retry_max;
00132   time_t          start_time;
00133   time_t          max_time;
00134   time_t          rx_time;
00135   unsigned short  block;
00136   struct Curl_sockaddr_storage   local_addr;
00137   struct Curl_sockaddr_storage   remote_addr;
00138   curl_socklen_t  remote_addrlen;
00139   int             rbytes;
00140   int             sbytes;
00141   int             blksize;
00142   int             requested_blksize;
00143   tftp_packet_t   rpacket;
00144   tftp_packet_t   spacket;
00145 } tftp_state_data_t;
00146 
00147 
00148 /* Forward declarations */
00149 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event);
00150 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event);
00151 static CURLcode tftp_connect(struct connectdata *conn, bool *done);
00152 static CURLcode tftp_disconnect(struct connectdata *conn,
00153                                 bool dead_connection);
00154 static CURLcode tftp_do(struct connectdata *conn, bool *done);
00155 static CURLcode tftp_done(struct connectdata *conn,
00156                           CURLcode, bool premature);
00157 static CURLcode tftp_setup_connection(struct connectdata * conn);
00158 static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
00159 static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
00160 static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
00161                         int numsocks);
00162 static CURLcode tftp_translate_code(tftp_error_t error);
00163 
00164 
00165 /*
00166  * TFTP protocol handler.
00167  */
00168 
00169 const struct Curl_handler Curl_handler_tftp = {
00170   "TFTP",                               /* scheme */
00171   tftp_setup_connection,                /* setup_connection */
00172   tftp_do,                              /* do_it */
00173   tftp_done,                            /* done */
00174   ZERO_NULL,                            /* do_more */
00175   tftp_connect,                         /* connect_it */
00176   tftp_multi_statemach,                 /* connecting */
00177   tftp_doing,                           /* doing */
00178   tftp_getsock,                         /* proto_getsock */
00179   tftp_getsock,                         /* doing_getsock */
00180   ZERO_NULL,                            /* domore_getsock */
00181   ZERO_NULL,                            /* perform_getsock */
00182   tftp_disconnect,                      /* disconnect */
00183   ZERO_NULL,                            /* readwrite */
00184   PORT_TFTP,                            /* defport */
00185   CURLPROTO_TFTP,                       /* protocol */
00186   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
00187 };
00188 
00189 /**********************************************************
00190  *
00191  * tftp_set_timeouts -
00192  *
00193  * Set timeouts based on state machine state.
00194  * Use user provided connect timeouts until DATA or ACK
00195  * packet is received, then use user-provided transfer timeouts
00196  *
00197  *
00198  **********************************************************/
00199 static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
00200 {
00201   time_t maxtime, timeout;
00202   time_t timeout_ms;
00203   bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
00204 
00205   time(&state->start_time);
00206 
00207   /* Compute drop-dead time */
00208   timeout_ms = Curl_timeleft(state->conn->data, NULL, start);
00209 
00210   if(timeout_ms < 0) {
00211     /* time-out, bail out, go home */
00212     failf(state->conn->data, "Connection time-out");
00213     return CURLE_OPERATION_TIMEDOUT;
00214   }
00215 
00216   if(start) {
00217 
00218     maxtime = (time_t)(timeout_ms + 500) / 1000;
00219     state->max_time = state->start_time+maxtime;
00220 
00221     /* Set per-block timeout to total */
00222     timeout = maxtime;
00223 
00224     /* Average restart after 5 seconds */
00225     state->retry_max = (int)timeout/5;
00226 
00227     if(state->retry_max < 1)
00228       /* avoid division by zero below */
00229       state->retry_max = 1;
00230 
00231     /* Compute the re-start interval to suit the timeout */
00232     state->retry_time = (int)timeout/state->retry_max;
00233     if(state->retry_time<1)
00234       state->retry_time=1;
00235 
00236   }
00237   else {
00238     if(timeout_ms > 0)
00239       maxtime = (time_t)(timeout_ms + 500) / 1000;
00240     else
00241       maxtime = 3600;
00242 
00243     state->max_time = state->start_time+maxtime;
00244 
00245     /* Set per-block timeout to total */
00246     timeout = maxtime;
00247 
00248     /* Average reposting an ACK after 5 seconds */
00249     state->retry_max = (int)timeout/5;
00250   }
00251   /* But bound the total number */
00252   if(state->retry_max<3)
00253     state->retry_max=3;
00254 
00255   if(state->retry_max>50)
00256     state->retry_max=50;
00257 
00258   /* Compute the re-ACK interval to suit the timeout */
00259   state->retry_time = (int)(timeout/state->retry_max);
00260   if(state->retry_time<1)
00261     state->retry_time=1;
00262 
00263   infof(state->conn->data,
00264         "set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
00265         (int)state->state, (long)(state->max_time-state->start_time),
00266         state->retry_time, state->retry_max);
00267 
00268   /* init RX time */
00269   time(&state->rx_time);
00270 
00271   return CURLE_OK;
00272 }
00273 
00274 /**********************************************************
00275  *
00276  * tftp_set_send_first
00277  *
00278  * Event handler for the START state
00279  *
00280  **********************************************************/
00281 
00282 static void setpacketevent(tftp_packet_t *packet, unsigned short num)
00283 {
00284   packet->data[0] = (unsigned char)(num >> 8);
00285   packet->data[1] = (unsigned char)(num & 0xff);
00286 }
00287 
00288 
00289 static void setpacketblock(tftp_packet_t *packet, unsigned short num)
00290 {
00291   packet->data[2] = (unsigned char)(num >> 8);
00292   packet->data[3] = (unsigned char)(num & 0xff);
00293 }
00294 
00295 static unsigned short getrpacketevent(const tftp_packet_t *packet)
00296 {
00297   return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
00298 }
00299 
00300 static unsigned short getrpacketblock(const tftp_packet_t *packet)
00301 {
00302   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
00303 }
00304 
00305 static size_t Curl_strnlen(const char *string, size_t maxlen)
00306 {
00307   const char *end = memchr(string, '\0', maxlen);
00308   return end ? (size_t) (end - string) : maxlen;
00309 }
00310 
00311 static const char *tftp_option_get(const char *buf, size_t len,
00312                                    const char **option, const char **value)
00313 {
00314   size_t loc;
00315 
00316   loc = Curl_strnlen(buf, len);
00317   loc++; /* NULL term */
00318 
00319   if(loc >= len)
00320     return NULL;
00321   *option = buf;
00322 
00323   loc += Curl_strnlen(buf+loc, len-loc);
00324   loc++; /* NULL term */
00325 
00326   if(loc > len)
00327     return NULL;
00328   *value = &buf[strlen(*option) + 1];
00329 
00330   return &buf[loc];
00331 }
00332 
00333 static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
00334                                       const char *ptr, int len)
00335 {
00336   const char *tmp = ptr;
00337   struct Curl_easy *data = state->conn->data;
00338 
00339   /* if OACK doesn't contain blksize option, the default (512) must be used */
00340   state->blksize = TFTP_BLKSIZE_DEFAULT;
00341 
00342   while(tmp < ptr + len) {
00343     const char *option, *value;
00344 
00345     tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
00346     if(tmp == NULL) {
00347       failf(data, "Malformed ACK packet, rejecting");
00348       return CURLE_TFTP_ILLEGAL;
00349     }
00350 
00351     infof(data, "got option=(%s) value=(%s)\n", option, value);
00352 
00353     if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
00354       long blksize;
00355 
00356       blksize = strtol(value, NULL, 10);
00357 
00358       if(!blksize) {
00359         failf(data, "invalid blocksize value in OACK packet");
00360         return CURLE_TFTP_ILLEGAL;
00361       }
00362       else if(blksize > TFTP_BLKSIZE_MAX) {
00363         failf(data, "%s (%d)", "blksize is larger than max supported",
00364               TFTP_BLKSIZE_MAX);
00365         return CURLE_TFTP_ILLEGAL;
00366       }
00367       else if(blksize < TFTP_BLKSIZE_MIN) {
00368         failf(data, "%s (%d)", "blksize is smaller than min supported",
00369               TFTP_BLKSIZE_MIN);
00370         return CURLE_TFTP_ILLEGAL;
00371       }
00372       else if(blksize > state->requested_blksize) {
00373         /* could realloc pkt buffers here, but the spec doesn't call out
00374          * support for the server requesting a bigger blksize than the client
00375          * requests */
00376         failf(data, "%s (%ld)",
00377               "server requested blksize larger than allocated", blksize);
00378         return CURLE_TFTP_ILLEGAL;
00379       }
00380 
00381       state->blksize = (int)blksize;
00382       infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
00383             state->blksize, "requested", state->requested_blksize);
00384     }
00385     else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
00386       long tsize = 0;
00387 
00388       tsize = strtol(value, NULL, 10);
00389       infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
00390 
00391       /* tsize should be ignored on upload: Who cares about the size of the
00392          remote file? */
00393       if(!data->set.upload) {
00394         if(!tsize) {
00395           failf(data, "invalid tsize -:%s:- value in OACK packet", value);
00396           return CURLE_TFTP_ILLEGAL;
00397         }
00398         Curl_pgrsSetDownloadSize(data, tsize);
00399       }
00400     }
00401   }
00402 
00403   return CURLE_OK;
00404 }
00405 
00406 static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
00407                               char *buf, const char *option)
00408 {
00409   if(( strlen(option) + csize + 1) > (size_t)state->blksize)
00410     return 0;
00411   strcpy(buf, option);
00412   return strlen(option) + 1;
00413 }
00414 
00415 static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
00416                                     tftp_event_t event)
00417 {
00418   CURLcode result;
00419 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00420   struct Curl_easy *data = state->conn->data;
00421 
00422   infof(data, "%s\n", "Connected for transmit");
00423 #endif
00424   state->state = TFTP_STATE_TX;
00425   result = tftp_set_timeouts(state);
00426   if(result)
00427     return result;
00428   return tftp_tx(state, event);
00429 }
00430 
00431 static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
00432                                     tftp_event_t event)
00433 {
00434   CURLcode result;
00435 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00436   struct Curl_easy *data = state->conn->data;
00437 
00438   infof(data, "%s\n", "Connected for receive");
00439 #endif
00440   state->state = TFTP_STATE_RX;
00441   result = tftp_set_timeouts(state);
00442   if(result)
00443     return result;
00444   return tftp_rx(state, event);
00445 }
00446 
00447 static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
00448 {
00449   size_t sbytes;
00450   ssize_t senddata;
00451   const char *mode = "octet";
00452   char *filename;
00453   char buf[64];
00454   struct Curl_easy *data = state->conn->data;
00455   CURLcode result = CURLE_OK;
00456 
00457   /* Set ascii mode if -B flag was used */
00458   if(data->set.prefer_ascii)
00459     mode = "netascii";
00460 
00461   switch(event) {
00462 
00463   case TFTP_EVENT_INIT:    /* Send the first packet out */
00464   case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
00465     /* Increment the retry counter, quit if over the limit */
00466     state->retries++;
00467     if(state->retries>state->retry_max) {
00468       state->error = TFTP_ERR_NORESPONSE;
00469       state->state = TFTP_STATE_FIN;
00470       return result;
00471     }
00472 
00473     if(data->set.upload) {
00474       /* If we are uploading, send an WRQ */
00475       setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
00476       state->conn->data->req.upload_fromhere =
00477         (char *)state->spacket.data+4;
00478       if(data->state.infilesize != -1)
00479         Curl_pgrsSetUploadSize(data, data->state.infilesize);
00480     }
00481     else {
00482       /* If we are downloading, send an RRQ */
00483       setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
00484     }
00485     /* As RFC3617 describes the separator slash is not actually part of the
00486        file name so we skip the always-present first letter of the path
00487        string. */
00488     result = Curl_urldecode(data, &state->conn->data->state.path[1], 0,
00489                             &filename, NULL, FALSE);
00490     if(result)
00491       return result;
00492 
00493     snprintf((char *)state->spacket.data+2,
00494              state->blksize,
00495              "%s%c%s%c", filename, '\0',  mode, '\0');
00496     sbytes = 4 + strlen(filename) + strlen(mode);
00497 
00498     /* optional addition of TFTP options */
00499     if(!data->set.tftp_no_options) {
00500       /* add tsize option */
00501       if(data->set.upload && (data->state.infilesize != -1))
00502         snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
00503                  data->state.infilesize);
00504       else
00505         strcpy(buf, "0"); /* the destination is large enough */
00506 
00507       sbytes += tftp_option_add(state, sbytes,
00508                                 (char *)state->spacket.data+sbytes,
00509                                 TFTP_OPTION_TSIZE);
00510       sbytes += tftp_option_add(state, sbytes,
00511                                 (char *)state->spacket.data+sbytes, buf);
00512       /* add blksize option */
00513       snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
00514       sbytes += tftp_option_add(state, sbytes,
00515                                 (char *)state->spacket.data+sbytes,
00516                                 TFTP_OPTION_BLKSIZE);
00517       sbytes += tftp_option_add(state, sbytes,
00518                                 (char *)state->spacket.data+sbytes, buf);
00519 
00520       /* add timeout option */
00521       snprintf(buf, sizeof(buf), "%d", state->retry_time);
00522       sbytes += tftp_option_add(state, sbytes,
00523                                 (char *)state->spacket.data+sbytes,
00524                                 TFTP_OPTION_INTERVAL);
00525       sbytes += tftp_option_add(state, sbytes,
00526                                 (char *)state->spacket.data+sbytes, buf);
00527     }
00528 
00529     /* the typecase for the 3rd argument is mostly for systems that do
00530        not have a size_t argument, like older unixes that want an 'int' */
00531     senddata = sendto(state->sockfd, (void *)state->spacket.data,
00532                       (SEND_TYPE_ARG3)sbytes, 0,
00533                       state->conn->ip_addr->ai_addr,
00534                       state->conn->ip_addr->ai_addrlen);
00535     if(senddata != (ssize_t)sbytes) {
00536       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00537     }
00538     free(filename);
00539     break;
00540 
00541   case TFTP_EVENT_OACK:
00542     if(data->set.upload) {
00543       result = tftp_connect_for_tx(state, event);
00544     }
00545     else {
00546       result = tftp_connect_for_rx(state, event);
00547     }
00548     break;
00549 
00550   case TFTP_EVENT_ACK: /* Connected for transmit */
00551     result = tftp_connect_for_tx(state, event);
00552     break;
00553 
00554   case TFTP_EVENT_DATA: /* Connected for receive */
00555     result = tftp_connect_for_rx(state, event);
00556     break;
00557 
00558   case TFTP_EVENT_ERROR:
00559     state->state = TFTP_STATE_FIN;
00560     break;
00561 
00562   default:
00563     failf(state->conn->data, "tftp_send_first: internal error");
00564     break;
00565   }
00566 
00567   return result;
00568 }
00569 
00570 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
00571    boundary */
00572 #define NEXT_BLOCKNUM(x) (((x)+1)&0xffff)
00573 
00574 /**********************************************************
00575  *
00576  * tftp_rx
00577  *
00578  * Event handler for the RX state
00579  *
00580  **********************************************************/
00581 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
00582 {
00583   ssize_t sbytes;
00584   int rblock;
00585   struct Curl_easy *data = state->conn->data;
00586 
00587   switch(event) {
00588 
00589   case TFTP_EVENT_DATA:
00590     /* Is this the block we expect? */
00591     rblock = getrpacketblock(&state->rpacket);
00592     if(NEXT_BLOCKNUM(state->block) == rblock) {
00593       /* This is the expected block.  Reset counters and ACK it. */
00594       state->retries = 0;
00595     }
00596     else if(state->block == rblock) {
00597       /* This is the last recently received block again. Log it and ACK it
00598          again. */
00599       infof(data, "Received last DATA packet block %d again.\n", rblock);
00600     }
00601     else {
00602       /* totally unexpected, just log it */
00603       infof(data,
00604             "Received unexpected DATA packet block %d, expecting block %d\n",
00605             rblock, NEXT_BLOCKNUM(state->block));
00606       break;
00607     }
00608 
00609     /* ACK this block. */
00610     state->block = (unsigned short)rblock;
00611     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
00612     setpacketblock(&state->spacket, state->block);
00613     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00614                     4, SEND_4TH_ARG,
00615                     (struct sockaddr *)&state->remote_addr,
00616                     state->remote_addrlen);
00617     if(sbytes < 0) {
00618       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00619       return CURLE_SEND_ERROR;
00620     }
00621 
00622     /* Check if completed (That is, a less than full packet is received) */
00623     if(state->rbytes < (ssize_t)state->blksize+4) {
00624       state->state = TFTP_STATE_FIN;
00625     }
00626     else {
00627       state->state = TFTP_STATE_RX;
00628     }
00629     time(&state->rx_time);
00630     break;
00631 
00632   case TFTP_EVENT_OACK:
00633     /* ACK option acknowledgement so we can move on to data */
00634     state->block = 0;
00635     state->retries = 0;
00636     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
00637     setpacketblock(&state->spacket, state->block);
00638     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00639                     4, SEND_4TH_ARG,
00640                     (struct sockaddr *)&state->remote_addr,
00641                     state->remote_addrlen);
00642     if(sbytes < 0) {
00643       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00644       return CURLE_SEND_ERROR;
00645     }
00646 
00647     /* we're ready to RX data */
00648     state->state = TFTP_STATE_RX;
00649     time(&state->rx_time);
00650     break;
00651 
00652   case TFTP_EVENT_TIMEOUT:
00653     /* Increment the retry count and fail if over the limit */
00654     state->retries++;
00655     infof(data,
00656           "Timeout waiting for block %d ACK.  Retries = %d\n",
00657           NEXT_BLOCKNUM(state->block), state->retries);
00658     if(state->retries > state->retry_max) {
00659       state->error = TFTP_ERR_TIMEOUT;
00660       state->state = TFTP_STATE_FIN;
00661     }
00662     else {
00663       /* Resend the previous ACK */
00664       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00665                       4, SEND_4TH_ARG,
00666                       (struct sockaddr *)&state->remote_addr,
00667                       state->remote_addrlen);
00668       if(sbytes<0) {
00669         failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00670         return CURLE_SEND_ERROR;
00671       }
00672     }
00673     break;
00674 
00675   case TFTP_EVENT_ERROR:
00676     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
00677     setpacketblock(&state->spacket, state->block);
00678     (void)sendto(state->sockfd, (void *)state->spacket.data,
00679                  4, SEND_4TH_ARG,
00680                  (struct sockaddr *)&state->remote_addr,
00681                  state->remote_addrlen);
00682     /* don't bother with the return code, but if the socket is still up we
00683      * should be a good TFTP client and let the server know we're done */
00684     state->state = TFTP_STATE_FIN;
00685     break;
00686 
00687   default:
00688     failf(data, "%s", "tftp_rx: internal error");
00689     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
00690                                   this */
00691   }
00692   return CURLE_OK;
00693 }
00694 
00695 /**********************************************************
00696  *
00697  * tftp_tx
00698  *
00699  * Event handler for the TX state
00700  *
00701  **********************************************************/
00702 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
00703 {
00704   struct Curl_easy *data = state->conn->data;
00705   ssize_t sbytes;
00706   int rblock;
00707   CURLcode result = CURLE_OK;
00708   struct SingleRequest *k = &data->req;
00709   int cb; /* Bytes currently read */
00710 
00711   switch(event) {
00712 
00713   case TFTP_EVENT_ACK:
00714   case TFTP_EVENT_OACK:
00715     if(event == TFTP_EVENT_ACK) {
00716       /* Ack the packet */
00717       rblock = getrpacketblock(&state->rpacket);
00718 
00719       if(rblock != state->block &&
00720          /* There's a bug in tftpd-hpa that causes it to send us an ack for
00721           * 65535 when the block number wraps to 0. So when we're expecting
00722           * 0, also accept 65535. See
00723           * http://syslinux.zytor.com/archives/2010-September/015253.html
00724           * */
00725          !(state->block == 0 && rblock == 65535)) {
00726         /* This isn't the expected block.  Log it and up the retry counter */
00727         infof(data, "Received ACK for block %d, expecting %d\n",
00728               rblock, state->block);
00729         state->retries++;
00730         /* Bail out if over the maximum */
00731         if(state->retries>state->retry_max) {
00732           failf(data, "tftp_tx: giving up waiting for block %d ack",
00733                 state->block);
00734           result = CURLE_SEND_ERROR;
00735         }
00736         else {
00737           /* Re-send the data packet */
00738           sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00739                           4+state->sbytes, SEND_4TH_ARG,
00740                           (struct sockaddr *)&state->remote_addr,
00741                           state->remote_addrlen);
00742           /* Check all sbytes were sent */
00743           if(sbytes<0) {
00744             failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00745             result = CURLE_SEND_ERROR;
00746           }
00747         }
00748 
00749         return result;
00750       }
00751       /* This is the expected packet.  Reset the counters and send the next
00752          block */
00753       time(&state->rx_time);
00754       state->block++;
00755     }
00756     else
00757       state->block = 1; /* first data block is 1 when using OACK */
00758 
00759     state->retries = 0;
00760     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
00761     setpacketblock(&state->spacket, state->block);
00762     if(state->block > 1 && state->sbytes < (int)state->blksize) {
00763       state->state = TFTP_STATE_FIN;
00764       return CURLE_OK;
00765     }
00766 
00767     /* TFTP considers data block size < 512 bytes as an end of session. So
00768      * in some cases we must wait for additional data to build full (512 bytes)
00769      * data block.
00770      * */
00771     state->sbytes = 0;
00772     state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4;
00773     do {
00774       result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes,
00775                                    &cb);
00776       if(result)
00777         return result;
00778       state->sbytes += cb;
00779       state->conn->data->req.upload_fromhere += cb;
00780     } while(state->sbytes < state->blksize && cb != 0);
00781 
00782     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
00783                     4 + state->sbytes, SEND_4TH_ARG,
00784                     (struct sockaddr *)&state->remote_addr,
00785                     state->remote_addrlen);
00786     /* Check all sbytes were sent */
00787     if(sbytes<0) {
00788       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00789       return CURLE_SEND_ERROR;
00790     }
00791     /* Update the progress meter */
00792     k->writebytecount += state->sbytes;
00793     Curl_pgrsSetUploadCounter(data, k->writebytecount);
00794     break;
00795 
00796   case TFTP_EVENT_TIMEOUT:
00797     /* Increment the retry counter and log the timeout */
00798     state->retries++;
00799     infof(data, "Timeout waiting for block %d ACK. "
00800           " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries);
00801     /* Decide if we've had enough */
00802     if(state->retries > state->retry_max) {
00803       state->error = TFTP_ERR_TIMEOUT;
00804       state->state = TFTP_STATE_FIN;
00805     }
00806     else {
00807       /* Re-send the data packet */
00808       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00809                       4+state->sbytes, SEND_4TH_ARG,
00810                       (struct sockaddr *)&state->remote_addr,
00811                       state->remote_addrlen);
00812       /* Check all sbytes were sent */
00813       if(sbytes<0) {
00814         failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00815         return CURLE_SEND_ERROR;
00816       }
00817       /* since this was a re-send, we remain at the still byte position */
00818       Curl_pgrsSetUploadCounter(data, k->writebytecount);
00819     }
00820     break;
00821 
00822   case TFTP_EVENT_ERROR:
00823     state->state = TFTP_STATE_FIN;
00824     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
00825     setpacketblock(&state->spacket, state->block);
00826     (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
00827                  (struct sockaddr *)&state->remote_addr,
00828                  state->remote_addrlen);
00829     /* don't bother with the return code, but if the socket is still up we
00830      * should be a good TFTP client and let the server know we're done */
00831     state->state = TFTP_STATE_FIN;
00832     break;
00833 
00834   default:
00835     failf(data, "tftp_tx: internal error, event: %i", (int)(event));
00836     break;
00837   }
00838 
00839   return result;
00840 }
00841 
00842 /**********************************************************
00843  *
00844  * tftp_translate_code
00845  *
00846  * Translate internal error codes to CURL error codes
00847  *
00848  **********************************************************/
00849 static CURLcode tftp_translate_code(tftp_error_t error)
00850 {
00851   CURLcode result = CURLE_OK;
00852 
00853   if(error != TFTP_ERR_NONE) {
00854     switch(error) {
00855     case TFTP_ERR_NOTFOUND:
00856       result = CURLE_TFTP_NOTFOUND;
00857       break;
00858     case TFTP_ERR_PERM:
00859       result = CURLE_TFTP_PERM;
00860       break;
00861     case TFTP_ERR_DISKFULL:
00862       result = CURLE_REMOTE_DISK_FULL;
00863       break;
00864     case TFTP_ERR_UNDEF:
00865     case TFTP_ERR_ILLEGAL:
00866       result = CURLE_TFTP_ILLEGAL;
00867       break;
00868     case TFTP_ERR_UNKNOWNID:
00869       result = CURLE_TFTP_UNKNOWNID;
00870       break;
00871     case TFTP_ERR_EXISTS:
00872       result = CURLE_REMOTE_FILE_EXISTS;
00873       break;
00874     case TFTP_ERR_NOSUCHUSER:
00875       result = CURLE_TFTP_NOSUCHUSER;
00876       break;
00877     case TFTP_ERR_TIMEOUT:
00878       result = CURLE_OPERATION_TIMEDOUT;
00879       break;
00880     case TFTP_ERR_NORESPONSE:
00881       result = CURLE_COULDNT_CONNECT;
00882       break;
00883     default:
00884       result = CURLE_ABORTED_BY_CALLBACK;
00885       break;
00886     }
00887   }
00888   else
00889     result = CURLE_OK;
00890 
00891   return result;
00892 }
00893 
00894 /**********************************************************
00895  *
00896  * tftp_state_machine
00897  *
00898  * The tftp state machine event dispatcher
00899  *
00900  **********************************************************/
00901 static CURLcode tftp_state_machine(tftp_state_data_t *state,
00902                                    tftp_event_t event)
00903 {
00904   CURLcode result = CURLE_OK;
00905   struct Curl_easy *data = state->conn->data;
00906 
00907   switch(state->state) {
00908   case TFTP_STATE_START:
00909     DEBUGF(infof(data, "TFTP_STATE_START\n"));
00910     result = tftp_send_first(state, event);
00911     break;
00912   case TFTP_STATE_RX:
00913     DEBUGF(infof(data, "TFTP_STATE_RX\n"));
00914     result = tftp_rx(state, event);
00915     break;
00916   case TFTP_STATE_TX:
00917     DEBUGF(infof(data, "TFTP_STATE_TX\n"));
00918     result = tftp_tx(state, event);
00919     break;
00920   case TFTP_STATE_FIN:
00921     infof(data, "%s\n", "TFTP finished");
00922     break;
00923   default:
00924     DEBUGF(infof(data, "STATE: %d\n", state->state));
00925     failf(data, "%s", "Internal state machine error");
00926     result = CURLE_TFTP_ILLEGAL;
00927     break;
00928   }
00929 
00930   return result;
00931 }
00932 
00933 /**********************************************************
00934  *
00935  * tftp_disconnect
00936  *
00937  * The disconnect callback
00938  *
00939  **********************************************************/
00940 static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
00941 {
00942   tftp_state_data_t *state = conn->proto.tftpc;
00943   (void) dead_connection;
00944 
00945   /* done, free dynamically allocated pkt buffers */
00946   if(state) {
00947     Curl_safefree(state->rpacket.data);
00948     Curl_safefree(state->spacket.data);
00949     free(state);
00950   }
00951 
00952   return CURLE_OK;
00953 }
00954 
00955 /**********************************************************
00956  *
00957  * tftp_connect
00958  *
00959  * The connect callback
00960  *
00961  **********************************************************/
00962 static CURLcode tftp_connect(struct connectdata *conn, bool *done)
00963 {
00964   tftp_state_data_t *state;
00965   int blksize, rc;
00966 
00967   blksize = TFTP_BLKSIZE_DEFAULT;
00968 
00969   state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
00970   if(!state)
00971     return CURLE_OUT_OF_MEMORY;
00972 
00973   /* alloc pkt buffers based on specified blksize */
00974   if(conn->data->set.tftp_blksize) {
00975     blksize = (int)conn->data->set.tftp_blksize;
00976     if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
00977       return CURLE_TFTP_ILLEGAL;
00978   }
00979 
00980   if(!state->rpacket.data) {
00981     state->rpacket.data = calloc(1, blksize + 2 + 2);
00982 
00983     if(!state->rpacket.data)
00984       return CURLE_OUT_OF_MEMORY;
00985   }
00986 
00987   if(!state->spacket.data) {
00988     state->spacket.data = calloc(1, blksize + 2 + 2);
00989 
00990     if(!state->spacket.data)
00991       return CURLE_OUT_OF_MEMORY;
00992   }
00993 
00994   /* we don't keep TFTP connections up basically because there's none or very
00995    * little gain for UDP */
00996   connclose(conn, "TFTP");
00997 
00998   state->conn = conn;
00999   state->sockfd = state->conn->sock[FIRSTSOCKET];
01000   state->state = TFTP_STATE_START;
01001   state->error = TFTP_ERR_NONE;
01002   state->blksize = TFTP_BLKSIZE_DEFAULT;
01003   state->requested_blksize = blksize;
01004 
01005   ((struct sockaddr *)&state->local_addr)->sa_family =
01006     (unsigned short)(conn->ip_addr->ai_family);
01007 
01008   tftp_set_timeouts(state);
01009 
01010   if(!conn->bits.bound) {
01011     /* If not already bound, bind to any interface, random UDP port. If it is
01012      * reused or a custom local port was desired, this has already been done!
01013      *
01014      * We once used the size of the local_addr struct as the third argument
01015      * for bind() to better work with IPv6 or whatever size the struct could
01016      * have, but we learned that at least Tru64, AIX and IRIX *requires* the
01017      * size of that argument to match the exact size of a 'sockaddr_in' struct
01018      * when running IPv4-only.
01019      *
01020      * Therefore we use the size from the address we connected to, which we
01021      * assume uses the same IP version and thus hopefully this works for both
01022      * IPv4 and IPv6...
01023      */
01024     rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
01025               conn->ip_addr->ai_addrlen);
01026     if(rc) {
01027       failf(conn->data, "bind() failed; %s",
01028             Curl_strerror(conn, SOCKERRNO));
01029       return CURLE_COULDNT_CONNECT;
01030     }
01031     conn->bits.bound = TRUE;
01032   }
01033 
01034   Curl_pgrsStartNow(conn->data);
01035 
01036   *done = TRUE;
01037 
01038   return CURLE_OK;
01039 }
01040 
01041 /**********************************************************
01042  *
01043  * tftp_done
01044  *
01045  * The done callback
01046  *
01047  **********************************************************/
01048 static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
01049                           bool premature)
01050 {
01051   CURLcode result = CURLE_OK;
01052   tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
01053 
01054   (void)status; /* unused */
01055   (void)premature; /* not used */
01056 
01057   if(Curl_pgrsDone(conn))
01058     return CURLE_ABORTED_BY_CALLBACK;
01059 
01060   /* If we have encountered an error */
01061   if(state)
01062     result = tftp_translate_code(state->error);
01063 
01064   return result;
01065 }
01066 
01067 /**********************************************************
01068  *
01069  * tftp_getsock
01070  *
01071  * The getsock callback
01072  *
01073  **********************************************************/
01074 static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
01075                         int numsocks)
01076 {
01077   if(!numsocks)
01078     return GETSOCK_BLANK;
01079 
01080   socks[0] = conn->sock[FIRSTSOCKET];
01081 
01082   return GETSOCK_READSOCK(0);
01083 }
01084 
01085 /**********************************************************
01086  *
01087  * tftp_receive_packet
01088  *
01089  * Called once select fires and data is ready on the socket
01090  *
01091  **********************************************************/
01092 static CURLcode tftp_receive_packet(struct connectdata *conn)
01093 {
01094   struct Curl_sockaddr_storage fromaddr;
01095   curl_socklen_t        fromlen;
01096   CURLcode              result = CURLE_OK;
01097   struct Curl_easy  *data = conn->data;
01098   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
01099   struct SingleRequest  *k = &data->req;
01100 
01101   /* Receive the packet */
01102   fromlen = sizeof(fromaddr);
01103   state->rbytes = (int)recvfrom(state->sockfd,
01104                                 (void *)state->rpacket.data,
01105                                 state->blksize+4,
01106                                 0,
01107                                 (struct sockaddr *)&fromaddr,
01108                                 &fromlen);
01109   if(state->remote_addrlen==0) {
01110     memcpy(&state->remote_addr, &fromaddr, fromlen);
01111     state->remote_addrlen = fromlen;
01112   }
01113 
01114   /* Sanity check packet length */
01115   if(state->rbytes < 4) {
01116     failf(data, "Received too short packet");
01117     /* Not a timeout, but how best to handle it? */
01118     state->event = TFTP_EVENT_TIMEOUT;
01119   }
01120   else {
01121     /* The event is given by the TFTP packet time */
01122     state->event = (tftp_event_t)getrpacketevent(&state->rpacket);
01123 
01124     switch(state->event) {
01125     case TFTP_EVENT_DATA:
01126       /* Don't pass to the client empty or retransmitted packets */
01127       if(state->rbytes > 4 &&
01128          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
01129         result = Curl_client_write(conn, CLIENTWRITE_BODY,
01130                                    (char *)state->rpacket.data+4,
01131                                    state->rbytes-4);
01132         if(result) {
01133           tftp_state_machine(state, TFTP_EVENT_ERROR);
01134           return result;
01135         }
01136         k->bytecount += state->rbytes-4;
01137         Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
01138       }
01139       break;
01140     case TFTP_EVENT_ERROR:
01141       state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
01142       infof(data, "%s\n", (const char *)state->rpacket.data+4);
01143       break;
01144     case TFTP_EVENT_ACK:
01145       break;
01146     case TFTP_EVENT_OACK:
01147       result = tftp_parse_option_ack(state,
01148                                      (const char *)state->rpacket.data+2,
01149                                      state->rbytes-2);
01150       if(result)
01151         return result;
01152       break;
01153     case TFTP_EVENT_RRQ:
01154     case TFTP_EVENT_WRQ:
01155     default:
01156       failf(data, "%s", "Internal error: Unexpected packet");
01157       break;
01158     }
01159 
01160     /* Update the progress meter */
01161     if(Curl_pgrsUpdate(conn)) {
01162       tftp_state_machine(state, TFTP_EVENT_ERROR);
01163       return CURLE_ABORTED_BY_CALLBACK;
01164     }
01165   }
01166   return result;
01167 }
01168 
01169 /**********************************************************
01170  *
01171  * tftp_state_timeout
01172  *
01173  * Check if timeouts have been reached
01174  *
01175  **********************************************************/
01176 static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
01177 {
01178   time_t                current;
01179   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
01180 
01181   if(event)
01182     *event = TFTP_EVENT_NONE;
01183 
01184   time(&current);
01185   if(current > state->max_time) {
01186     DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
01187                  (long)current, (long)state->max_time));
01188     state->error = TFTP_ERR_TIMEOUT;
01189     state->state = TFTP_STATE_FIN;
01190     return 0;
01191   }
01192   else if(current > state->rx_time+state->retry_time) {
01193     if(event)
01194       *event = TFTP_EVENT_TIMEOUT;
01195     time(&state->rx_time); /* update even though we received nothing */
01196   }
01197 
01198   /* there's a typecast below here since 'time_t' may in fact be larger than
01199      'long', but we estimate that a 'long' will still be able to hold number
01200      of seconds even if "only" 32 bit */
01201   return (long)(state->max_time - current);
01202 }
01203 
01204 /**********************************************************
01205  *
01206  * tftp_multi_statemach
01207  *
01208  * Handle single RX socket event and return
01209  *
01210  **********************************************************/
01211 static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
01212 {
01213   int                   rc;
01214   tftp_event_t          event;
01215   CURLcode              result = CURLE_OK;
01216   struct Curl_easy  *data = conn->data;
01217   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
01218   long                  timeout_ms = tftp_state_timeout(conn, &event);
01219 
01220   *done = FALSE;
01221 
01222   if(timeout_ms <= 0) {
01223     failf(data, "TFTP response timeout");
01224     return CURLE_OPERATION_TIMEDOUT;
01225   }
01226   else if(event != TFTP_EVENT_NONE) {
01227     result = tftp_state_machine(state, event);
01228     if(result)
01229       return result;
01230     *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
01231     if(*done)
01232       /* Tell curl we're done */
01233       Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01234   }
01235   else {
01236     /* no timeouts to handle, check our socket */
01237     rc = SOCKET_READABLE(state->sockfd, 0);
01238 
01239     if(rc == -1) {
01240       /* bail out */
01241       int error = SOCKERRNO;
01242       failf(data, "%s", Curl_strerror(conn, error));
01243       state->event = TFTP_EVENT_ERROR;
01244     }
01245     else if(rc != 0) {
01246       result = tftp_receive_packet(conn);
01247       if(result)
01248         return result;
01249       result = tftp_state_machine(state, state->event);
01250       if(result)
01251         return result;
01252       *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
01253       if(*done)
01254         /* Tell curl we're done */
01255         Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01256     }
01257     /* if rc == 0, then select() timed out */
01258   }
01259 
01260   return result;
01261 }
01262 
01263 /**********************************************************
01264  *
01265  * tftp_doing
01266  *
01267  * Called from multi.c while DOing
01268  *
01269  **********************************************************/
01270 static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
01271 {
01272   CURLcode result;
01273   result = tftp_multi_statemach(conn, dophase_done);
01274 
01275   if(*dophase_done) {
01276     DEBUGF(infof(conn->data, "DO phase is complete\n"));
01277   }
01278   else if(!result) {
01279     /* The multi code doesn't have this logic for the DOING state so we
01280        provide it for TFTP since it may do the entire transfer in this
01281        state. */
01282     if(Curl_pgrsUpdate(conn))
01283       result = CURLE_ABORTED_BY_CALLBACK;
01284     else
01285       result = Curl_speedcheck(conn->data, Curl_tvnow());
01286   }
01287   return result;
01288 }
01289 
01290 /**********************************************************
01291  *
01292  * tftp_peform
01293  *
01294  * Entry point for transfer from tftp_do, sarts state mach
01295  *
01296  **********************************************************/
01297 static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
01298 {
01299   CURLcode              result = CURLE_OK;
01300   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
01301 
01302   *dophase_done = FALSE;
01303 
01304   result = tftp_state_machine(state, TFTP_EVENT_INIT);
01305 
01306   if((state->state == TFTP_STATE_FIN) || result)
01307     return result;
01308 
01309   tftp_multi_statemach(conn, dophase_done);
01310 
01311   if(*dophase_done)
01312     DEBUGF(infof(conn->data, "DO phase is complete\n"));
01313 
01314   return result;
01315 }
01316 
01317 
01318 /**********************************************************
01319  *
01320  * tftp_do
01321  *
01322  * The do callback
01323  *
01324  * This callback initiates the TFTP transfer
01325  *
01326  **********************************************************/
01327 
01328 static CURLcode tftp_do(struct connectdata *conn, bool *done)
01329 {
01330   tftp_state_data_t *state;
01331   CURLcode result;
01332 
01333   *done = FALSE;
01334 
01335   if(!conn->proto.tftpc) {
01336     result = tftp_connect(conn, done);
01337     if(result)
01338       return result;
01339   }
01340 
01341   state = (tftp_state_data_t *)conn->proto.tftpc;
01342   if(!state)
01343     return CURLE_BAD_CALLING_ORDER;
01344 
01345   result = tftp_perform(conn, done);
01346 
01347   /* If tftp_perform() returned an error, use that for return code. If it
01348      was OK, see if tftp_translate_code() has an error. */
01349   if(!result)
01350     /* If we have encountered an internal tftp error, translate it. */
01351     result = tftp_translate_code(state->error);
01352 
01353   return result;
01354 }
01355 
01356 static CURLcode tftp_setup_connection(struct connectdata * conn)
01357 {
01358   struct Curl_easy *data = conn->data;
01359   char *type;
01360   char command;
01361 
01362   conn->socktype = SOCK_DGRAM;   /* UDP datagram based */
01363 
01364   /* TFTP URLs support an extension like ";mode=<typecode>" that
01365    * we'll try to get now! */
01366   type = strstr(data->state.path, ";mode=");
01367 
01368   if(!type)
01369     type = strstr(conn->host.rawalloc, ";mode=");
01370 
01371   if(type) {
01372     *type = 0;                   /* it was in the middle of the hostname */
01373     command = Curl_raw_toupper(type[6]);
01374 
01375     switch(command) {
01376     case 'A': /* ASCII mode */
01377     case 'N': /* NETASCII mode */
01378       data->set.prefer_ascii = TRUE;
01379       break;
01380 
01381     case 'O': /* octet mode */
01382     case 'I': /* binary mode */
01383     default:
01384       /* switch off ASCII */
01385       data->set.prefer_ascii = FALSE;
01386       break;
01387     }
01388   }
01389 
01390   return CURLE_OK;
01391 }
01392 #endif


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:06