From 9354822e09ce11fce78a45a897fe2a184565a35e Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Thu, 9 Nov 2006 21:36:18 +0000 Subject: Ciprian Badescu found a SIGSEGV when doing multiple TFTP transfers using the multi interface, but I could also repeat it doing multiple sequential ones with the easy interface. Using Ciprian's test case, I could fix it. --- lib/tftp.c | 64 +++++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 43 insertions(+), 21 deletions(-) (limited to 'lib') diff --git a/lib/tftp.c b/lib/tftp.c index 09998fa70..76b248fdb 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -569,10 +569,13 @@ CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) tftp_state_data_t *state; int rc; - state = conn->data->reqdata.proto.tftp = calloc(sizeof(tftp_state_data_t), 1); + state = conn->data->reqdata.proto.tftp = calloc(sizeof(tftp_state_data_t), + 1); if(!state) return CURLE_OUT_OF_MEMORY; + conn->bits.close = FALSE; /* keep it open if possible */ + state->conn = conn; state->sockfd = state->conn->sock[FIRSTSOCKET]; state->state = TFTP_STATE_START; @@ -582,24 +585,27 @@ CURLcode Curl_tftp_connect(struct connectdata *conn, bool *done) tftp_set_timeouts(state); - /* Bind to any interface, random UDP port. - * - * We once used the size of the local_addr struct as the third argument for - * bind() to better work with IPv6 or whatever size the struct could have, - * but we learned that at least Tru64, AIX and IRIX *requires* the size of - * that argument to match the exact size of a 'sockaddr_in' struct when - * running IPv4-only. - * - * Therefore we use the size from the address we connected to, which we - * assume uses the same IP version and thus hopefully this works for both - * IPv4 and IPv6... - */ - rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr, - conn->ip_addr->ai_addrlen); - if(rc) { - failf(conn->data, "bind() failed; %s\n", - Curl_strerror(conn, Curl_sockerrno())); - return CURLE_COULDNT_CONNECT; + if(!conn->bits.reuse) { + /* If not reused, bind to any interface, random UDP port. If it is reused, + * this has already been done! + * + * We once used the size of the local_addr struct as the third argument for + * bind() to better work with IPv6 or whatever size the struct could have, + * but we learned that at least Tru64, AIX and IRIX *requires* the size of + * that argument to match the exact size of a 'sockaddr_in' struct when + * running IPv4-only. + * + * Therefore we use the size from the address we connected to, which we + * assume uses the same IP version and thus hopefully this works for both + * IPv4 and IPv6... + */ + rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr, + conn->ip_addr->ai_addrlen); + if(rc) { + failf(conn->data, "bind() failed; %s\n", + Curl_strerror(conn, Curl_sockerrno())); + return CURLE_COULDNT_CONNECT; + } } Curl_pgrsStartNow(conn->data); @@ -620,8 +626,10 @@ CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status) { (void)status; /* unused */ +#if 0 free(conn->data->reqdata.proto.tftp); conn->data->reqdata.proto.tftp = NULL; +#endif Curl_pgrsDone(conn); return CURLE_OK; @@ -641,7 +649,8 @@ CURLcode Curl_tftp_done(struct connectdata *conn, CURLcode status) CURLcode Curl_tftp(struct connectdata *conn, bool *done) { struct SessionHandle *data = conn->data; - tftp_state_data_t *state = (tftp_state_data_t *)(conn->data->reqdata.proto.tftp); + tftp_state_data_t *state = + (tftp_state_data_t *) conn->data->reqdata.proto.tftp; tftp_event_t event; CURLcode code; int rc; @@ -649,7 +658,20 @@ CURLcode Curl_tftp(struct connectdata *conn, bool *done) socklen_t fromlen; int check_time = 0; - (void)done; /* prevent compiler warning */ + *done = TRUE; + + /* + Since connections can be re-used between SessionHandles, this might be a + connection already existing but on a fresh SessionHandle struct so we must + make sure we have a good 'struct TFTP' to play with. For new connections, + the struct TFTP is allocated and setup in the Curl_tftp_connect() function. + */ + if(!state) { + code = Curl_tftp_connect(conn, done); + if(code) + return code; + state = (tftp_state_data_t *)conn->data->reqdata.proto.tftp; + } /* Run the TFTP State Machine */ for(tftp_state_machine(state, TFTP_EVENT_INIT); -- cgit v1.2.3