s/socklen_t/curl_socklen_t/g
[platform/upstream/curl.git] / lib / tftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2009, 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 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 %d, retry %d maxtry %d\n",
277         state->state, (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 (%d)",
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 (%d)\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", state->retries);
647     if(state->retries > state->retry_max) {
648       state->error = TFTP_ERR_TIMEOUT;
649       state->state = TFTP_STATE_FIN;
650     }
651     else {
652       /* Resend the previous ACK */
653       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
654                       4, SEND_4TH_ARG,
655                       (struct sockaddr *)&state->remote_addr,
656                       state->remote_addrlen);
657       /* Check all sbytes were sent */
658       if(sbytes<0) {
659         failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
660         return CURLE_SEND_ERROR;
661       }
662     }
663     break;
664
665   case TFTP_EVENT_ERROR:
666     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
667     setpacketblock(&state->spacket, state->block);
668     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
669                     4, SEND_4TH_ARG,
670                     (struct sockaddr *)&state->remote_addr,
671                     state->remote_addrlen);
672     /* don't bother with the return code, but if the socket is still up we
673      * should be a good TFTP client and let the server know we're done */
674     state->state = TFTP_STATE_FIN;
675     break;
676
677   default:
678     failf(data, "%s", "tftp_rx: internal error");
679     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
680                                   this */
681   }
682   return CURLE_OK;
683 }
684
685 /**********************************************************
686  *
687  * tftp_tx
688  *
689  * Event handler for the TX state
690  *
691  **********************************************************/
692 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
693 {
694   struct SessionHandle *data = state->conn->data;
695   ssize_t sbytes;
696   int rblock;
697   CURLcode res = CURLE_OK;
698   struct SingleRequest *k = &data->req;
699
700   switch(event) {
701
702   case TFTP_EVENT_ACK:
703     /* Ack the packet */
704     rblock = getrpacketblock(&state->rpacket);
705
706     if(rblock != state->block) {
707       /* This isn't the expected block.  Log it and up the retry counter */
708       infof(data, "Received ACK for block %d, expecting %d\n",
709             rblock, state->block);
710       state->retries++;
711       /* Bail out if over the maximum */
712       if(state->retries>state->retry_max) {
713         failf(data, "tftp_tx: giving up waiting for block %d ack",
714               state->block);
715         res = CURLE_SEND_ERROR;
716       }
717       else {
718         /* Re-send the data packet */
719         sbytes = sendto(state->sockfd, (void *)&state->spacket,
720                         4+state->sbytes, SEND_4TH_ARG,
721                         (struct sockaddr *)&state->remote_addr,
722                         state->remote_addrlen);
723         /* Check all sbytes were sent */
724         if(sbytes<0) {
725           failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
726           res = CURLE_SEND_ERROR;
727         }
728       }
729       return res;
730     }
731     /* This is the expected packet.  Reset the counters and send the next
732        block */
733     time(&state->rx_time);
734     state->block++;
735     state->retries = 0;
736     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
737     setpacketblock(&state->spacket, state->block);
738     if(state->block > 1 && state->sbytes < (int)state->blksize) {
739       state->state = TFTP_STATE_FIN;
740       return CURLE_OK;
741     }
742     res = Curl_fillreadbuffer(state->conn, (size_t)state->blksize,
743                               &state->sbytes);
744     if(res)
745       return res;
746     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
747                     4+state->sbytes, SEND_4TH_ARG,
748                     (struct sockaddr *)&state->remote_addr,
749                     state->remote_addrlen);
750     /* Check all sbytes were sent */
751     if(sbytes<0) {
752       failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
753       return CURLE_SEND_ERROR;
754     }
755     /* Update the progress meter */
756     k->writebytecount += state->sbytes;
757     Curl_pgrsSetUploadCounter(data, k->writebytecount);
758     break;
759
760   case TFTP_EVENT_TIMEOUT:
761     /* Increment the retry counter and log the timeout */
762     state->retries++;
763     infof(data, "Timeout waiting for block %d ACK. "
764           " Retries = %d\n", state->retries);
765     /* Decide if we've had enough */
766     if(state->retries > state->retry_max) {
767       state->error = TFTP_ERR_TIMEOUT;
768       state->state = TFTP_STATE_FIN;
769     }
770     else {
771       /* Re-send the data packet */
772       sbytes = sendto(state->sockfd, (void *)state->spacket.data,
773                       4+state->sbytes, SEND_4TH_ARG,
774                       (struct sockaddr *)&state->remote_addr,
775                       state->remote_addrlen);
776       /* Check all sbytes were sent */
777       if(sbytes<0) {
778         failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
779         return CURLE_SEND_ERROR;
780       }
781       /* since this was a re-send, we remain at the still byte position */
782       Curl_pgrsSetUploadCounter(data, k->writebytecount);
783     }
784     break;
785
786   case TFTP_EVENT_ERROR:
787     state->state = TFTP_STATE_FIN;
788     setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
789     setpacketblock(&state->spacket, state->block);
790     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
791                     4, SEND_4TH_ARG,
792                     (struct sockaddr *)&state->remote_addr,
793                     state->remote_addrlen);
794     /* don't bother with the return code, but if the socket is still up we
795      * should be a good TFTP client and let the server know we're done */
796     state->state = TFTP_STATE_FIN;
797     break;
798
799   default:
800     failf(data, "%s", "tftp_tx: internal error");
801     break;
802   }
803
804   return res;
805 }
806
807 /**********************************************************
808  *
809  * tftp_translate_code
810  *
811  * Translate internal error codes to CURL error codes
812  *
813  **********************************************************/
814 CURLcode tftp_translate_code(tftp_error_t error)
815 {
816   CURLcode code = CURLE_OK;
817
818   if(error != TFTP_ERR_NONE) {
819     switch(error) {
820     case TFTP_ERR_NOTFOUND:
821       code = CURLE_TFTP_NOTFOUND;
822       break;
823     case TFTP_ERR_PERM:
824       code = CURLE_TFTP_PERM;
825       break;
826     case TFTP_ERR_DISKFULL:
827       code = CURLE_REMOTE_DISK_FULL;
828       break;
829     case TFTP_ERR_UNDEF:
830     case TFTP_ERR_ILLEGAL:
831       code = CURLE_TFTP_ILLEGAL;
832       break;
833     case TFTP_ERR_UNKNOWNID:
834       code = CURLE_TFTP_UNKNOWNID;
835       break;
836     case TFTP_ERR_EXISTS:
837       code = CURLE_REMOTE_FILE_EXISTS;
838       break;
839     case TFTP_ERR_NOSUCHUSER:
840       code = CURLE_TFTP_NOSUCHUSER;
841       break;
842     case TFTP_ERR_TIMEOUT:
843       code = CURLE_OPERATION_TIMEDOUT;
844       break;
845     case TFTP_ERR_NORESPONSE:
846       code = CURLE_COULDNT_CONNECT;
847       break;
848     default:
849       code= CURLE_ABORTED_BY_CALLBACK;
850       break;
851     }
852   }
853   else {
854     code = CURLE_OK;
855   }
856
857   return(code);
858 }
859
860 /**********************************************************
861  *
862  * tftp_state_machine
863  *
864  * The tftp state machine event dispatcher
865  *
866  **********************************************************/
867 static CURLcode tftp_state_machine(tftp_state_data_t *state,
868                                    tftp_event_t event)
869 {
870   CURLcode res = CURLE_OK;
871   struct SessionHandle *data = state->conn->data;
872   switch(state->state) {
873   case TFTP_STATE_START:
874     DEBUGF(infof(data, "TFTP_STATE_START\n"));
875     res = tftp_send_first(state, event);
876     break;
877   case TFTP_STATE_RX:
878     DEBUGF(infof(data, "TFTP_STATE_RX\n"));
879     res = tftp_rx(state, event);
880     break;
881   case TFTP_STATE_TX:
882     DEBUGF(infof(data, "TFTP_STATE_TX\n"));
883     res = tftp_tx(state, event);
884     break;
885   case TFTP_STATE_FIN:
886     infof(data, "%s\n", "TFTP finished");
887     break;
888   default:
889     DEBUGF(infof(data, "STATE: %d\n", state->state));
890     failf(data, "%s", "Internal state machine error");
891     res = CURLE_TFTP_ILLEGAL;
892     break;
893   }
894   return res;
895 }
896
897 /**********************************************************
898  *
899  * tftp_disconnect
900  *
901  * The disconnect callback
902  *
903  **********************************************************/
904 static CURLcode tftp_disconnect(struct connectdata *conn)
905 {
906   tftp_state_data_t *state = conn->proto.tftpc;
907
908   /* done, free dynamically allocated pkt buffers */
909   if(state) {
910     Curl_safefree(state->rpacket.data);
911     Curl_safefree(state->spacket.data);
912     free(state);
913   }
914
915   return CURLE_OK;
916 }
917
918 /**********************************************************
919  *
920  * tftp_connect
921  *
922  * The connect callback
923  *
924  **********************************************************/
925 static CURLcode tftp_connect(struct connectdata *conn, bool *done)
926 {
927   CURLcode code;
928   tftp_state_data_t *state;
929   int blksize, rc;
930
931   blksize = TFTP_BLKSIZE_DEFAULT;
932
933   /* If there already is a protocol-specific struct allocated for this
934      sessionhandle, deal with it */
935   Curl_reset_reqproto(conn);
936
937   state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
938   if(!state)
939     return CURLE_OUT_OF_MEMORY;
940
941   /* alloc pkt buffers based on specified blksize */
942   if(conn->data->set.tftp_blksize) {
943     blksize = (int)conn->data->set.tftp_blksize;
944     if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN )
945       return CURLE_TFTP_ILLEGAL;
946   }
947
948   if(!state->rpacket.data) {
949     state->rpacket.data = calloc(1, blksize + 2 + 2);
950
951     if(!state->rpacket.data)
952       return CURLE_OUT_OF_MEMORY;
953   }
954
955   if(!state->spacket.data) {
956     state->spacket.data = calloc(1, blksize + 2 + 2);
957
958     if(!state->spacket.data)
959       return CURLE_OUT_OF_MEMORY;
960   }
961
962   conn->bits.close = TRUE; /* we don't keep TFTP connections up bascially
963                               because there's none or very little gain for UDP
964                            */
965
966   state->conn = conn;
967   state->sockfd = state->conn->sock[FIRSTSOCKET];
968   state->state = TFTP_STATE_START;
969   state->error = TFTP_ERR_NONE;
970   state->blksize = TFTP_BLKSIZE_DEFAULT;
971   state->requested_blksize = blksize;
972
973   ((struct sockaddr *)&state->local_addr)->sa_family =
974     (unsigned short)(conn->ip_addr->ai_family);
975
976   tftp_set_timeouts(state);
977
978   if(!conn->bits.bound) {
979     /* If not already bound, bind to any interface, random UDP port. If it is
980      * reused or a custom local port was desired, this has already been done!
981      *
982      * We once used the size of the local_addr struct as the third argument
983      * for bind() to better work with IPv6 or whatever size the struct could
984      * have, but we learned that at least Tru64, AIX and IRIX *requires* the
985      * size of that argument to match the exact size of a 'sockaddr_in' struct
986      * when running IPv4-only.
987      *
988      * Therefore we use the size from the address we connected to, which we
989      * assume uses the same IP version and thus hopefully this works for both
990      * IPv4 and IPv6...
991      */
992     rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
993               conn->ip_addr->ai_addrlen);
994     if(rc) {
995       failf(conn->data, "bind() failed; %s",
996             Curl_strerror(conn, SOCKERRNO));
997       return CURLE_COULDNT_CONNECT;
998     }
999     conn->bits.bound = TRUE;
1000   }
1001
1002   Curl_pgrsStartNow(conn->data);
1003
1004   *done = TRUE;
1005   code = CURLE_OK;
1006   return(code);
1007 }
1008
1009 /**********************************************************
1010  *
1011  * tftp_done
1012  *
1013  * The done callback
1014  *
1015  **********************************************************/
1016 static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
1017                                bool premature)
1018 {
1019   CURLcode code = CURLE_OK;
1020   tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
1021
1022   (void)status; /* unused */
1023   (void)premature; /* not used */
1024
1025   Curl_pgrsDone(conn);
1026
1027   /* If we have encountered an error */
1028   code = tftp_translate_code(state->error);
1029
1030   return code;
1031 }
1032
1033 /**********************************************************
1034  *
1035  * tftp_getsock
1036  *
1037  * The getsock callback
1038  *
1039  **********************************************************/
1040 static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
1041                        int numsocks)
1042 {
1043   if(!numsocks)
1044     return GETSOCK_BLANK;
1045
1046   socks[0] = conn->sock[FIRSTSOCKET];
1047
1048   return GETSOCK_READSOCK(0);
1049 }
1050
1051 /**********************************************************
1052  *
1053  * tftp_receive_packet
1054  *
1055  * Called once select fires and data is ready on the socket
1056  *
1057  **********************************************************/
1058 static CURLcode tftp_receive_packet(struct connectdata *conn)
1059 {
1060   struct Curl_sockaddr_storage fromaddr;
1061   curl_socklen_t        fromlen;
1062   CURLcode              result = CURLE_OK;
1063   struct SessionHandle  *data = conn->data;
1064   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1065   struct SingleRequest  *k = &data->req;
1066
1067   /* Receive the packet */
1068   fromlen = sizeof(fromaddr);
1069   state->rbytes = (int)recvfrom(state->sockfd,
1070                                    (void *)state->rpacket.data,
1071                                    state->blksize+4,
1072                                    0,
1073                                    (struct sockaddr *)&fromaddr,
1074                                    &fromlen);
1075   if(state->remote_addrlen==0) {
1076     memcpy(&state->remote_addr, &fromaddr, fromlen);
1077     state->remote_addrlen = fromlen;
1078   }
1079
1080   /* Sanity check packet length */
1081   if(state->rbytes < 4) {
1082     failf(data, "Received too short packet");
1083     /* Not a timeout, but how best to handle it? */
1084     state->event = TFTP_EVENT_TIMEOUT;
1085   }
1086   else {
1087     /* The event is given by the TFTP packet time */
1088     state->event = (tftp_event_t)getrpacketevent(&state->rpacket);
1089
1090     switch(state->event) {
1091     case TFTP_EVENT_DATA:
1092       /* Don't pass to the client empty or retransmitted packets */
1093       if(state->rbytes > 4 &&
1094           ((state->block+1) == getrpacketblock(&state->rpacket))) {
1095         result = Curl_client_write(conn, CLIENTWRITE_BODY,
1096                                  (char *)state->rpacket.data+4,
1097                                  state->rbytes-4);
1098         if(result) {
1099           tftp_state_machine(state, TFTP_EVENT_ERROR);
1100           return result;
1101         }
1102         k->bytecount += state->rbytes-4;
1103         Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
1104       }
1105       break;
1106     case TFTP_EVENT_ERROR:
1107       state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
1108       infof(data, "%s\n", (const char *)state->rpacket.data+4);
1109       break;
1110     case TFTP_EVENT_ACK:
1111       break;
1112     case TFTP_EVENT_OACK:
1113       result = tftp_parse_option_ack(state,
1114                                    (const char *)state->rpacket.data+2,
1115                                    state->rbytes-2);
1116       if(result)
1117         return result;
1118       break;
1119     case TFTP_EVENT_RRQ:
1120     case TFTP_EVENT_WRQ:
1121     default:
1122       failf(data, "%s", "Internal error: Unexpected packet");
1123       break;
1124     }
1125
1126     /* Update the progress meter */
1127     if(Curl_pgrsUpdate(conn)) {
1128       tftp_state_machine(state, TFTP_EVENT_ERROR);
1129       return CURLE_ABORTED_BY_CALLBACK;
1130     }
1131   }
1132   return result;
1133 }
1134
1135 /**********************************************************
1136  *
1137  * tftp_state_timeout
1138  *
1139  * Check if timeouts have been reached
1140  *
1141  **********************************************************/
1142 static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
1143 {
1144   time_t                current;
1145   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1146
1147   if (event)
1148     *event = TFTP_EVENT_NONE;
1149
1150   time(&current);
1151   if(current > state->max_time) {
1152     DEBUGF(infof(conn->data, "timeout: %d > %d\n",
1153                  current, state->max_time));
1154     state->error = TFTP_ERR_TIMEOUT;
1155     state->state = TFTP_STATE_FIN;
1156     return(0);
1157   }
1158   else if (current > state->rx_time+state->retry_time) {
1159     if (event)
1160       *event = TFTP_EVENT_TIMEOUT;
1161     time(&state->rx_time); /* update even though we received nothing */
1162     return(state->max_time-current);
1163   }
1164   else {
1165     return(state->max_time-current);
1166   }
1167 }
1168
1169 /**********************************************************
1170  *
1171  * tftp_easy_statemach
1172  *
1173  * Handle easy request until completion
1174  *
1175  **********************************************************/
1176 static CURLcode tftp_easy_statemach(struct connectdata *conn)
1177 {
1178   int                   rc;
1179   int                   check_time = 0;
1180   CURLcode              result = CURLE_OK;
1181   struct SessionHandle  *data = conn->data;
1182   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1183
1184   /* Run the TFTP State Machine */
1185   for(;
1186       (state->state != TFTP_STATE_FIN) && (result == CURLE_OK);
1187       result=tftp_state_machine(state, state->event) ) {
1188
1189     /* Wait until ready to read or timeout occurs */
1190     rc=Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD,
1191                          state->retry_time * 1000);
1192
1193     if(rc == -1) {
1194       /* bail out */
1195       int error = SOCKERRNO;
1196       failf(data, "%s", Curl_strerror(conn, error));
1197       state->event = TFTP_EVENT_ERROR;
1198     }
1199     else if(rc==0) {
1200       /* A timeout occured */
1201       state->event = TFTP_EVENT_TIMEOUT;
1202
1203       /* Force a look at transfer timeouts */
1204       check_time = 0;
1205
1206     }
1207     else {
1208         result = tftp_receive_packet(conn);
1209     }
1210
1211     /* Check for transfer timeout every 10 blocks, or after timeout */
1212     if(check_time%10==0) {
1213       /* ignore the event here as Curl_socket_ready() handles
1214        * retransmission timeouts inside the easy state mach */
1215       tftp_state_timeout(conn, NULL);
1216     }
1217
1218     if(result)
1219       return(result);
1220   }
1221
1222   /* Tell curl we're done */
1223   result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1224
1225   return(result);
1226 }
1227
1228 /**********************************************************
1229  *
1230  * tftp_multi_statemach
1231  *
1232  * Handle single RX socket event and return
1233  *
1234  **********************************************************/
1235 static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
1236 {
1237   int                   rc;
1238   tftp_event_t          event;
1239   CURLcode              result = CURLE_OK;
1240   struct SessionHandle  *data = conn->data;
1241   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1242   long                  timeout_ms = tftp_state_timeout(conn, &event);
1243
1244   *done = FALSE;
1245
1246   if(timeout_ms <= 0) {
1247     failf(data, "TFTP response timeout");
1248     return CURLE_OPERATION_TIMEDOUT;
1249   }
1250   else if (event != TFTP_EVENT_NONE) {
1251     result = tftp_state_machine(state, event);
1252     if(result != CURLE_OK)
1253       return(result);
1254     *done = (bool)(state->state == TFTP_STATE_FIN);
1255     if(*done)
1256       /* Tell curl we're done */
1257       result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1258   }
1259   else {
1260     /* no timeouts to handle, check our socket */
1261     rc = Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD, 0);
1262
1263     if(rc == -1) {
1264       /* bail out */
1265       int error = SOCKERRNO;
1266       failf(data, "%s", Curl_strerror(conn, error));
1267       state->event = TFTP_EVENT_ERROR;
1268     }
1269     else if(rc != 0) {
1270       result = tftp_receive_packet(conn);
1271       if(result != CURLE_OK)
1272         return(result);
1273       result = tftp_state_machine(state, state->event);
1274       if(result != CURLE_OK)
1275         return(result);
1276       *done = (bool)(state->state == TFTP_STATE_FIN);
1277       if(*done)
1278         /* Tell curl we're done */
1279         result = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
1280     }
1281     /* if rc == 0, then select() timed out */
1282   }
1283
1284   return result;
1285 }
1286
1287 /**********************************************************
1288  *
1289  * tftp_doing
1290  *
1291  * Called from multi.c while DOing
1292  *
1293  **********************************************************/
1294 static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
1295 {
1296   CURLcode result;
1297   result = tftp_multi_statemach(conn, dophase_done);
1298
1299   if(*dophase_done) {
1300     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1301   }
1302   return result;
1303 }
1304
1305 /**********************************************************
1306  *
1307  * tftp_peform
1308  *
1309  * Entry point for transfer from tftp_do, sarts state mach
1310  *
1311  **********************************************************/
1312 static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
1313 {
1314   CURLcode              result = CURLE_OK;
1315   tftp_state_data_t     *state = (tftp_state_data_t *)conn->proto.tftpc;
1316
1317   *dophase_done = FALSE;
1318
1319   result = tftp_state_machine(state, TFTP_EVENT_INIT);
1320
1321   if(state->state == TFTP_STATE_FIN || result != CURLE_OK)
1322     return(result);
1323
1324   if(conn->data->state.used_interface == Curl_if_multi)
1325     tftp_multi_statemach(conn, dophase_done);
1326   else {
1327     result = tftp_easy_statemach(conn);
1328     *dophase_done = TRUE; /* with the easy interface we are done here */
1329   }
1330
1331   if(*dophase_done)
1332     DEBUGF(infof(conn->data, "DO phase is complete\n"));
1333
1334   return result;
1335 }
1336
1337
1338 /**********************************************************
1339  *
1340  * tftp_do
1341  *
1342  * The do callback
1343  *
1344  * This callback initiates the TFTP transfer
1345  *
1346  **********************************************************/
1347
1348 static CURLcode tftp_do(struct connectdata *conn, bool *done)
1349 {
1350   tftp_state_data_t     *state;
1351   CURLcode              code;
1352
1353   *done = FALSE;
1354
1355   /*
1356     Since connections can be re-used between SessionHandles, this might be a
1357     connection already existing but on a fresh SessionHandle struct so we must
1358     make sure we have a good 'struct TFTP' to play with. For new connections,
1359     the struct TFTP is allocated and setup in the tftp_connect() function.
1360   */
1361   Curl_reset_reqproto(conn);
1362
1363   if(!conn->proto.tftpc) {
1364     code = tftp_connect(conn, done);
1365     if(code)
1366       return code;
1367   }
1368   state = (tftp_state_data_t *)conn->proto.tftpc;
1369
1370   code = tftp_perform(conn, done);
1371
1372   /* If we have encountered an error */
1373   code = tftp_translate_code(state->error);
1374
1375   return code;
1376 }
1377
1378 static CURLcode tftp_setup_connection(struct connectdata * conn)
1379 {
1380   struct SessionHandle *data = conn->data;
1381   char * type;
1382   char command;
1383
1384   conn->socktype = SOCK_DGRAM;   /* UDP datagram based */
1385
1386   /* TFTP URLs support an extension like ";mode=<typecode>" that
1387    * we'll try to get now! */
1388   type = strstr(data->state.path, ";mode=");
1389
1390   if(!type)
1391     type = strstr(conn->host.rawalloc, ";mode=");
1392
1393   if(type) {
1394     *type = 0;                   /* it was in the middle of the hostname */
1395     command = Curl_raw_toupper(type[6]);
1396
1397     switch (command) {
1398     case 'A': /* ASCII mode */
1399     case 'N': /* NETASCII mode */
1400       data->set.prefer_ascii = TRUE;
1401       break;
1402
1403     case 'O': /* octet mode */
1404     case 'I': /* binary mode */
1405     default:
1406       /* switch off ASCII */
1407       data->set.prefer_ascii = FALSE;
1408       break;
1409     }
1410   }
1411
1412   return CURLE_OK;
1413 }
1414 #endif