Curl_creader_def_resume_from,
Curl_creader_def_rewind,
cr_hyper_unpause,
+ Curl_creader_def_is_paused,
Curl_creader_def_done,
sizeof(struct Curl_creader)
};
Curl_creader_def_resume_from,
Curl_creader_def_rewind,
Curl_creader_def_unpause,
+ Curl_creader_def_is_paused,
cr_exp100_done,
sizeof(struct cr_exp100_ctx)
};
Curl_creader_def_resume_from,
Curl_creader_def_rewind,
Curl_creader_def_unpause,
+ Curl_creader_def_is_paused,
Curl_creader_def_done,
sizeof(struct chunked_reader)
};
return CURLE_OK;
}
+static bool cr_mime_is_paused(struct Curl_easy *data,
+ struct Curl_creader *reader)
+{
+ struct cr_mime_ctx *ctx = reader->ctx;
+ (void)data;
+ return (ctx->part && ctx->part->lastreadstatus == CURL_READFUNC_PAUSE);
+}
+
static const struct Curl_crtype cr_mime = {
"cr-mime",
cr_mime_init,
cr_mime_resume_from,
cr_mime_rewind,
cr_mime_unpause,
+ cr_mime_is_paused,
Curl_creader_def_done,
sizeof(struct cr_mime_ctx)
};
}
}
}
- else if(data->state.select_bits) {
+ else if(data->state.select_bits && !Curl_xfer_is_blocked(data)) {
/* This avoids CURLM_CALL_MULTI_PERFORM so that a very fast transfer
won't get stuck on this transfer at the expense of other concurrent
transfers */
return CURLE_OK;
}
+bool Curl_creader_def_is_paused(struct Curl_easy *data,
+ struct Curl_creader *reader)
+{
+ (void)data;
+ (void)reader;
+ return FALSE;
+}
+
void Curl_creader_def_done(struct Curl_easy *data,
struct Curl_creader *reader, int premature)
{
BIT(seen_eos);
BIT(errored);
BIT(has_used_cb);
+ BIT(is_paused);
};
static CURLcode cr_in_init(struct Curl_easy *data, struct Curl_creader *reader)
struct cr_in_ctx *ctx = reader->ctx;
size_t nread;
+ ctx->is_paused = FALSE;
+
/* Once we have errored, we will return the same error forever */
if(ctx->errored) {
*pnread = 0;
}
/* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
CURL_TRC_READ(data, "cr_in_read, callback returned CURL_READFUNC_PAUSE");
+ ctx->is_paused = TRUE;
data->req.keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
*pnread = 0;
*peos = FALSE;
return CURLE_OK;
}
+static CURLcode cr_in_unpause(struct Curl_easy *data,
+ struct Curl_creader *reader)
+{
+ struct cr_in_ctx *ctx = reader->ctx;
+ (void)data;
+ ctx->is_paused = FALSE;
+ return CURLE_OK;
+}
+
+static bool cr_in_is_paused(struct Curl_easy *data,
+ struct Curl_creader *reader)
+{
+ struct cr_in_ctx *ctx = reader->ctx;
+ (void)data;
+ return ctx->is_paused;
+}
static const struct Curl_crtype cr_in = {
"cr-in",
cr_in_total_length,
cr_in_resume_from,
cr_in_rewind,
- Curl_creader_def_unpause,
+ cr_in_unpause,
+ cr_in_is_paused,
Curl_creader_def_done,
sizeof(struct cr_in_ctx)
};
Curl_creader_def_resume_from,
Curl_creader_def_rewind,
Curl_creader_def_unpause,
+ Curl_creader_def_is_paused,
Curl_creader_def_done,
sizeof(struct cr_lc_ctx)
};
Curl_creader_def_resume_from,
Curl_creader_def_rewind,
Curl_creader_def_unpause,
+ Curl_creader_def_is_paused,
Curl_creader_def_done,
sizeof(struct Curl_creader)
};
cr_buf_resume_from,
Curl_creader_def_rewind,
Curl_creader_def_unpause,
+ Curl_creader_def_is_paused,
Curl_creader_def_done,
sizeof(struct cr_buf_ctx)
};
return result;
}
+bool Curl_creader_is_paused(struct Curl_easy *data)
+{
+ struct Curl_creader *reader = data->req.reader_stack;
+
+ while(reader) {
+ if(reader->crt->is_paused(data, reader))
+ return TRUE;
+ reader = reader->next;
+ }
+ return FALSE;
+}
+
void Curl_creader_done(struct Curl_easy *data, int premature)
{
struct Curl_creader *reader = data->req.reader_stack;
struct Curl_creader *reader, curl_off_t offset);
CURLcode (*rewind)(struct Curl_easy *data, struct Curl_creader *reader);
CURLcode (*unpause)(struct Curl_easy *data, struct Curl_creader *reader);
+ bool (*is_paused)(struct Curl_easy *data, struct Curl_creader *reader);
void (*done)(struct Curl_easy *data,
struct Curl_creader *reader, int premature);
size_t creader_size; /* sizeof() allocated struct Curl_creader */
struct Curl_creader *reader);
CURLcode Curl_creader_def_unpause(struct Curl_easy *data,
struct Curl_creader *reader);
+bool Curl_creader_def_is_paused(struct Curl_easy *data,
+ struct Curl_creader *reader);
void Curl_creader_def_done(struct Curl_easy *data,
struct Curl_creader *reader, int premature);
*/
CURLcode Curl_creader_unpause(struct Curl_easy *data);
+/**
+ * Return TRUE iff any of the installed readers is paused.
+ */
+bool Curl_creader_is_paused(struct Curl_easy *data);
+
/**
* Tell all client readers that they are done.
*/
Curl_creader_def_resume_from,
Curl_creader_def_rewind,
Curl_creader_def_unpause,
+ Curl_creader_def_is_paused,
Curl_creader_def_done,
sizeof(struct cr_eob_ctx)
};
sockindex = (data->conn->writesockfd == data->conn->sock[SECONDARYSOCKET]);
return Curl_conn_shutdown(data, sockindex, done);
}
+
+bool Curl_xfer_is_blocked(struct Curl_easy *data)
+{
+ bool want_send = ((data)->req.keepon & KEEP_SEND);
+ bool want_recv = ((data)->req.keepon & KEEP_RECV);
+ if(!want_send)
+ return (want_recv && Curl_cwriter_is_paused(data));
+ else if(!want_recv)
+ return (want_send && Curl_creader_is_paused(data));
+ else
+ return Curl_creader_is_paused(data) && Curl_cwriter_is_paused(data);
+}
CURLcode Curl_xfer_send_close(struct Curl_easy *data);
CURLcode Curl_xfer_send_shutdown(struct Curl_easy *data, bool *done);
+/**
+ * Return TRUE iff the transfer is not done, but further progress
+ * is blocked. For example when it is only receiving and its writer
+ * is PAUSED.
+ */
+bool Curl_xfer_is_blocked(struct Curl_easy *data);
+
#endif /* HEADER_CURL_TRANSFER_H */