Commit 6eb60c2d authored by Daniel Stenberg's avatar Daniel Stenberg
Browse files

transfer: return without select when the read loop reached maxcount

Regression added in 790d6de4. The was then added to avoid one
particular transfer to starve out others. But when aborting due to
reading the maxcount, the connection must be marked to be read from
again without first doing a select as for some protocols (like SFTP/SCP)
the data may already have been read off the socket.

Reported-by: Dan Donahue
Bug: https://curl.haxx.se/mail/lib-2016-07/0057.html
parent 497e7c9d
Loading
Loading
Loading
Loading
+4 −1
Original line number Original line Diff line number Diff line
@@ -1810,6 +1810,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
    {
    {
      char *newurl = NULL;
      char *newurl = NULL;
      bool retry = FALSE;
      bool retry = FALSE;
      bool comeback = FALSE;


      /* check if over send speed */
      /* check if over send speed */
      if((data->set.max_send_speed > 0) &&
      if((data->set.max_send_speed > 0) &&
@@ -1844,7 +1845,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
      }
      }


      /* read/write data if it is ready to do so */
      /* read/write data if it is ready to do so */
      result = Curl_readwrite(data->easy_conn, data, &done);
      result = Curl_readwrite(data->easy_conn, data, &done, &comeback);


      k = &data->req;
      k = &data->req;


@@ -1950,6 +1951,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
          rc = CURLM_CALL_MULTI_PERFORM;
          rc = CURLM_CALL_MULTI_PERFORM;
        }
        }
      }
      }
      else if(comeback)
        rc = CURLM_CALL_MULTI_PERFORM;


      free(newurl);
      free(newurl);
      break;
      break;
+18 −3
Original line number Original line Diff line number Diff line
@@ -384,11 +384,15 @@ bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc)
 * Go ahead and do a read if we have a readable socket or if
 * Go ahead and do a read if we have a readable socket or if
 * the stream was rewound (in which case we have data in a
 * the stream was rewound (in which case we have data in a
 * buffer)
 * buffer)
 *
 * return '*comeback' TRUE if we didn't properly drain the socket so this
 * function should get called again without select() or similar in between!
 */
 */
static CURLcode readwrite_data(struct Curl_easy *data,
static CURLcode readwrite_data(struct Curl_easy *data,
                               struct connectdata *conn,
                               struct connectdata *conn,
                               struct SingleRequest *k,
                               struct SingleRequest *k,
                               int *didwhat, bool *done)
                               int *didwhat, bool *done,
                               bool *comeback)
{
{
  CURLcode result = CURLE_OK;
  CURLcode result = CURLE_OK;
  ssize_t nread; /* number of bytes read */
  ssize_t nread; /* number of bytes read */
@@ -398,6 +402,7 @@ static CURLcode readwrite_data(struct Curl_easy *data,
  int maxloops = 100;
  int maxloops = 100;


  *done = FALSE;
  *done = FALSE;
  *comeback = FALSE;


  /* This is where we loop until we have read everything there is to
  /* This is where we loop until we have read everything there is to
     read or we get a CURLE_AGAIN */
     read or we get a CURLE_AGAIN */
@@ -804,6 +809,12 @@ static CURLcode readwrite_data(struct Curl_easy *data,


  } while(data_pending(conn) && maxloops--);
  } while(data_pending(conn) && maxloops--);


  if(maxloops <= 0) {
    /* we mark it as read-again-please */
    conn->cselect_bits = CURL_CSELECT_IN;
    *comeback = TRUE;
  }

  if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
  if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
     conn->bits.close) {
     conn->bits.close) {
    /* When we've read the entire thing and the close bit is set, the server
    /* When we've read the entire thing and the close bit is set, the server
@@ -1029,10 +1040,14 @@ static CURLcode readwrite_upload(struct Curl_easy *data,
/*
/*
 * Curl_readwrite() is the low-level function to be called when data is to
 * Curl_readwrite() is the low-level function to be called when data is to
 * be read and written to/from the connection.
 * be read and written to/from the connection.
 *
 * return '*comeback' TRUE if we didn't properly drain the socket so this
 * function should get called again without select() or similar in between!
 */
 */
CURLcode Curl_readwrite(struct connectdata *conn,
CURLcode Curl_readwrite(struct connectdata *conn,
                        struct Curl_easy *data,
                        struct Curl_easy *data,
                        bool *done)
                        bool *done,
                        bool *comeback)
{
{
  struct SingleRequest *k = &data->req;
  struct SingleRequest *k = &data->req;
  CURLcode result;
  CURLcode result;
@@ -1077,7 +1092,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
  if((k->keepon & KEEP_RECV) &&
  if((k->keepon & KEEP_RECV) &&
     ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) {
     ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) {


    result = readwrite_data(data, conn, k, &didwhat, done);
    result = readwrite_data(data, conn, k, &didwhat, done, comeback);
    if(result || *done)
    if(result || *done)
      return result;
      return result;
  }
  }
+2 −3
Original line number Original line Diff line number Diff line
@@ -40,10 +40,9 @@ typedef enum {


CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
                     followtype type);
                     followtype type);


CURLcode Curl_readwrite(struct connectdata *conn,
CURLcode Curl_readwrite(struct connectdata *conn,
                        struct Curl_easy *data, bool *done);
                        struct Curl_easy *data, bool *done,
                        bool *comeback);
int Curl_single_getsock(const struct connectdata *conn,
int Curl_single_getsock(const struct connectdata *conn,
                        curl_socket_t *socks,
                        curl_socket_t *socks,
                        int numsocks);
                        int numsocks);