00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "curl_setup.h"
00024
00025 #ifndef CURL_DISABLE_TFTP
00026
00027 #ifdef HAVE_NETINET_IN_H
00028 #include <netinet/in.h>
00029 #endif
00030 #ifdef HAVE_NETDB_H
00031 #include <netdb.h>
00032 #endif
00033 #ifdef HAVE_ARPA_INET_H
00034 #include <arpa/inet.h>
00035 #endif
00036 #ifdef HAVE_NET_IF_H
00037 #include <net/if.h>
00038 #endif
00039 #ifdef HAVE_SYS_IOCTL_H
00040 #include <sys/ioctl.h>
00041 #endif
00042
00043 #ifdef HAVE_SYS_PARAM_H
00044 #include <sys/param.h>
00045 #endif
00046
00047 #include "urldata.h"
00048 #include <curl/curl.h>
00049 #include "transfer.h"
00050 #include "sendf.h"
00051 #include "tftp.h"
00052 #include "progress.h"
00053 #include "connect.h"
00054 #include "strerror.h"
00055 #include "sockaddr.h"
00056 #include "multiif.h"
00057 #include "url.h"
00058 #include "strcase.h"
00059 #include "speedcheck.h"
00060 #include "select.h"
00061 #include "escape.h"
00062
00063
00064 #include "curl_printf.h"
00065 #include "curl_memory.h"
00066 #include "memdebug.h"
00067
00068
00069 #define TFTP_BLKSIZE_DEFAULT 512
00070 #define TFTP_BLKSIZE_MIN 8
00071 #define TFTP_BLKSIZE_MAX 65464
00072 #define TFTP_OPTION_BLKSIZE "blksize"
00073
00074
00075 #define TFTP_OPTION_TSIZE "tsize"
00076 #define TFTP_OPTION_INTERVAL "timeout"
00077
00078 typedef enum {
00079 TFTP_MODE_NETASCII=0,
00080 TFTP_MODE_OCTET
00081 } tftp_mode_t;
00082
00083 typedef enum {
00084 TFTP_STATE_START=0,
00085 TFTP_STATE_RX,
00086 TFTP_STATE_TX,
00087 TFTP_STATE_FIN
00088 } tftp_state_t;
00089
00090 typedef enum {
00091 TFTP_EVENT_NONE = -1,
00092 TFTP_EVENT_INIT = 0,
00093 TFTP_EVENT_RRQ = 1,
00094 TFTP_EVENT_WRQ = 2,
00095 TFTP_EVENT_DATA = 3,
00096 TFTP_EVENT_ACK = 4,
00097 TFTP_EVENT_ERROR = 5,
00098 TFTP_EVENT_OACK = 6,
00099 TFTP_EVENT_TIMEOUT
00100 } tftp_event_t;
00101
00102 typedef enum {
00103 TFTP_ERR_UNDEF=0,
00104 TFTP_ERR_NOTFOUND,
00105 TFTP_ERR_PERM,
00106 TFTP_ERR_DISKFULL,
00107 TFTP_ERR_ILLEGAL,
00108 TFTP_ERR_UNKNOWNID,
00109 TFTP_ERR_EXISTS,
00110 TFTP_ERR_NOSUCHUSER,
00111
00112
00113 TFTP_ERR_NONE = -100,
00114 TFTP_ERR_TIMEOUT,
00115 TFTP_ERR_NORESPONSE
00116 } tftp_error_t;
00117
00118 typedef struct tftp_packet {
00119 unsigned char *data;
00120 } tftp_packet_t;
00121
00122 typedef struct tftp_state_data {
00123 tftp_state_t state;
00124 tftp_mode_t mode;
00125 tftp_error_t error;
00126 tftp_event_t event;
00127 struct connectdata *conn;
00128 curl_socket_t sockfd;
00129 int retries;
00130 int retry_time;
00131 int retry_max;
00132 time_t start_time;
00133 time_t max_time;
00134 time_t rx_time;
00135 unsigned short block;
00136 struct Curl_sockaddr_storage local_addr;
00137 struct Curl_sockaddr_storage remote_addr;
00138 curl_socklen_t remote_addrlen;
00139 int rbytes;
00140 int sbytes;
00141 int blksize;
00142 int requested_blksize;
00143 tftp_packet_t rpacket;
00144 tftp_packet_t spacket;
00145 } tftp_state_data_t;
00146
00147
00148
00149 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event);
00150 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event);
00151 static CURLcode tftp_connect(struct connectdata *conn, bool *done);
00152 static CURLcode tftp_disconnect(struct connectdata *conn,
00153 bool dead_connection);
00154 static CURLcode tftp_do(struct connectdata *conn, bool *done);
00155 static CURLcode tftp_done(struct connectdata *conn,
00156 CURLcode, bool premature);
00157 static CURLcode tftp_setup_connection(struct connectdata * conn);
00158 static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
00159 static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
00160 static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
00161 int numsocks);
00162 static CURLcode tftp_translate_code(tftp_error_t error);
00163
00164
00165
00166
00167
00168
00169 const struct Curl_handler Curl_handler_tftp = {
00170 "TFTP",
00171 tftp_setup_connection,
00172 tftp_do,
00173 tftp_done,
00174 ZERO_NULL,
00175 tftp_connect,
00176 tftp_multi_statemach,
00177 tftp_doing,
00178 tftp_getsock,
00179 tftp_getsock,
00180 ZERO_NULL,
00181 ZERO_NULL,
00182 tftp_disconnect,
00183 ZERO_NULL,
00184 PORT_TFTP,
00185 CURLPROTO_TFTP,
00186 PROTOPT_NONE | PROTOPT_NOURLQUERY
00187 };
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199 static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
00200 {
00201 time_t maxtime, timeout;
00202 time_t timeout_ms;
00203 bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
00204
00205 time(&state->start_time);
00206
00207
00208 timeout_ms = Curl_timeleft(state->conn->data, NULL, start);
00209
00210 if(timeout_ms < 0) {
00211
00212 failf(state->conn->data, "Connection time-out");
00213 return CURLE_OPERATION_TIMEDOUT;
00214 }
00215
00216 if(start) {
00217
00218 maxtime = (time_t)(timeout_ms + 500) / 1000;
00219 state->max_time = state->start_time+maxtime;
00220
00221
00222 timeout = maxtime;
00223
00224
00225 state->retry_max = (int)timeout/5;
00226
00227 if(state->retry_max < 1)
00228
00229 state->retry_max = 1;
00230
00231
00232 state->retry_time = (int)timeout/state->retry_max;
00233 if(state->retry_time<1)
00234 state->retry_time=1;
00235
00236 }
00237 else {
00238 if(timeout_ms > 0)
00239 maxtime = (time_t)(timeout_ms + 500) / 1000;
00240 else
00241 maxtime = 3600;
00242
00243 state->max_time = state->start_time+maxtime;
00244
00245
00246 timeout = maxtime;
00247
00248
00249 state->retry_max = (int)timeout/5;
00250 }
00251
00252 if(state->retry_max<3)
00253 state->retry_max=3;
00254
00255 if(state->retry_max>50)
00256 state->retry_max=50;
00257
00258
00259 state->retry_time = (int)(timeout/state->retry_max);
00260 if(state->retry_time<1)
00261 state->retry_time=1;
00262
00263 infof(state->conn->data,
00264 "set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
00265 (int)state->state, (long)(state->max_time-state->start_time),
00266 state->retry_time, state->retry_max);
00267
00268
00269 time(&state->rx_time);
00270
00271 return CURLE_OK;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 static void setpacketevent(tftp_packet_t *packet, unsigned short num)
00283 {
00284 packet->data[0] = (unsigned char)(num >> 8);
00285 packet->data[1] = (unsigned char)(num & 0xff);
00286 }
00287
00288
00289 static void setpacketblock(tftp_packet_t *packet, unsigned short num)
00290 {
00291 packet->data[2] = (unsigned char)(num >> 8);
00292 packet->data[3] = (unsigned char)(num & 0xff);
00293 }
00294
00295 static unsigned short getrpacketevent(const tftp_packet_t *packet)
00296 {
00297 return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
00298 }
00299
00300 static unsigned short getrpacketblock(const tftp_packet_t *packet)
00301 {
00302 return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
00303 }
00304
00305 static size_t Curl_strnlen(const char *string, size_t maxlen)
00306 {
00307 const char *end = memchr(string, '\0', maxlen);
00308 return end ? (size_t) (end - string) : maxlen;
00309 }
00310
00311 static const char *tftp_option_get(const char *buf, size_t len,
00312 const char **option, const char **value)
00313 {
00314 size_t loc;
00315
00316 loc = Curl_strnlen(buf, len);
00317 loc++;
00318
00319 if(loc >= len)
00320 return NULL;
00321 *option = buf;
00322
00323 loc += Curl_strnlen(buf+loc, len-loc);
00324 loc++;
00325
00326 if(loc > len)
00327 return NULL;
00328 *value = &buf[strlen(*option) + 1];
00329
00330 return &buf[loc];
00331 }
00332
00333 static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
00334 const char *ptr, int len)
00335 {
00336 const char *tmp = ptr;
00337 struct Curl_easy *data = state->conn->data;
00338
00339
00340 state->blksize = TFTP_BLKSIZE_DEFAULT;
00341
00342 while(tmp < ptr + len) {
00343 const char *option, *value;
00344
00345 tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
00346 if(tmp == NULL) {
00347 failf(data, "Malformed ACK packet, rejecting");
00348 return CURLE_TFTP_ILLEGAL;
00349 }
00350
00351 infof(data, "got option=(%s) value=(%s)\n", option, value);
00352
00353 if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
00354 long blksize;
00355
00356 blksize = strtol(value, NULL, 10);
00357
00358 if(!blksize) {
00359 failf(data, "invalid blocksize value in OACK packet");
00360 return CURLE_TFTP_ILLEGAL;
00361 }
00362 else if(blksize > TFTP_BLKSIZE_MAX) {
00363 failf(data, "%s (%d)", "blksize is larger than max supported",
00364 TFTP_BLKSIZE_MAX);
00365 return CURLE_TFTP_ILLEGAL;
00366 }
00367 else if(blksize < TFTP_BLKSIZE_MIN) {
00368 failf(data, "%s (%d)", "blksize is smaller than min supported",
00369 TFTP_BLKSIZE_MIN);
00370 return CURLE_TFTP_ILLEGAL;
00371 }
00372 else if(blksize > state->requested_blksize) {
00373
00374
00375
00376 failf(data, "%s (%ld)",
00377 "server requested blksize larger than allocated", blksize);
00378 return CURLE_TFTP_ILLEGAL;
00379 }
00380
00381 state->blksize = (int)blksize;
00382 infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
00383 state->blksize, "requested", state->requested_blksize);
00384 }
00385 else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
00386 long tsize = 0;
00387
00388 tsize = strtol(value, NULL, 10);
00389 infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
00390
00391
00392
00393 if(!data->set.upload) {
00394 if(!tsize) {
00395 failf(data, "invalid tsize -:%s:- value in OACK packet", value);
00396 return CURLE_TFTP_ILLEGAL;
00397 }
00398 Curl_pgrsSetDownloadSize(data, tsize);
00399 }
00400 }
00401 }
00402
00403 return CURLE_OK;
00404 }
00405
00406 static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
00407 char *buf, const char *option)
00408 {
00409 if(( strlen(option) + csize + 1) > (size_t)state->blksize)
00410 return 0;
00411 strcpy(buf, option);
00412 return strlen(option) + 1;
00413 }
00414
00415 static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
00416 tftp_event_t event)
00417 {
00418 CURLcode result;
00419 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00420 struct Curl_easy *data = state->conn->data;
00421
00422 infof(data, "%s\n", "Connected for transmit");
00423 #endif
00424 state->state = TFTP_STATE_TX;
00425 result = tftp_set_timeouts(state);
00426 if(result)
00427 return result;
00428 return tftp_tx(state, event);
00429 }
00430
00431 static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
00432 tftp_event_t event)
00433 {
00434 CURLcode result;
00435 #ifndef CURL_DISABLE_VERBOSE_STRINGS
00436 struct Curl_easy *data = state->conn->data;
00437
00438 infof(data, "%s\n", "Connected for receive");
00439 #endif
00440 state->state = TFTP_STATE_RX;
00441 result = tftp_set_timeouts(state);
00442 if(result)
00443 return result;
00444 return tftp_rx(state, event);
00445 }
00446
00447 static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
00448 {
00449 size_t sbytes;
00450 ssize_t senddata;
00451 const char *mode = "octet";
00452 char *filename;
00453 char buf[64];
00454 struct Curl_easy *data = state->conn->data;
00455 CURLcode result = CURLE_OK;
00456
00457
00458 if(data->set.prefer_ascii)
00459 mode = "netascii";
00460
00461 switch(event) {
00462
00463 case TFTP_EVENT_INIT:
00464 case TFTP_EVENT_TIMEOUT:
00465
00466 state->retries++;
00467 if(state->retries>state->retry_max) {
00468 state->error = TFTP_ERR_NORESPONSE;
00469 state->state = TFTP_STATE_FIN;
00470 return result;
00471 }
00472
00473 if(data->set.upload) {
00474
00475 setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
00476 state->conn->data->req.upload_fromhere =
00477 (char *)state->spacket.data+4;
00478 if(data->state.infilesize != -1)
00479 Curl_pgrsSetUploadSize(data, data->state.infilesize);
00480 }
00481 else {
00482
00483 setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
00484 }
00485
00486
00487
00488 result = Curl_urldecode(data, &state->conn->data->state.path[1], 0,
00489 &filename, NULL, FALSE);
00490 if(result)
00491 return result;
00492
00493 snprintf((char *)state->spacket.data+2,
00494 state->blksize,
00495 "%s%c%s%c", filename, '\0', mode, '\0');
00496 sbytes = 4 + strlen(filename) + strlen(mode);
00497
00498
00499 if(!data->set.tftp_no_options) {
00500
00501 if(data->set.upload && (data->state.infilesize != -1))
00502 snprintf(buf, sizeof(buf), "%" CURL_FORMAT_CURL_OFF_T,
00503 data->state.infilesize);
00504 else
00505 strcpy(buf, "0");
00506
00507 sbytes += tftp_option_add(state, sbytes,
00508 (char *)state->spacket.data+sbytes,
00509 TFTP_OPTION_TSIZE);
00510 sbytes += tftp_option_add(state, sbytes,
00511 (char *)state->spacket.data+sbytes, buf);
00512
00513 snprintf(buf, sizeof(buf), "%d", state->requested_blksize);
00514 sbytes += tftp_option_add(state, sbytes,
00515 (char *)state->spacket.data+sbytes,
00516 TFTP_OPTION_BLKSIZE);
00517 sbytes += tftp_option_add(state, sbytes,
00518 (char *)state->spacket.data+sbytes, buf);
00519
00520
00521 snprintf(buf, sizeof(buf), "%d", state->retry_time);
00522 sbytes += tftp_option_add(state, sbytes,
00523 (char *)state->spacket.data+sbytes,
00524 TFTP_OPTION_INTERVAL);
00525 sbytes += tftp_option_add(state, sbytes,
00526 (char *)state->spacket.data+sbytes, buf);
00527 }
00528
00529
00530
00531 senddata = sendto(state->sockfd, (void *)state->spacket.data,
00532 (SEND_TYPE_ARG3)sbytes, 0,
00533 state->conn->ip_addr->ai_addr,
00534 state->conn->ip_addr->ai_addrlen);
00535 if(senddata != (ssize_t)sbytes) {
00536 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00537 }
00538 free(filename);
00539 break;
00540
00541 case TFTP_EVENT_OACK:
00542 if(data->set.upload) {
00543 result = tftp_connect_for_tx(state, event);
00544 }
00545 else {
00546 result = tftp_connect_for_rx(state, event);
00547 }
00548 break;
00549
00550 case TFTP_EVENT_ACK:
00551 result = tftp_connect_for_tx(state, event);
00552 break;
00553
00554 case TFTP_EVENT_DATA:
00555 result = tftp_connect_for_rx(state, event);
00556 break;
00557
00558 case TFTP_EVENT_ERROR:
00559 state->state = TFTP_STATE_FIN;
00560 break;
00561
00562 default:
00563 failf(state->conn->data, "tftp_send_first: internal error");
00564 break;
00565 }
00566
00567 return result;
00568 }
00569
00570
00571
00572 #define NEXT_BLOCKNUM(x) (((x)+1)&0xffff)
00573
00574
00575
00576
00577
00578
00579
00580
00581 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
00582 {
00583 ssize_t sbytes;
00584 int rblock;
00585 struct Curl_easy *data = state->conn->data;
00586
00587 switch(event) {
00588
00589 case TFTP_EVENT_DATA:
00590
00591 rblock = getrpacketblock(&state->rpacket);
00592 if(NEXT_BLOCKNUM(state->block) == rblock) {
00593
00594 state->retries = 0;
00595 }
00596 else if(state->block == rblock) {
00597
00598
00599 infof(data, "Received last DATA packet block %d again.\n", rblock);
00600 }
00601 else {
00602
00603 infof(data,
00604 "Received unexpected DATA packet block %d, expecting block %d\n",
00605 rblock, NEXT_BLOCKNUM(state->block));
00606 break;
00607 }
00608
00609
00610 state->block = (unsigned short)rblock;
00611 setpacketevent(&state->spacket, TFTP_EVENT_ACK);
00612 setpacketblock(&state->spacket, state->block);
00613 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00614 4, SEND_4TH_ARG,
00615 (struct sockaddr *)&state->remote_addr,
00616 state->remote_addrlen);
00617 if(sbytes < 0) {
00618 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00619 return CURLE_SEND_ERROR;
00620 }
00621
00622
00623 if(state->rbytes < (ssize_t)state->blksize+4) {
00624 state->state = TFTP_STATE_FIN;
00625 }
00626 else {
00627 state->state = TFTP_STATE_RX;
00628 }
00629 time(&state->rx_time);
00630 break;
00631
00632 case TFTP_EVENT_OACK:
00633
00634 state->block = 0;
00635 state->retries = 0;
00636 setpacketevent(&state->spacket, TFTP_EVENT_ACK);
00637 setpacketblock(&state->spacket, state->block);
00638 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00639 4, SEND_4TH_ARG,
00640 (struct sockaddr *)&state->remote_addr,
00641 state->remote_addrlen);
00642 if(sbytes < 0) {
00643 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00644 return CURLE_SEND_ERROR;
00645 }
00646
00647
00648 state->state = TFTP_STATE_RX;
00649 time(&state->rx_time);
00650 break;
00651
00652 case TFTP_EVENT_TIMEOUT:
00653
00654 state->retries++;
00655 infof(data,
00656 "Timeout waiting for block %d ACK. Retries = %d\n",
00657 NEXT_BLOCKNUM(state->block), state->retries);
00658 if(state->retries > state->retry_max) {
00659 state->error = TFTP_ERR_TIMEOUT;
00660 state->state = TFTP_STATE_FIN;
00661 }
00662 else {
00663
00664 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00665 4, SEND_4TH_ARG,
00666 (struct sockaddr *)&state->remote_addr,
00667 state->remote_addrlen);
00668 if(sbytes<0) {
00669 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00670 return CURLE_SEND_ERROR;
00671 }
00672 }
00673 break;
00674
00675 case TFTP_EVENT_ERROR:
00676 setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
00677 setpacketblock(&state->spacket, state->block);
00678 (void)sendto(state->sockfd, (void *)state->spacket.data,
00679 4, SEND_4TH_ARG,
00680 (struct sockaddr *)&state->remote_addr,
00681 state->remote_addrlen);
00682
00683
00684 state->state = TFTP_STATE_FIN;
00685 break;
00686
00687 default:
00688 failf(data, "%s", "tftp_rx: internal error");
00689 return CURLE_TFTP_ILLEGAL;
00690
00691 }
00692 return CURLE_OK;
00693 }
00694
00695
00696
00697
00698
00699
00700
00701
00702 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
00703 {
00704 struct Curl_easy *data = state->conn->data;
00705 ssize_t sbytes;
00706 int rblock;
00707 CURLcode result = CURLE_OK;
00708 struct SingleRequest *k = &data->req;
00709 int cb;
00710
00711 switch(event) {
00712
00713 case TFTP_EVENT_ACK:
00714 case TFTP_EVENT_OACK:
00715 if(event == TFTP_EVENT_ACK) {
00716
00717 rblock = getrpacketblock(&state->rpacket);
00718
00719 if(rblock != state->block &&
00720
00721
00722
00723
00724
00725 !(state->block == 0 && rblock == 65535)) {
00726
00727 infof(data, "Received ACK for block %d, expecting %d\n",
00728 rblock, state->block);
00729 state->retries++;
00730
00731 if(state->retries>state->retry_max) {
00732 failf(data, "tftp_tx: giving up waiting for block %d ack",
00733 state->block);
00734 result = CURLE_SEND_ERROR;
00735 }
00736 else {
00737
00738 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00739 4+state->sbytes, SEND_4TH_ARG,
00740 (struct sockaddr *)&state->remote_addr,
00741 state->remote_addrlen);
00742
00743 if(sbytes<0) {
00744 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00745 result = CURLE_SEND_ERROR;
00746 }
00747 }
00748
00749 return result;
00750 }
00751
00752
00753 time(&state->rx_time);
00754 state->block++;
00755 }
00756 else
00757 state->block = 1;
00758
00759 state->retries = 0;
00760 setpacketevent(&state->spacket, TFTP_EVENT_DATA);
00761 setpacketblock(&state->spacket, state->block);
00762 if(state->block > 1 && state->sbytes < (int)state->blksize) {
00763 state->state = TFTP_STATE_FIN;
00764 return CURLE_OK;
00765 }
00766
00767
00768
00769
00770
00771 state->sbytes = 0;
00772 state->conn->data->req.upload_fromhere = (char *)state->spacket.data+4;
00773 do {
00774 result = Curl_fillreadbuffer(state->conn, state->blksize - state->sbytes,
00775 &cb);
00776 if(result)
00777 return result;
00778 state->sbytes += cb;
00779 state->conn->data->req.upload_fromhere += cb;
00780 } while(state->sbytes < state->blksize && cb != 0);
00781
00782 sbytes = sendto(state->sockfd, (void *) state->spacket.data,
00783 4 + state->sbytes, SEND_4TH_ARG,
00784 (struct sockaddr *)&state->remote_addr,
00785 state->remote_addrlen);
00786
00787 if(sbytes<0) {
00788 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00789 return CURLE_SEND_ERROR;
00790 }
00791
00792 k->writebytecount += state->sbytes;
00793 Curl_pgrsSetUploadCounter(data, k->writebytecount);
00794 break;
00795
00796 case TFTP_EVENT_TIMEOUT:
00797
00798 state->retries++;
00799 infof(data, "Timeout waiting for block %d ACK. "
00800 " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries);
00801
00802 if(state->retries > state->retry_max) {
00803 state->error = TFTP_ERR_TIMEOUT;
00804 state->state = TFTP_STATE_FIN;
00805 }
00806 else {
00807
00808 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00809 4+state->sbytes, SEND_4TH_ARG,
00810 (struct sockaddr *)&state->remote_addr,
00811 state->remote_addrlen);
00812
00813 if(sbytes<0) {
00814 failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
00815 return CURLE_SEND_ERROR;
00816 }
00817
00818 Curl_pgrsSetUploadCounter(data, k->writebytecount);
00819 }
00820 break;
00821
00822 case TFTP_EVENT_ERROR:
00823 state->state = TFTP_STATE_FIN;
00824 setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
00825 setpacketblock(&state->spacket, state->block);
00826 (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
00827 (struct sockaddr *)&state->remote_addr,
00828 state->remote_addrlen);
00829
00830
00831 state->state = TFTP_STATE_FIN;
00832 break;
00833
00834 default:
00835 failf(data, "tftp_tx: internal error, event: %i", (int)(event));
00836 break;
00837 }
00838
00839 return result;
00840 }
00841
00842
00843
00844
00845
00846
00847
00848
00849 static CURLcode tftp_translate_code(tftp_error_t error)
00850 {
00851 CURLcode result = CURLE_OK;
00852
00853 if(error != TFTP_ERR_NONE) {
00854 switch(error) {
00855 case TFTP_ERR_NOTFOUND:
00856 result = CURLE_TFTP_NOTFOUND;
00857 break;
00858 case TFTP_ERR_PERM:
00859 result = CURLE_TFTP_PERM;
00860 break;
00861 case TFTP_ERR_DISKFULL:
00862 result = CURLE_REMOTE_DISK_FULL;
00863 break;
00864 case TFTP_ERR_UNDEF:
00865 case TFTP_ERR_ILLEGAL:
00866 result = CURLE_TFTP_ILLEGAL;
00867 break;
00868 case TFTP_ERR_UNKNOWNID:
00869 result = CURLE_TFTP_UNKNOWNID;
00870 break;
00871 case TFTP_ERR_EXISTS:
00872 result = CURLE_REMOTE_FILE_EXISTS;
00873 break;
00874 case TFTP_ERR_NOSUCHUSER:
00875 result = CURLE_TFTP_NOSUCHUSER;
00876 break;
00877 case TFTP_ERR_TIMEOUT:
00878 result = CURLE_OPERATION_TIMEDOUT;
00879 break;
00880 case TFTP_ERR_NORESPONSE:
00881 result = CURLE_COULDNT_CONNECT;
00882 break;
00883 default:
00884 result = CURLE_ABORTED_BY_CALLBACK;
00885 break;
00886 }
00887 }
00888 else
00889 result = CURLE_OK;
00890
00891 return result;
00892 }
00893
00894
00895
00896
00897
00898
00899
00900
00901 static CURLcode tftp_state_machine(tftp_state_data_t *state,
00902 tftp_event_t event)
00903 {
00904 CURLcode result = CURLE_OK;
00905 struct Curl_easy *data = state->conn->data;
00906
00907 switch(state->state) {
00908 case TFTP_STATE_START:
00909 DEBUGF(infof(data, "TFTP_STATE_START\n"));
00910 result = tftp_send_first(state, event);
00911 break;
00912 case TFTP_STATE_RX:
00913 DEBUGF(infof(data, "TFTP_STATE_RX\n"));
00914 result = tftp_rx(state, event);
00915 break;
00916 case TFTP_STATE_TX:
00917 DEBUGF(infof(data, "TFTP_STATE_TX\n"));
00918 result = tftp_tx(state, event);
00919 break;
00920 case TFTP_STATE_FIN:
00921 infof(data, "%s\n", "TFTP finished");
00922 break;
00923 default:
00924 DEBUGF(infof(data, "STATE: %d\n", state->state));
00925 failf(data, "%s", "Internal state machine error");
00926 result = CURLE_TFTP_ILLEGAL;
00927 break;
00928 }
00929
00930 return result;
00931 }
00932
00933
00934
00935
00936
00937
00938
00939
00940 static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
00941 {
00942 tftp_state_data_t *state = conn->proto.tftpc;
00943 (void) dead_connection;
00944
00945
00946 if(state) {
00947 Curl_safefree(state->rpacket.data);
00948 Curl_safefree(state->spacket.data);
00949 free(state);
00950 }
00951
00952 return CURLE_OK;
00953 }
00954
00955
00956
00957
00958
00959
00960
00961
00962 static CURLcode tftp_connect(struct connectdata *conn, bool *done)
00963 {
00964 tftp_state_data_t *state;
00965 int blksize, rc;
00966
00967 blksize = TFTP_BLKSIZE_DEFAULT;
00968
00969 state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
00970 if(!state)
00971 return CURLE_OUT_OF_MEMORY;
00972
00973
00974 if(conn->data->set.tftp_blksize) {
00975 blksize = (int)conn->data->set.tftp_blksize;
00976 if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN)
00977 return CURLE_TFTP_ILLEGAL;
00978 }
00979
00980 if(!state->rpacket.data) {
00981 state->rpacket.data = calloc(1, blksize + 2 + 2);
00982
00983 if(!state->rpacket.data)
00984 return CURLE_OUT_OF_MEMORY;
00985 }
00986
00987 if(!state->spacket.data) {
00988 state->spacket.data = calloc(1, blksize + 2 + 2);
00989
00990 if(!state->spacket.data)
00991 return CURLE_OUT_OF_MEMORY;
00992 }
00993
00994
00995
00996 connclose(conn, "TFTP");
00997
00998 state->conn = conn;
00999 state->sockfd = state->conn->sock[FIRSTSOCKET];
01000 state->state = TFTP_STATE_START;
01001 state->error = TFTP_ERR_NONE;
01002 state->blksize = TFTP_BLKSIZE_DEFAULT;
01003 state->requested_blksize = blksize;
01004
01005 ((struct sockaddr *)&state->local_addr)->sa_family =
01006 (unsigned short)(conn->ip_addr->ai_family);
01007
01008 tftp_set_timeouts(state);
01009
01010 if(!conn->bits.bound) {
01011
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024 rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
01025 conn->ip_addr->ai_addrlen);
01026 if(rc) {
01027 failf(conn->data, "bind() failed; %s",
01028 Curl_strerror(conn, SOCKERRNO));
01029 return CURLE_COULDNT_CONNECT;
01030 }
01031 conn->bits.bound = TRUE;
01032 }
01033
01034 Curl_pgrsStartNow(conn->data);
01035
01036 *done = TRUE;
01037
01038 return CURLE_OK;
01039 }
01040
01041
01042
01043
01044
01045
01046
01047
01048 static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
01049 bool premature)
01050 {
01051 CURLcode result = CURLE_OK;
01052 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
01053
01054 (void)status;
01055 (void)premature;
01056
01057 if(Curl_pgrsDone(conn))
01058 return CURLE_ABORTED_BY_CALLBACK;
01059
01060
01061 if(state)
01062 result = tftp_translate_code(state->error);
01063
01064 return result;
01065 }
01066
01067
01068
01069
01070
01071
01072
01073
01074 static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
01075 int numsocks)
01076 {
01077 if(!numsocks)
01078 return GETSOCK_BLANK;
01079
01080 socks[0] = conn->sock[FIRSTSOCKET];
01081
01082 return GETSOCK_READSOCK(0);
01083 }
01084
01085
01086
01087
01088
01089
01090
01091
01092 static CURLcode tftp_receive_packet(struct connectdata *conn)
01093 {
01094 struct Curl_sockaddr_storage fromaddr;
01095 curl_socklen_t fromlen;
01096 CURLcode result = CURLE_OK;
01097 struct Curl_easy *data = conn->data;
01098 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
01099 struct SingleRequest *k = &data->req;
01100
01101
01102 fromlen = sizeof(fromaddr);
01103 state->rbytes = (int)recvfrom(state->sockfd,
01104 (void *)state->rpacket.data,
01105 state->blksize+4,
01106 0,
01107 (struct sockaddr *)&fromaddr,
01108 &fromlen);
01109 if(state->remote_addrlen==0) {
01110 memcpy(&state->remote_addr, &fromaddr, fromlen);
01111 state->remote_addrlen = fromlen;
01112 }
01113
01114
01115 if(state->rbytes < 4) {
01116 failf(data, "Received too short packet");
01117
01118 state->event = TFTP_EVENT_TIMEOUT;
01119 }
01120 else {
01121
01122 state->event = (tftp_event_t)getrpacketevent(&state->rpacket);
01123
01124 switch(state->event) {
01125 case TFTP_EVENT_DATA:
01126
01127 if(state->rbytes > 4 &&
01128 (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
01129 result = Curl_client_write(conn, CLIENTWRITE_BODY,
01130 (char *)state->rpacket.data+4,
01131 state->rbytes-4);
01132 if(result) {
01133 tftp_state_machine(state, TFTP_EVENT_ERROR);
01134 return result;
01135 }
01136 k->bytecount += state->rbytes-4;
01137 Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
01138 }
01139 break;
01140 case TFTP_EVENT_ERROR:
01141 state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
01142 infof(data, "%s\n", (const char *)state->rpacket.data+4);
01143 break;
01144 case TFTP_EVENT_ACK:
01145 break;
01146 case TFTP_EVENT_OACK:
01147 result = tftp_parse_option_ack(state,
01148 (const char *)state->rpacket.data+2,
01149 state->rbytes-2);
01150 if(result)
01151 return result;
01152 break;
01153 case TFTP_EVENT_RRQ:
01154 case TFTP_EVENT_WRQ:
01155 default:
01156 failf(data, "%s", "Internal error: Unexpected packet");
01157 break;
01158 }
01159
01160
01161 if(Curl_pgrsUpdate(conn)) {
01162 tftp_state_machine(state, TFTP_EVENT_ERROR);
01163 return CURLE_ABORTED_BY_CALLBACK;
01164 }
01165 }
01166 return result;
01167 }
01168
01169
01170
01171
01172
01173
01174
01175
01176 static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
01177 {
01178 time_t current;
01179 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
01180
01181 if(event)
01182 *event = TFTP_EVENT_NONE;
01183
01184 time(¤t);
01185 if(current > state->max_time) {
01186 DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
01187 (long)current, (long)state->max_time));
01188 state->error = TFTP_ERR_TIMEOUT;
01189 state->state = TFTP_STATE_FIN;
01190 return 0;
01191 }
01192 else if(current > state->rx_time+state->retry_time) {
01193 if(event)
01194 *event = TFTP_EVENT_TIMEOUT;
01195 time(&state->rx_time);
01196 }
01197
01198
01199
01200
01201 return (long)(state->max_time - current);
01202 }
01203
01204
01205
01206
01207
01208
01209
01210
01211 static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
01212 {
01213 int rc;
01214 tftp_event_t event;
01215 CURLcode result = CURLE_OK;
01216 struct Curl_easy *data = conn->data;
01217 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
01218 long timeout_ms = tftp_state_timeout(conn, &event);
01219
01220 *done = FALSE;
01221
01222 if(timeout_ms <= 0) {
01223 failf(data, "TFTP response timeout");
01224 return CURLE_OPERATION_TIMEDOUT;
01225 }
01226 else if(event != TFTP_EVENT_NONE) {
01227 result = tftp_state_machine(state, event);
01228 if(result)
01229 return result;
01230 *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
01231 if(*done)
01232
01233 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01234 }
01235 else {
01236
01237 rc = SOCKET_READABLE(state->sockfd, 0);
01238
01239 if(rc == -1) {
01240
01241 int error = SOCKERRNO;
01242 failf(data, "%s", Curl_strerror(conn, error));
01243 state->event = TFTP_EVENT_ERROR;
01244 }
01245 else if(rc != 0) {
01246 result = tftp_receive_packet(conn);
01247 if(result)
01248 return result;
01249 result = tftp_state_machine(state, state->event);
01250 if(result)
01251 return result;
01252 *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
01253 if(*done)
01254
01255 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
01256 }
01257
01258 }
01259
01260 return result;
01261 }
01262
01263
01264
01265
01266
01267
01268
01269
01270 static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
01271 {
01272 CURLcode result;
01273 result = tftp_multi_statemach(conn, dophase_done);
01274
01275 if(*dophase_done) {
01276 DEBUGF(infof(conn->data, "DO phase is complete\n"));
01277 }
01278 else if(!result) {
01279
01280
01281
01282 if(Curl_pgrsUpdate(conn))
01283 result = CURLE_ABORTED_BY_CALLBACK;
01284 else
01285 result = Curl_speedcheck(conn->data, Curl_tvnow());
01286 }
01287 return result;
01288 }
01289
01290
01291
01292
01293
01294
01295
01296
01297 static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
01298 {
01299 CURLcode result = CURLE_OK;
01300 tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
01301
01302 *dophase_done = FALSE;
01303
01304 result = tftp_state_machine(state, TFTP_EVENT_INIT);
01305
01306 if((state->state == TFTP_STATE_FIN) || result)
01307 return result;
01308
01309 tftp_multi_statemach(conn, dophase_done);
01310
01311 if(*dophase_done)
01312 DEBUGF(infof(conn->data, "DO phase is complete\n"));
01313
01314 return result;
01315 }
01316
01317
01318
01319
01320
01321
01322
01323
01324
01325
01326
01327
01328 static CURLcode tftp_do(struct connectdata *conn, bool *done)
01329 {
01330 tftp_state_data_t *state;
01331 CURLcode result;
01332
01333 *done = FALSE;
01334
01335 if(!conn->proto.tftpc) {
01336 result = tftp_connect(conn, done);
01337 if(result)
01338 return result;
01339 }
01340
01341 state = (tftp_state_data_t *)conn->proto.tftpc;
01342 if(!state)
01343 return CURLE_BAD_CALLING_ORDER;
01344
01345 result = tftp_perform(conn, done);
01346
01347
01348
01349 if(!result)
01350
01351 result = tftp_translate_code(state->error);
01352
01353 return result;
01354 }
01355
01356 static CURLcode tftp_setup_connection(struct connectdata * conn)
01357 {
01358 struct Curl_easy *data = conn->data;
01359 char *type;
01360 char command;
01361
01362 conn->socktype = SOCK_DGRAM;
01363
01364
01365
01366 type = strstr(data->state.path, ";mode=");
01367
01368 if(!type)
01369 type = strstr(conn->host.rawalloc, ";mode=");
01370
01371 if(type) {
01372 *type = 0;
01373 command = Curl_raw_toupper(type[6]);
01374
01375 switch(command) {
01376 case 'A':
01377 case 'N':
01378 data->set.prefer_ascii = TRUE;
01379 break;
01380
01381 case 'O':
01382 case 'I':
01383 default:
01384
01385 data->set.prefer_ascii = FALSE;
01386 break;
01387 }
01388 }
01389
01390 return CURLE_OK;
01391 }
01392 #endif