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, /* write_resp_hd */
186 ZERO_NULL, /* connection_check */
187 ZERO_NULL, /* attach connection */
188 ZERO_NULL, /* follow */
189 PORT_TFTP, /* defport */
190 CURLPROTO_TFTP, /* protocol */
191 CURLPROTO_TFTP, /* family */
192 PROTOPT_NOTCPPROXY | PROTOPT_NOURLQUERY /* flags */
193 };
194
195 /**********************************************************
196 *
197 * tftp_set_timeouts -
198 *
199 * Set timeouts based on state machine state.
200 * Use user provided connect timeouts until DATA or ACK
201 * packet is received, then use user-provided transfer timeouts
202 *
203 *
204 **********************************************************/
tftp_set_timeouts(struct tftp_state_data * state)205 static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
206 {
207 time_t maxtime, timeout;
208 timediff_t timeout_ms;
209 bool start = (state->state == TFTP_STATE_START);
210
211 /* Compute drop-dead time */
212 timeout_ms = Curl_timeleft(state->data, NULL, start);
213
214 if(timeout_ms < 0) {
215 /* time-out, bail out, go home */
216 failf(state->data, "Connection time-out");
217 return CURLE_OPERATION_TIMEDOUT;
218 }
219
220 if(timeout_ms > 0)
221 maxtime = (time_t)(timeout_ms + 500) / 1000;
222 else
223 maxtime = 3600; /* use for calculating block timeouts */
224
225 /* Set per-block timeout to total */
226 timeout = maxtime;
227
228 /* Average reposting an ACK after 5 seconds */
229 state->retry_max = (int)timeout/5;
230
231 /* But bound the total number */
232 if(state->retry_max < 3)
233 state->retry_max = 3;
234
235 if(state->retry_max > 50)
236 state->retry_max = 50;
237
238 /* Compute the re-ACK interval to suit the timeout */
239 state->retry_time = (int)(timeout/state->retry_max);
240 if(state->retry_time < 1)
241 state->retry_time = 1;
242
243 infof(state->data,
244 "set timeouts for state %d; Total % " FMT_OFF_T ", retry %d maxtry %d",
245 (int)state->state, timeout_ms, state->retry_time, state->retry_max);
246
247 /* init RX time */
248 state->rx_time = time(NULL);
249
250 return CURLE_OK;
251 }
252
253 /**********************************************************
254 *
255 * tftp_set_send_first
256 *
257 * Event handler for the START state
258 *
259 **********************************************************/
260
setpacketevent(struct tftp_packet * packet,unsigned short num)261 static void setpacketevent(struct tftp_packet *packet, unsigned short num)
262 {
263 packet->data[0] = (unsigned char)(num >> 8);
264 packet->data[1] = (unsigned char)(num & 0xff);
265 }
266
267
setpacketblock(struct tftp_packet * packet,unsigned short num)268 static void setpacketblock(struct tftp_packet *packet, unsigned short num)
269 {
270 packet->data[2] = (unsigned char)(num >> 8);
271 packet->data[3] = (unsigned char)(num & 0xff);
272 }
273
getrpacketevent(const struct tftp_packet * packet)274 static unsigned short getrpacketevent(const struct tftp_packet *packet)
275 {
276 return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
277 }
278
getrpacketblock(const struct tftp_packet * packet)279 static unsigned short getrpacketblock(const struct tftp_packet *packet)
280 {
281 return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
282 }
283
tftp_strnlen(const char * string,size_t maxlen)284 static size_t tftp_strnlen(const char *string, size_t maxlen)
285 {
286 const char *end = memchr(string, '\0', maxlen);
287 return end ? (size_t) (end - string) : maxlen;
288 }
289
tftp_option_get(const char * buf,size_t len,const char ** option,const char ** value)290 static const char *tftp_option_get(const char *buf, size_t len,
291 const char **option, const char **value)
292 {
293 size_t loc;
294
295 loc = tftp_strnlen(buf, len);
296 loc++; /* NULL term */
297
298 if(loc >= len)
299 return NULL;
300 *option = buf;
301
302 loc += tftp_strnlen(buf + loc, len-loc);
303 loc++; /* NULL term */
304
305 if(loc > len)
306 return NULL;
307 *value = &buf[strlen(*option) + 1];
308
309 return &buf[loc];
310 }
311
tftp_parse_option_ack(struct tftp_state_data * state,const char * ptr,int len)312 static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
313 const char *ptr, int len)
314 {
315 const char *tmp = ptr;
316 struct Curl_easy *data = state->data;
317
318 /* if OACK does not contain blksize option, the default (512) must be used */
319 state->blksize = TFTP_BLKSIZE_DEFAULT;
320
321 while(tmp < ptr + len) {
322 const char *option, *value;
323
324 tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
325 if(!tmp) {
326 failf(data, "Malformed ACK packet, rejecting");
327 return CURLE_TFTP_ILLEGAL;
328 }
329
330 infof(data, "got option=(%s) value=(%s)", option, value);
331
332 if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
333 long blksize;
334
335 blksize = strtol(value, NULL, 10);
336
337 if(!blksize) {
338 failf(data, "invalid blocksize value in OACK packet");
339 return CURLE_TFTP_ILLEGAL;
340 }
341 if(blksize > TFTP_BLKSIZE_MAX) {
342 failf(data, "%s (%d)", "blksize is larger than max supported",
343 TFTP_BLKSIZE_MAX);
344 return CURLE_TFTP_ILLEGAL;
345 }
346 else if(blksize < TFTP_BLKSIZE_MIN) {
347 failf(data, "%s (%d)", "blksize is smaller than min supported",
348 TFTP_BLKSIZE_MIN);
349 return CURLE_TFTP_ILLEGAL;
350 }
351 else if(blksize > state->requested_blksize) {
352 /* could realloc pkt buffers here, but the spec does not call out
353 * support for the server requesting a bigger blksize than the client
354 * requests */
355 failf(data, "%s (%ld)",
356 "server requested blksize larger than allocated", blksize);
357 return CURLE_TFTP_ILLEGAL;
358 }
359
360 state->blksize = (int)blksize;
361 infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
362 state->blksize, "requested", state->requested_blksize);
363 }
364 else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
365 long tsize = 0;
366
367 tsize = strtol(value, NULL, 10);
368 infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
369
370 /* tsize should be ignored on upload: Who cares about the size of the
371 remote file? */
372 if(!data->state.upload) {
373 if(!tsize) {
374 failf(data, "invalid tsize -:%s:- value in OACK packet", value);
375 return CURLE_TFTP_ILLEGAL;
376 }
377 Curl_pgrsSetDownloadSize(data, tsize);
378 }
379 }
380 }
381
382 return CURLE_OK;
383 }
384
tftp_option_add(struct tftp_state_data * state,size_t * csize,char * buf,const char * option)385 static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
386 char *buf, const char *option)
387 {
388 if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
389 return CURLE_TFTP_ILLEGAL;
390 strcpy(buf, option);
391 *csize += strlen(option) + 1;
392 return CURLE_OK;
393 }
394
tftp_connect_for_tx(struct tftp_state_data * state,tftp_event_t event)395 static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
396 tftp_event_t event)
397 {
398 CURLcode result;
399 #ifndef CURL_DISABLE_VERBOSE_STRINGS
400 struct Curl_easy *data = state->data;
401
402 infof(data, "%s", "Connected for transmit");
403 #endif
404 state->state = TFTP_STATE_TX;
405 result = tftp_set_timeouts(state);
406 if(result)
407 return result;
408 return tftp_tx(state, event);
409 }
410
tftp_connect_for_rx(struct tftp_state_data * state,tftp_event_t event)411 static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
412 tftp_event_t event)
413 {
414 CURLcode result;
415 #ifndef CURL_DISABLE_VERBOSE_STRINGS
416 struct Curl_easy *data = state->data;
417
418 infof(data, "%s", "Connected for receive");
419 #endif
420 state->state = TFTP_STATE_RX;
421 result = tftp_set_timeouts(state);
422 if(result)
423 return result;
424 return tftp_rx(state, event);
425 }
426
tftp_send_first(struct tftp_state_data * state,tftp_event_t event)427 static CURLcode tftp_send_first(struct tftp_state_data *state,
428 tftp_event_t event)
429 {
430 size_t sbytes;
431 ssize_t senddata;
432 const char *mode = "octet";
433 char *filename;
434 struct Curl_easy *data = state->data;
435 CURLcode result = CURLE_OK;
436
437 /* Set ASCII mode if -B flag was used */
438 if(data->state.prefer_ascii)
439 mode = "netascii";
440
441 switch(event) {
442
443 case TFTP_EVENT_INIT: /* Send the first packet out */
444 case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
445 /* Increment the retry counter, quit if over the limit */
446 state->retries++;
447 if(state->retries > state->retry_max) {
448 state->error = TFTP_ERR_NORESPONSE;
449 state->state = TFTP_STATE_FIN;
450 return result;
451 }
452
453 if(data->state.upload) {
454 /* If we are uploading, send an WRQ */
455 setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
456 if(data->state.infilesize != -1)
457 Curl_pgrsSetUploadSize(data, data->state.infilesize);
458 }
459 else {
460 /* If we are downloading, send an RRQ */
461 setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
462 }
463 /* As RFC3617 describes the separator slash is not actually part of the
464 filename so we skip the always-present first letter of the path
465 string. */
466 result = Curl_urldecode(&state->data->state.up.path[1], 0,
467 &filename, NULL, REJECT_ZERO);
468 if(result)
469 return result;
470
471 if(strlen(filename) > (state->blksize - strlen(mode) - 4)) {
472 failf(data, "TFTP filename too long");
473 free(filename);
474 return CURLE_TFTP_ILLEGAL; /* too long filename field */
475 }
476
477 msnprintf((char *)state->spacket.data + 2,
478 state->blksize,
479 "%s%c%s%c", filename, '\0', mode, '\0');
480 sbytes = 4 + strlen(filename) + strlen(mode);
481
482 /* optional addition of TFTP options */
483 if(!data->set.tftp_no_options) {
484 char buf[64];
485 /* add tsize option */
486 msnprintf(buf, sizeof(buf), "%" FMT_OFF_T,
487 data->state.upload && (data->state.infilesize != -1) ?
488 data->state.infilesize : 0);
489
490 result = tftp_option_add(state, &sbytes,
491 (char *)state->spacket.data + sbytes,
492 TFTP_OPTION_TSIZE);
493 if(result == CURLE_OK)
494 result = tftp_option_add(state, &sbytes,
495 (char *)state->spacket.data + sbytes, buf);
496
497 /* add blksize option */
498 msnprintf(buf, sizeof(buf), "%d", state->requested_blksize);
499 if(result == CURLE_OK)
500 result = tftp_option_add(state, &sbytes,
501 (char *)state->spacket.data + sbytes,
502 TFTP_OPTION_BLKSIZE);
503 if(result == CURLE_OK)
504 result = tftp_option_add(state, &sbytes,
505 (char *)state->spacket.data + sbytes, buf);
506
507 /* add timeout option */
508 msnprintf(buf, sizeof(buf), "%d", state->retry_time);
509 if(result == CURLE_OK)
510 result = tftp_option_add(state, &sbytes,
511 (char *)state->spacket.data + sbytes,
512 TFTP_OPTION_INTERVAL);
513 if(result == CURLE_OK)
514 result = tftp_option_add(state, &sbytes,
515 (char *)state->spacket.data + sbytes, buf);
516
517 if(result != CURLE_OK) {
518 failf(data, "TFTP buffer too small for options");
519 free(filename);
520 return CURLE_TFTP_ILLEGAL;
521 }
522 }
523
524 /* the typecase for the 3rd argument is mostly for systems that do
525 not have a size_t argument, like older unixes that want an 'int' */
526 senddata = sendto(state->sockfd, (void *)state->spacket.data,
527 (SEND_TYPE_ARG3)sbytes, 0,
528 (struct sockaddr *)&data->conn->remote_addr->curl_sa_addr,
529 (curl_socklen_t)data->conn->remote_addr->addrlen);
530 if(senddata != (ssize_t)sbytes) {
531 char buffer[STRERROR_LEN];
532 failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
533 }
534 free(filename);
535 break;
536
537 case TFTP_EVENT_OACK:
538 if(data->state.upload) {
539 result = tftp_connect_for_tx(state, event);
540 }
541 else {
542 result = tftp_connect_for_rx(state, event);
543 }
544 break;
545
546 case TFTP_EVENT_ACK: /* Connected for transmit */
547 result = tftp_connect_for_tx(state, event);
548 break;
549
550 case TFTP_EVENT_DATA: /* Connected for receive */
551 result = tftp_connect_for_rx(state, event);
552 break;
553
554 case TFTP_EVENT_ERROR:
555 state->state = TFTP_STATE_FIN;
556 break;
557
558 default:
559 failf(state->data, "tftp_send_first: internal error");
560 break;
561 }
562
563 return result;
564 }
565
566 /* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
567 boundary */
568 #define NEXT_BLOCKNUM(x) (((x) + 1)&0xffff)
569
570 /**********************************************************
571 *
572 * tftp_rx
573 *
574 * Event handler for the RX state
575 *
576 **********************************************************/
tftp_rx(struct tftp_state_data * state,tftp_event_t event)577 static CURLcode tftp_rx(struct tftp_state_data *state,
578 tftp_event_t event)
579 {
580 ssize_t sbytes;
581 int rblock;
582 struct Curl_easy *data = state->data;
583 char buffer[STRERROR_LEN];
584
585 switch(event) {
586
587 case TFTP_EVENT_DATA:
588 /* Is this the block we expect? */
589 rblock = getrpacketblock(&state->rpacket);
590 if(NEXT_BLOCKNUM(state->block) == rblock) {
591 /* This is the expected block. Reset counters and ACK it. */
592 state->retries = 0;
593 }
594 else if(state->block == rblock) {
595 /* This is the last recently received block again. Log it and ACK it
596 again. */
597 infof(data, "Received last DATA packet block %d again.", rblock);
598 }
599 else {
600 /* totally unexpected, just log it */
601 infof(data,
602 "Received unexpected DATA packet block %d, expecting block %d",
603 rblock, NEXT_BLOCKNUM(state->block));
604 break;
605 }
606
607 /* ACK this block. */
608 state->block = (unsigned short)rblock;
609 setpacketevent(&state->spacket, TFTP_EVENT_ACK);
610 setpacketblock(&state->spacket, state->block);
611 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
612 4, SEND_4TH_ARG,
613 (struct sockaddr *)&state->remote_addr,
614 state->remote_addrlen);
615 if(sbytes < 0) {
616 failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
617 return CURLE_SEND_ERROR;
618 }
619
620 /* Check if completed (That is, a less than full packet is received) */
621 if(state->rbytes < (ssize_t)state->blksize + 4) {
622 state->state = TFTP_STATE_FIN;
623 }
624 else {
625 state->state = TFTP_STATE_RX;
626 }
627 state->rx_time = time(NULL);
628 break;
629
630 case TFTP_EVENT_OACK:
631 /* ACK option acknowledgement so we can move on to data */
632 state->block = 0;
633 state->retries = 0;
634 setpacketevent(&state->spacket, TFTP_EVENT_ACK);
635 setpacketblock(&state->spacket, state->block);
636 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
637 4, SEND_4TH_ARG,
638 (struct sockaddr *)&state->remote_addr,
639 state->remote_addrlen);
640 if(sbytes < 0) {
641 failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
642 return CURLE_SEND_ERROR;
643 }
644
645 /* we are ready to RX data */
646 state->state = TFTP_STATE_RX;
647 state->rx_time = time(NULL);
648 break;
649
650 case TFTP_EVENT_TIMEOUT:
651 /* Increment the retry count and fail if over the limit */
652 state->retries++;
653 infof(data,
654 "Timeout waiting for block %d ACK. Retries = %d",
655 NEXT_BLOCKNUM(state->block), state->retries);
656 if(state->retries > state->retry_max) {
657 state->error = TFTP_ERR_TIMEOUT;
658 state->state = TFTP_STATE_FIN;
659 }
660 else {
661 /* Resend the previous ACK */
662 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
663 4, SEND_4TH_ARG,
664 (struct sockaddr *)&state->remote_addr,
665 state->remote_addrlen);
666 if(sbytes < 0) {
667 failf(data, "%s", Curl_strerror(SOCKERRNO, buffer, sizeof(buffer)));
668 return CURLE_SEND_ERROR;
669 }
670 }
671 break;
672
673 case TFTP_EVENT_ERROR:
674 setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
675 setpacketblock(&state->spacket, state->block);
676 (void)sendto(state->sockfd, (void *)state->spacket.data,
677 4, SEND_4TH_ARG,
678 (struct sockaddr *)&state->remote_addr,
679 state->remote_addrlen);
680 /* do not bother with the return code, but if the socket is still up we
681 * should be a good TFTP client and let the server know we are done */
682 state->state = TFTP_STATE_FIN;
683 break;
684
685 default:
686 failf(data, "%s", "tftp_rx: internal error");
687 return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
688 this */
689 }
690 return CURLE_OK;
691 }
692
693 /**********************************************************
694 *
695 * tftp_tx
696 *
697 * Event handler for the TX state
698 *
699 **********************************************************/
tftp_tx(struct tftp_state_data * state,tftp_event_t event)700 static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
701 {
702 struct Curl_easy *data = state->data;
703 ssize_t sbytes;
704 CURLcode result = CURLE_OK;
705 struct SingleRequest *k = &data->req;
706 size_t cb; /* Bytes currently read */
707 char buffer[STRERROR_LEN];
708 char *bufptr;
709 bool eos;
710
711 switch(event) {
712
713 case TFTP_EVENT_ACK:
714 case TFTP_EVENT_OACK:
715 if(event == TFTP_EVENT_ACK) {
716 /* Ack the packet */
717 int rblock = getrpacketblock(&state->rpacket);
718
719 if(rblock != state->block &&
720 /* There is a bug in tftpd-hpa that causes it to send us an ack for
721 * 65535 when the block number wraps to 0. So when we are expecting
722 * 0, also accept 65535. See
723 * https://www.syslinux.org/archives/2010-September/015612.html
724 * */
725 !(state->block == 0 && rblock == 65535)) {
726 /* This is not the expected block. Log it and up the retry counter */
727 infof(data, "Received ACK for block %d, expecting %d",
728 rblock, state->block);
729 state->retries++;
730 /* Bail out if over the maximum */
731 if(state->retries > state->retry_max) {
732 failf(data, "tftp_tx: giving up waiting for block %d ack",
733 state->block);
734 result = CURLE_SEND_ERROR;
735 }
736 else {
737 /* Re-send the data packet */
738 sbytes = sendto(state->sockfd, (void *)state->spacket.data,
739 4 + (SEND_TYPE_ARG3)state->sbytes, SEND_4TH_ARG,
740 (struct sockaddr *)&state->remote_addr,
741 state->remote_addrlen);
742 /* Check all sbytes were sent */
743 if(sbytes < 0) {
744 failf(data, "%s", Curl_strerror(SOCKERRNO,
745 buffer, sizeof(buffer)));
746 result = CURLE_SEND_ERROR;
747 }
748 }
749
750 return result;
751 }
752 /* This is the expected packet. Reset the counters and send the next
753 block */
754 state->rx_time = time(NULL);
755 state->block++;
756 }
757 else
758 state->block = 1; /* first data block is 1 when using OACK */
759
760 state->retries = 0;
761 setpacketevent(&state->spacket, TFTP_EVENT_DATA);
762 setpacketblock(&state->spacket, state->block);
763 if(state->block > 1 && state->sbytes < state->blksize) {
764 state->state = TFTP_STATE_FIN;
765 return CURLE_OK;
766 }
767
768 /* TFTP considers data block size < 512 bytes as an end of session. So
769 * in some cases we must wait for additional data to build full (512 bytes)
770 * data block.
771 * */
772 state->sbytes = 0;
773 bufptr = (char *)state->spacket.data + 4;
774 do {
775 result = Curl_client_read(data, bufptr, state->blksize - state->sbytes,
776 &cb, &eos);
777 if(result)
778 return result;
779 state->sbytes += (int)cb;
780 bufptr += cb;
781 } while(state->sbytes < state->blksize && cb);
782
783 sbytes = sendto(state->sockfd, (void *) state->spacket.data,
784 4 + (SEND_TYPE_ARG3)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 have 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 + (SEND_TYPE_ARG3)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 /* do not 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 are 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 do not keep TFTP connections up basically because there is none or
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 (curl_socklen_t)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 curl_socklen_t fromlen;
1102 CURLcode result = CURLE_OK;
1103 struct connectdata *conn = data->conn;
1104 struct tftp_state_data *state = conn->proto.tftpc;
1105
1106 /* Receive the packet */
1107 fromlen = sizeof(state->remote_addr);
1108 state->rbytes = (int)recvfrom(state->sockfd,
1109 (void *)state->rpacket.data,
1110 (RECV_TYPE_ARG3)state->blksize + 4,
1111 0,
1112 (struct sockaddr *)&state->remote_addr,
1113 &fromlen);
1114 state->remote_addrlen = fromlen;
1115
1116 /* Sanity check packet length */
1117 if(state->rbytes < 4) {
1118 failf(data, "Received too short packet");
1119 /* Not a timeout, but how best to handle it? */
1120 state->event = TFTP_EVENT_TIMEOUT;
1121 }
1122 else {
1123 /* The event is given by the TFTP packet time */
1124 unsigned short event = getrpacketevent(&state->rpacket);
1125 state->event = (tftp_event_t)event;
1126
1127 switch(state->event) {
1128 case TFTP_EVENT_DATA:
1129 /* Do not pass to the client empty or retransmitted packets */
1130 if(state->rbytes > 4 &&
1131 (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
1132 result = Curl_client_write(data, CLIENTWRITE_BODY,
1133 (char *)state->rpacket.data + 4,
1134 state->rbytes-4);
1135 if(result) {
1136 tftp_state_machine(state, TFTP_EVENT_ERROR);
1137 return result;
1138 }
1139 }
1140 break;
1141 case TFTP_EVENT_ERROR:
1142 {
1143 unsigned short error = getrpacketblock(&state->rpacket);
1144 char *str = (char *)state->rpacket.data + 4;
1145 size_t strn = state->rbytes - 4;
1146 state->error = (tftp_error_t)error;
1147 if(tftp_strnlen(str, strn) < strn)
1148 infof(data, "TFTP error: %s", str);
1149 break;
1150 }
1151 case TFTP_EVENT_ACK:
1152 break;
1153 case TFTP_EVENT_OACK:
1154 result = tftp_parse_option_ack(state,
1155 (const char *)state->rpacket.data + 2,
1156 state->rbytes-2);
1157 if(result)
1158 return result;
1159 break;
1160 case TFTP_EVENT_RRQ:
1161 case TFTP_EVENT_WRQ:
1162 default:
1163 failf(data, "%s", "Internal error: Unexpected packet");
1164 break;
1165 }
1166
1167 /* Update the progress meter */
1168 if(Curl_pgrsUpdate(data)) {
1169 tftp_state_machine(state, TFTP_EVENT_ERROR);
1170 return CURLE_ABORTED_BY_CALLBACK;
1171 }
1172 }
1173 return result;
1174 }
1175
1176 /**********************************************************
1177 *
1178 * tftp_state_timeout
1179 *
1180 * Check if timeouts have been reached
1181 *
1182 **********************************************************/
tftp_state_timeout(struct Curl_easy * data,tftp_event_t * event)1183 static timediff_t tftp_state_timeout(struct Curl_easy *data,
1184 tftp_event_t *event)
1185 {
1186 time_t current;
1187 struct connectdata *conn = data->conn;
1188 struct tftp_state_data *state = conn->proto.tftpc;
1189 timediff_t timeout_ms;
1190
1191 if(event)
1192 *event = TFTP_EVENT_NONE;
1193
1194 timeout_ms = Curl_timeleft(state->data, NULL,
1195 (state->state == TFTP_STATE_START));
1196 if(timeout_ms < 0) {
1197 state->error = TFTP_ERR_TIMEOUT;
1198 state->state = TFTP_STATE_FIN;
1199 return 0;
1200 }
1201 current = time(NULL);
1202 if(current > state->rx_time + state->retry_time) {
1203 if(event)
1204 *event = TFTP_EVENT_TIMEOUT;
1205 state->rx_time = time(NULL); /* update even though we received nothing */
1206 }
1207
1208 return timeout_ms;
1209 }
1210
1211 /**********************************************************
1212 *
1213 * tftp_multi_statemach
1214 *
1215 * Handle single RX socket event and return
1216 *
1217 **********************************************************/
tftp_multi_statemach(struct Curl_easy * data,bool * done)1218 static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
1219 {
1220 tftp_event_t event;
1221 CURLcode result = CURLE_OK;
1222 struct connectdata *conn = data->conn;
1223 struct tftp_state_data *state = conn->proto.tftpc;
1224 timediff_t timeout_ms = tftp_state_timeout(data, &event);
1225
1226 *done = FALSE;
1227
1228 if(timeout_ms < 0) {
1229 failf(data, "TFTP response timeout");
1230 return CURLE_OPERATION_TIMEDOUT;
1231 }
1232 if(event != TFTP_EVENT_NONE) {
1233 result = tftp_state_machine(state, event);
1234 if(result)
1235 return result;
1236 *done = (state->state == TFTP_STATE_FIN);
1237 if(*done)
1238 /* Tell curl we are done */
1239 Curl_xfer_setup_nop(data);
1240 }
1241 else {
1242 /* no timeouts to handle, check our socket */
1243 int rc = SOCKET_READABLE(state->sockfd, 0);
1244
1245 if(rc == -1) {
1246 /* bail out */
1247 int error = SOCKERRNO;
1248 char buffer[STRERROR_LEN];
1249 failf(data, "%s", Curl_strerror(error, buffer, sizeof(buffer)));
1250 state->event = TFTP_EVENT_ERROR;
1251 }
1252 else if(rc) {
1253 result = tftp_receive_packet(data);
1254 if(result)
1255 return result;
1256 result = tftp_state_machine(state, state->event);
1257 if(result)
1258 return result;
1259 *done = (state->state == TFTP_STATE_FIN);
1260 if(*done)
1261 /* Tell curl we are done */
1262 Curl_xfer_setup_nop(data);
1263 }
1264 /* if rc == 0, then select() timed out */
1265 }
1266
1267 return result;
1268 }
1269
1270 /**********************************************************
1271 *
1272 * tftp_doing
1273 *
1274 * Called from multi.c while DOing
1275 *
1276 **********************************************************/
tftp_doing(struct Curl_easy * data,bool * dophase_done)1277 static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
1278 {
1279 CURLcode result;
1280 result = tftp_multi_statemach(data, dophase_done);
1281
1282 if(*dophase_done) {
1283 DEBUGF(infof(data, "DO phase is complete"));
1284 }
1285 else if(!result) {
1286 /* The multi code does not have this logic for the DOING state so we
1287 provide it for TFTP since it may do the entire transfer in this
1288 state. */
1289 if(Curl_pgrsUpdate(data))
1290 result = CURLE_ABORTED_BY_CALLBACK;
1291 else
1292 result = Curl_speedcheck(data, Curl_now());
1293 }
1294 return result;
1295 }
1296
1297 /**********************************************************
1298 *
1299 * tftp_perform
1300 *
1301 * Entry point for transfer from tftp_do, starts state mach
1302 *
1303 **********************************************************/
tftp_perform(struct Curl_easy * data,bool * dophase_done)1304 static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
1305 {
1306 CURLcode result = CURLE_OK;
1307 struct connectdata *conn = data->conn;
1308 struct tftp_state_data *state = conn->proto.tftpc;
1309
1310 *dophase_done = FALSE;
1311
1312 result = tftp_state_machine(state, TFTP_EVENT_INIT);
1313
1314 if((state->state == TFTP_STATE_FIN) || result)
1315 return result;
1316
1317 tftp_multi_statemach(data, dophase_done);
1318
1319 if(*dophase_done)
1320 DEBUGF(infof(data, "DO phase is complete"));
1321
1322 return result;
1323 }
1324
1325
1326 /**********************************************************
1327 *
1328 * tftp_do
1329 *
1330 * The do callback
1331 *
1332 * This callback initiates the TFTP transfer
1333 *
1334 **********************************************************/
1335
tftp_do(struct Curl_easy * data,bool * done)1336 static CURLcode tftp_do(struct Curl_easy *data, bool *done)
1337 {
1338 struct tftp_state_data *state;
1339 CURLcode result;
1340 struct connectdata *conn = data->conn;
1341
1342 *done = FALSE;
1343
1344 if(!conn->proto.tftpc) {
1345 result = tftp_connect(data, done);
1346 if(result)
1347 return result;
1348 }
1349
1350 state = conn->proto.tftpc;
1351 if(!state)
1352 return CURLE_TFTP_ILLEGAL;
1353
1354 result = tftp_perform(data, done);
1355
1356 /* If tftp_perform() returned an error, use that for return code. If it
1357 was OK, see if tftp_translate_code() has an error. */
1358 if(!result)
1359 /* If we have encountered an internal tftp error, translate it. */
1360 result = tftp_translate_code(state->error);
1361
1362 return result;
1363 }
1364
tftp_setup_connection(struct Curl_easy * data,struct connectdata * conn)1365 static CURLcode tftp_setup_connection(struct Curl_easy *data,
1366 struct connectdata *conn)
1367 {
1368 char *type;
1369
1370 conn->transport = TRNSPRT_UDP;
1371
1372 /* TFTP URLs support an extension like ";mode=<typecode>" that
1373 * we will try to get now! */
1374 type = strstr(data->state.up.path, ";mode=");
1375
1376 if(!type)
1377 type = strstr(conn->host.rawalloc, ";mode=");
1378
1379 if(type) {
1380 char command;
1381 *type = 0; /* it was in the middle of the hostname */
1382 command = Curl_raw_toupper(type[6]);
1383
1384 switch(command) {
1385 case 'A': /* ASCII mode */
1386 case 'N': /* NETASCII mode */
1387 data->state.prefer_ascii = TRUE;
1388 break;
1389
1390 case 'O': /* octet mode */
1391 case 'I': /* binary mode */
1392 default:
1393 /* switch off ASCII */
1394 data->state.prefer_ascii = FALSE;
1395 break;
1396 }
1397 }
1398
1399 return CURLE_OK;
1400 }
1401 #endif
1402