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