291
303
return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
306
static size_t Curl_strnlen(const char *string, size_t maxlen)
308
const char *end = memchr (string, '\0', maxlen);
309
return end ? (size_t) (end - string) : maxlen;
312
static const char *tftp_option_get(const char *buf, size_t len,
313
const char **option, const char **value)
317
loc = Curl_strnlen( buf, len );
318
loc++; /* NULL term */
324
loc += Curl_strnlen( buf+loc, len-loc );
325
loc++; /* NULL term */
329
*value = &buf[strlen(*option) + 1];
334
static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
335
const char *ptr, int len)
337
const char *tmp = ptr;
338
struct SessionHandle *data = state->conn->data;
340
/* if OACK doesn't contain blksize option, the default (512) must be used */
341
state->blksize = TFTP_BLKSIZE_DEFAULT;
343
while (tmp < ptr + len) {
344
const char *option, *value;
346
tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
348
failf(data, "Malformed ACK packet, rejecting");
349
return CURLE_TFTP_ILLEGAL;
352
infof(data, "got option=(%s) value=(%s)\n", option, value);
354
if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
357
blksize = strtol( value, NULL, 10 );
360
failf(data, "invalid blocksize value in OACK packet");
361
return CURLE_TFTP_ILLEGAL;
363
else if(blksize > TFTP_BLKSIZE_MAX) {
364
failf(data, "%s (%d)", "blksize is larger than max supported",
366
return CURLE_TFTP_ILLEGAL;
368
else if(blksize < TFTP_BLKSIZE_MIN) {
369
failf(data, "%s (%d)", "blksize is smaller than min supported",
371
return CURLE_TFTP_ILLEGAL;
373
else if (blksize > state->requested_blksize) {
374
/* could realloc pkt buffers here, but the spec doesn't call out
375
* support for the server requesting a bigger blksize than the client
377
failf(data, "%s (%d)",
378
"server requested blksize larger than allocated", blksize);
379
return CURLE_TFTP_ILLEGAL;
382
state->blksize = blksize;
383
infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
384
state->blksize, "requested", state->requested_blksize);
386
else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
389
tsize = strtol( value, NULL, 10 );
391
failf(data, "invalid tsize value in OACK packet");
392
return CURLE_TFTP_ILLEGAL;
394
Curl_pgrsSetDownloadSize(data, tsize);
395
infof(data, "%s (%d)\n", "tsize parsed from OACK", tsize);
402
static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
403
char *buf, const char *option)
405
if( ( strlen(option) + csize + 1U ) > state->blksize )
408
return( strlen(option) + 1 );
411
static CURLcode tftp_connect_for_tx(tftp_state_data_t *state, tftp_event_t event)
414
struct SessionHandle *data = state->conn->data;
416
infof(data, "%s\n", "Connected for transmit");
417
state->state = TFTP_STATE_TX;
418
res = tftp_set_timeouts(state);
421
return tftp_tx(state, event);
424
static CURLcode tftp_connect_for_rx(tftp_state_data_t *state, tftp_event_t event)
427
struct SessionHandle *data = state->conn->data;
429
infof(data, "%s\n", "Connected for receive");
430
state->state = TFTP_STATE_RX;
431
res = tftp_set_timeouts(state);
434
return tftp_rx(state, event);
294
437
static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
297
440
const char *mode = "octet";
299
443
struct SessionHandle *data = state->conn->data;
300
444
CURLcode res = CURLE_OK;
328
472
setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
330
474
/* As RFC3617 describes the separator slash is not actually part of the
331
file name so we skip the always-present first letter of the path string. */
475
file name so we skip the always-present first letter of the path
332
477
filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0,
335
480
return CURLE_OUT_OF_MEMORY;
337
snprintf((char *)&state->spacket.data[2],
482
snprintf((char *)state->spacket.data+2,
339
484
"%s%c%s%c", filename, '\0', mode, '\0');
340
sbytes = 4 + (int)strlen(filename) + (int)strlen(mode);
341
sbytes = sendto(state->sockfd, (void *)&state->spacket,
485
sbytes = 4 + strlen(filename) + strlen(mode);
487
/* add tsize option */
488
sbytes += tftp_option_add(state, sbytes,
489
(char *)state->spacket.data+sbytes,
491
sbytes += tftp_option_add(state, sbytes,
492
(char *)state->spacket.data+sbytes, "0");
493
/* add blksize option */
494
snprintf( buf, sizeof(buf), "%d", state->requested_blksize );
495
sbytes += tftp_option_add(state, sbytes,
496
(char *)state->spacket.data+sbytes,
497
TFTP_OPTION_BLKSIZE);
498
sbytes += tftp_option_add(state, sbytes,
499
(char *)state->spacket.data+sbytes, buf );
500
/* add timeout option */
501
snprintf( buf, sizeof(buf), "%d", state->retry_time );
502
sbytes += tftp_option_add(state, sbytes,
503
(char *)state->spacket.data+sbytes,
504
TFTP_OPTION_INTERVAL);
505
sbytes += tftp_option_add(state, sbytes,
506
(char *)state->spacket.data+sbytes, buf );
508
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
343
510
state->conn->ip_addr->ai_addr,
344
511
state->conn->ip_addr->ai_addrlen);
348
515
Curl_safefree(filename);
518
case TFTP_EVENT_OACK:
519
if(data->set.upload) {
520
res = tftp_connect_for_tx(state, event);
523
res = tftp_connect_for_rx(state, event);
351
527
case TFTP_EVENT_ACK: /* Connected for transmit */
352
infof(data, "%s\n", "Connected for transmit");
353
state->state = TFTP_STATE_TX;
354
res = tftp_set_timeouts(state);
357
return tftp_tx(state, event);
528
res = tftp_connect_for_tx(state, event);
359
case TFTP_EVENT_DATA: /* connected for receive */
360
infof(data, "%s\n", "Connected for receive");
361
state->state = TFTP_STATE_RX;
362
res = tftp_set_timeouts(state);
365
return tftp_rx(state, event);
531
case TFTP_EVENT_DATA: /* Connected for receive */
532
res = tftp_connect_for_rx(state, event);
367
535
case TFTP_EVENT_ERROR:
368
536
state->state = TFTP_STATE_FIN;
625
832
tftp_state_data_t *state;
835
blksize = TFTP_BLKSIZE_DEFAULT;
628
837
/* If there already is a protocol-specific struct allocated for this
629
838
sessionhandle, deal with it */
630
839
Curl_reset_reqproto(conn);
632
state = conn->data->state.proto.tftp;
634
state = conn->data->state.proto.tftp = calloc(sizeof(tftp_state_data_t),
841
state = conn->proto.tftpc = calloc(sizeof(tftp_state_data_t), 1);
843
return CURLE_OUT_OF_MEMORY;
845
/* alloc pkt buffers based on specified blksize */
846
if(conn->data->set.tftp_blksize) {
847
blksize = conn->data->set.tftp_blksize;
848
if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN )
849
return CURLE_TFTP_ILLEGAL;
852
if(!state->rpacket.data) {
853
state->rpacket.data = calloc(1, blksize + 2 + 2);
855
if(!state->rpacket.data)
856
return CURLE_OUT_OF_MEMORY;
859
if(!state->spacket.data) {
860
state->spacket.data = calloc(1, blksize + 2 + 2);
862
if(!state->spacket.data)
637
863
return CURLE_OUT_OF_MEMORY;
766
994
/* Receive the packet */
767
fromlen=sizeof(fromaddr);
768
state->rbytes = recvfrom(state->sockfd,
769
(void *)&state->rpacket, sizeof(state->rpacket),
770
0, (struct sockaddr *)&fromaddr, &fromlen);
995
fromlen = sizeof(fromaddr);
996
state->rbytes = (ssize_t)recvfrom(state->sockfd,
997
(void *)state->rpacket.data,
1000
(struct sockaddr *)&fromaddr,
771
1002
if(state->remote_addrlen==0) {
772
1003
memcpy(&state->remote_addr, &fromaddr, fromlen);
773
1004
state->remote_addrlen = fromlen;