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