diff --git a/lib/connect.c b/lib/connect.c index 2d5b641af..be8c0e45a 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -1239,7 +1239,7 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, * 'conn' can be NULL, beware! */ int Curl_closesocket(struct connectdata *conn, - curl_socket_t sock) + curl_socket_t sock) { if(conn && conn->fclosesocket) { if((sock == conn->sock[SECONDARYSOCKET]) && @@ -1251,7 +1251,13 @@ int Curl_closesocket(struct connectdata *conn, else return conn->fclosesocket(conn->closesocket_client, sock); } - return sclose(sock); + sclose(sock); + + if(conn) + /* tell the multi-socket code about this */ + Curl_multi_closed(conn, sock); + + return 0; } /* diff --git a/lib/multi.c b/lib/multi.c index 25efce154..09a5b2d8b 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -2051,6 +2051,39 @@ static void singlesocket(struct Curl_multi *multi, easy->numsocks = num; } +/* + * Curl_multi_closed() + * + * Used by the connect code to tell the multi_socket code that one of the + * sockets we were using have just been closed. This function will then + * remove it from the sockethash for this handle to make the multi_socket API + * behave properly, especially for the case when libcurl will create another + * socket again and it gets the same file descriptor number. + */ + +void Curl_multi_closed(struct connectdata *conn, curl_socket_t s) +{ + struct Curl_multi *multi = conn->data->multi; + if(multi) { + /* this is set if this connection is part of a handle that is added to + a multi handle, and only then this is necessary */ + struct Curl_sh_entry *entry = + Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s)); + + if(entry) { + if(multi->socket_cb) + multi->socket_cb(conn->data, s, CURL_POLL_REMOVE, + multi->socket_userp, + entry->socketp); + + /* now remove it from the socket hash */ + sh_delentry(multi->sockhash, s); + } + } +} + + + /* * add_next_timeout() * diff --git a/lib/multiif.h b/lib/multiif.h index 799daebcc..d1b0e2fb3 100644 --- a/lib/multiif.h +++ b/lib/multiif.h @@ -83,4 +83,16 @@ struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi); /* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */ size_t Curl_multi_max_total_connections(struct Curl_multi *multi); +/* + * Curl_multi_closed() + * + * Used by the connect code to tell the multi_socket code that one of the + * sockets we were using have just been closed. This function will then + * remove it from the sockethash for this handle to make the multi_socket API + * behave properly, especially for the case when libcurl will create another + * socket again and it gets the same file descriptor number. + */ + +void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); + #endif /* HEADER_CURL_MULTIIF_H */