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