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