Commit 216ad268 authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

- Igor Novoseltsev fixed a bad situation for the multi_socket() API when doing

  pipelining, as libcurl could then easily get confused and A) work on the
  handle that was not "first in queue" on a pipeline, or even B) tell the app
  to REMOVE a socket while it was in use by a second handle in a pipeline. Both
  errors caused hanging or stalling applications.
parent e16509d5
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -6,6 +6,13 @@

                                  Changelog

Daniel Stenberg (20 Dec 2008)
- Igor Novoseltsev fixed a bad situation for the multi_socket() API when doing
  pipelining, as libcurl could then easily get confused and A) work on the
  handle that was not "first in queue" on a pipeline, or even B) tell the app
  to REMOVE a socket while it was in use by a second handle in a pipeline. Both
  errors caused hanging or stalling applications.

Daniel Stenberg (19 Dec 2008)
- curl_multi_timeout() could return a timeout value of 0 even though nothing
  was actually ready to get done, as the internal time resolution is higher
+1 −0
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ This release includes the following bugfixes:
   0.19 or later
 o curl_multi_timeout() no longer returns timeout 0 when there's nothing to do
   yet
 o the multi_socket API and HTTP pipelining now work a lot better when combined

This release includes the following known bugs:

+67 −2
Original line number Diff line number Diff line
@@ -1668,6 +1668,8 @@ static void singlesocket(struct Curl_multi *multi,
  curl_socket_t s;
  int num;
  unsigned int curraction;
  struct Curl_one_easy *easy_by_hash;
  bool remove_sock_from_hash;

  memset(&socks, 0, sizeof(socks));
  for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
@@ -1735,21 +1737,69 @@ static void singlesocket(struct Curl_multi *multi,
      }
    }
    if(s != CURL_SOCKET_BAD) {
      /* this socket has been removed. Remove it */

      /* this socket has been removed. Tell the app to remove it */
      remove_sock_from_hash = TRUE;

      entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
      if(entry) {
        /* check if the socket to be removed serves a connection which has
           other easy-s in a pipeline. In this case the socket should not be
           removed. */
        struct connectdata *easy_conn;

        easy_by_hash = entry->easy->multi_pos;
        easy_conn = easy_by_hash->easy_conn;
        if(easy_conn) {
          if (easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
            /* the handle should not be removed from the pipe yet */
            remove_sock_from_hash = FALSE;

            /* Update the sockhash entry to instead point to the next in line
               for the recv_pipe, or the first (in case this particular easy
               isn't already) */
            if (entry->easy == easy->easy_handle) {
              if (isHandleAtHead(easy->easy_handle, easy_conn->recv_pipe))
                entry->easy = easy_conn->recv_pipe->head->next->ptr;
              else
                entry->easy = easy_conn->recv_pipe->head->ptr;
            }
          }
          if (easy_conn->send_pipe  && easy_conn->send_pipe->size > 1) {
            /* the handle should not be removed from the pipe yet */
            remove_sock_from_hash = FALSE;

            /* Update the sockhash entry to instead point to the next in line
               for the send_pipe, or the first (in case this particular easy
               isn't already) */
            if (entry->easy == easy->easy_handle) {
              if (isHandleAtHead(easy->easy_handle, easy_conn->send_pipe))
                entry->easy = easy_conn->send_pipe->head->next->ptr;
              else
                entry->easy = easy_conn->send_pipe->head->ptr;
            }
          }
          /* Don't worry about overwriting recv_pipe head with send_pipe_head,
             when action will be asked on the socket (see multi_socket()), the
             head of the correct pipe will be taken according to the
             action. */
        }
      }
      else
        /* just a precaution, this socket really SHOULD be in the hash already
           but in case it isn't, we don't have to tell the app to remove it
           either since it never got to know about it */
        remove_sock_from_hash = FALSE;

      if (remove_sock_from_hash) {
        multi->socket_cb(easy->easy_handle,
                         s,
                         CURL_POLL_REMOVE,
                         multi->socket_userp,
                         entry ? entry->socketp : NULL);

        sh_delentry(multi->sockhash, s);
      }

    }
  }

@@ -1802,6 +1852,21 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
        /* bad bad bad bad bad bad bad */
        return CURLM_INTERNAL_ERROR;

      /* If the pipeline is enabled, take the handle which is in the head of
         the pipeline. If we should write into the socket, take the send_pipe
         head.  If we should read from the socket, take the recv_pipe head. */
      if(data->set.one_easy->easy_conn) {
        if ((ev_bitmask & CURL_POLL_OUT) &&
            data->set.one_easy->easy_conn->send_pipe &&
            data->set.one_easy->easy_conn->send_pipe->head)
          data = data->set.one_easy->easy_conn->send_pipe->head->ptr;
        else
        if ((ev_bitmask & CURL_POLL_IN) &&
            data->set.one_easy->easy_conn->recv_pipe &&
            data->set.one_easy->easy_conn->recv_pipe->head)
          data = data->set.one_easy->easy_conn->recv_pipe->head->ptr;
      }

      if(data->set.one_easy->easy_conn)  /* set socket event bitmask */
        data->set.one_easy->easy_conn->cselect_bits = ev_bitmask;