1
0
mirror of https://github.com/moparisthebest/curl synced 2024-12-22 08:08:50 -05:00

- Chad Monroe provided the new CURLOPT_TFTP_BLKSIZE option that allows an app

to set desired block size to use for TFTP transfers instead of the default
  512 bytes.
This commit is contained in:
Daniel Stenberg 2009-01-26 22:43:06 +00:00
parent bb86462ed7
commit 0516ce7786
7 changed files with 303 additions and 48 deletions

View File

@ -7,6 +7,10 @@
Changelog Changelog
Daniel Stenberg (26 Jan 2009) Daniel Stenberg (26 Jan 2009)
- Chad Monroe provided the new CURLOPT_TFTP_BLKSIZE option that allows an app
to set desired block size to use for TFTP transfers instead of the default
512 bytes.
- The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to - The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to
disable "rfc4507bis session ticket support". rfc4507bis was later turned disable "rfc4507bis session ticket support". rfc4507bis was later turned
into the proper RFC5077 it seems: http://tools.ietf.org/html/rfc5077 into the proper RFC5077 it seems: http://tools.ietf.org/html/rfc5077

View File

@ -12,6 +12,7 @@ This release includes the following changes:
o Added CURLOPT_NOPROXY and the corresponding --noproxy o Added CURLOPT_NOPROXY and the corresponding --noproxy
o the OpenSSL-specific code disables TICKET (rfc5077) which is enabled by o the OpenSSL-specific code disables TICKET (rfc5077) which is enabled by
default in openssl 0.9.8j default in openssl 0.9.8j
o Added CURLOPT_TFTP_BLKSIZE
This release includes the following bugfixes: This release includes the following bugfixes:
@ -27,6 +28,6 @@ This release would not have looked like this without help, code, reports and
advice from friends like these: advice from friends like these:
Lisa Xu, Daniel Fandrich, Craig A West, Alexey Borzov, Sharad Gupta, Lisa Xu, Daniel Fandrich, Craig A West, Alexey Borzov, Sharad Gupta,
Peter Sylvester Peter Sylvester, Chad Monroe
Thanks! (and sorry if I forgot to mention someone) Thanks! (and sorry if I forgot to mention someone)

View File

@ -1008,6 +1008,14 @@ Pass a long to tell libcurl how to act on transfer decoding. If set to zero,
transfer decoding will be disabled, if set to 1 it is enabled transfer decoding will be disabled, if set to 1 it is enabled
(default). libcurl does chunked transfer decoding by default unless this (default). libcurl does chunked transfer decoding by default unless this
option is set to zero. (added in 7.16.2) option is set to zero. (added in 7.16.2)
.SH TFTP OPTIONS
.IP CURLOPT_TFTPBLKSIZE
Specify block size to use for TFTP data transmission. Valid range as per RFC
2348 is 8-65464 bytes. The default of 512 bytes will be used if this option is
not specified. The specified block size will only be used pending support by
the remote server. If the server does not return an option acknowledgement or
returns an option acknowledgement with no blksize, the default of 512 bytes
will be used. (added in 7.19.4)
.SH FTP OPTIONS .SH FTP OPTIONS
.IP CURLOPT_FTPPORT .IP CURLOPT_FTPPORT
Pass a pointer to a zero terminated string as parameter. It will be used to Pass a pointer to a zero terminated string as parameter. It will be used to

View File

@ -1159,6 +1159,9 @@ typedef enum {
disables the use of proxy. */ disables the use of proxy. */
CINIT(NOPROXY, OBJECTPOINT, 177), CINIT(NOPROXY, OBJECTPOINT, 177),
/* block size for TFTP transfers */
CINIT(TFTP_BLKSIZE, LONG, 178),
CURLOPT_LASTENTRY /* the last unused */ CURLOPT_LASTENTRY /* the last unused */
} CURLoption; } CURLoption;

View File

@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___ * | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____| * \___|\___/|_| \_\_____|
* *
* Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al. * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
* *
* This software is licensed as described in the file COPYING, which * This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms * you should have received as part of this distribution. The terms
@ -26,7 +26,6 @@
#ifndef CURL_DISABLE_TFTP #ifndef CURL_DISABLE_TFTP
/* -- WIN32 approved -- */ /* -- WIN32 approved -- */
#include <stdio.h> #include <stdio.h>
#include <string.h>
#include <stdarg.h> #include <stdarg.h>
#include <stdlib.h> #include <stdlib.h>
#include <ctype.h> #include <ctype.h>
@ -83,8 +82,13 @@
/* The last #include file should be: */ /* The last #include file should be: */
#include "memdebug.h" #include "memdebug.h"
/* RFC2348 allows the block size to be negotiated, but we don't support that */ /* RFC2348 allows the block size to be negotiated */
#define TFTP_BLOCKSIZE 512 #define TFTP_BLKSIZE_DEFAULT 512
#define TFTP_BLKSIZE_MIN 8
#define TFTP_BLKSIZE_MAX 65464
#define TFTP_OPTION_BLKSIZE "blksize"
#define TFTP_OPTION_TSIZE "tsize"
#define TFTP_OPTION_INTERVAL "interval"
typedef enum { typedef enum {
TFTP_MODE_NETASCII=0, TFTP_MODE_NETASCII=0,
@ -105,6 +109,7 @@ typedef enum {
TFTP_EVENT_DATA = 3, TFTP_EVENT_DATA = 3,
TFTP_EVENT_ACK = 4, TFTP_EVENT_ACK = 4,
TFTP_EVENT_ERROR = 5, TFTP_EVENT_ERROR = 5,
TFTP_EVENT_OACK = 6,
TFTP_EVENT_TIMEOUT TFTP_EVENT_TIMEOUT
} tftp_event_t; } tftp_event_t;
@ -125,7 +130,7 @@ typedef enum {
} tftp_error_t; } tftp_error_t;
typedef struct tftp_packet { typedef struct tftp_packet {
unsigned char data[2 + 2 + TFTP_BLOCKSIZE]; unsigned char *data;
} tftp_packet_t; } tftp_packet_t;
typedef struct tftp_state_data { typedef struct tftp_state_data {
@ -144,7 +149,9 @@ typedef struct tftp_state_data {
struct Curl_sockaddr_storage remote_addr; struct Curl_sockaddr_storage remote_addr;
socklen_t remote_addrlen; socklen_t remote_addrlen;
ssize_t rbytes; ssize_t rbytes;
int sbytes; size_t sbytes;
size_t blksize;
int requested_blksize;
tftp_packet_t rpacket; tftp_packet_t rpacket;
tftp_packet_t spacket; tftp_packet_t spacket;
} tftp_state_data_t; } tftp_state_data_t;
@ -154,6 +161,7 @@ typedef struct tftp_state_data {
static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ; static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ;
static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ; static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ;
static CURLcode tftp_connect(struct connectdata *conn, bool *done); static CURLcode tftp_connect(struct connectdata *conn, bool *done);
static CURLcode tftp_disconnect(struct connectdata *conn);
static CURLcode tftp_do(struct connectdata *conn, bool *done); static CURLcode tftp_do(struct connectdata *conn, bool *done);
static CURLcode tftp_done(struct connectdata *conn, static CURLcode tftp_done(struct connectdata *conn,
CURLcode, bool premature); CURLcode, bool premature);
@ -176,7 +184,7 @@ const struct Curl_handler Curl_handler_tftp = {
ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */ ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* disconnect */ tftp_disconnect, /* disconnect */
PORT_TFTP, /* defport */ PORT_TFTP, /* defport */
PROT_TFTP /* protocol */ PROT_TFTP /* protocol */
}; };
@ -257,7 +265,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
state->retry_time=1; state->retry_time=1;
infof(state->conn->data, infof(state->conn->data,
"set timeouts for state %d; Total %d, retry %d maxtry %d\n", "set timeouts for state %d; Total %d, retry %d maxtry %d\n",
state->state, (state->max_time-state->start_time), state->state, (state->max_time-state->start_time),
state->retry_time, state->retry_max); state->retry_time, state->retry_max);
@ -295,11 +303,143 @@ static unsigned short getrpacketblock(const tftp_packet_t *packet)
return (unsigned short)((packet->data[2] << 8) | packet->data[3]); return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
} }
static size_t Curl_strnlen(const char *string, size_t maxlen)
{
const char *end = memchr (string, '\0', maxlen);
return end ? (size_t) (end - string) : maxlen;
}
static const char *tftp_option_get(const char *buf, size_t len,
const char **option, const char **value)
{
size_t loc;
loc = Curl_strnlen( buf, len );
loc++; /* NULL term */
if (loc >= len)
return NULL;
*option = buf;
loc += Curl_strnlen( buf+loc, len-loc );
loc++; /* NULL term */
if (loc > len)
return NULL;
*value = &buf[strlen(*option) + 1];
return &buf[loc];
}
static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
const char *ptr, int len)
{
const char *tmp = ptr;
struct SessionHandle *data = state->conn->data;
/* if OACK doesn't contain blksize option, the default (512) must be used */
state->blksize = TFTP_BLKSIZE_DEFAULT;
while (tmp < ptr + len) {
const char *option, *value;
tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
if(tmp == NULL) {
failf(data, "Malformed ACK packet, rejecting");
return CURLE_TFTP_ILLEGAL;
}
infof(data, "got option=(%s) value=(%s)\n", option, value);
if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
int blksize;
blksize = strtol( value, NULL, 10 );
if(!blksize) {
failf(data, "invalid blocksize value in OACK packet");
return CURLE_TFTP_ILLEGAL;
}
else if(blksize > TFTP_BLKSIZE_MAX) {
failf(data, "%s (%d)", "blksize is larger than max supported",
TFTP_BLKSIZE_MAX);
return CURLE_TFTP_ILLEGAL;
}
else if(blksize < TFTP_BLKSIZE_MIN) {
failf(data, "%s (%d)", "blksize is smaller than min supported",
TFTP_BLKSIZE_MIN);
return CURLE_TFTP_ILLEGAL;
}
else if (blksize > state->requested_blksize) {
/* could realloc pkt buffers here, but the spec doesn't call out
* support for the server requesting a bigger blksize than the client
* requests */
failf(data, "%s (%d)",
"server requested blksize larger than allocated", blksize);
return CURLE_TFTP_ILLEGAL;
}
state->blksize = blksize;
infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
state->blksize, "requested", state->requested_blksize);
}
else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
long tsize = 0;
tsize = strtol( value, NULL, 10 );
if(!tsize) {
failf(data, "invalid tsize value in OACK packet");
return CURLE_TFTP_ILLEGAL;
}
Curl_pgrsSetDownloadSize(data, tsize);
infof(data, "%s (%d)\n", "tsize parsed from OACK", tsize);
}
}
return CURLE_OK;
}
static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
char *buf, const char *option)
{
if( ( strlen(option) + csize + 1U ) > state->blksize )
return 0;
strcpy(buf, option);
return( strlen(option) + 1 );
}
static int tftp_connect_for_tx(tftp_state_data_t *state, tftp_event_t event)
{
int res = 0;
struct SessionHandle *data = state->conn->data;
infof(data, "%s\n", "Connected for transmit");
state->state = TFTP_STATE_TX;
res = tftp_set_timeouts(state);
if(res)
return(res);
return tftp_tx(state, event);
}
static int tftp_connect_for_rx(tftp_state_data_t *state, tftp_event_t event)
{
int res = 0;
struct SessionHandle *data = state->conn->data;
infof(data, "%s\n", "Connected for receive");
state->state = TFTP_STATE_RX;
res = tftp_set_timeouts(state);
if(res)
return(res);
return tftp_rx(state, event);
}
static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event) static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
{ {
int sbytes; int sbytes;
const char *mode = "octet"; const char *mode = "octet";
char *filename; char *filename;
char buf[8];
struct SessionHandle *data = state->conn->data; struct SessionHandle *data = state->conn->data;
CURLcode res = CURLE_OK; CURLcode res = CURLE_OK;
@ -323,7 +463,7 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
/* If we are uploading, send an WRQ */ /* If we are uploading, send an WRQ */
setpacketevent(&state->spacket, TFTP_EVENT_WRQ); setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
state->conn->data->req.upload_fromhere = state->conn->data->req.upload_fromhere =
(char *)&state->spacket.data[4]; (char *)state->spacket.data+4;
if(data->set.infilesize != -1) if(data->set.infilesize != -1)
Curl_pgrsSetUploadSize(data, data->set.infilesize); Curl_pgrsSetUploadSize(data, data->set.infilesize);
} }
@ -332,17 +472,40 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
setpacketevent(&state->spacket, TFTP_EVENT_RRQ); setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
} }
/* As RFC3617 describes the separator slash is not actually part of the /* As RFC3617 describes the separator slash is not actually part of the
file name so we skip the always-present first letter of the path string. */ file name so we skip the always-present first letter of the path
string. */
filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0, filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0,
NULL); NULL);
if(!filename) if(!filename)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
snprintf((char *)&state->spacket.data[2], snprintf((char *)state->spacket.data+2,
TFTP_BLOCKSIZE, state->blksize,
"%s%c%s%c", filename, '\0', mode, '\0'); "%s%c%s%c", filename, '\0', mode, '\0');
sbytes = 4 + (int)strlen(filename) + (int)strlen(mode); sbytes = 4 + strlen(filename) + strlen(mode);
sbytes = sendto(state->sockfd, (void *)&state->spacket,
/* add tsize option */
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data+sbytes,
TFTP_OPTION_TSIZE);
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data+sbytes, "0");
/* add blksize option */
snprintf( buf, sizeof(buf), "%d", state->requested_blksize );
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data+sbytes,
TFTP_OPTION_BLKSIZE);
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data+sbytes, buf );
/* add timeout option */
snprintf( buf, sizeof(buf), "%d", state->retry_time );
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data+sbytes,
TFTP_OPTION_INTERVAL);
sbytes += tftp_option_add(state, sbytes,
(char *)state->spacket.data+sbytes, buf );
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
sbytes, 0, sbytes, 0,
state->conn->ip_addr->ai_addr, state->conn->ip_addr->ai_addr,
state->conn->ip_addr->ai_addrlen); state->conn->ip_addr->ai_addrlen);
@ -352,21 +515,22 @@ static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
Curl_safefree(filename); Curl_safefree(filename);
break; break;
case TFTP_EVENT_ACK: /* Connected for transmit */ case TFTP_EVENT_OACK:
infof(data, "%s\n", "Connected for transmit"); if(data->set.upload) {
state->state = TFTP_STATE_TX; res = tftp_connect_for_tx(state, event);
res = tftp_set_timeouts(state); }
if(res) else {
break; res = tftp_connect_for_rx(state, event);
return tftp_tx(state, event); }
break;
case TFTP_EVENT_DATA: /* connected for receive */ case TFTP_EVENT_ACK: /* Connected for transmit */
infof(data, "%s\n", "Connected for receive"); res = tftp_connect_for_tx(state, event);
state->state = TFTP_STATE_RX; break;
res = tftp_set_timeouts(state);
if(res) case TFTP_EVENT_DATA: /* Connected for receive */
break; res = tftp_connect_for_rx(state, event);
return tftp_rx(state, event); break;
case TFTP_EVENT_ERROR: case TFTP_EVENT_ERROR:
state->state = TFTP_STATE_FIN; state->state = TFTP_STATE_FIN;
@ -395,7 +559,6 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
switch(event) { switch(event) {
case TFTP_EVENT_DATA: case TFTP_EVENT_DATA:
/* Is this the block we expect? */ /* Is this the block we expect? */
rblock = getrpacketblock(&state->rpacket); rblock = getrpacketblock(&state->rpacket);
if((state->block+1) != rblock) { if((state->block+1) != rblock) {
@ -424,7 +587,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
} }
/* Check if completed (That is, a less than full packet is received) */ /* Check if completed (That is, a less than full packet is received) */
if(state->rbytes < (ssize_t)sizeof(state->spacket)){ if(state->rbytes < (ssize_t)state->blksize+4){
state->state = TFTP_STATE_FIN; state->state = TFTP_STATE_FIN;
} }
else { else {
@ -432,6 +595,25 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
} }
break; break;
case TFTP_EVENT_OACK:
/* ACK option acknowledgement so we can move on to data */
state->block = 0;
state->retries = 0;
setpacketevent(&state->spacket, TFTP_EVENT_ACK);
setpacketblock(&state->spacket, state->block);
sbytes = sendto(state->sockfd, (void *)state->spacket.data,
4, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr,
state->remote_addrlen);
if(sbytes < 0) {
failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
return CURLE_SEND_ERROR;
}
/* we're ready to RX data */
state->state = TFTP_STATE_RX;
break;
case TFTP_EVENT_TIMEOUT: case TFTP_EVENT_TIMEOUT:
/* Increment the retry count and fail if over the limit */ /* Increment the retry count and fail if over the limit */
state->retries++; state->retries++;
@ -443,7 +625,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
} }
else { else {
/* Resend the previous ACK */ /* Resend the previous ACK */
sbytes = sendto(state->sockfd, (void *)&state->spacket, sbytes = sendto(state->sockfd, (void *)state->spacket.data,
4, SEND_4TH_ARG, 4, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr, (struct sockaddr *)&state->remote_addr,
state->remote_addrlen); state->remote_addrlen);
@ -519,11 +701,12 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
state->retries = 0; state->retries = 0;
setpacketevent(&state->spacket, TFTP_EVENT_DATA); setpacketevent(&state->spacket, TFTP_EVENT_DATA);
setpacketblock(&state->spacket, state->block); setpacketblock(&state->spacket, state->block);
if(state->block > 1 && state->sbytes < TFTP_BLOCKSIZE) { if(state->block > 1 && state->sbytes < state->blksize) {
state->state = TFTP_STATE_FIN; state->state = TFTP_STATE_FIN;
return CURLE_OK; return CURLE_OK;
} }
res = Curl_fillreadbuffer(state->conn, TFTP_BLOCKSIZE, &state->sbytes); res = Curl_fillreadbuffer(state->conn, state->blksize,
(int *)&state->sbytes);
if(res) if(res)
return res; return res;
sbytes = sendto(state->sockfd, (void *)state->spacket.data, sbytes = sendto(state->sockfd, (void *)state->spacket.data,
@ -552,7 +735,7 @@ static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
} }
else { else {
/* Re-send the data packet */ /* Re-send the data packet */
sbytes = sendto(state->sockfd, (void *)&state->spacket, sbytes = sendto(state->sockfd, (void *)state->spacket.data,
4+state->sbytes, SEND_4TH_ARG, 4+state->sbytes, SEND_4TH_ARG,
(struct sockaddr *)&state->remote_addr, (struct sockaddr *)&state->remote_addr,
state->remote_addrlen); state->remote_addrlen);
@ -615,6 +798,26 @@ static CURLcode tftp_state_machine(tftp_state_data_t *state,
return res; return res;
} }
/**********************************************************
*
* tftp_disconnect
*
* The disconnect callback
*
**********************************************************/
static CURLcode tftp_disconnect(struct connectdata *conn)
{
tftp_state_data_t *state = conn->proto.tftpc;
/* done, free dynamically allocated pkt buffers */
if(state) {
Curl_safefree(state->rpacket.data);
Curl_safefree(state->spacket.data);
free(state);
}
return CURLE_OK;
}
/********************************************************** /**********************************************************
* *
@ -627,17 +830,36 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
{ {
CURLcode code; CURLcode code;
tftp_state_data_t *state; tftp_state_data_t *state;
int rc; int blksize, rc;
blksize = TFTP_BLKSIZE_DEFAULT;
/* If there already is a protocol-specific struct allocated for this /* If there already is a protocol-specific struct allocated for this
sessionhandle, deal with it */ sessionhandle, deal with it */
Curl_reset_reqproto(conn); Curl_reset_reqproto(conn);
state = conn->data->state.proto.tftp; state = conn->proto.tftpc = calloc(sizeof(tftp_state_data_t), 1);
if(!state) { if(!state)
state = conn->data->state.proto.tftp = calloc(sizeof(tftp_state_data_t), return CURLE_OUT_OF_MEMORY;
1);
if(!state) /* alloc pkt buffers based on specified blksize */
if(conn->data->set.tftp_blksize) {
blksize = conn->data->set.tftp_blksize;
if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN )
return CURLE_TFTP_ILLEGAL;
}
if(!state->rpacket.data) {
state->rpacket.data = calloc(1, blksize + 2 + 2);
if(!state->rpacket.data)
return CURLE_OUT_OF_MEMORY;
}
if(!state->spacket.data) {
state->spacket.data = calloc(1, blksize + 2 + 2);
if(!state->spacket.data)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
@ -647,6 +869,8 @@ static CURLcode tftp_connect(struct connectdata *conn, bool *done)
state->sockfd = state->conn->sock[FIRSTSOCKET]; state->sockfd = state->conn->sock[FIRSTSOCKET];
state->state = TFTP_STATE_START; state->state = TFTP_STATE_START;
state->error = TFTP_ERR_NONE; state->error = TFTP_ERR_NONE;
state->blksize = TFTP_BLKSIZE_DEFAULT;
state->requested_blksize = blksize;
((struct sockaddr *)&state->local_addr)->sa_family = ((struct sockaddr *)&state->local_addr)->sa_family =
(unsigned short)(conn->ip_addr->ai_family); (unsigned short)(conn->ip_addr->ai_family);
@ -735,12 +959,12 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
*/ */
Curl_reset_reqproto(conn); Curl_reset_reqproto(conn);
if(!data->state.proto.tftp) { if(!conn->proto.tftpc) {
code = tftp_connect(conn, done); code = tftp_connect(conn, done);
if(code) if(code)
return code; return code;
} }
state = (tftp_state_data_t *)data->state.proto.tftp; state = (tftp_state_data_t *)conn->proto.tftpc;
/* Run the TFTP State Machine */ /* Run the TFTP State Machine */
for(code=tftp_state_machine(state, TFTP_EVENT_INIT); for(code=tftp_state_machine(state, TFTP_EVENT_INIT);
@ -770,8 +994,8 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
/* Receive the packet */ /* Receive the packet */
fromlen = sizeof(fromaddr); fromlen = sizeof(fromaddr);
state->rbytes = (ssize_t)recvfrom(state->sockfd, state->rbytes = (ssize_t)recvfrom(state->sockfd,
(void *)&state->rpacket, (void *)state->rpacket.data,
sizeof(state->rpacket), state->blksize+4,
0, 0,
(struct sockaddr *)&fromaddr, (struct sockaddr *)&fromaddr,
&fromlen); &fromlen);
@ -797,7 +1021,7 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
if(state->rbytes > 4 && if(state->rbytes > 4 &&
((state->block+1) == getrpacketblock(&state->rpacket))) { ((state->block+1) == getrpacketblock(&state->rpacket))) {
code = Curl_client_write(conn, CLIENTWRITE_BODY, code = Curl_client_write(conn, CLIENTWRITE_BODY,
(char *)&state->rpacket.data[4], (char *)state->rpacket.data+4,
state->rbytes-4); state->rbytes-4);
if(code) if(code)
return code; return code;
@ -807,10 +1031,17 @@ static CURLcode tftp_do(struct connectdata *conn, bool *done)
break; break;
case TFTP_EVENT_ERROR: case TFTP_EVENT_ERROR:
state->error = (tftp_error_t)getrpacketblock(&state->rpacket); state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
infof(data, "%s\n", (const char *)&state->rpacket.data[4]); infof(data, "%s\n", (const char *)state->rpacket.data+4);
break; break;
case TFTP_EVENT_ACK: case TFTP_EVENT_ACK:
break; break;
case TFTP_EVENT_OACK:
code = tftp_parse_option_ack(state,
(const char *)state->rpacket.data+2,
state->rbytes-2);
if(code)
return code;
break;
case TFTP_EVENT_RRQ: case TFTP_EVENT_RRQ:
case TFTP_EVENT_WRQ: case TFTP_EVENT_WRQ:
default: default:

View File

@ -932,6 +932,12 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
*/ */
data->set.ftp_response_timeout = va_arg( param , long ) * 1000; data->set.ftp_response_timeout = va_arg( param , long ) * 1000;
break; break;
case CURLOPT_TFTP_BLKSIZE:
/*
* TFTP option that specifies the block size to use for data transmission
*/
data->set.tftp_blksize = va_arg(param, long);
break;
case CURLOPT_DIRLISTONLY: case CURLOPT_DIRLISTONLY:
/* /*
* An option that changes the command to one that asks for a list * An option that changes the command to one that asks for a list

View File

@ -1047,6 +1047,7 @@ struct connectdata {
union { union {
struct ftp_conn ftpc; struct ftp_conn ftpc;
struct ssh_conn sshc; struct ssh_conn sshc;
struct tftp_state_data *tftpc;
} proto; } proto;
int cselect_bits; /* bitmask of socket events */ int cselect_bits; /* bitmask of socket events */
@ -1288,7 +1289,7 @@ struct UrlState {
struct HTTP *http; struct HTTP *http;
struct HTTP *https; /* alias, just for the sake of being more readable */ struct HTTP *https; /* alias, just for the sake of being more readable */
struct FTP *ftp; struct FTP *ftp;
void *tftp; /* private for tftp.c-eyes only */ /* void *tftp; not used */
struct FILEPROTO *file; struct FILEPROTO *file;
void *telnet; /* private for telnet.c-eyes only */ void *telnet; /* private for telnet.c-eyes only */
void *generic; void *generic;
@ -1425,6 +1426,7 @@ struct UserDefined {
long timeout; /* in milliseconds, 0 means no timeout */ long timeout; /* in milliseconds, 0 means no timeout */
long connecttimeout; /* in milliseconds, 0 means no timeout */ long connecttimeout; /* in milliseconds, 0 means no timeout */
long ftp_response_timeout; /* in milliseconds, 0 means no timeout */ long ftp_response_timeout; /* in milliseconds, 0 means no timeout */
long tftp_blksize ; /* in bytes, 0 means use default */
curl_off_t infilesize; /* size of file to upload, -1 means unknown */ curl_off_t infilesize; /* size of file to upload, -1 means unknown */
long low_speed_limit; /* bytes/second */ long low_speed_limit; /* bytes/second */
long low_speed_time; /* number of seconds */ long low_speed_time; /* number of seconds */