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