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