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