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