multi_socket: react on socket close immediately
authorDaniel Stenberg <daniel@haxx.se>
Wed, 19 Jun 2013 21:54:28 +0000 (23:54 +0200)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 20 Jun 2013 20:36:52 +0000 (22:36 +0200)
As a remedy to the problem when a socket gets closed and a new one is
opened with the same file descriptor number and as a result
multi.c:singlesocket() doesn't detect the difference, the new function
Curl_multi_closed() gets told when a socket is closed so that it can be
removed from the socket hash. When the old one has been removed, a new
socket should be detected fine by the singlesocket() on next invoke.

Bug: http://curl.haxx.se/bug/view.cgi?id=1248
Reported-by: Erik Johansson
lib/connect.c
lib/multi.c
lib/multiif.h

index 2d5b641..be8c0e4 100644 (file)
@@ -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;
 }
 
 /*
index 25efce1..09a5b2d 100644 (file)
@@ -2052,6 +2052,39 @@ static void singlesocket(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)
+{
+  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()
  *
  * Each SessionHandle has a list of timeouts. The add_next_timeout() is called
index 799daeb..d1b0e2f 100644 (file)
@@ -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 */