00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "setup.h"
00025
00026 #ifndef CURL_DISABLE_TFTP
00027
00028 #include <stdio.h>
00029 #include <string.h>
00030 #include <stdarg.h>
00031 #include <stdlib.h>
00032 #include <ctype.h>
00033
00034 #if defined(WIN32)
00035 #include <time.h>
00036 #include <io.h>
00037 #else
00038 #ifdef HAVE_SYS_SOCKET_H
00039 #include <sys/socket.h>
00040 #endif
00041 #include <netinet/in.h>
00042 #ifdef HAVE_SYS_TIME_H
00043 #include <sys/time.h>
00044 #endif
00045 #ifdef HAVE_UNISTD_H
00046 #include <unistd.h>
00047 #endif
00048 #include <netdb.h>
00049 #ifdef HAVE_ARPA_INET_H
00050 #include <arpa/inet.h>
00051 #endif
00052 #ifdef HAVE_NET_IF_H
00053 #include <net/if.h>
00054 #endif
00055 #include <sys/ioctl.h>
00056 #include <signal.h>
00057
00058 #ifdef HAVE_SYS_PARAM_H
00059 #include <sys/param.h>
00060 #endif
00061
00062 #endif
00063
00064 #include "urldata.h"
00065 #include <curl/curl.h>
00066 #include "transfer.h"
00067 #include "sendf.h"
00068 #include "tftp.h"
00069 #include "progress.h"
00070 #include "connect.h"
00071 #include "strerror.h"
00072 #include "sockaddr.h"
00073 #include "url.h"
00074
00075 #define _MPRINTF_REPLACE
00076 #include <curl/mprintf.h>
00077
00078 #include "memory.h"
00079 #include "select.h"
00080
00081
00082 #include "memdebug.h"
00083
00084
00085 #define TFTP_BLOCKSIZE 512
00086
00087 typedef enum {
00088 TFTP_MODE_NETASCII=0,
00089 TFTP_MODE_OCTET
00090 } tftp_mode_t;
00091
00092 typedef enum {
00093 TFTP_STATE_START=0,
00094 TFTP_STATE_RX,
00095 TFTP_STATE_TX,
00096 TFTP_STATE_FIN
00097 } tftp_state_t;
00098
00099 typedef enum {
00100 TFTP_EVENT_INIT=0,
00101 TFTP_EVENT_RRQ = 1,
00102 TFTP_EVENT_WRQ = 2,
00103 TFTP_EVENT_DATA = 3,
00104 TFTP_EVENT_ACK = 4,
00105 TFTP_EVENT_ERROR = 5,
00106 TFTP_EVENT_TIMEOUT
00107 } tftp_event_t;
00108
00109 typedef enum {
00110 TFTP_ERR_UNDEF=0,
00111 TFTP_ERR_NOTFOUND,
00112 TFTP_ERR_PERM,
00113 TFTP_ERR_DISKFULL,
00114 TFTP_ERR_ILLEGAL,
00115 TFTP_ERR_UNKNOWNID,
00116 TFTP_ERR_EXISTS,
00117 TFTP_ERR_NOSUCHUSER,
00118 TFTP_ERR_TIMEOUT,
00119 TFTP_ERR_NORESPONSE
00120 } tftp_error_t;
00121
00122 typedef struct tftp_packet {
00123 unsigned char data[2 + 2 + TFTP_BLOCKSIZE];
00124 } tftp_packet_t;
00125
00126 typedef struct tftp_state_data {
00127 tftp_state_t state;
00128 tftp_mode_t mode;
00129 tftp_error_t error;
00130 struct connectdata *conn;
00131 curl_socket_t sockfd;
00132 int retries;
00133 int retry_time;
00134 int retry_max;
00135 time_t start_time;
00136 time_t max_time;
00137 unsigned short block;
00138 struct Curl_sockaddr_storage local_addr;
00139 struct Curl_sockaddr_storage remote_addr;
00140 socklen_t remote_addrlen;
00141 int rbytes;
00142 int sbytes;
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 void tftp_set_timeouts(tftp_state_data_t *state) ;
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163 void tftp_set_timeouts(tftp_state_data_t *state)
00164 {
00165
00166 struct SessionHandle *data = state->conn->data;
00167 time_t maxtime, timeout;
00168
00169 time(&state->start_time);
00170 if(state->state == TFTP_STATE_START) {
00171
00172 maxtime = (time_t)(data->set.connecttimeout/1000L?
00173 data->set.connecttimeout/1000L:30);
00174 state->max_time = state->start_time+maxtime;
00175
00176
00177 timeout = maxtime ;
00178
00179
00180 state->retry_max = timeout/5;
00181
00182 if(state->retry_max < 1)
00183
00184 state->retry_max = 1;
00185
00186
00187 state->retry_time = timeout/state->retry_max;
00188 if(state->retry_time<1)
00189 state->retry_time=1;
00190
00191 }
00192 else {
00193
00194
00195 maxtime = (time_t)(data->set.timeout/1000L?
00196 data->set.timeout/1000L:3600);
00197 state->max_time = state->start_time+maxtime;
00198
00199
00200 timeout = maxtime/10 ;
00201
00202
00203 state->retry_max = timeout/15;
00204 }
00205
00206 if(state->retry_max<3)
00207 state->retry_max=3;
00208
00209 if(state->retry_max>50)
00210 state->retry_max=50;
00211
00212
00213 state->retry_time = timeout/state->retry_max;
00214 if(state->retry_time<1)
00215 state->retry_time=1;
00216
00217 infof(data, "set timeouts for state %d; Total %d, retry %d maxtry %d\n",
00218 state->state, (state->max_time-state->start_time),
00219 state->retry_time, state->retry_max);
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230 static void setpacketevent(tftp_packet_t *packet, unsigned short num)
00231 {
00232 packet->data[0] = (unsigned char)(num >> 8);
00233 packet->data[1] = (unsigned char)(num & 0xff);
00234 }
00235
00236
00237 static void setpacketblock(tftp_packet_t *packet, unsigned short num)
00238 {
00239 packet->data[2] = (unsigned char)(num >> 8);
00240 packet->data[3] = (unsigned char)(num & 0xff);
00241 }
00242
00243 static unsigned short getrpacketevent(tftp_packet_t *packet)
00244 {
00245 return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
00246 }
00247
00248 static unsigned short getrpacketblock(tftp_packet_t *packet)
00249 {
00250 return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
00251 }
00252
00253 static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
00254 {
00255 int sbytes;
00256 const char *mode = "octet";
00257 char *filename;
00258 struct SessionHandle *data = state->conn->data;
00259 CURLcode res = CURLE_OK;
00260
00261
00262 if(data->set.prefer_ascii)
00263 mode = "netascii";
00264
00265 switch(event) {
00266
00267 case TFTP_EVENT_INIT:
00268 case TFTP_EVENT_TIMEOUT:
00269
00270 state->retries++;
00271 if(state->retries>state->retry_max) {
00272 state->error = TFTP_ERR_NORESPONSE;
00273 state->state = TFTP_STATE_FIN;
00274 return res;
00275 }
00276
00277 if(data->set.upload) {
00278
00279 setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
00280 state->conn->data->reqdata.upload_fromhere = (char *)&state->spacket.data[4];
00281 if(data->set.infilesize != -1)
00282 Curl_pgrsSetUploadSize(data, data->set.infilesize);
00283 }
00284 else {
00285
00286 setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
00287 }
00288
00289
00290 filename = curl_easy_unescape(data, &state->conn->data->reqdata.path[1], 0,
00291 NULL);
00292 if (!filename)
00293 return CURLE_OUT_OF_MEMORY;
00294
00295 snprintf((char *)&state->spacket.data[2],
00296 TFTP_BLOCKSIZE,
00297 "%s%c%s%c", filename, '\0', mode, '\0');
00298 sbytes = 4 + (int)strlen(filename) + (int)strlen(mode);
00299 sbytes = sendto(state->sockfd, (void *)&state->spacket,
00300 sbytes, 0,
00301 state->conn->ip_addr->ai_addr,
00302 state->conn->ip_addr->ai_addrlen);
00303 if(sbytes < 0) {
00304 failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
00305 }
00306 Curl_safefree(filename);
00307 break;
00308
00309 case TFTP_EVENT_ACK:
00310 infof(data, "%s\n", "Connected for transmit");
00311 state->state = TFTP_STATE_TX;
00312 tftp_set_timeouts(state);
00313 return tftp_tx(state, event);
00314
00315 case TFTP_EVENT_DATA:
00316 infof(data, "%s\n", "Connected for receive");
00317 state->state = TFTP_STATE_RX;
00318 tftp_set_timeouts(state);
00319 return tftp_rx(state, event);
00320
00321 case TFTP_EVENT_ERROR:
00322 state->state = TFTP_STATE_FIN;
00323 break;
00324
00325 default:
00326 failf(state->conn->data, "tftp_send_first: internal error\n");
00327 break;
00328 }
00329 return res;
00330 }
00331
00332
00333
00334
00335
00336
00337
00338
00339 static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
00340 {
00341 int sbytes;
00342 int rblock;
00343 struct SessionHandle *data = state->conn->data;
00344
00345 switch(event) {
00346
00347 case TFTP_EVENT_DATA:
00348
00349
00350 rblock = getrpacketblock(&state->rpacket);
00351 if ((state->block+1) != rblock) {
00352
00353 infof(data,
00354 "Received unexpected DATA packet block %d\n", rblock);
00355 state->retries++;
00356 if (state->retries>state->retry_max) {
00357 failf(data, "tftp_rx: giving up waiting for block %d\n",
00358 state->block+1);
00359 return CURLE_TFTP_ILLEGAL;
00360 }
00361 }
00362
00363 state->block = (unsigned short)rblock;
00364 state->retries = 0;
00365 setpacketevent(&state->spacket, TFTP_EVENT_ACK);
00366 setpacketblock(&state->spacket, state->block);
00367 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00368 4, SEND_4TH_ARG,
00369 (struct sockaddr *)&state->remote_addr,
00370 state->remote_addrlen);
00371 if(sbytes < 0) {
00372 failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
00373 return CURLE_SEND_ERROR;
00374 }
00375
00376
00377 if (state->rbytes < (int)sizeof(state->spacket)){
00378 state->state = TFTP_STATE_FIN;
00379 }
00380 else {
00381 state->state = TFTP_STATE_RX;
00382 }
00383 break;
00384
00385 case TFTP_EVENT_TIMEOUT:
00386
00387 state->retries++;
00388 infof(data,
00389 "Timeout waiting for block %d ACK. Retries = %d\n", state->retries);
00390 if(state->retries > state->retry_max) {
00391 state->error = TFTP_ERR_TIMEOUT;
00392 state->state = TFTP_STATE_FIN;
00393 }
00394 else {
00395
00396 sbytes = sendto(state->sockfd, (void *)&state->spacket,
00397 4, SEND_4TH_ARG,
00398 (struct sockaddr *)&state->remote_addr,
00399 state->remote_addrlen);
00400
00401 if(sbytes<0) {
00402 failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
00403 return CURLE_SEND_ERROR;
00404 }
00405 }
00406 break;
00407
00408 case TFTP_EVENT_ERROR:
00409 state->state = TFTP_STATE_FIN;
00410 break;
00411
00412 default:
00413 failf(data, "%s\n", "tftp_rx: internal error");
00414 return CURLE_TFTP_ILLEGAL;
00415
00416 }
00417 return CURLE_OK;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427 static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
00428 {
00429 struct SessionHandle *data = state->conn->data;
00430 int sbytes;
00431 int rblock;
00432 CURLcode res = CURLE_OK;
00433 struct Curl_transfer_keeper *k = &data->reqdata.keep;
00434
00435 switch(event) {
00436
00437 case TFTP_EVENT_ACK:
00438
00439 rblock = getrpacketblock(&state->rpacket);
00440
00441 if(rblock != state->block) {
00442
00443 infof(data, "Received ACK for block %d, expecting %d\n",
00444 rblock, state->block);
00445 state->retries++;
00446
00447 if(state->retries>state->retry_max) {
00448 failf(data, "tftp_tx: giving up waiting for block %d ack",
00449 state->block);
00450 res = CURLE_SEND_ERROR;
00451 }
00452 else {
00453
00454 sbytes = sendto(state->sockfd, (void *)&state->spacket,
00455 4+state->sbytes, SEND_4TH_ARG,
00456 (struct sockaddr *)&state->remote_addr,
00457 state->remote_addrlen);
00458
00459 if(sbytes<0) {
00460 failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
00461 res = CURLE_SEND_ERROR;
00462 }
00463 }
00464 return res;
00465 }
00466
00467
00468 state->block++;
00469 state->retries = 0;
00470 setpacketevent(&state->spacket, TFTP_EVENT_DATA);
00471 setpacketblock(&state->spacket, state->block);
00472 if(state->block > 1 && state->sbytes < TFTP_BLOCKSIZE) {
00473 state->state = TFTP_STATE_FIN;
00474 return CURLE_OK;
00475 }
00476 res = Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes);
00477 if(res)
00478 return res;
00479 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
00480 4+state->sbytes, SEND_4TH_ARG,
00481 (struct sockaddr *)&state->remote_addr,
00482 state->remote_addrlen);
00483
00484 if(sbytes<0) {
00485 failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
00486 return CURLE_SEND_ERROR;
00487 }
00488
00489 k->writebytecount += state->sbytes;
00490 Curl_pgrsSetUploadCounter(data, k->writebytecount);
00491 break;
00492
00493 case TFTP_EVENT_TIMEOUT:
00494
00495 state->retries++;
00496 infof(data, "Timeout waiting for block %d ACK. "
00497 " Retries = %d\n", state->retries);
00498
00499 if(state->retries > state->retry_max) {
00500 state->error = TFTP_ERR_TIMEOUT;
00501 state->state = TFTP_STATE_FIN;
00502 }
00503 else {
00504
00505 sbytes = sendto(state->sockfd, (void *)&state->spacket,
00506 4+state->sbytes, SEND_4TH_ARG,
00507 (struct sockaddr *)&state->remote_addr,
00508 state->remote_addrlen);
00509
00510 if(sbytes<0) {
00511 failf(data, "%s\n", Curl_strerror(state->conn, SOCKERRNO));
00512 return CURLE_SEND_ERROR;
00513 }
00514
00515 Curl_pgrsSetUploadCounter(data, k->writebytecount);
00516 }
00517 break;
00518
00519 case TFTP_EVENT_ERROR:
00520 state->state = TFTP_STATE_FIN;
00521 break;
00522
00523 default:
00524 failf(data, "%s\n", "tftp_tx: internal error");
00525 break;
00526 }
00527
00528 return res;
00529 }
00530
00531
00532
00533
00534
00535
00536
00537
00538 static CURLcode tftp_state_machine(tftp_state_data_t *state,
00539 tftp_event_t event)
00540 {
00541 CURLcode res = CURLE_OK;
00542 struct SessionHandle *data = state->conn->data;
00543 switch(state->state) {
00544 case TFTP_STATE_START:
00545 DEBUGF(infof(data, "TFTP_STATE_START\n"));
00546 res = tftp_send_first(state, event);
00547 break;
00548 case TFTP_STATE_RX:
00549 DEBUGF(infof(data, "TFTP_STATE_RX\n"));
00550 res = tftp_rx(state, event);
00551 break;
00552 case TFTP_STATE_TX:
00553 DEBUGF(infof(data, "TFTP_STATE_TX\n"));
00554 res = tftp_tx(state, event);
00555 break;
00556 case TFTP_STATE_FIN:
00557 infof(data, "%s\n", "TFTP finished");
00558 break;
00559 default:
00560 DEBUGF(infof(data, "STATE: %d\n", state->state));
00561 failf(data, "%s\n", "Internal state machine error");
00562 res = CURLE_TFTP_ILLEGAL;
00563 break;
00564 }
00565 return res;
00566 }
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576 CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done)
00577 {
00578 CURLcode code;
00579 tftp_state_data_t *state;
00580 int rc;
00581
00582 state = conn->data->reqdata.proto.tftp = calloc(sizeof(tftp_state_data_t),
00583 1);
00584 if(!state)
00585 return CURLE_OUT_OF_MEMORY;
00586
00587 conn->bits.close = FALSE;
00588
00589 state->conn = conn;
00590 state->sockfd = state->conn->sock[FIRSTSOCKET];
00591 state->state = TFTP_STATE_START;
00592
00593 ((struct sockaddr *)&state->local_addr)->sa_family =
00594 (unsigned short)(conn->ip_addr->ai_family);
00595
00596 tftp_set_timeouts(state);
00597
00598 if(!conn->bits.reuse) {
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612 rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
00613 conn->ip_addr->ai_addrlen);
00614 if(rc) {
00615 failf(conn->data, "bind() failed; %s\n",
00616 Curl_strerror(conn, SOCKERRNO));
00617 return CURLE_COULDNT_CONNECT;
00618 }
00619 }
00620
00621 Curl_pgrsStartNow(conn->data);
00622
00623 *done = TRUE;
00624 code = CURLE_OK;
00625 return(code);
00626 }
00627
00628
00629
00630
00631
00632
00633
00634
00635 CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status,
00636 bool premature)
00637 {
00638 (void)status;
00639 (void)premature;
00640
00641 #if 0
00642 free(conn->data->reqdata.proto.tftp);
00643 conn->data->reqdata.proto.tftp = NULL;
00644 #endif
00645 Curl_pgrsDone(conn);
00646
00647 return CURLE_OK;
00648 }
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 CURLcode Curl_tftp(struct connectdata *conn, bool *done)
00662 {
00663 struct SessionHandle *data = conn->data;
00664 tftp_state_data_t *state =
00665 (tftp_state_data_t *) conn->data->reqdata.proto.tftp;
00666 tftp_event_t event;
00667 CURLcode code;
00668 int rc;
00669 struct Curl_sockaddr_storage fromaddr;
00670 socklen_t fromlen;
00671 int check_time = 0;
00672 struct Curl_transfer_keeper *k = &data->reqdata.keep;
00673
00674 *done = TRUE;
00675
00676
00677
00678
00679
00680
00681
00682 if(!state) {
00683 code = Curl_tftp_connect(conn, done);
00684 if(code)
00685 return code;
00686 state = (tftp_state_data_t *)conn->data->reqdata.proto.tftp;
00687 }
00688
00689 code = Curl_readwrite_init(conn);
00690 if(code)
00691 return code;
00692
00693
00694 for(code=tftp_state_machine(state, TFTP_EVENT_INIT);
00695 (state->state != TFTP_STATE_FIN) && (code == CURLE_OK);
00696 code=tftp_state_machine(state, event) ) {
00697
00698
00699 rc=Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD,
00700 state->retry_time * 1000);
00701
00702 if(rc == -1) {
00703
00704 int error = SOCKERRNO;
00705 failf(data, "%s\n", Curl_strerror(conn, error));
00706 event = TFTP_EVENT_ERROR;
00707 }
00708 else if (rc==0) {
00709
00710 event = TFTP_EVENT_TIMEOUT;
00711
00712
00713 check_time = 0;
00714
00715 }
00716 else {
00717
00718
00719 fromlen=sizeof(fromaddr);
00720 state->rbytes = recvfrom(state->sockfd,
00721 (void *)&state->rpacket, sizeof(state->rpacket),
00722 0, (struct sockaddr *)&fromaddr, &fromlen);
00723 if(state->remote_addrlen==0) {
00724 memcpy(&state->remote_addr, &fromaddr, fromlen);
00725 state->remote_addrlen = fromlen;
00726 }
00727
00728
00729 if (state->rbytes < 4) {
00730 failf(conn->data, "Received too short packet\n");
00731
00732 event = TFTP_EVENT_TIMEOUT;
00733 }
00734 else {
00735
00736
00737 event = (tftp_event_t)getrpacketevent(&state->rpacket);
00738
00739 switch(event) {
00740 case TFTP_EVENT_DATA:
00741
00742 if (state->rbytes > 4 &&
00743 ((state->block+1) == getrpacketblock(&state->rpacket))) {
00744 code = Curl_client_write(conn, CLIENTWRITE_BODY,
00745 (char *)&state->rpacket.data[4],
00746 state->rbytes-4);
00747 if(code)
00748 return code;
00749 k->bytecount += state->rbytes-4;
00750 Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
00751 }
00752 break;
00753 case TFTP_EVENT_ERROR:
00754 state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
00755 infof(conn->data, "%s\n", (char *)&state->rpacket.data[4]);
00756 break;
00757 case TFTP_EVENT_ACK:
00758 break;
00759 case TFTP_EVENT_RRQ:
00760 case TFTP_EVENT_WRQ:
00761 default:
00762 failf(conn->data, "%s\n", "Internal error: Unexpected packet");
00763 break;
00764 }
00765
00766
00767 if(Curl_pgrsUpdate(conn))
00768 return CURLE_ABORTED_BY_CALLBACK;
00769 }
00770 }
00771
00772
00773 if(check_time%10==0) {
00774 time_t current;
00775 time(¤t);
00776 if(current>state->max_time) {
00777 DEBUGF(infof(data, "timeout: %d > %d\n",
00778 current, state->max_time));
00779 state->error = TFTP_ERR_TIMEOUT;
00780 state->state = TFTP_STATE_FIN;
00781 }
00782 }
00783
00784 }
00785 if(code)
00786 return code;
00787
00788
00789 code = Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
00790 if(code)
00791 return code;
00792
00793
00794 if(state->error) {
00795
00796
00797 switch(state->error) {
00798 case TFTP_ERR_NOTFOUND:
00799 code = CURLE_TFTP_NOTFOUND;
00800 break;
00801 case TFTP_ERR_PERM:
00802 code = CURLE_TFTP_PERM;
00803 break;
00804 case TFTP_ERR_DISKFULL:
00805 code = CURLE_TFTP_DISKFULL;
00806 break;
00807 case TFTP_ERR_ILLEGAL:
00808 code = CURLE_TFTP_ILLEGAL;
00809 break;
00810 case TFTP_ERR_UNKNOWNID:
00811 code = CURLE_TFTP_UNKNOWNID;
00812 break;
00813 case TFTP_ERR_EXISTS:
00814 code = CURLE_TFTP_EXISTS;
00815 break;
00816 case TFTP_ERR_NOSUCHUSER:
00817 code = CURLE_TFTP_NOSUCHUSER;
00818 break;
00819 case TFTP_ERR_TIMEOUT:
00820 code = CURLE_OPERATION_TIMEOUTED;
00821 break;
00822 case TFTP_ERR_NORESPONSE:
00823 code = CURLE_COULDNT_CONNECT;
00824 break;
00825 default:
00826 code= CURLE_ABORTED_BY_CALLBACK;
00827 break;
00828 }
00829 }
00830 else
00831 code = CURLE_OK;
00832 return code;
00833 }
00834 #endif