All static functions that were previously name Curl_* something no longer
[platform/upstream/curl.git] / lib / tftp.c
1 /***************************************************************************
2  *                                  _   _ ____  _
3  *  Project                     ___| | | |  _ \| |
4  *                             / __| | | | |_) | |
5  *                            | (__| |_| |  _ <| |___
6  *                             \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 1998 - 2007, 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 <string.h>
30 #include <stdarg.h>
31 #include <stdlib.h>
32 #include <ctype.h>
33
34 #if defined(WIN32)
35 #include <time.h>
36 #include <io.h>
37 #else
38 #ifdef HAVE_SYS_SOCKET_H
39 #include <sys/socket.h>
40 #endif
41 #include <netinet/in.h>
42 #ifdef HAVE_SYS_TIME_H
43 #include <sys/time.h>
44 #endif
45 #ifdef HAVE_UNISTD_H
46 #include <unistd.h>
47 #endif
48 #include <netdb.h>
49 #ifdef HAVE_ARPA_INET_H
50 #include <arpa/inet.h>
51 #endif
52 #ifdef HAVE_NET_IF_H
53 #include <net/if.h>
54 #endif
55 #include <sys/ioctl.h>
56 #include <signal.h>
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 "url.h"
74
75 #define _MPRINTF_REPLACE /* use our functions only */
76 #include <curl/mprintf.h>
77
78 #include "memory.h"
79 #include "select.h"
80
81 /* The last #include file should be: */
82 #include "memdebug.h"
83
84 /* RFC2348 allows the block size to be negotiated, but we don't support that */
85 #define TFTP_BLOCKSIZE 512
86
87 typedef enum {
88   TFTP_MODE_NETASCII=0,
89   TFTP_MODE_OCTET
90 } tftp_mode_t;
91
92 typedef enum {
93   TFTP_STATE_START=0,
94   TFTP_STATE_RX,
95   TFTP_STATE_TX,
96   TFTP_STATE_FIN
97 } tftp_state_t;
98
99 typedef enum {
100   TFTP_EVENT_INIT=0,
101   TFTP_EVENT_RRQ = 1,
102   TFTP_EVENT_WRQ = 2,
103   TFTP_EVENT_DATA = 3,
104   TFTP_EVENT_ACK = 4,
105   TFTP_EVENT_ERROR = 5,
106   TFTP_EVENT_TIMEOUT
107 } tftp_event_t;
108
109 typedef enum {
110   TFTP_ERR_UNDEF=0,
111   TFTP_ERR_NOTFOUND,
112   TFTP_ERR_PERM,
113   TFTP_ERR_DISKFULL,
114   TFTP_ERR_ILLEGAL,
115   TFTP_ERR_UNKNOWNID,
116   TFTP_ERR_EXISTS,
117   TFTP_ERR_NOSUCHUSER,  /* This will never be triggered by this code */
118
119   /* The remaining error codes are internal to curl */
120   TFTP_ERR_NONE = -100,
121   TFTP_ERR_TIMEOUT,
122   TFTP_ERR_NORESPONSE
123 } tftp_error_t;
124
125 typedef struct tftp_packet {
126   unsigned char data[2 + 2 + TFTP_BLOCKSIZE];
127 } tftp_packet_t;
128
129 typedef struct tftp_state_data {
130   tftp_state_t    state;
131   tftp_mode_t     mode;
132   tftp_error_t    error;
133   struct connectdata      *conn;
134   curl_socket_t   sockfd;
135   int             retries;
136   int             retry_time;
137   int             retry_max;
138   time_t          start_time;
139   time_t          max_time;
140   unsigned short  block;
141   struct Curl_sockaddr_storage   local_addr;
142   struct Curl_sockaddr_storage   remote_addr;
143   socklen_t       remote_addrlen;
144   int             rbytes;
145   int             sbytes;
146   tftp_packet_t   rpacket;
147   tftp_packet_t   spacket;
148 } tftp_state_data_t;
149
150
151 /* Forward declarations */
152 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ;
153 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ;
154 static CURLcode tftp_connect(struct connectdata *conn, bool *done);
155 static CURLcode tftp_do(struct connectdata *conn, bool *done);
156 static CURLcode tftp_done(struct connectdata *conn,
157                                CURLcode, bool premature);
158 static CURLcode tftp_setup_connection(struct connectdata * conn);
159
160
161 /*
162  * TFTP protocol handler.
163  */
164
165 const struct Curl_handler Curl_handler_tftp = {
166   "TFTP",                               /* scheme */
167   tftp_setup_connection,                /* setup_connection */
168   tftp_do,                              /* do_it */
169   tftp_done,                            /* done */
170   ZERO_NULL,                            /* do_more */
171   tftp_connect,                         /* connect_it */
172   ZERO_NULL,                            /* connecting */
173   ZERO_NULL,                            /* doing */
174   ZERO_NULL,                            /* proto_getsock */
175   ZERO_NULL,                            /* doing_getsock */
176   ZERO_NULL,                            /* disconnect */
177   PORT_TFTP,                            /* defport */
178   PROT_TFTP                             /* protocol */
179 };
180
181
182 /**********************************************************
183  *
184  * tftp_set_timeouts -
185  *
186  * Set timeouts based on state machine state.
187  * Use user provided connect timeouts until DATA or ACK
188  * packet is received, then use user-provided transfer timeouts
189  *
190  *
191  **********************************************************/
192 static void tftp_set_timeouts(tftp_state_data_t *state)
193 {
194
195   struct SessionHandle *data = state->conn->data;
196   time_t maxtime, timeout;
197
198   time(&state->start_time);
199   if(state->state == TFTP_STATE_START) {
200     /* Compute drop-dead time */
201     maxtime = (time_t)(data->set.connecttimeout/1000L?
202                        data->set.connecttimeout/1000L:30);
203     state->max_time = state->start_time+maxtime;
204
205     /* Set per-block timeout to total */
206     timeout = maxtime ;
207
208     /* Average restart after 5 seconds */
209     state->retry_max = timeout/5;
210
211     if(state->retry_max < 1)
212       /* avoid division by zero below */
213       state->retry_max = 1;
214
215     /* Compute the re-start interval to suit the timeout */
216     state->retry_time = timeout/state->retry_max;
217     if(state->retry_time<1)
218       state->retry_time=1;
219
220   }
221   else {
222
223     /* Compute drop-dead time */
224     maxtime = (time_t)(data->set.timeout/1000L?
225                        data->set.timeout/1000L:3600);
226     state->max_time = state->start_time+maxtime;
227
228     /* Set per-block timeout to 10% of total */
229     timeout = maxtime/10 ;
230
231     /* Average reposting an ACK after 15 seconds */
232     state->retry_max = timeout/15;
233   }
234   /* But bound the total number  */
235   if(state->retry_max<3)
236     state->retry_max=3;
237
238   if(state->retry_max>50)
239     state->retry_max=50;
240
241   /* Compute the re-ACK interval to suit the timeout */
242   state->retry_time = timeout/state->retry_max;
243   if(state->retry_time<1)
244     state->retry_time=1;
245
246   infof(data, "set timeouts for state %d; Total %d, retry %d maxtry %d\n",
247         state->state, (state->max_time-state->start_time),
248         state->retry_time, state->retry_max);
249 }
250
251 /**********************************************************
252  *
253  * tftp_set_send_first
254  *
255  * Event handler for the START state
256  *
257  **********************************************************/
258
259 static void setpacketevent(tftp_packet_t *packet, unsigned short num)
260 {
261   packet->data[0] = (unsigned char)(num >> 8);
262   packet->data[1] = (unsigned char)(num & 0xff);
263 }
264
265
266 static void setpacketblock(tftp_packet_t *packet, unsigned short num)
267 {
268   packet->data[2] = (unsigned char)(num >> 8);
269   packet->data[3] = (unsigned char)(num & 0xff);
270 }
271
272 static unsigned short getrpacketevent(const tftp_packet_t *packet)
273 {
274   return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
275 }
276
277 static unsigned short getrpacketblock(const tftp_packet_t *packet)
278 {
279   return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
280 }
281
282 static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
283 {
284   int sbytes;
285   const char *mode = "octet";
286   char *filename;
287   struct SessionHandle *data = state->conn->data;
288   CURLcode res = CURLE_OK;
289
290   /* Set ascii mode if -B flag was used */
291   if(data->set.prefer_ascii)
292     mode = "netascii";
293
294   switch(event) {
295
296   case TFTP_EVENT_INIT:    /* Send the first packet out */
297   case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
298     /* Increment the retry counter, quit if over the limit */
299     state->retries++;
300     if(state->retries>state->retry_max) {
301       state->error = TFTP_ERR_NORESPONSE;
302       state->state = TFTP_STATE_FIN;
303       return res;
304     }
305
306     if(data->set.upload) {
307       /* If we are uploading, send an WRQ */
308       setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
309       state->conn->data->req.upload_fromhere =
310         (char *)&state->spacket.data[4];
311       if(data->set.infilesize != -1)
312         Curl_pgrsSetUploadSize(data, data->set.infilesize);
313     }
314     else {
315       /* If we are downloading, send an RRQ */
316       setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
317     }
318     /* As RFC3617 describes the separator slash is not actually part of the
319     file name so we skip the always-present first letter of the path string. */
320     filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0,
321                                   NULL);
322     if(!filename)
323       return CURLE_OUT_OF_MEMORY;
324
325     snprintf((char *)&state->spacket.data[2],
326              TFTP_BLOCKSIZE,
327              "%s%c%s%c", filename, '\0',  mode, '\0');
328     sbytes = 4 + (int)strlen(filename) + (int)strlen(mode);
329     sbytes = sendto(state->sockfd, (void *)&state->spacket,
330                     sbytes, 0,
331                     state->conn->ip_addr->ai_addr,
332                     state->conn->ip_addr->ai_addrlen);
333     if(sbytes < 0) {
334       failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
335     }
336     Curl_safefree(filename);
337     break;
338
339   case TFTP_EVENT_ACK: /* Connected for transmit */
340     infof(data, "%s\n", "Connected for transmit");
341     state->state = TFTP_STATE_TX;
342     tftp_set_timeouts(state);
343     return tftp_tx(state, event);
344
345   case TFTP_EVENT_DATA: /* connected for receive */
346     infof(data, "%s\n", "Connected for receive");
347     state->state = TFTP_STATE_RX;
348     tftp_set_timeouts(state);
349     return tftp_rx(state, event);
350
351   case TFTP_EVENT_ERROR:
352     state->state = TFTP_STATE_FIN;
353     break;
354
355   default:
356     failf(state->conn->data, "tftp_send_first: internal error\n");
357     break;
358   }
359   return res;
360 }
361
362 /**********************************************************
363  *
364  * tftp_rx
365  *
366  * Event handler for the RX state
367  *
368  **********************************************************/
369 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
370 {
371   int sbytes;
372   int rblock;
373   struct SessionHandle *data = state->conn->data;
374
375   switch(event) {
376
377   case TFTP_EVENT_DATA:
378
379     /* Is this the block we expect? */
380     rblock = getrpacketblock(&state->rpacket);
381     if((state->block+1) != rblock) {
382       /* No, log it, up the retry count and fail if over the limit */
383       infof(data,
384             "Received unexpected DATA packet block %d\n", rblock);
385       state->retries++;
386       if(state->retries>state->retry_max) {
387         failf(data, "tftp_rx: giving up waiting for block %d\n",
388               state->block+1);
389         return CURLE_TFTP_ILLEGAL;
390       }
391     }
392     /* This is the expected block.  Reset counters and ACK it. */
393     state->block = (unsigned short)rblock;
394     state->retries = 0;
395     setpacketevent(&state->spacket, TFTP_EVENT_ACK);
396     setpacketblock(&state->spacket, state->block);
397     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
398                     4, SEND_4TH_ARG,
399                     (struct sockaddr *)&state->remote_addr,
400                     state->remote_addrlen);
401     if(sbytes < 0) {
402       failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
403       return CURLE_SEND_ERROR;
404     }
405
406     /* Check if completed (That is, a less than full packet is received) */
407     if(state->rbytes < (int)sizeof(state->spacket)){
408       state->state = TFTP_STATE_FIN;
409     }
410     else {
411       state->state = TFTP_STATE_RX;
412     }
413     break;
414
415   case TFTP_EVENT_TIMEOUT:
416     /* Increment the retry count and fail if over the limit */
417     state->retries++;
418     infof(data,
419           "Timeout waiting for block %d ACK.  Retries = %d\n", state->retries);
420     if(state->retries > state->retry_max) {
421       state->error = TFTP_ERR_TIMEOUT;
422       state->state = TFTP_STATE_FIN;
423     }
424     else {
425       /* Resend the previous ACK */
426       sbytes = sendto(state->sockfd, (void *)&state->spacket,
427                       4, SEND_4TH_ARG,
428                       (struct sockaddr *)&state->remote_addr,
429                       state->remote_addrlen);
430       /* Check all sbytes were sent */
431       if(sbytes<0) {
432         failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
433         return CURLE_SEND_ERROR;
434       }
435     }
436     break;
437
438   case TFTP_EVENT_ERROR:
439     state->state = TFTP_STATE_FIN;
440     break;
441
442   default:
443     failf(data, "%s\n", "tftp_rx: internal error");
444     return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
445                                   this */
446   }
447   return CURLE_OK;
448 }
449
450 /**********************************************************
451  *
452  * tftp_tx
453  *
454  * Event handler for the TX state
455  *
456  **********************************************************/
457 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
458 {
459   struct SessionHandle *data = state->conn->data;
460   int sbytes;
461   int rblock;
462   CURLcode res = CURLE_OK;
463   struct SingleRequest *k = &data->req;
464
465   switch(event) {
466
467   case TFTP_EVENT_ACK:
468     /* Ack the packet */
469     rblock = getrpacketblock(&state->rpacket);
470
471     if(rblock != state->block) {
472       /* This isn't the expected block.  Log it and up the retry counter */
473       infof(data, "Received ACK for block %d, expecting %d\n",
474             rblock, state->block);
475       state->retries++;
476       /* Bail out if over the maximum */
477       if(state->retries>state->retry_max) {
478         failf(data, "tftp_tx: giving up waiting for block %d ack",
479               state->block);
480         res = CURLE_SEND_ERROR;
481       }
482       else {
483         /* Re-send the data packet */
484         sbytes = sendto(state->sockfd, (void *)&state->spacket,
485                         4+state->sbytes, SEND_4TH_ARG,
486                         (struct sockaddr *)&state->remote_addr,
487                         state->remote_addrlen);
488         /* Check all sbytes were sent */
489         if(sbytes<0) {
490           failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
491           res = CURLE_SEND_ERROR;
492         }
493       }
494       return res;
495     }
496     /* This is the expected packet.  Reset the counters and send the next
497        block */
498     state->block++;
499     state->retries = 0;
500     setpacketevent(&state->spacket, TFTP_EVENT_DATA);
501     setpacketblock(&state->spacket, state->block);
502     if(state->block > 1 && state->sbytes < TFTP_BLOCKSIZE) {
503       state->state = TFTP_STATE_FIN;
504       return CURLE_OK;
505     }
506     res = Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes);
507     if(res)
508       return res;
509     sbytes = sendto(state->sockfd, (void *)state->spacket.data,
510                     4+state->sbytes, SEND_4TH_ARG,
511                     (struct sockaddr *)&state->remote_addr,
512                     state->remote_addrlen);
513     /* Check all sbytes were sent */
514     if(sbytes<0) {
515       failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
516       return CURLE_SEND_ERROR;
517     }
518     /* Update the progress meter */
519     k->writebytecount += state->sbytes;
520     Curl_pgrsSetUploadCounter(data, k->writebytecount);
521     break;
522
523   case TFTP_EVENT_TIMEOUT:
524     /* Increment the retry counter and log the timeout */
525     state->retries++;
526     infof(data, "Timeout waiting for block %d ACK. "
527           " Retries = %d\n", state->retries);
528     /* Decide if we've had enough */
529     if(state->retries > state->retry_max) {
530       state->error = TFTP_ERR_TIMEOUT;
531       state->state = TFTP_STATE_FIN;
532     }
533     else {
534       /* Re-send the data packet */
535       sbytes = sendto(state->sockfd, (void *)&state->spacket,
536                       4+state->sbytes, SEND_4TH_ARG,
537                       (struct sockaddr *)&state->remote_addr,
538                       state->remote_addrlen);
539       /* Check all sbytes were sent */
540       if(sbytes<0) {
541         failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
542         return CURLE_SEND_ERROR;
543       }
544       /* since this was a re-send, we remain at the still byte position */
545       Curl_pgrsSetUploadCounter(data, k->writebytecount);
546     }
547     break;
548
549   case TFTP_EVENT_ERROR:
550     state->state = TFTP_STATE_FIN;
551     break;
552
553   default:
554     failf(data, "%s\n", "tftp_tx: internal error");
555     break;
556   }
557
558   return res;
559 }
560
561 /**********************************************************
562  *
563  * tftp_state_machine
564  *
565  * The tftp state machine event dispatcher
566  *
567  **********************************************************/
568 static CURLcode tftp_state_machine(tftp_state_data_t *state,
569                                    tftp_event_t event)
570 {
571   CURLcode res = CURLE_OK;
572   struct SessionHandle *data = state->conn->data;
573   switch(state->state) {
574   case TFTP_STATE_START:
575     DEBUGF(infof(data, "TFTP_STATE_START\n"));
576     res = tftp_send_first(state, event);
577     break;
578   case TFTP_STATE_RX:
579     DEBUGF(infof(data, "TFTP_STATE_RX\n"));
580     res = tftp_rx(state, event);
581     break;
582   case TFTP_STATE_TX:
583     DEBUGF(infof(data, "TFTP_STATE_TX\n"));
584     res = tftp_tx(state, event);
585     break;
586   case TFTP_STATE_FIN:
587     infof(data, "%s\n", "TFTP finished");
588     break;
589   default:
590     DEBUGF(infof(data, "STATE: %d\n", state->state));
591     failf(data, "%s\n", "Internal state machine error");
592     res = CURLE_TFTP_ILLEGAL;
593     break;
594   }
595   return res;
596 }
597
598
599 /**********************************************************
600  *
601  * tftp_connect
602  *
603  * The connect callback
604  *
605  **********************************************************/
606 static CURLcode tftp_connect(struct connectdata *conn, bool *done)
607 {
608   CURLcode code;
609   tftp_state_data_t *state;
610   int rc;
611
612   /* If there already is a protocol-specific struct allocated for this
613      sessionhandle, deal with it */
614   Curl_reset_reqproto(conn);
615
616   if(!(state = conn->data->state.proto.tftp)) {
617     state = conn->data->state.proto.tftp = calloc(sizeof(tftp_state_data_t),
618                                                   1);
619     if(!state)
620       return CURLE_OUT_OF_MEMORY;
621   }
622
623   conn->bits.close = FALSE; /* keep it open if possible */
624
625   state->conn = conn;
626   state->sockfd = state->conn->sock[FIRSTSOCKET];
627   state->state = TFTP_STATE_START;
628   state->error = TFTP_ERR_NONE;
629
630   ((struct sockaddr *)&state->local_addr)->sa_family =
631     (unsigned short)(conn->ip_addr->ai_family);
632
633   tftp_set_timeouts(state);
634
635   if(!conn->bits.bound) {
636     /* If not already bound, bind to any interface, random UDP port. If it is
637      * reused or a custom local port was desired, this has already been done!
638      *
639      * We once used the size of the local_addr struct as the third argument for
640      * bind() to better work with IPv6 or whatever size the struct could have,
641      * but we learned that at least Tru64, AIX and IRIX *requires* the size of
642      * that argument to match the exact size of a 'sockaddr_in' struct when
643      * running IPv4-only.
644      *
645      * Therefore we use the size from the address we connected to, which we
646      * assume uses the same IP version and thus hopefully this works for both
647      * IPv4 and IPv6...
648      */
649     rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
650               conn->ip_addr->ai_addrlen);
651     if(rc) {
652       failf(conn->data, "bind() failed; %s\n",
653             Curl_strerror(conn, SOCKERRNO));
654       return CURLE_COULDNT_CONNECT;
655     }
656     conn->bits.bound = TRUE;
657   }
658
659   Curl_pgrsStartNow(conn->data);
660
661   *done = TRUE;
662   code = CURLE_OK;
663   return(code);
664 }
665
666 /**********************************************************
667  *
668  * tftp_done
669  *
670  * The done callback
671  *
672  **********************************************************/
673 static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
674                                bool premature)
675 {
676   (void)status; /* unused */
677   (void)premature; /* not used */
678
679   Curl_pgrsDone(conn);
680
681   return CURLE_OK;
682 }
683
684
685 /**********************************************************
686  *
687  * tftp
688  *
689  * The do callback
690  *
691  * This callback handles the entire TFTP transfer
692  *
693  **********************************************************/
694
695 static CURLcode tftp_do(struct connectdata *conn, bool *done)
696 {
697   struct SessionHandle  *data = conn->data;
698   tftp_state_data_t     *state;
699   tftp_event_t          event;
700   CURLcode              code;
701   int                   rc;
702   struct Curl_sockaddr_storage fromaddr;
703   socklen_t             fromlen;
704   int                   check_time = 0;
705   struct SingleRequest *k = &data->req;
706
707   *done = TRUE;
708
709   /*
710     Since connections can be re-used between SessionHandles, this might be a
711     connection already existing but on a fresh SessionHandle struct so we must
712     make sure we have a good 'struct TFTP' to play with. For new connections,
713     the struct TFTP is allocated and setup in the tftp_connect() function.
714   */
715   Curl_reset_reqproto(conn);
716
717   if(!data->state.proto.tftp) {
718     code = tftp_connect(conn, done);
719     if(code)
720       return code;
721   }
722   state = (tftp_state_data_t *)data->state.proto.tftp;
723
724   /* Run the TFTP State Machine */
725   for(code=tftp_state_machine(state, TFTP_EVENT_INIT);
726       (state->state != TFTP_STATE_FIN) && (code == CURLE_OK);
727       code=tftp_state_machine(state, event) ) {
728
729     /* Wait until ready to read or timeout occurs */
730     rc=Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD,
731                          state->retry_time * 1000);
732
733     if(rc == -1) {
734       /* bail out */
735       int error = SOCKERRNO;
736       failf(data, "%s\n", Curl_strerror(conn, error));
737       event = TFTP_EVENT_ERROR;
738     }
739     else if(rc==0) {
740       /* A timeout occured */
741       event = TFTP_EVENT_TIMEOUT;
742
743       /* Force a look at transfer timeouts */
744       check_time = 0;
745
746     }
747     else {
748
749       /* Receive the packet */
750       fromlen=sizeof(fromaddr);
751       state->rbytes = recvfrom(state->sockfd,
752                                (void *)&state->rpacket, sizeof(state->rpacket),
753                                0, (struct sockaddr *)&fromaddr, &fromlen);
754       if(state->remote_addrlen==0) {
755         memcpy(&state->remote_addr, &fromaddr, fromlen);
756         state->remote_addrlen = fromlen;
757       }
758
759       /* Sanity check packet length */
760       if(state->rbytes < 4) {
761         failf(data, "Received too short packet\n");
762         /* Not a timeout, but how best to handle it? */
763         event = TFTP_EVENT_TIMEOUT;
764       }
765       else {
766
767         /* The event is given by the TFTP packet time */
768         event = (tftp_event_t)getrpacketevent(&state->rpacket);
769
770         switch(event) {
771         case TFTP_EVENT_DATA:
772           /* Don't pass to the client empty or retransmitted packets */
773           if(state->rbytes > 4 &&
774               ((state->block+1) == getrpacketblock(&state->rpacket))) {
775             code = Curl_client_write(conn, CLIENTWRITE_BODY,
776                                      (char *)&state->rpacket.data[4],
777                                      state->rbytes-4);
778             if(code)
779               return code;
780             k->bytecount += state->rbytes-4;
781             Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
782           }
783           break;
784         case TFTP_EVENT_ERROR:
785           state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
786           infof(data, "%s\n", (char *)&state->rpacket.data[4]);
787           break;
788         case TFTP_EVENT_ACK:
789           break;
790         case TFTP_EVENT_RRQ:
791         case TFTP_EVENT_WRQ:
792         default:
793           failf(data, "%s\n", "Internal error: Unexpected packet");
794           break;
795         }
796
797         /* Update the progress meter */
798         if(Curl_pgrsUpdate(conn))
799           return CURLE_ABORTED_BY_CALLBACK;
800       }
801     }
802
803     /* Check for transfer timeout every 10 blocks, or after timeout */
804     if(check_time%10==0) {
805       time_t current;
806       time(&current);
807       if(current>state->max_time) {
808         DEBUGF(infof(data, "timeout: %d > %d\n",
809                      current, state->max_time));
810         state->error = TFTP_ERR_TIMEOUT;
811         state->state = TFTP_STATE_FIN;
812       }
813     }
814
815   }
816   if(code)
817     return code;
818
819   /* Tell curl we're done */
820   code = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
821   if(code)
822     return code;
823
824   /* If we have encountered an error */
825   if(state->error != TFTP_ERR_NONE) {
826
827     /* Translate internal error codes to curl error codes */
828     switch(state->error) {
829     case TFTP_ERR_NOTFOUND:
830       code = CURLE_TFTP_NOTFOUND;
831       break;
832     case TFTP_ERR_PERM:
833       code = CURLE_TFTP_PERM;
834       break;
835     case TFTP_ERR_DISKFULL:
836       code = CURLE_REMOTE_DISK_FULL;
837       break;
838     case TFTP_ERR_UNDEF:
839     case TFTP_ERR_ILLEGAL:
840       code = CURLE_TFTP_ILLEGAL;
841       break;
842     case TFTP_ERR_UNKNOWNID:
843       code = CURLE_TFTP_UNKNOWNID;
844       break;
845     case TFTP_ERR_EXISTS:
846       code = CURLE_REMOTE_FILE_EXISTS;
847       break;
848     case TFTP_ERR_NOSUCHUSER:
849       code = CURLE_TFTP_NOSUCHUSER;
850       break;
851     case TFTP_ERR_TIMEOUT:
852       code = CURLE_OPERATION_TIMEDOUT;
853       break;
854     case TFTP_ERR_NORESPONSE:
855       code = CURLE_COULDNT_CONNECT;
856       break;
857     default:
858       code= CURLE_ABORTED_BY_CALLBACK;
859       break;
860     }
861   }
862   else
863     code = CURLE_OK;
864   return code;
865 }
866
867 static CURLcode tftp_setup_connection(struct connectdata * conn)
868 {
869   struct SessionHandle *data = conn->data;
870   char * type;
871   char command;
872
873   conn->socktype = SOCK_DGRAM;   /* UDP datagram based */
874
875   /* TFTP URLs support an extension like ";mode=<typecode>" that
876    * we'll try to get now! */
877   type = strstr(data->state.path, ";mode=");
878
879   if(!type)
880     type = strstr(conn->host.rawalloc, ";mode=");
881
882   if(type) {
883     *type = 0;                   /* it was in the middle of the hostname */
884     command = (char) toupper((int) type[6]);
885
886     switch (command) {
887     case 'A': /* ASCII mode */
888     case 'N': /* NETASCII mode */
889       data->set.prefer_ascii = TRUE;
890       break;
891
892     case 'O': /* octet mode */
893     case 'I': /* binary mode */
894     default:
895       /* switch off ASCII */
896       data->set.prefer_ascii = FALSE;
897       break;
898     }
899   }
900
901   return CURLE_OK;
902 }
903 #endif