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