• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2016, 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                         int numsocks);
162 static CURLcode tftp_translate_code(tftp_error_t error);
163 
164 
165 /*
166  * TFTP protocol handler.
167  */
168 
169 const struct Curl_handler Curl_handler_tftp = {
170   "TFTP",                               /* scheme */
171   tftp_setup_connection,                /* setup_connection */
172   tftp_do,                              /* do_it */
173   tftp_done,                            /* done */
174   ZERO_NULL,                            /* do_more */
175   tftp_connect,                         /* connect_it */
176   tftp_multi_statemach,                 /* connecting */
177   tftp_doing,                           /* doing */
178   tftp_getsock,                         /* proto_getsock */
179   tftp_getsock,                         /* doing_getsock */
180   ZERO_NULL,                            /* domore_getsock */
181   ZERO_NULL,                            /* perform_getsock */
182   tftp_disconnect,                      /* disconnect */
183   ZERO_NULL,                            /* readwrite */
184   PORT_TFTP,                            /* defport */
185   CURLPROTO_TFTP,                       /* protocol */
186   PROTOPT_NONE | PROTOPT_NOURLQUERY     /* flags */
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  **********************************************************/
tftp_set_timeouts(tftp_state_data_t * state)199 static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
200 {
201   time_t maxtime, timeout;
202   time_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 
setpacketevent(tftp_packet_t * packet,unsigned short num)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 
setpacketblock(tftp_packet_t * packet,unsigned short num)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 
getrpacketevent(const tftp_packet_t * packet)295 static unsigned short getrpacketevent(const tftp_packet_t *packet)
296 {
297   return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
298 }
299 
getrpacketblock(const tftp_packet_t * packet)300 static unsigned short getrpacketblock(const tftp_packet_t *packet)
301 {
302   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
303 }
304 
Curl_strnlen(const char * string,size_t maxlen)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 
tftp_option_get(const char * buf,size_t len,const char ** option,const char ** value)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 
tftp_parse_option_ack(tftp_state_data_t * state,const char * ptr,int len)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       else 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 
tftp_option_add(tftp_state_data_t * state,size_t csize,char * buf,const char * option)406 static size_t 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 0;
411   strcpy(buf, option);
412   return strlen(option) + 1;
413 }
414 
tftp_connect_for_tx(tftp_state_data_t * state,tftp_event_t event)415 static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
416                                     tftp_event_t event)
417 {
418   CURLcode result;
419 #ifndef CURL_DISABLE_VERBOSE_STRINGS
420   struct Curl_easy *data = state->conn->data;
421 
422   infof(data, "%s\n", "Connected for transmit");
423 #endif
424   state->state = TFTP_STATE_TX;
425   result = tftp_set_timeouts(state);
426   if(result)
427     return result;
428   return tftp_tx(state, event);
429 }
430 
tftp_connect_for_rx(tftp_state_data_t * state,tftp_event_t event)431 static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
432                                     tftp_event_t event)
433 {
434   CURLcode result;
435 #ifndef CURL_DISABLE_VERBOSE_STRINGS
436   struct Curl_easy *data = state->conn->data;
437 
438   infof(data, "%s\n", "Connected for receive");
439 #endif
440   state->state = TFTP_STATE_RX;
441   result = tftp_set_timeouts(state);
442   if(result)
443     return result;
444   return tftp_rx(state, event);
445 }
446 
tftp_send_first(tftp_state_data_t * state,tftp_event_t event)447 static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
448 {
449   size_t sbytes;
450   ssize_t senddata;
451   const char *mode = "octet";
452   char *filename;
453   char buf[64];
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.path[1], 0,
489                             &filename, NULL, FALSE);
490     if(result)
491       return result;
492 
493     snprintf((char *)state->spacket.data+2,
494              state->blksize,
495              "%s%c%s%c", filename, '\0',  mode, '\0');
496     sbytes = 4 + strlen(filename) + strlen(mode);
497 
498     /* optional addition of TFTP options */
499     if(!data->set.tftp_no_options) {
500       /* add tsize option */
501       if(data->set.upload && (data->state.infilesize != -1))
502         snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
503                  data->state.infilesize);
504       else
505         strcpy(buf, "0"); /* the destination is large enough */
506 
507       sbytes += tftp_option_add(state, sbytes,
508                                 (char *)state->spacket.data+sbytes,
509                                 TFTP_OPTION_TSIZE);
510       sbytes += tftp_option_add(state, sbytes,
511                                 (char *)state->spacket.data+sbytes, buf);
512       /* add blksize option */
513       snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
514       sbytes += tftp_option_add(state, sbytes,
515                                 (char *)state->spacket.data+sbytes,
516                                 TFTP_OPTION_BLKSIZE);
517       sbytes += tftp_option_add(state, sbytes,
518                                 (char *)state->spacket.data+sbytes, buf);
519 
520       /* add timeout option */
521       snprintf(buf, sizeof(buf), "%d", state->retry_time);
522       sbytes += tftp_option_add(state, sbytes,
523                                 (char *)state->spacket.data+sbytes,
524                                 TFTP_OPTION_INTERVAL);
525       sbytes += tftp_option_add(state, sbytes,
526                                 (char *)state->spacket.data+sbytes, buf);
527     }
528 
529     /* the typecase for the 3rd argument is mostly for systems that do
530        not have a size_t argument, like older unixes that want an 'int' */
531     senddata = sendto(state->sockfd, (void *)state->spacket.data,
532                       (SEND_TYPE_ARG3)sbytes, 0,
533                       state->conn->ip_addr->ai_addr,
534                       state->conn->ip_addr->ai_addrlen);
535     if(senddata != (ssize_t)sbytes) {
536       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
537     }
538     free(filename);
539     break;
540 
541   case TFTP_EVENT_OACK:
542     if(data->set.upload) {
543       result = tftp_connect_for_tx(state, event);
544     }
545     else {
546       result = tftp_connect_for_rx(state, event);
547     }
548     break;
549 
550   case TFTP_EVENT_ACK: /* Connected for transmit */
551     result = tftp_connect_for_tx(state, event);
552     break;
553 
554   case TFTP_EVENT_DATA: /* Connected for receive */
555     result = tftp_connect_for_rx(state, event);
556     break;
557 
558   case TFTP_EVENT_ERROR:
559     state->state = TFTP_STATE_FIN;
560     break;
561 
562   default:
563     failf(state->conn->data, "tftp_send_first: internal error");
564     break;
565   }
566 
567   return result;
568 }
569 
570 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
571    boundary */
572 #define NEXT_BLOCKNUM(x) (((x)+1)&0xffff)
573 
574 /**********************************************************
575  *
576  * tftp_rx
577  *
578  * Event handler for the RX state
579  *
580  **********************************************************/
tftp_rx(tftp_state_data_t * state,tftp_event_t event)581 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
582 {
583   ssize_t sbytes;
584   int rblock;
585   struct Curl_easy *data = state->conn->data;
586 
587   switch(event) {
588 
589   case TFTP_EVENT_DATA:
590     /* Is this the block we expect? */
591     rblock = getrpacketblock(&state->rpacket);
592     if(NEXT_BLOCKNUM(state->block) == rblock) {
593       /* This is the expected block.  Reset counters and ACK it. */
594       state->retries = 0;
595     }
596     else if(state->block == rblock) {
597       /* This is the last recently received block again. Log it and ACK it
598          again. */
599       infof(data, "Received last DATA packet block %d again.\n", rblock);
600     }
601     else {
602       /* totally unexpected, just log it */
603       infof(data,
604             "Received unexpected DATA packet block %d, expecting block %d\n",
605             rblock, NEXT_BLOCKNUM(state->block));
606       break;
607     }
608 
609     /* ACK this block. */
610     state->block = (unsigned short)rblock;
611     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
612     setpacketblock(&state->spacket, state->block);
613     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
614                     4, SEND_4TH_ARG,
615                     (struct sockaddr *)&state->remote_addr,
616                     state->remote_addrlen);
617     if(sbytes < 0) {
618       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
619       return CURLE_SEND_ERROR;
620     }
621 
622     /* Check if completed (That is, a less than full packet is received) */
623     if(state->rbytes < (ssize_t)state->blksize+4) {
624       state->state = TFTP_STATE_FIN;
625     }
626     else {
627       state->state = TFTP_STATE_RX;
628     }
629     time(&state->rx_time);
630     break;
631 
632   case TFTP_EVENT_OACK:
633     /* ACK option acknowledgement so we can move on to data */
634     state->block = 0;
635     state->retries = 0;
636     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
637     setpacketblock(&state->spacket, state->block);
638     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
639                     4, SEND_4TH_ARG,
640                     (struct sockaddr *)&state->remote_addr,
641                     state->remote_addrlen);
642     if(sbytes < 0) {
643       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
644       return CURLE_SEND_ERROR;
645     }
646 
647     /* we're ready to RX data */
648     state->state = TFTP_STATE_RX;
649     time(&state->rx_time);
650     break;
651 
652   case TFTP_EVENT_TIMEOUT:
653     /* Increment the retry count and fail if over the limit */
654     state->retries++;
655     infof(data,
656           "Timeout waiting for block %d ACK.  Retries = %d\n",
657           NEXT_BLOCKNUM(state->block), state->retries);
658     if(state->retries > state->retry_max) {
659       state->error = TFTP_ERR_TIMEOUT;
660       state->state = TFTP_STATE_FIN;
661     }
662     else {
663       /* Resend the previous ACK */
664       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
665                       4, SEND_4TH_ARG,
666                       (struct sockaddr *)&state->remote_addr,
667                       state->remote_addrlen);
668       if(sbytes<0) {
669         failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
670         return CURLE_SEND_ERROR;
671       }
672     }
673     break;
674 
675   case TFTP_EVENT_ERROR:
676     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
677     setpacketblock(&state->spacket, state->block);
678     (void)sendto(state->sockfd, (void *)state->spacket.data,
679                  4, SEND_4TH_ARG,
680                  (struct sockaddr *)&state->remote_addr,
681                  state->remote_addrlen);
682     /* don't bother with the return code, but if the socket is still up we
683      * should be a good TFTP client and let the server know we're done */
684     state->state = TFTP_STATE_FIN;
685     break;
686 
687   default:
688     failf(data, "%s", "tftp_rx: internal error");
689     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
690                                   this */
691   }
692   return CURLE_OK;
693 }
694 
695 /**********************************************************
696  *
697  * tftp_tx
698  *
699  * Event handler for the TX state
700  *
701  **********************************************************/
tftp_tx(tftp_state_data_t * state,tftp_event_t event)702 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
703 {
704   struct Curl_easy *data = state->conn->data;
705   ssize_t sbytes;
706   int rblock;
707   CURLcode result = CURLE_OK;
708   struct SingleRequest *k = &data->req;
709   int cb; /* Bytes currently read */
710 
711   switch(event) {
712 
713   case TFTP_EVENT_ACK:
714   case TFTP_EVENT_OACK:
715     if(event == TFTP_EVENT_ACK) {
716       /* Ack the packet */
717       rblock = getrpacketblock(&state->rpacket);
718 
719       if(rblock != state->block &&
720          /* There's a bug in tftpd-hpa that causes it to send us an ack for
721           * 65535 when the block number wraps to 0. So when we're expecting
722           * 0, also accept 65535. See
723           * http://syslinux.zytor.com/archives/2010-September/015253.html
724           * */
725          !(state->block == 0 && rblock == 65535)) {
726         /* This isn't the expected block.  Log it and up the retry counter */
727         infof(data, "Received ACK for block %d, expecting %d\n",
728               rblock, state->block);
729         state->retries++;
730         /* Bail out if over the maximum */
731         if(state->retries>state->retry_max) {
732           failf(data, "tftp_tx: giving up waiting for block %d ack",
733                 state->block);
734           result = CURLE_SEND_ERROR;
735         }
736         else {
737           /* Re-send the data packet */
738           sbytes = sendto(state->sockfd, (void *)state->spacket.data,
739                           4+state->sbytes, SEND_4TH_ARG,
740                           (struct sockaddr *)&state->remote_addr,
741                           state->remote_addrlen);
742           /* Check all sbytes were sent */
743           if(sbytes<0) {
744             failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
745             result = CURLE_SEND_ERROR;
746           }
747         }
748 
749         return result;
750       }
751       /* This is the expected packet.  Reset the counters and send the next
752          block */
753       time(&state->rx_time);
754       state->block++;
755     }
756     else
757       state->block = 1; /* first data block is 1 when using OACK */
758 
759     state->retries = 0;
760     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
761     setpacketblock(&state->spacket, state->block);
762     if(state->block > 1 && state->sbytes < (int)state->blksize) {
763       state->state = TFTP_STATE_FIN;
764       return CURLE_OK;
765     }
766 
767     /* TFTP considers data block size < 512 bytes as an end of session. So
768      * in some cases we must wait for additional data to build full (512 bytes)
769      * data block.
770      * */
771     state->sbytes = 0;
772     state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4;
773     do {
774       result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes,
775                                    &cb);
776       if(result)
777         return result;
778       state->sbytes += cb;
779       state->conn->data->req.upload_fromhere += cb;
780     } while(state->sbytes < state->blksize && cb != 0);
781 
782     sbytes = sendto(state->sockfd, (void *) state->spacket.data,
783                     4 + state->sbytes, SEND_4TH_ARG,
784                     (struct sockaddr *)&state->remote_addr,
785                     state->remote_addrlen);
786     /* Check all sbytes were sent */
787     if(sbytes<0) {
788       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
789       return CURLE_SEND_ERROR;
790     }
791     /* Update the progress meter */
792     k->writebytecount += state->sbytes;
793     Curl_pgrsSetUploadCounter(data, k->writebytecount);
794     break;
795 
796   case TFTP_EVENT_TIMEOUT:
797     /* Increment the retry counter and log the timeout */
798     state->retries++;
799     infof(data, "Timeout waiting for block %d ACK. "
800           " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries);
801     /* Decide if we've had enough */
802     if(state->retries > state->retry_max) {
803       state->error = TFTP_ERR_TIMEOUT;
804       state->state = TFTP_STATE_FIN;
805     }
806     else {
807       /* Re-send the data packet */
808       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
809                       4+state->sbytes, SEND_4TH_ARG,
810                       (struct sockaddr *)&state->remote_addr,
811                       state->remote_addrlen);
812       /* Check all sbytes were sent */
813       if(sbytes<0) {
814         failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
815         return CURLE_SEND_ERROR;
816       }
817       /* since this was a re-send, we remain at the still byte position */
818       Curl_pgrsSetUploadCounter(data, k->writebytecount);
819     }
820     break;
821 
822   case TFTP_EVENT_ERROR:
823     state->state = TFTP_STATE_FIN;
824     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
825     setpacketblock(&state->spacket, state->block);
826     (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
827                  (struct sockaddr *)&state->remote_addr,
828                  state->remote_addrlen);
829     /* don't bother with the return code, but if the socket is still up we
830      * should be a good TFTP client and let the server know we're done */
831     state->state = TFTP_STATE_FIN;
832     break;
833 
834   default:
835     failf(data, "tftp_tx: internal error, event: %i", (int)(event));
836     break;
837   }
838 
839   return result;
840 }
841 
842 /**********************************************************
843  *
844  * tftp_translate_code
845  *
846  * Translate internal error codes to CURL error codes
847  *
848  **********************************************************/
tftp_translate_code(tftp_error_t error)849 static CURLcode tftp_translate_code(tftp_error_t error)
850 {
851   CURLcode result = CURLE_OK;
852 
853   if(error != TFTP_ERR_NONE) {
854     switch(error) {
855     case TFTP_ERR_NOTFOUND:
856       result = CURLE_TFTP_NOTFOUND;
857       break;
858     case TFTP_ERR_PERM:
859       result = CURLE_TFTP_PERM;
860       break;
861     case TFTP_ERR_DISKFULL:
862       result = CURLE_REMOTE_DISK_FULL;
863       break;
864     case TFTP_ERR_UNDEF:
865     case TFTP_ERR_ILLEGAL:
866       result = CURLE_TFTP_ILLEGAL;
867       break;
868     case TFTP_ERR_UNKNOWNID:
869       result = CURLE_TFTP_UNKNOWNID;
870       break;
871     case TFTP_ERR_EXISTS:
872       result = CURLE_REMOTE_FILE_EXISTS;
873       break;
874     case TFTP_ERR_NOSUCHUSER:
875       result = CURLE_TFTP_NOSUCHUSER;
876       break;
877     case TFTP_ERR_TIMEOUT:
878       result = CURLE_OPERATION_TIMEDOUT;
879       break;
880     case TFTP_ERR_NORESPONSE:
881       result = CURLE_COULDNT_CONNECT;
882       break;
883     default:
884       result = CURLE_ABORTED_BY_CALLBACK;
885       break;
886     }
887   }
888   else
889     result = CURLE_OK;
890 
891   return result;
892 }
893 
894 /**********************************************************
895  *
896  * tftp_state_machine
897  *
898  * The tftp state machine event dispatcher
899  *
900  **********************************************************/
tftp_state_machine(tftp_state_data_t * state,tftp_event_t event)901 static CURLcode tftp_state_machine(tftp_state_data_t *state,
902                                    tftp_event_t event)
903 {
904   CURLcode result = CURLE_OK;
905   struct Curl_easy *data = state->conn->data;
906 
907   switch(state->state) {
908   case TFTP_STATE_START:
909     DEBUGF(infof(data, "TFTP_STATE_START\n"));
910     result = tftp_send_first(state, event);
911     break;
912   case TFTP_STATE_RX:
913     DEBUGF(infof(data, "TFTP_STATE_RX\n"));
914     result = tftp_rx(state, event);
915     break;
916   case TFTP_STATE_TX:
917     DEBUGF(infof(data, "TFTP_STATE_TX\n"));
918     result = tftp_tx(state, event);
919     break;
920   case TFTP_STATE_FIN:
921     infof(data, "%s\n", "TFTP finished");
922     break;
923   default:
924     DEBUGF(infof(data, "STATE: %d\n", state->state));
925     failf(data, "%s", "Internal state machine error");
926     result = CURLE_TFTP_ILLEGAL;
927     break;
928   }
929 
930   return result;
931 }
932 
933 /**********************************************************
934  *
935  * tftp_disconnect
936  *
937  * The disconnect callback
938  *
939  **********************************************************/
tftp_disconnect(struct connectdata * conn,bool dead_connection)940 static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
941 {
942   tftp_state_data_t *state = conn->proto.tftpc;
943   (void) dead_connection;
944 
945   /* done, free dynamically allocated pkt buffers */
946   if(state) {
947     Curl_safefree(state->rpacket.data);
948     Curl_safefree(state->spacket.data);
949     free(state);
950   }
951 
952   return CURLE_OK;
953 }
954 
955 /**********************************************************
956  *
957  * tftp_connect
958  *
959  * The connect callback
960  *
961  **********************************************************/
tftp_connect(struct connectdata * conn,bool * done)962 static CURLcode tftp_connect(struct connectdata *conn, bool *done)
963 {
964   tftp_state_data_t *state;
965   int blksize, rc;
966 
967   blksize = TFTP_BLKSIZE_DEFAULT;
968 
969   state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
970   if(!state)
971     return CURLE_OUT_OF_MEMORY;
972 
973   /* alloc pkt buffers based on specified blksize */
974   if(conn->data->set.tftp_blksize) {
975     blksize = (int)conn->data->set.tftp_blksize;
976     if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
977       return CURLE_TFTP_ILLEGAL;
978   }
979 
980   if(!state->rpacket.data) {
981     state->rpacket.data = calloc(1, blksize + 2 + 2);
982 
983     if(!state->rpacket.data)
984       return CURLE_OUT_OF_MEMORY;
985   }
986 
987   if(!state->spacket.data) {
988     state->spacket.data = calloc(1, blksize + 2 + 2);
989 
990     if(!state->spacket.data)
991       return CURLE_OUT_OF_MEMORY;
992   }
993 
994   /* we don't keep TFTP connections up basically because there's none or very
995    * little gain for UDP */
996   connclose(conn, "TFTP");
997 
998   state->conn = conn;
999   state->sockfd = state->conn->sock[FIRSTSOCKET];
1000   state->state = TFTP_STATE_START;
1001   state->error = TFTP_ERR_NONE;
1002   state->blksize = TFTP_BLKSIZE_DEFAULT;
1003   state->requested_blksize = blksize;
1004 
1005   ((struct sockaddr *)&state->local_addr)->sa_family =
1006     (unsigned short)(conn->ip_addr->ai_family);
1007 
1008   tftp_set_timeouts(state);
1009 
1010   if(!conn->bits.bound) {
1011     /* If not already bound, bind to any interface, random UDP port. If it is
1012      * reused or a custom local port was desired, this has already been done!
1013      *
1014      * We once used the size of the local_addr struct as the third argument
1015      * for bind() to better work with IPv6 or whatever size the struct could
1016      * have, but we learned that at least Tru64, AIX and IRIX *requires* the
1017      * size of that argument to match the exact size of a 'sockaddr_in' struct
1018      * when running IPv4-only.
1019      *
1020      * Therefore we use the size from the address we connected to, which we
1021      * assume uses the same IP version and thus hopefully this works for both
1022      * IPv4 and IPv6...
1023      */
1024     rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
1025               conn->ip_addr->ai_addrlen);
1026     if(rc) {
1027       failf(conn->data, "bind() failed; %s",
1028             Curl_strerror(conn, SOCKERRNO));
1029       return CURLE_COULDNT_CONNECT;
1030     }
1031     conn->bits.bound = TRUE;
1032   }
1033 
1034   Curl_pgrsStartNow(conn->data);
1035 
1036   *done = TRUE;
1037 
1038   return CURLE_OK;
1039 }
1040 
1041 /**********************************************************
1042  *
1043  * tftp_done
1044  *
1045  * The done callback
1046  *
1047  **********************************************************/
tftp_done(struct connectdata * conn,CURLcode status,bool premature)1048 static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
1049                           bool premature)
1050 {
1051   CURLcode result = CURLE_OK;
1052   tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
1053 
1054   (void)status; /* unused */
1055   (void)premature; /* not used */
1056 
1057   if(Curl_pgrsDone(conn))
1058     return CURLE_ABORTED_BY_CALLBACK;
1059 
1060   /* If we have encountered an error */
1061   if(state)
1062     result = tftp_translate_code(state->error);
1063 
1064   return result;
1065 }
1066 
1067 /**********************************************************
1068  *
1069  * tftp_getsock
1070  *
1071  * The getsock callback
1072  *
1073  **********************************************************/
tftp_getsock(struct connectdata * conn,curl_socket_t * socks,int numsocks)1074 static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
1075                         int numsocks)
1076 {
1077   if(!numsocks)
1078     return GETSOCK_BLANK;
1079 
1080   socks[0] = conn->sock[FIRSTSOCKET];
1081 
1082   return GETSOCK_READSOCK(0);
1083 }
1084 
1085 /**********************************************************
1086  *
1087  * tftp_receive_packet
1088  *
1089  * Called once select fires and data is ready on the socket
1090  *
1091  **********************************************************/
tftp_receive_packet(struct connectdata * conn)1092 static CURLcode tftp_receive_packet(struct connectdata *conn)
1093 {
1094   struct Curl_sockaddr_storage fromaddr;
1095   curl_socklen_t        fromlen;
1096   CURLcode              result = CURLE_OK;
1097   struct Curl_easy  *data = conn->data;
1098   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1099   struct SingleRequest  *k = &data->req;
1100 
1101   /* Receive the packet */
1102   fromlen = sizeof(fromaddr);
1103   state->rbytes = (int)recvfrom(state->sockfd,
1104                                 (void *)state->rpacket.data,
1105                                 state->blksize+4,
1106                                 0,
1107                                 (struct sockaddr *)&fromaddr,
1108                                 &fromlen);
1109   if(state->remote_addrlen==0) {
1110     memcpy(&state->remote_addr, &fromaddr, fromlen);
1111     state->remote_addrlen = fromlen;
1112   }
1113 
1114   /* Sanity check packet length */
1115   if(state->rbytes < 4) {
1116     failf(data, "Received too short packet");
1117     /* Not a timeout, but how best to handle it? */
1118     state->event = TFTP_EVENT_TIMEOUT;
1119   }
1120   else {
1121     /* The event is given by the TFTP packet time */
1122     state->event = (tftp_event_t)getrpacketevent(&state->rpacket);
1123 
1124     switch(state->event) {
1125     case TFTP_EVENT_DATA:
1126       /* Don't pass to the client empty or retransmitted packets */
1127       if(state->rbytes > 4 &&
1128          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
1129         result = Curl_client_write(conn, CLIENTWRITE_BODY,
1130                                    (char *)state->rpacket.data+4,
1131                                    state->rbytes-4);
1132         if(result) {
1133           tftp_state_machine(state, TFTP_EVENT_ERROR);
1134           return result;
1135         }
1136         k->bytecount += state->rbytes-4;
1137         Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
1138       }
1139       break;
1140     case TFTP_EVENT_ERROR:
1141       state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
1142       infof(data, "%s\n", (const char *)state->rpacket.data+4);
1143       break;
1144     case TFTP_EVENT_ACK:
1145       break;
1146     case TFTP_EVENT_OACK:
1147       result = tftp_parse_option_ack(state,
1148                                      (const char *)state->rpacket.data+2,
1149                                      state->rbytes-2);
1150       if(result)
1151         return result;
1152       break;
1153     case TFTP_EVENT_RRQ:
1154     case TFTP_EVENT_WRQ:
1155     default:
1156       failf(data, "%s", "Internal error: Unexpected packet");
1157       break;
1158     }
1159 
1160     /* Update the progress meter */
1161     if(Curl_pgrsUpdate(conn)) {
1162       tftp_state_machine(state, TFTP_EVENT_ERROR);
1163       return CURLE_ABORTED_BY_CALLBACK;
1164     }
1165   }
1166   return result;
1167 }
1168 
1169 /**********************************************************
1170  *
1171  * tftp_state_timeout
1172  *
1173  * Check if timeouts have been reached
1174  *
1175  **********************************************************/
tftp_state_timeout(struct connectdata * conn,tftp_event_t * event)1176 static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
1177 {
1178   time_t                current;
1179   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1180 
1181   if(event)
1182     *event = TFTP_EVENT_NONE;
1183 
1184   time(&current);
1185   if(current > state->max_time) {
1186     DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
1187                  (long)current, (long)state->max_time));
1188     state->error = TFTP_ERR_TIMEOUT;
1189     state->state = TFTP_STATE_FIN;
1190     return 0;
1191   }
1192   else if(current > state->rx_time+state->retry_time) {
1193     if(event)
1194       *event = TFTP_EVENT_TIMEOUT;
1195     time(&state->rx_time); /* update even though we received nothing */
1196   }
1197 
1198   /* there's a typecast below here since 'time_t' may in fact be larger than
1199      'long', but we estimate that a 'long' will still be able to hold number
1200      of seconds even if "only" 32 bit */
1201   return (long)(state->max_time - current);
1202 }
1203 
1204 /**********************************************************
1205  *
1206  * tftp_multi_statemach
1207  *
1208  * Handle single RX socket event and return
1209  *
1210  **********************************************************/
tftp_multi_statemach(struct connectdata * conn,bool * done)1211 static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
1212 {
1213   int                   rc;
1214   tftp_event_t          event;
1215   CURLcode              result = CURLE_OK;
1216   struct Curl_easy  *data = conn->data;
1217   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1218   long                  timeout_ms = tftp_state_timeout(conn, &event);
1219 
1220   *done = FALSE;
1221 
1222   if(timeout_ms <= 0) {
1223     failf(data, "TFTP response timeout");
1224     return CURLE_OPERATION_TIMEDOUT;
1225   }
1226   else if(event != TFTP_EVENT_NONE) {
1227     result = tftp_state_machine(state, event);
1228     if(result)
1229       return result;
1230     *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
1231     if(*done)
1232       /* Tell curl we're done */
1233       Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1234   }
1235   else {
1236     /* no timeouts to handle, check our socket */
1237     rc = SOCKET_READABLE(state->sockfd, 0);
1238 
1239     if(rc == -1) {
1240       /* bail out */
1241       int error = SOCKERRNO;
1242       failf(data, "%s", Curl_strerror(conn, error));
1243       state->event = TFTP_EVENT_ERROR;
1244     }
1245     else if(rc != 0) {
1246       result = tftp_receive_packet(conn);
1247       if(result)
1248         return result;
1249       result = tftp_state_machine(state, state->event);
1250       if(result)
1251         return result;
1252       *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
1253       if(*done)
1254         /* Tell curl we're done */
1255         Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1256     }
1257     /* if rc == 0, then select() timed out */
1258   }
1259 
1260   return result;
1261 }
1262 
1263 /**********************************************************
1264  *
1265  * tftp_doing
1266  *
1267  * Called from multi.c while DOing
1268  *
1269  **********************************************************/
tftp_doing(struct connectdata * conn,bool * dophase_done)1270 static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
1271 {
1272   CURLcode result;
1273   result = tftp_multi_statemach(conn, dophase_done);
1274 
1275   if(*dophase_done) {
1276     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1277   }
1278   else if(!result) {
1279     /* The multi code doesn't have this logic for the DOING state so we
1280        provide it for TFTP since it may do the entire transfer in this
1281        state. */
1282     if(Curl_pgrsUpdate(conn))
1283       result = CURLE_ABORTED_BY_CALLBACK;
1284     else
1285       result = Curl_speedcheck(conn->data, Curl_tvnow());
1286   }
1287   return result;
1288 }
1289 
1290 /**********************************************************
1291  *
1292  * tftp_peform
1293  *
1294  * Entry point for transfer from tftp_do, sarts state mach
1295  *
1296  **********************************************************/
tftp_perform(struct connectdata * conn,bool * dophase_done)1297 static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
1298 {
1299   CURLcode              result = CURLE_OK;
1300   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1301 
1302   *dophase_done = FALSE;
1303 
1304   result = tftp_state_machine(state, TFTP_EVENT_INIT);
1305 
1306   if((state->state == TFTP_STATE_FIN) || result)
1307     return result;
1308 
1309   tftp_multi_statemach(conn, dophase_done);
1310 
1311   if(*dophase_done)
1312     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1313 
1314   return result;
1315 }
1316 
1317 
1318 /**********************************************************
1319  *
1320  * tftp_do
1321  *
1322  * The do callback
1323  *
1324  * This callback initiates the TFTP transfer
1325  *
1326  **********************************************************/
1327 
tftp_do(struct connectdata * conn,bool * done)1328 static CURLcode tftp_do(struct connectdata *conn, bool *done)
1329 {
1330   tftp_state_data_t *state;
1331   CURLcode result;
1332 
1333   *done = FALSE;
1334 
1335   if(!conn->proto.tftpc) {
1336     result = tftp_connect(conn, done);
1337     if(result)
1338       return result;
1339   }
1340 
1341   state = (tftp_state_data_t *)conn->proto.tftpc;
1342   if(!state)
1343     return CURLE_BAD_CALLING_ORDER;
1344 
1345   result = tftp_perform(conn, done);
1346 
1347   /* If tftp_perform() returned an error, use that for return code. If it
1348      was OK, see if tftp_translate_code() has an error. */
1349   if(!result)
1350     /* If we have encountered an internal tftp error, translate it. */
1351     result = tftp_translate_code(state->error);
1352 
1353   return result;
1354 }
1355 
tftp_setup_connection(struct connectdata * conn)1356 static CURLcode tftp_setup_connection(struct connectdata * conn)
1357 {
1358   struct Curl_easy *data = conn->data;
1359   char *type;
1360   char command;
1361 
1362   conn->socktype = SOCK_DGRAM;   /* UDP datagram based */
1363 
1364   /* TFTP URLs support an extension like ";mode=<typecode>" that
1365    * we'll try to get now! */
1366   type = strstr(data->state.path, ";mode=");
1367 
1368   if(!type)
1369     type = strstr(conn->host.rawalloc, ";mode=");
1370 
1371   if(type) {
1372     *type = 0;                   /* it was in the middle of the hostname */
1373     command = Curl_raw_toupper(type[6]);
1374 
1375     switch (command) {
1376     case 'A': /* ASCII mode */
1377     case 'N': /* NETASCII mode */
1378       data->set.prefer_ascii = TRUE;
1379       break;
1380 
1381     case 'O': /* octet mode */
1382     case 'I': /* binary mode */
1383     default:
1384       /* switch off ASCII */
1385       data->set.prefer_ascii = FALSE;
1386       break;
1387     }
1388   }
1389 
1390   return CURLE_OK;
1391 }
1392 #endif
1393