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