7f2c88b71e338590ecd940cc898adc470ac51ca8
[platform/upstream/cmake.git] / Utilities / cmcurl / lib / tftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2022, Daniel Stenberg, <daniel@haxx.se>, et al.
9  *
10  * This software is licensed as described in the file COPYING, which
11  * you should have received as part of this distribution. The terms
12  * are also available at https://curl.se/docs/copyright.html.
13  *
14  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15  * copies of the Software, and permit persons to whom the Software is
16  * furnished to do so, under the terms of the COPYING file.
17  *
18  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19  * KIND, either express or implied.
20  *
21  ***************************************************************************/
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 struct tftp_packet {
119   unsigned char *data;
120 };
121
122 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 Curl_easy *data;
128   curl_socket_t   sockfd;
129   int             retries;
130   int             retry_time;
131   int             retry_max;
132   time_t          rx_time;
133   struct Curl_sockaddr_storage   local_addr;
134   struct Curl_sockaddr_storage   remote_addr;
135   curl_socklen_t  remote_addrlen;
136   int             rbytes;
137   int             sbytes;
138   int             blksize;
139   int             requested_blksize;
140   unsigned short  block;
141   struct tftp_packet rpacket;
142   struct tftp_packet spacket;
143 };
144
145
146 /* Forward declarations */
147 static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event);
148 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event);
149 static CURLcode tftp_connect(struct Curl_easy *data, bool *done);
150 static CURLcode tftp_disconnect(struct Curl_easy *data,
151                                 struct connectdata *conn,
152                                 bool dead_connection);
153 static CURLcode tftp_do(struct Curl_easy *data, bool *done);
154 static CURLcode tftp_done(struct Curl_easy *data,
155                           CURLcode, bool premature);
156 static CURLcode tftp_setup_connection(struct Curl_easy *data,
157                                       struct connectdata *conn);
158 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done);
159 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done);
160 static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn,
161                         curl_socket_t *socks);
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   ZERO_NULL,                            /* connection_check */
185   ZERO_NULL,                            /* attach connection */
186   PORT_TFTP,                            /* defport */
187   CURLPROTO_TFTP,                       /* protocol */
188   CURLPROTO_TFTP,                       /* family */
189   PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
190 };
191
192 /**********************************************************
193  *
194  * tftp_set_timeouts -
195  *
196  * Set timeouts based on state machine state.
197  * Use user provided connect timeouts until DATA or ACK
198  * packet is received, then use user-provided transfer timeouts
199  *
200  *
201  **********************************************************/
202 static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
203 {
204   time_t maxtime, timeout;
205   timediff_t timeout_ms;
206   bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
207
208   /* Compute drop-dead time */
209   timeout_ms = Curl_timeleft(state->data, NULL, start);
210
211   if(timeout_ms < 0) {
212     /* time-out, bail out, go home */
213     failf(state->data, "Connection time-out");
214     return CURLE_OPERATION_TIMEDOUT;
215   }
216
217   if(timeout_ms > 0)
218     maxtime = (time_t)(timeout_ms + 500) / 1000;
219   else
220     maxtime = 3600; /* use for calculating block timeouts */
221
222   /* Set per-block timeout to total */
223   timeout = maxtime;
224
225   /* Average reposting an ACK after 5 seconds */
226   state->retry_max = (int)timeout/5;
227
228   /* But bound the total number */
229   if(state->retry_max<3)
230     state->retry_max = 3;
231
232   if(state->retry_max>50)
233     state->retry_max = 50;
234
235   /* Compute the re-ACK interval to suit the timeout */
236   state->retry_time = (int)(timeout/state->retry_max);
237   if(state->retry_time<1)
238     state->retry_time = 1;
239
240   infof(state->data,
241         "set timeouts for state %d; Total % " CURL_FORMAT_CURL_OFF_T
242         ", retry %d maxtry %d",
243         (int)state->state, timeout_ms, state->retry_time, state->retry_max);
244
245   /* init RX time */
246   time(&state->rx_time);
247
248   return CURLE_OK;
249 }
250
251 /**********************************************************
252  *
253  * tftp_set_send_first
254  *
255  * Event handler for the START state
256  *
257  **********************************************************/
258
259 static void setpacketevent(struct tftp_packet *packet, unsigned short num)
260 {
261   packet->data[0] = (unsigned char)(num >> 8);
262   packet->data[1] = (unsigned char)(num & 0xff);
263 }
264
265
266 static void setpacketblock(struct tftp_packet *packet, unsigned short num)
267 {
268   packet->data[2] = (unsigned char)(num >> 8);
269   packet->data[3] = (unsigned char)(num & 0xff);
270 }
271
272 static unsigned short getrpacketevent(const struct tftp_packet *packet)
273 {
274   return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
275 }
276
277 static unsigned short getrpacketblock(const struct tftp_packet *packet)
278 {
279   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
280 }
281
282 static size_t tftp_strnlen(const char *string, size_t maxlen)
283 {
284   const char *end = memchr(string, '\0', maxlen);
285   return end ? (size_t) (end - string) : maxlen;
286 }
287
288 static const char *tftp_option_get(const char *buf, size_t len,
289                                    const char **option, const char **value)
290 {
291   size_t loc;
292
293   loc = tftp_strnlen(buf, len);
294   loc++; /* NULL term */
295
296   if(loc >= len)
297     return NULL;
298   *option = buf;
299
300   loc += tftp_strnlen(buf + loc, len-loc);
301   loc++; /* NULL term */
302
303   if(loc > len)
304     return NULL;
305   *value = &buf[strlen(*option) + 1];
306
307   return &buf[loc];
308 }
309
310 static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
311                                       const char *ptr, int len)
312 {
313   const char *tmp = ptr;
314   struct Curl_easy *data = state->data;
315
316   /* if OACK doesn't contain blksize option, the default (512) must be used */
317   state->blksize = TFTP_BLKSIZE_DEFAULT;
318
319   while(tmp < ptr + len) {
320     const char *option, *value;
321
322     tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
323     if(!tmp) {
324       failf(data, "Malformed ACK packet, rejecting");
325       return CURLE_TFTP_ILLEGAL;
326     }
327
328     infof(data, "got option=(%s) value=(%s)", option, value);
329
330     if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
331       long blksize;
332
333       blksize = strtol(value, NULL, 10);
334
335       if(!blksize) {
336         failf(data, "invalid blocksize value in OACK packet");
337         return CURLE_TFTP_ILLEGAL;
338       }
339       if(blksize > TFTP_BLKSIZE_MAX) {
340         failf(data, "%s (%d)", "blksize is larger than max supported",
341               TFTP_BLKSIZE_MAX);
342         return CURLE_TFTP_ILLEGAL;
343       }
344       else if(blksize < TFTP_BLKSIZE_MIN) {
345         failf(data, "%s (%d)", "blksize is smaller than min supported",
346               TFTP_BLKSIZE_MIN);
347         return CURLE_TFTP_ILLEGAL;
348       }
349       else if(blksize > state->requested_blksize) {
350         /* could realloc pkt buffers here, but the spec doesn't call out
351          * support for the server requesting a bigger blksize than the client
352          * requests */
353         failf(data, "%s (%ld)",
354               "server requested blksize larger than allocated", blksize);
355         return CURLE_TFTP_ILLEGAL;
356       }
357
358       state->blksize = (int)blksize;
359       infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
360             state->blksize, "requested", state->requested_blksize);
361     }
362     else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
363       long tsize = 0;
364
365       tsize = strtol(value, NULL, 10);
366       infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
367
368       /* tsize should be ignored on upload: Who cares about the size of the
369          remote file? */
370       if(!data->set.upload) {
371         if(!tsize) {
372           failf(data, "invalid tsize -:%s:- value in OACK packet", value);
373           return CURLE_TFTP_ILLEGAL;
374         }
375         Curl_pgrsSetDownloadSize(data, tsize);
376       }
377     }
378   }
379
380   return CURLE_OK;
381 }
382
383 static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
384                                 char *buf, const char *option)
385 {
386   if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
387     return CURLE_TFTP_ILLEGAL;
388   strcpy(buf, option);
389   *csize += strlen(option) + 1;
390   return CURLE_OK;
391 }
392
393 static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
394                                     tftp_event_t event)
395 {
396   CURLcode result;
397 #ifndef CURL_DISABLE_VERBOSE_STRINGS
398   struct Curl_easy *data = state->data;
399
400   infof(data, "%s", "Connected for transmit");
401 #endif
402   state->state = TFTP_STATE_TX;
403   result = tftp_set_timeouts(state);
404   if(result)
405     return result;
406   return tftp_tx(state, event);
407 }
408
409 static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
410                                     tftp_event_t event)
411 {
412   CURLcode result;
413 #ifndef CURL_DISABLE_VERBOSE_STRINGS
414   struct Curl_easy *data = state->data;
415
416   infof(data, "%s", "Connected for receive");
417 #endif
418   state->state = TFTP_STATE_RX;
419   result = tftp_set_timeouts(state);
420   if(result)
421     return result;
422   return tftp_rx(state, event);
423 }
424
425 static CURLcode tftp_send_first(struct tftp_state_data *state,
426                                 tftp_event_t event)
427 {
428   size_t sbytes;
429   ssize_t senddata;
430   const char *mode = "octet";
431   char *filename;
432   struct Curl_easy *data = state->data;
433   CURLcode result = CURLE_OK;
434
435   /* Set ascii mode if -B flag was used */
436   if(data->state.prefer_ascii)
437     mode = "netascii";
438
439   switch(event) {
440
441   case TFTP_EVENT_INIT:    /* Send the first packet out */
442   case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
443     /* Increment the retry counter, quit if over the limit */
444     state->retries++;
445     if(state->retries>state->retry_max) {
446       state->error = TFTP_ERR_NORESPONSE;
447       state->state = TFTP_STATE_FIN;
448       return result;
449     }
450
451     if(data->set.upload) {
452       /* If we are uploading, send an WRQ */
453       setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
454       state->data->req.upload_fromhere =
455         (char *)state->spacket.data + 4;
456       if(data->state.infilesize != -1)
457         Curl_pgrsSetUploadSize(data, data->state.infilesize);
458     }
459     else {
460       /* If we are downloading, send an RRQ */
461       setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
462     }
463     /* As RFC3617 describes the separator slash is not actually part of the
464        file name so we skip the always-present first letter of the path
465        string. */
466     result = Curl_urldecode(&state->data->state.up.path[1], 0,
467                             &filename, NULL, REJECT_ZERO);
468     if(result)
469       return result;
470
471     if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
472       failf(data, "TFTP file name too long");
473       free(filename);
474       return CURLE_TFTP_ILLEGAL; /* too long file name field */
475     }
476
477     msnprintf((char *)state->spacket.data + 2,
478               state->blksize,
479               "%s%c%s%c", filename, '\0',  mode, '\0');
480     sbytes = 4 + strlen(filename) + strlen(mode);
481
482     /* optional addition of TFTP options */
483     if(!data->set.tftp_no_options) {
484       char buf[64];
485       /* add tsize option */
486       if(data->set.upload && (data->state.infilesize != -1))
487         msnprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
488                   data->state.infilesize);
489       else
490         strcpy(buf, "0"); /* the destination is large enough */
491
492       result = tftp_option_add(state, &sbytes,
493                                (char *)state->spacket.data + sbytes,
494                                TFTP_OPTION_TSIZE);
495       if(result == CURLE_OK)
496         result = tftp_option_add(state, &sbytes,
497                                  (char *)state->spacket.data + sbytes, buf);
498
499       /* add blksize option */
500       msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
501       if(result == CURLE_OK)
502         result = tftp_option_add(state, &sbytes,
503                                  (char *)state->spacket.data + sbytes,
504                                  TFTP_OPTION_BLKSIZE);
505       if(result == CURLE_OK)
506         result = tftp_option_add(state, &sbytes,
507                                  (char *)state->spacket.data + sbytes, buf);
508
509       /* add timeout option */
510       msnprintf(buf, sizeof(buf), "%d", state->retry_time);
511       if(result == CURLE_OK)
512         result = tftp_option_add(state, &sbytes,
513                                  (char *)state->spacket.data + sbytes,
514                                  TFTP_OPTION_INTERVAL);
515       if(result == CURLE_OK)
516         result = tftp_option_add(state, &sbytes,
517                                  (char *)state->spacket.data + sbytes, buf);
518
519       if(result != CURLE_OK) {
520         failf(data, "TFTP buffer too small for options");
521         free(filename);
522         return CURLE_TFTP_ILLEGAL;
523       }
524     }
525
526     /* the typecase for the 3rd argument is mostly for systems that do
527        not have a size_t argument, like older unixes that want an 'int' */
528     senddata = sendto(state->sockfd, (void *)state->spacket.data,
529                       (SEND_TYPE_ARG3)sbytes, 0,
530                       data->conn->ip_addr->ai_addr,
531                       data->conn->ip_addr->ai_addrlen);
532     if(senddata != (ssize_t)sbytes) {
533       char buffer[STRERROR_LEN];
534       failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
535     }
536     free(filename);
537     break;
538
539   case TFTP_EVENT_OACK:
540     if(data->set.upload) {
541       result = tftp_connect_for_tx(state, event);
542     }
543     else {
544       result = tftp_connect_for_rx(state, event);
545     }
546     break;
547
548   case TFTP_EVENT_ACK: /* Connected for transmit */
549     result = tftp_connect_for_tx(state, event);
550     break;
551
552   case TFTP_EVENT_DATA: /* Connected for receive */
553     result = tftp_connect_for_rx(state, event);
554     break;
555
556   case TFTP_EVENT_ERROR:
557     state->state = TFTP_STATE_FIN;
558     break;
559
560   default:
561     failf(state->data, "tftp_send_first: internal error");
562     break;
563   }
564
565   return result;
566 }
567
568 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
569    boundary */
570 #define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
571
572 /**********************************************************
573  *
574  * tftp_rx
575  *
576  * Event handler for the RX state
577  *
578  **********************************************************/
579 static CURLcode tftp_rx(struct tftp_state_data *state,
580                         tftp_event_t event)
581 {
582   ssize_t sbytes;
583   int rblock;
584   struct Curl_easy *data = state->data;
585   char buffer[STRERROR_LEN];
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.", rblock);
600     }
601     else {
602       /* totally unexpected, just log it */
603       infof(data,
604             "Received unexpected DATA packet block %d, expecting block %d",
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(SOCKERRNO, buffer, sizeof(buffer)));
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(SOCKERRNO, buffer, sizeof(buffer)));
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",
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(SOCKERRNO, buffer, sizeof(buffer)));
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  **********************************************************/
702 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
703 {
704   struct Curl_easy *data = state->data;
705   ssize_t sbytes;
706   CURLcode result = CURLE_OK;
707   struct SingleRequest *k = &data->req;
708   size_t cb; /* Bytes currently read */
709   char buffer[STRERROR_LEN];
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       int 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           * https://www.syslinux.org/archives/2010-September/015612.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",
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(SOCKERRNO,
745                                             buffer, sizeof(buffer)));
746             result = CURLE_SEND_ERROR;
747           }
748         }
749
750         return result;
751       }
752       /* This is the expected packet.  Reset the counters and send the next
753          block */
754       time(&state->rx_time);
755       state->block++;
756     }
757     else
758       state->block = 1; /* first data block is 1 when using OACK */
759
760     state->retries = 0;
761     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
762     setpacketblock(&state->spacket, state->block);
763     if(state->block > 1 && state->sbytes < state->blksize) {
764       state->state = TFTP_STATE_FIN;
765       return CURLE_OK;
766     }
767
768     /* TFTP considers data block size < 512 bytes as an end of session. So
769      * in some cases we must wait for additional data to build full (512 bytes)
770      * data block.
771      * */
772     state->sbytes = 0;
773     state->data->req.upload_fromhere = (char *)state->spacket.data + 4;
774     do {
775       result = Curl_fillreadbuffer(data, state->blksize - state->sbytes, &cb);
776       if(result)
777         return result;
778       state->sbytes += (int)cb;
779       state->data->req.upload_fromhere += cb;
780     } while(state->sbytes < state->blksize && cb);
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(SOCKERRNO, buffer, sizeof(buffer)));
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", 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(SOCKERRNO, buffer, sizeof(buffer)));
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  **********************************************************/
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  **********************************************************/
901 static CURLcode tftp_state_machine(struct tftp_state_data *state,
902                                    tftp_event_t event)
903 {
904   CURLcode result = CURLE_OK;
905   struct Curl_easy *data = state->data;
906
907   switch(state->state) {
908   case TFTP_STATE_START:
909     DEBUGF(infof(data, "TFTP_STATE_START"));
910     result = tftp_send_first(state, event);
911     break;
912   case TFTP_STATE_RX:
913     DEBUGF(infof(data, "TFTP_STATE_RX"));
914     result = tftp_rx(state, event);
915     break;
916   case TFTP_STATE_TX:
917     DEBUGF(infof(data, "TFTP_STATE_TX"));
918     result = tftp_tx(state, event);
919     break;
920   case TFTP_STATE_FIN:
921     infof(data, "%s", "TFTP finished");
922     break;
923   default:
924     DEBUGF(infof(data, "STATE: %d", 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  **********************************************************/
940 static CURLcode tftp_disconnect(struct Curl_easy *data,
941                                 struct connectdata *conn, bool dead_connection)
942 {
943   struct tftp_state_data *state = conn->proto.tftpc;
944   (void) data;
945   (void) dead_connection;
946
947   /* done, free dynamically allocated pkt buffers */
948   if(state) {
949     Curl_safefree(state->rpacket.data);
950     Curl_safefree(state->spacket.data);
951     free(state);
952   }
953
954   return CURLE_OK;
955 }
956
957 /**********************************************************
958  *
959  * tftp_connect
960  *
961  * The connect callback
962  *
963  **********************************************************/
964 static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
965 {
966   struct tftp_state_data *state;
967   int blksize;
968   int need_blksize;
969   struct connectdata *conn = data->conn;
970
971   blksize = TFTP_BLKSIZE_DEFAULT;
972
973   state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data));
974   if(!state)
975     return CURLE_OUT_OF_MEMORY;
976
977   /* alloc pkt buffers based on specified blksize */
978   if(data->set.tftp_blksize) {
979     blksize = (int)data->set.tftp_blksize;
980     if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
981       return CURLE_TFTP_ILLEGAL;
982   }
983
984   need_blksize = blksize;
985   /* default size is the fallback when no OACK is received */
986   if(need_blksize < TFTP_BLKSIZE_DEFAULT)
987     need_blksize = TFTP_BLKSIZE_DEFAULT;
988
989   if(!state->rpacket.data) {
990     state->rpacket.data = calloc(1, need_blksize + 2 + 2);
991
992     if(!state->rpacket.data)
993       return CURLE_OUT_OF_MEMORY;
994   }
995
996   if(!state->spacket.data) {
997     state->spacket.data = calloc(1, need_blksize + 2 + 2);
998
999     if(!state->spacket.data)
1000       return CURLE_OUT_OF_MEMORY;
1001   }
1002
1003   /* we don't keep TFTP connections up basically because there's none or very
1004    * little gain for UDP */
1005   connclose(conn, "TFTP");
1006
1007   state->data = data;
1008   state->sockfd = conn->sock[FIRSTSOCKET];
1009   state->state = TFTP_STATE_START;
1010   state->error = TFTP_ERR_NONE;
1011   state->blksize = TFTP_BLKSIZE_DEFAULT; /* Unless updated by OACK response */
1012   state->requested_blksize = blksize;
1013
1014   ((struct sockaddr *)&state->local_addr)->sa_family =
1015     (CURL_SA_FAMILY_T)(conn->ip_addr->ai_family);
1016
1017   tftp_set_timeouts(state);
1018
1019   if(!conn->bits.bound) {
1020     /* If not already bound, bind to any interface, random UDP port. If it is
1021      * reused or a custom local port was desired, this has already been done!
1022      *
1023      * We once used the size of the local_addr struct as the third argument
1024      * for bind() to better work with IPv6 or whatever size the struct could
1025      * have, but we learned that at least Tru64, AIX and IRIX *requires* the
1026      * size of that argument to match the exact size of a 'sockaddr_in' struct
1027      * when running IPv4-only.
1028      *
1029      * Therefore we use the size from the address we connected to, which we
1030      * assume uses the same IP version and thus hopefully this works for both
1031      * IPv4 and IPv6...
1032      */
1033     int rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
1034                   conn->ip_addr->ai_addrlen);
1035     if(rc) {
1036       char buffer[STRERROR_LEN];
1037       failf(data, "bind() failed; %s",
1038             Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
1039       return CURLE_COULDNT_CONNECT;
1040     }
1041     conn->bits.bound = TRUE;
1042   }
1043
1044   Curl_pgrsStartNow(data);
1045
1046   *done = TRUE;
1047
1048   return CURLE_OK;
1049 }
1050
1051 /**********************************************************
1052  *
1053  * tftp_done
1054  *
1055  * The done callback
1056  *
1057  **********************************************************/
1058 static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
1059                           bool premature)
1060 {
1061   CURLcode result = CURLE_OK;
1062   struct connectdata *conn = data->conn;
1063   struct tftp_state_data *state = conn->proto.tftpc;
1064
1065   (void)status; /* unused */
1066   (void)premature; /* not used */
1067
1068   if(Curl_pgrsDone(data))
1069     return CURLE_ABORTED_BY_CALLBACK;
1070
1071   /* If we have encountered an error */
1072   if(state)
1073     result = tftp_translate_code(state->error);
1074
1075   return result;
1076 }
1077
1078 /**********************************************************
1079  *
1080  * tftp_getsock
1081  *
1082  * The getsock callback
1083  *
1084  **********************************************************/
1085 static int tftp_getsock(struct Curl_easy *data,
1086                         struct connectdata *conn, curl_socket_t *socks)
1087 {
1088   (void)data;
1089   socks[0] = conn->sock[FIRSTSOCKET];
1090   return GETSOCK_READSOCK(0);
1091 }
1092
1093 /**********************************************************
1094  *
1095  * tftp_receive_packet
1096  *
1097  * Called once select fires and data is ready on the socket
1098  *
1099  **********************************************************/
1100 static CURLcode tftp_receive_packet(struct Curl_easy *data)
1101 {
1102   struct Curl_sockaddr_storage fromaddr;
1103   curl_socklen_t        fromlen;
1104   CURLcode              result = CURLE_OK;
1105   struct connectdata *conn = data->conn;
1106   struct tftp_state_data *state = conn->proto.tftpc;
1107   struct SingleRequest  *k = &data->req;
1108
1109   /* Receive the packet */
1110   fromlen = sizeof(fromaddr);
1111   state->rbytes = (int)recvfrom(state->sockfd,
1112                                 (void *)state->rpacket.data,
1113                                 state->blksize + 4,
1114                                 0,
1115                                 (struct sockaddr *)&fromaddr,
1116                                 &fromlen);
1117   if(state->remote_addrlen == 0) {
1118     memcpy(&state->remote_addr, &fromaddr, fromlen);
1119     state->remote_addrlen = fromlen;
1120   }
1121
1122   /* Sanity check packet length */
1123   if(state->rbytes < 4) {
1124     failf(data, "Received too short packet");
1125     /* Not a timeout, but how best to handle it? */
1126     state->event = TFTP_EVENT_TIMEOUT;
1127   }
1128   else {
1129     /* The event is given by the TFTP packet time */
1130     unsigned short event = getrpacketevent(&state->rpacket);
1131     state->event = (tftp_event_t)event;
1132
1133     switch(state->event) {
1134     case TFTP_EVENT_DATA:
1135       /* Don't pass to the client empty or retransmitted packets */
1136       if(state->rbytes > 4 &&
1137          (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
1138         result = Curl_client_write(data, CLIENTWRITE_BODY,
1139                                    (char *)state->rpacket.data + 4,
1140                                    state->rbytes-4);
1141         if(result) {
1142           tftp_state_machine(state, TFTP_EVENT_ERROR);
1143           return result;
1144         }
1145         k->bytecount += state->rbytes-4;
1146         Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
1147       }
1148       break;
1149     case TFTP_EVENT_ERROR:
1150     {
1151       unsigned short error = getrpacketblock(&state->rpacket);
1152       char *str = (char *)state->rpacket.data + 4;
1153       size_t strn = state->rbytes - 4;
1154       state->error = (tftp_error_t)error;
1155       if(tftp_strnlen(str, strn) < strn)
1156         infof(data, "TFTP error: %s", str);
1157       break;
1158     }
1159     case TFTP_EVENT_ACK:
1160       break;
1161     case TFTP_EVENT_OACK:
1162       result = tftp_parse_option_ack(state,
1163                                      (const char *)state->rpacket.data + 2,
1164                                      state->rbytes-2);
1165       if(result)
1166         return result;
1167       break;
1168     case TFTP_EVENT_RRQ:
1169     case TFTP_EVENT_WRQ:
1170     default:
1171       failf(data, "%s", "Internal error: Unexpected packet");
1172       break;
1173     }
1174
1175     /* Update the progress meter */
1176     if(Curl_pgrsUpdate(data)) {
1177       tftp_state_machine(state, TFTP_EVENT_ERROR);
1178       return CURLE_ABORTED_BY_CALLBACK;
1179     }
1180   }
1181   return result;
1182 }
1183
1184 /**********************************************************
1185  *
1186  * tftp_state_timeout
1187  *
1188  * Check if timeouts have been reached
1189  *
1190  **********************************************************/
1191 static timediff_t tftp_state_timeout(struct Curl_easy *data,
1192                                      tftp_event_t *event)
1193 {
1194   time_t current;
1195   struct connectdata *conn = data->conn;
1196   struct tftp_state_data *state = conn->proto.tftpc;
1197   timediff_t timeout_ms;
1198
1199   if(event)
1200     *event = TFTP_EVENT_NONE;
1201
1202   timeout_ms = Curl_timeleft(state->data, NULL,
1203                              (state->state == TFTP_STATE_START));
1204   if(timeout_ms < 0) {
1205     state->error = TFTP_ERR_TIMEOUT;
1206     state->state = TFTP_STATE_FIN;
1207     return 0;
1208   }
1209   time(&current);
1210   if(current > state->rx_time + state->retry_time) {
1211     if(event)
1212       *event = TFTP_EVENT_TIMEOUT;
1213     time(&state->rx_time); /* update even though we received nothing */
1214   }
1215
1216   return timeout_ms;
1217 }
1218
1219 /**********************************************************
1220  *
1221  * tftp_multi_statemach
1222  *
1223  * Handle single RX socket event and return
1224  *
1225  **********************************************************/
1226 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
1227 {
1228   tftp_event_t event;
1229   CURLcode result = CURLE_OK;
1230   struct connectdata *conn = data->conn;
1231   struct tftp_state_data *state = conn->proto.tftpc;
1232   timediff_t timeout_ms = tftp_state_timeout(data, &event);
1233
1234   *done = FALSE;
1235
1236   if(timeout_ms < 0) {
1237     failf(data, "TFTP response timeout");
1238     return CURLE_OPERATION_TIMEDOUT;
1239   }
1240   if(event != TFTP_EVENT_NONE) {
1241     result = tftp_state_machine(state, event);
1242     if(result)
1243       return result;
1244     *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
1245     if(*done)
1246       /* Tell curl we're done */
1247       Curl_setup_transfer(data, -1, -1, FALSE, -1);
1248   }
1249   else {
1250     /* no timeouts to handle, check our socket */
1251     int rc = SOCKET_READABLE(state->sockfd, 0);
1252
1253     if(rc == -1) {
1254       /* bail out */
1255       int error = SOCKERRNO;
1256       char buffer[STRERROR_LEN];
1257       failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
1258       state->event = TFTP_EVENT_ERROR;
1259     }
1260     else if(rc) {
1261       result = tftp_receive_packet(data);
1262       if(result)
1263         return result;
1264       result = tftp_state_machine(state, state->event);
1265       if(result)
1266         return result;
1267       *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
1268       if(*done)
1269         /* Tell curl we're done */
1270         Curl_setup_transfer(data, -1, -1, FALSE, -1);
1271     }
1272     /* if rc == 0, then select() timed out */
1273   }
1274
1275   return result;
1276 }
1277
1278 /**********************************************************
1279  *
1280  * tftp_doing
1281  *
1282  * Called from multi.c while DOing
1283  *
1284  **********************************************************/
1285 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
1286 {
1287   CURLcode result;
1288   result = tftp_multi_statemach(data, dophase_done);
1289
1290   if(*dophase_done) {
1291     DEBUGF(infof(data, "DO phase is complete"));
1292   }
1293   else if(!result) {
1294     /* The multi code doesn't have this logic for the DOING state so we
1295        provide it for TFTP since it may do the entire transfer in this
1296        state. */
1297     if(Curl_pgrsUpdate(data))
1298       result = CURLE_ABORTED_BY_CALLBACK;
1299     else
1300       result = Curl_speedcheck(data, Curl_now());
1301   }
1302   return result;
1303 }
1304
1305 /**********************************************************
1306  *
1307  * tftp_perform
1308  *
1309  * Entry point for transfer from tftp_do, starts state mach
1310  *
1311  **********************************************************/
1312 static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
1313 {
1314   CURLcode result = CURLE_OK;
1315   struct connectdata *conn = data->conn;
1316   struct tftp_state_data *state = conn->proto.tftpc;
1317
1318   *dophase_done = FALSE;
1319
1320   result = tftp_state_machine(state, TFTP_EVENT_INIT);
1321
1322   if((state->state == TFTP_STATE_FIN) || result)
1323     return result;
1324
1325   tftp_multi_statemach(data, dophase_done);
1326
1327   if(*dophase_done)
1328     DEBUGF(infof(data, "DO phase is complete"));
1329
1330   return result;
1331 }
1332
1333
1334 /**********************************************************
1335  *
1336  * tftp_do
1337  *
1338  * The do callback
1339  *
1340  * This callback initiates the TFTP transfer
1341  *
1342  **********************************************************/
1343
1344 static CURLcode tftp_do(struct Curl_easy *data, bool *done)
1345 {
1346   struct tftp_state_data *state;
1347   CURLcode result;
1348   struct connectdata *conn = data->conn;
1349
1350   *done = FALSE;
1351
1352   if(!conn->proto.tftpc) {
1353     result = tftp_connect(data, done);
1354     if(result)
1355       return result;
1356   }
1357
1358   state = conn->proto.tftpc;
1359   if(!state)
1360     return CURLE_TFTP_ILLEGAL;
1361
1362   result = tftp_perform(data, done);
1363
1364   /* If tftp_perform() returned an error, use that for return code. If it
1365      was OK, see if tftp_translate_code() has an error. */
1366   if(!result)
1367     /* If we have encountered an internal tftp error, translate it. */
1368     result = tftp_translate_code(state->error);
1369
1370   return result;
1371 }
1372
1373 static CURLcode tftp_setup_connection(struct Curl_easy *data,
1374                                       struct connectdata *conn)
1375 {
1376   char *type;
1377
1378   conn->transport = TRNSPRT_UDP;
1379
1380   /* TFTP URLs support an extension like ";mode=<typecode>" that
1381    * we'll try to get now! */
1382   type = strstr(data->state.up.path, ";mode=");
1383
1384   if(!type)
1385     type = strstr(conn->host.rawalloc, ";mode=");
1386
1387   if(type) {
1388     char command;
1389     *type = 0;                   /* it was in the middle of the hostname */
1390     command = Curl_raw_toupper(type[6]);
1391
1392     switch(command) {
1393     case 'A': /* ASCII mode */
1394     case 'N': /* NETASCII mode */
1395       data->state.prefer_ascii = TRUE;
1396       break;
1397
1398     case 'O': /* octet mode */
1399     case 'I': /* binary mode */
1400     default:
1401       /* switch off ASCII */
1402       data->state.prefer_ascii = FALSE;
1403       break;
1404     }
1405   }
1406
1407   return CURLE_OK;
1408 }
1409 #endif