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