summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/tftp.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/tftp.c')
-rw-r--r--libs/libcurl/src/tftp.c159
1 files changed, 75 insertions, 84 deletions
diff --git a/libs/libcurl/src/tftp.c b/libs/libcurl/src/tftp.c
index 13d5e068d1..f6ba609797 100644
--- a/libs/libcurl/src/tftp.c
+++ b/libs/libcurl/src/tftp.c
@@ -62,6 +62,7 @@
#include "speedcheck.h"
#include "select.h"
#include "escape.h"
+#include "curlx/strparse.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -120,7 +121,10 @@ struct tftp_packet {
unsigned char *data;
};
-struct tftp_state_data {
+/* meta key for storing protocol meta at connection */
+#define CURL_META_TFTP_CONN "meta:proto:tftp:conn"
+
+struct tftp_conn {
tftp_state_t state;
tftp_mode_t mode;
tftp_error_t error;
@@ -135,9 +139,9 @@ struct tftp_state_data {
struct Curl_sockaddr_storage remote_addr;
curl_socklen_t remote_addrlen;
int rbytes;
- int sbytes;
- int blksize;
- int requested_blksize;
+ size_t sbytes;
+ unsigned int blksize;
+ unsigned int requested_blksize;
unsigned short block;
struct tftp_packet rpacket;
struct tftp_packet spacket;
@@ -145,12 +149,9 @@ struct tftp_state_data {
/* Forward declarations */
-static CURLcode tftp_rx(struct tftp_state_data *state, tftp_event_t event);
-static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event);
+static CURLcode tftp_rx(struct tftp_conn *state, tftp_event_t event);
+static CURLcode tftp_tx(struct tftp_conn *state, tftp_event_t event);
static CURLcode tftp_connect(struct Curl_easy *data, bool *done);
-static CURLcode tftp_disconnect(struct Curl_easy *data,
- struct connectdata *conn,
- bool dead_connection);
static CURLcode tftp_do(struct Curl_easy *data, bool *done);
static CURLcode tftp_done(struct Curl_easy *data,
CURLcode, bool premature);
@@ -180,11 +181,12 @@ const struct Curl_handler Curl_handler_tftp = {
tftp_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
- tftp_disconnect, /* disconnect */
+ ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
ZERO_NULL, /* connection_check */
ZERO_NULL, /* attach connection */
+ ZERO_NULL, /* follow */
PORT_TFTP, /* defport */
CURLPROTO_TFTP, /* protocol */
CURLPROTO_TFTP, /* family */
@@ -201,7 +203,7 @@ const struct Curl_handler Curl_handler_tftp = {
*
*
**********************************************************/
-static CURLcode tftp_set_timeouts(struct tftp_state_data *state)
+static CURLcode tftp_set_timeouts(struct tftp_conn *state)
{
time_t maxtime, timeout;
timediff_t timeout_ms;
@@ -308,7 +310,7 @@ static const char *tftp_option_get(const char *buf, size_t len,
return &buf[loc];
}
-static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
+static CURLcode tftp_parse_option_ack(struct tftp_conn *state,
const char *ptr, int len)
{
const char *tmp = ptr;
@@ -329,19 +331,16 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
infof(data, "got option=(%s) value=(%s)", option, value);
if(checkprefix(TFTP_OPTION_BLKSIZE, option)) {
- long blksize;
-
- blksize = strtol(value, NULL, 10);
-
- if(!blksize) {
- failf(data, "invalid blocksize value in OACK packet");
- return CURLE_TFTP_ILLEGAL;
- }
- if(blksize > TFTP_BLKSIZE_MAX) {
+ curl_off_t blksize;
+ if(curlx_str_number(&value, &blksize, TFTP_BLKSIZE_MAX)) {
failf(data, "%s (%d)", "blksize is larger than max supported",
TFTP_BLKSIZE_MAX);
return CURLE_TFTP_ILLEGAL;
}
+ if(!blksize) {
+ failf(data, "invalid blocksize value in OACK packet");
+ return CURLE_TFTP_ILLEGAL;
+ }
else if(blksize < TFTP_BLKSIZE_MIN) {
failf(data, "%s (%d)", "blksize is smaller than min supported",
TFTP_BLKSIZE_MIN);
@@ -351,28 +350,27 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
/* could realloc pkt buffers here, but the spec does not call out
* support for the server requesting a bigger blksize than the client
* requests */
- failf(data, "%s (%ld)",
- "server requested blksize larger than allocated", blksize);
+ failf(data, "server requested blksize larger than allocated (%"
+ CURL_FORMAT_CURL_OFF_T ")", blksize);
return CURLE_TFTP_ILLEGAL;
}
state->blksize = (int)blksize;
- infof(data, "%s (%d) %s (%d)", "blksize parsed from OACK",
- state->blksize, "requested", state->requested_blksize);
+ infof(data, "blksize parsed from OACK (%d) requested (%d)",
+ state->blksize, state->requested_blksize);
}
else if(checkprefix(TFTP_OPTION_TSIZE, option)) {
- long tsize = 0;
-
- tsize = strtol(value, NULL, 10);
- infof(data, "%s (%ld)", "tsize parsed from OACK", tsize);
-
+ curl_off_t tsize = 0;
/* tsize should be ignored on upload: Who cares about the size of the
remote file? */
- if(!data->state.upload) {
+ if(!data->state.upload &&
+ !curlx_str_number(&value, &tsize, CURL_OFF_T_MAX)) {
if(!tsize) {
failf(data, "invalid tsize -:%s:- value in OACK packet", value);
return CURLE_TFTP_ILLEGAL;
}
+ infof(data, "tsize parsed from OACK (%" CURL_FORMAT_CURL_OFF_T ")",
+ tsize);
Curl_pgrsSetDownloadSize(data, tsize);
}
}
@@ -381,7 +379,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_state_data *state,
return CURLE_OK;
}
-static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
+static CURLcode tftp_option_add(struct tftp_conn *state, size_t *csize,
char *buf, const char *option)
{
if(( strlen(option) + *csize + 1) > (size_t)state->blksize)
@@ -391,7 +389,7 @@ static CURLcode tftp_option_add(struct tftp_state_data *state, size_t *csize,
return CURLE_OK;
}
-static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
+static CURLcode tftp_connect_for_tx(struct tftp_conn *state,
tftp_event_t event)
{
CURLcode result;
@@ -407,7 +405,7 @@ static CURLcode tftp_connect_for_tx(struct tftp_state_data *state,
return tftp_tx(state, event);
}
-static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
+static CURLcode tftp_connect_for_rx(struct tftp_conn *state,
tftp_event_t event)
{
CURLcode result;
@@ -423,7 +421,7 @@ static CURLcode tftp_connect_for_rx(struct tftp_state_data *state,
return tftp_rx(state, event);
}
-static CURLcode tftp_send_first(struct tftp_state_data *state,
+static CURLcode tftp_send_first(struct tftp_conn *state,
tftp_event_t event)
{
size_t sbytes;
@@ -522,9 +520,14 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
/* the typecase for the 3rd argument is mostly for systems that do
not have a size_t argument, like older unixes that want an 'int' */
+#ifdef __AMIGA__
+#define CURL_SENDTO_ARG5(x) CURL_UNCONST(x)
+#else
+#define CURL_SENDTO_ARG5(x) (x)
+#endif
senddata = sendto(state->sockfd, (void *)state->spacket.data,
(SEND_TYPE_ARG3)sbytes, 0,
- &data->conn->remote_addr->curl_sa_addr,
+ CURL_SENDTO_ARG5(&data->conn->remote_addr->curl_sa_addr),
(curl_socklen_t)data->conn->remote_addr->addrlen);
if(senddata != (ssize_t)sbytes) {
char buffer[STRERROR_LEN];
@@ -573,8 +576,7 @@ static CURLcode tftp_send_first(struct tftp_state_data *state,
* Event handler for the RX state
*
**********************************************************/
-static CURLcode tftp_rx(struct tftp_state_data *state,
- tftp_event_t event)
+static CURLcode tftp_rx(struct tftp_conn *state, tftp_event_t event)
{
ssize_t sbytes;
int rblock;
@@ -696,7 +698,7 @@ static CURLcode tftp_rx(struct tftp_state_data *state,
* Event handler for the TX state
*
**********************************************************/
-static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
+static CURLcode tftp_tx(struct tftp_conn *state, tftp_event_t event)
{
struct Curl_easy *data = state->data;
ssize_t sbytes;
@@ -775,7 +777,7 @@ static CURLcode tftp_tx(struct tftp_state_data *state, tftp_event_t event)
&cb, &eos);
if(result)
return result;
- state->sbytes += (int)cb;
+ state->sbytes += cb;
bufptr += cb;
} while(state->sbytes < state->blksize && cb);
@@ -898,7 +900,7 @@ static CURLcode tftp_translate_code(tftp_error_t error)
* The tftp state machine event dispatcher
*
**********************************************************/
-static CURLcode tftp_state_machine(struct tftp_state_data *state,
+static CURLcode tftp_state_machine(struct tftp_conn *state,
tftp_event_t event)
{
CURLcode result = CURLE_OK;
@@ -930,28 +932,14 @@ static CURLcode tftp_state_machine(struct tftp_state_data *state,
return result;
}
-/**********************************************************
- *
- * tftp_disconnect
- *
- * The disconnect callback
- *
- **********************************************************/
-static CURLcode tftp_disconnect(struct Curl_easy *data,
- struct connectdata *conn, bool dead_connection)
+static void tftp_conn_dtor(void *key, size_t klen, void *entry)
{
- struct tftp_state_data *state = conn->proto.tftpc;
- (void) data;
- (void) dead_connection;
-
- /* done, free dynamically allocated pkt buffers */
- if(state) {
- Curl_safefree(state->rpacket.data);
- Curl_safefree(state->spacket.data);
- free(state);
- }
-
- return CURLE_OK;
+ struct tftp_conn *state = entry;
+ (void)key;
+ (void)klen;
+ Curl_safefree(state->rpacket.data);
+ Curl_safefree(state->spacket.data);
+ free(state);
}
/**********************************************************
@@ -963,15 +951,16 @@ static CURLcode tftp_disconnect(struct Curl_easy *data,
**********************************************************/
static CURLcode tftp_connect(struct Curl_easy *data, bool *done)
{
- struct tftp_state_data *state;
+ struct tftp_conn *state;
int blksize;
int need_blksize;
struct connectdata *conn = data->conn;
blksize = TFTP_BLKSIZE_DEFAULT;
- state = conn->proto.tftpc = calloc(1, sizeof(struct tftp_state_data));
- if(!state)
+ state = calloc(1, sizeof(*state));
+ if(!state ||
+ Curl_conn_meta_set(conn, CURL_META_TFTP_CONN, state, tftp_conn_dtor))
return CURLE_OUT_OF_MEMORY;
/* alloc pkt buffers based on specified blksize */
@@ -1058,7 +1047,7 @@ static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- struct tftp_state_data *state = conn->proto.tftpc;
+ struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
(void)status; /* unused */
(void)premature; /* not used */
@@ -1095,12 +1084,11 @@ static int tftp_getsock(struct Curl_easy *data,
* Called once select fires and data is ready on the socket
*
**********************************************************/
-static CURLcode tftp_receive_packet(struct Curl_easy *data)
+static CURLcode tftp_receive_packet(struct Curl_easy *data,
+ struct tftp_conn *state)
{
curl_socklen_t fromlen;
CURLcode result = CURLE_OK;
- struct connectdata *conn = data->conn;
- struct tftp_state_data *state = conn->proto.tftpc;
/* Receive the packet */
fromlen = sizeof(state->remote_addr);
@@ -1179,12 +1167,10 @@ static CURLcode tftp_receive_packet(struct Curl_easy *data)
* Check if timeouts have been reached
*
**********************************************************/
-static timediff_t tftp_state_timeout(struct Curl_easy *data,
+static timediff_t tftp_state_timeout(struct tftp_conn *state,
tftp_event_t *event)
{
time_t current;
- struct connectdata *conn = data->conn;
- struct tftp_state_data *state = conn->proto.tftpc;
timediff_t timeout_ms;
if(event)
@@ -1219,11 +1205,14 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
tftp_event_t event;
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- struct tftp_state_data *state = conn->proto.tftpc;
- timediff_t timeout_ms = tftp_state_timeout(data, &event);
+ struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
+ timediff_t timeout_ms;
*done = FALSE;
+ if(!state)
+ return CURLE_FAILED_INIT;
+ timeout_ms = tftp_state_timeout(state, &event);
if(timeout_ms < 0) {
failf(data, "TFTP response timeout");
return CURLE_OPERATION_TIMEDOUT;
@@ -1249,7 +1238,7 @@ static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done)
state->event = TFTP_EVENT_ERROR;
}
else if(rc) {
- result = tftp_receive_packet(data);
+ result = tftp_receive_packet(data, state);
if(result)
return result;
result = tftp_state_machine(state, state->event);
@@ -1288,7 +1277,7 @@ static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done)
if(Curl_pgrsUpdate(data))
result = CURLE_ABORTED_BY_CALLBACK;
else
- result = Curl_speedcheck(data, Curl_now());
+ result = Curl_speedcheck(data, curlx_now());
}
return result;
}
@@ -1304,9 +1293,11 @@ static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
{
CURLcode result = CURLE_OK;
struct connectdata *conn = data->conn;
- struct tftp_state_data *state = conn->proto.tftpc;
+ struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
*dophase_done = FALSE;
+ if(!state)
+ return CURLE_FAILED_INIT;
result = tftp_state_machine(state, TFTP_EVENT_INIT);
@@ -1334,21 +1325,21 @@ static CURLcode tftp_perform(struct Curl_easy *data, bool *dophase_done)
static CURLcode tftp_do(struct Curl_easy *data, bool *done)
{
- struct tftp_state_data *state;
- CURLcode result;
struct connectdata *conn = data->conn;
+ struct tftp_conn *state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
+ CURLcode result;
*done = FALSE;
- if(!conn->proto.tftpc) {
+ if(!state) {
result = tftp_connect(data, done);
if(result)
return result;
- }
- state = conn->proto.tftpc;
- if(!state)
- return CURLE_TFTP_ILLEGAL;
+ state = Curl_conn_meta_get(conn, CURL_META_TFTP_CONN);
+ if(!state)
+ return CURLE_TFTP_ILLEGAL;
+ }
result = tftp_perform(data, done);