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