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
95typedef enum {
96  TFTP_MODE_NETASCII=0,
97  TFTP_MODE_OCTET
98} tftp_mode_t;
99
100typedef enum {
101  TFTP_STATE_START=0,
102  TFTP_STATE_RX,
103  TFTP_STATE_TX,
104  TFTP_STATE_FIN
105} tftp_state_t;
106
107typedef 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
119typedef 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
135typedef struct tftp_packet {
136  unsigned char *data;
137} tftp_packet_t;
138
139typedef 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 */
166static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ;
167static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ;
168static CURLcode tftp_connect(struct connectdata *conn, bool *done);
169static CURLcode tftp_disconnect(struct connectdata *conn,
170                                bool dead_connection);
171static CURLcode tftp_do(struct connectdata *conn, bool *done);
172static CURLcode tftp_done(struct connectdata *conn,
173                          CURLcode, bool premature);
174static CURLcode tftp_setup_connection(struct connectdata * conn);
175static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
176static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
177static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
178                        int numsocks);
179static CURLcode tftp_translate_code(tftp_error_t error);
180
181
182/*
183 * TFTP protocol handler.
184 */
185
186const 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 **********************************************************/
215static 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
298static 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
305static 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
311static unsigned short getrpacketevent(const tftp_packet_t *packet)
312{
313  return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
314}
315
316static unsigned short getrpacketblock(const tftp_packet_t *packet)
317{
318  return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
319}
320
321static 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
327static 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
349static 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
422static 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
431static 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
447static 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
463static 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 **********************************************************/
592static 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 **********************************************************/
709static 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 **********************************************************/
841static 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 **********************************************************/
894static 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 **********************************************************/
931static 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 **********************************************************/
953static 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 **********************************************************/
1044static 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 **********************************************************/
1068static 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 **********************************************************/
1086static 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 **********************************************************/
1170static 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 **********************************************************/
1206static 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 **********************************************************/
1328static 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 **********************************************************/
1387static 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 **********************************************************/
1405static 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
1441static 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
1474static 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
1511