Commit e1edd41e authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

Ravi Pratap provided a major update with pipelining fixes. We also no longer

re-use connections (for pipelining) before the name resolving is done.
parent 13e60c55
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -6,6 +6,10 @@

                                  Changelog

Daniel (23 October 2006)
- Ravi Pratap provided a major update with pipelining fixes. We also no longer
  re-use connections (for pipelining) before the name resolving is done.

Daniel (21 October 2006)
- Nir Soffer made the tests/libtest/Makefile.am use a proper variable for all
  the single test applications' link and dependences, so that you easier can
+2 −1
Original line number Diff line number Diff line
@@ -773,7 +773,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
      return CURLM_BAD_EASY_HANDLE;

    if (easy->easy_handle->state.pipe_broke) {
      infof(easy->easy_handle, "Pipe broke: handle 0x%x\n", easy);
      infof(easy->easy_handle, "Pipe broke: handle 0x%x, url = %s\n",
            easy, easy->easy_handle->reqdata.path);
      if(easy->easy_handle->state.is_in_pipeline) {
        /* Head back to the CONNECT state */
        multistate(easy, CURLM_STATE_CONNECT);
+40 −29
Original line number Diff line number Diff line
@@ -438,14 +438,25 @@ CURLcode Curl_client_write(struct connectdata *conn,
  return CURLE_OK;
}

#define MIN(a,b) (a < b ? a : b)

void Curl_read_rewind(struct connectdata *conn,
                      size_t extraBytesRead)
{
    char buf[512 + 1];
    size_t bytesToShow;

    conn->read_pos -= extraBytesRead;
    conn->bits.stream_was_rewound = TRUE;
}

#define MIN(a,b) (a < b ? a : b)
    bytesToShow = MIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
    memcpy(buf, conn->master_buffer + conn->read_pos, bytesToShow);
    buf[bytesToShow] = '\0';

    DEBUGF(infof(conn->data,
                 "Buffer after stream rewind (read_pos = %d): [%s]",
                 conn->read_pos, buf));
}

/*
 * Internal read-from-socket function. This is meant to deal with plain
@@ -457,12 +468,12 @@ void Curl_read_rewind(struct connectdata *conn,
int Curl_read(struct connectdata *conn, /* connection data */
              curl_socket_t sockfd,     /* read from this socket */
              char *buf,                /* store read data here */
              size_t buffersize,        /* max amount to read */
              size_t sizerequested,     /* max amount to read */
              ssize_t *n)               /* amount bytes read */
{
  ssize_t nread;
  size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, buffersize);
  size_t bytesremaining = buffersize - bytestocopy;
  size_t bytestocopy = MIN(conn->buf_len - conn->read_pos, sizerequested);
  size_t bytesfromsocket = 0;

  /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
     If it is the second socket, we set num to 1. Otherwise to 0. This lets
@@ -471,34 +482,34 @@ int Curl_read(struct connectdata *conn, /* connection data */

  *n=0; /* reset amount to zero */

  bytesremaining = MIN(bytesremaining, sizeof(conn->master_buffer));

  /* Copy from our master buffer first */
  /* Copy from our master buffer first if we have some unread data there*/
  if (bytestocopy > 0) {
    memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
    conn->read_pos += bytestocopy;

    conn->bits.stream_was_rewound = FALSE;

    *n = (ssize_t)bytestocopy;

  if (bytesremaining == 0) {
    return CURLE_OK;
  }

  /* If we come here, it means that there is no data to read from the buffer,
   * so we read from the socket */
  bytesfromsocket = MIN(sizerequested, sizeof(conn->master_buffer));

  if(conn->ssl[num].use) {
    nread = Curl_ssl_recv(conn, num, conn->master_buffer, bytesremaining);
    nread = Curl_ssl_recv(conn, num, conn->master_buffer, bytesfromsocket);

    if(nread == -1 && bytestocopy == 0) {
    if(nread == -1)
      return -1; /* -1 from Curl_ssl_recv() means EWOULDBLOCK */
  }

  } else {
  else {
    if(conn->sec_complete)
      nread = Curl_sec_read(conn, sockfd, conn->master_buffer, bytesremaining);
      nread = Curl_sec_read(conn, sockfd, conn->master_buffer,
                            bytesfromsocket);
    else
      nread = sread(sockfd, conn->master_buffer, bytesremaining);
      nread = sread(sockfd, conn->master_buffer, bytesfromsocket);

    if(-1 == nread && bytestocopy == 0) {
    if(-1 == nread) {
      int err = Curl_sockerrno();
#ifdef USE_WINSOCK
      if(WSAEWOULDBLOCK == err)
@@ -509,12 +520,12 @@ int Curl_read(struct connectdata *conn, /* connection data */
    }
  }

  if (nread > 0) {
  if (nread >= 0) {
    memcpy(buf, conn->master_buffer, nread);

    conn->buf_len = nread;
    conn->read_pos = nread;
      *n += nread;
    *n = nread;
  }

  return CURLE_OK;
+16 −10
Original line number Diff line number Diff line
@@ -743,8 +743,10 @@ CURLcode Curl_readwrite(struct connectdata *conn,
                failf(data, "Maximum file size exceeded");
                return CURLE_FILESIZE_EXCEEDED;
              }
              if(contentlength >= 0)
              if(contentlength >= 0) {
                k->size = contentlength;
                k->maxdownload = k->size;
              }
              else {
                /* Negative Content-Length is really odd, and we know it
                   happens for example when older Apache servers send large
@@ -1133,13 +1135,17 @@ CURLcode Curl_readwrite(struct connectdata *conn,

          if((-1 != k->maxdownload) &&
             (k->bytecount + nread >= k->maxdownload)) {
            size_t excess = (size_t)(k->bytecount + 
                             (curl_off_t)nread - k->maxdownload);

            if (excess > 0) {
                infof(data, "Rewinding stream by : %d bytes\n", excess);
            curl_off_t excess = k->bytecount +
              ((curl_off_t) nread) - k->maxdownload;
            if (excess > 0 && !k->ignorebody) {
              infof(data,
                    "Rewinding stream by : %" FORMAT_OFF_T
                    " bytes on url %s (size = %" FORMAT_OFF_T
                    ", maxdownload = %" FORMAT_OFF_T
                    ", bytecount = %" FORMAT_OFF_T ", nread = %d)\n",
                    excess, conn->data->reqdata.path,
                    k->size, k->maxdownload, k->bytecount, nread);
              Curl_read_rewind(conn, excess);
                conn->bits.stream_was_rewound = TRUE;
            }

            nread = (ssize_t) (k->maxdownload - k->bytecount);
+40 −18
Original line number Diff line number Diff line
@@ -1854,6 +1854,7 @@ int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
    }
    curr = curr->next;
  }

  return 0;
}

@@ -1899,8 +1900,8 @@ static void signalPipeClose(struct curl_llist *pipe)
    }
    else
#endif
      data->state.pipe_broke = TRUE;

    data->state.pipe_broke = TRUE;
    Curl_llist_remove(pipe, curr, NULL);
    curr = next;
  }
@@ -1936,12 +1937,19 @@ ConnectionExists(struct SessionHandle *data,
      /* NULL pointer means not filled-in entry */
      continue;

#ifdef USE_ARES
    /* ip_addr_str is NULL only if the resolving of the name hasn't completed
       yet and until then we don't re-use this connection */
    if (!check->ip_addr_str)
        continue;
#endif

    if(check->inuse && !canPipeline)
      /* can only happen within multi handles, and means that another easy
         handle is using this connection */
      continue;

    if (check->send_pipe->size >= MAX_PIPELINE_LENGTH ||
    if (check->send_pipe->size +
        check->recv_pipe->size >= MAX_PIPELINE_LENGTH)
      continue;

@@ -1994,14 +2002,28 @@ ConnectionExists(struct SessionHandle *data,
    }

    if(match) {

      bool dead = SocketIsDead(check->sock[FIRSTSOCKET]);
      if(dead) {
        /*
         */
        if (!check->is_in_pipeline) {
          check->data = data;
          infof(data, "Connection %d seems to be dead!\n", i);

          Curl_disconnect(check); /* disconnect resources */
          data->state.connc->connects[i]=NULL; /* nothing here */
        }
        else {
          /* In the pipelining case, freeing the connection right away
           * doesn't work. Instead, we mark the connection for close
           * so that the handles will detect this automatically when
           * they try to do something and deal with it there.
           * Prematurely freeing this connection prevents handles that
           * have already finished with their transfers to shut down
           * cleanly.
           */
          infof(data, "Connection %d seems dead - marking for close\n", i);
          check->bits.close = TRUE;
        }

        /* There's no need to continue searching, because we only store
           one connection for each unique set of identifiers */
@@ -2016,6 +2038,9 @@ ConnectionExists(struct SessionHandle *data,
        check->is_in_pipeline = TRUE;
      }

      check->connectindex = i; /* Set this appropriately since it might have
                                  been set to -1 when the easy was removed
                                  from the multi */
      *usethis = check;
      return TRUE; /* yes, we found one to use! */
    }
@@ -2690,6 +2715,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
  conn->readchannel_inuse = FALSE;
  conn->writechannel_inuse = FALSE;

  conn->read_pos = 0;
  conn->buf_len = 0;

  /* Initialize the pipeline lists */
  conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
  conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
@@ -3622,12 +3650,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
    infof(data, "Re-using existing connection! (#%ld) with host %s\n",
          conn->connectindex,
          conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
#ifdef CURLRES_ASYNCH
    if(!conn->ip_addr_str) {
      infof(data, "... but it is not resolved yet!\n");
      *async = TRUE;
    }
#endif
  }
  else {
    /*
@@ -3990,10 +4012,10 @@ CURLcode Curl_done(struct connectdata **connp,

  if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) &&
     conn->readchannel_inuse)
    conn->readchannel_inuse--;
    conn->readchannel_inuse = FALSE;
  if(Curl_removeHandleFromPipeline(data, conn->send_pipe) &&
     conn->writechannel_inuse)
    conn->writechannel_inuse--;
    conn->writechannel_inuse = FALSE;

  /* cleanups done even if the connection is re-used */
  if(data->reqdata.rangestringalloc) {
Loading