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