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