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