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