{
if(cpool && cpool->initialised && cpool->idata) {
struct connectdata *conn;
- SIGPIPE_VARIABLE(pipe_st);
+ struct Curl_sigpipe_ctx pipe_ctx;
CURL_TRC_M(cpool->idata, "%s[CPOOL] destroy, %zu connections",
cpool->share ? "[SHARE] " : "", cpool->num_conn);
/* Move all connections to the shutdown list */
- sigpipe_init(&pipe_st);
+ sigpipe_init(&pipe_ctx);
CPOOL_LOCK(cpool, cpool->idata);
conn = cpool_get_first(cpool);
+ if(conn)
+ sigpipe_apply(cpool->idata, &pipe_ctx);
while(conn) {
cpool_remove_conn(cpool, conn);
- sigpipe_apply(cpool->idata, &pipe_st);
cpool_discard_conn(cpool, cpool->idata, conn, FALSE);
conn = cpool_get_first(cpool);
}
CPOOL_UNLOCK(cpool, cpool->idata);
- sigpipe_restore(&pipe_st);
+ sigpipe_restore(&pipe_ctx);
Curl_hash_destroy(&cpool->dest2bundle);
}
}
}
if(e) {
- SIGPIPE_VARIABLE(pipe_st);
+ struct Curl_sigpipe_ctx sigpipe_ctx;
conn = Curl_node_elem(e);
Curl_node_remove(e);
- sigpipe_init(&pipe_st);
- sigpipe_apply(data, &pipe_st);
+ sigpipe_init(&sigpipe_ctx);
+ sigpipe_apply(data, &sigpipe_ctx);
Curl_cshutdn_terminate(data, conn, FALSE);
- sigpipe_restore(&pipe_st);
+ sigpipe_restore(&sigpipe_ctx);
return TRUE;
}
return FALSE;
}
static void cshutdn_perform(struct cshutdn *cshutdn,
- struct Curl_easy *data)
+ struct Curl_easy *data,
+ struct Curl_sigpipe_ctx *sigpipe_ctx)
{
struct Curl_llist_node *e = Curl_llist_head(&cshutdn->list);
struct Curl_llist_node *enext;
CURL_TRC_M(data, "[SHUTDOWN] perform on %zu connections",
Curl_llist_count(&cshutdn->list));
+ sigpipe_apply(data, sigpipe_ctx);
while(e) {
enext = Curl_node_next(e);
conn = Curl_node_elem(e);
{
struct curltime started = *Curl_pgrs_now(data);
struct Curl_llist_node *e;
- SIGPIPE_VARIABLE(pipe_st);
+ struct Curl_sigpipe_ctx sigpipe_ctx;
DEBUGASSERT(cshutdn);
DEBUGASSERT(data);
CURL_TRC_M(data, "[SHUTDOWN] shutdown all");
- sigpipe_init(&pipe_st);
- sigpipe_apply(data, &pipe_st);
+ sigpipe_init(&sigpipe_ctx);
while(Curl_llist_head(&cshutdn->list)) {
timediff_t spent_ms;
int remain_ms;
- cshutdn_perform(cshutdn, data);
+ cshutdn_perform(cshutdn, data, &sigpipe_ctx);
if(!Curl_llist_head(&cshutdn->list)) {
CURL_TRC_M(data, "[SHUTDOWN] shutdown finished cleanly");
}
DEBUGASSERT(!Curl_llist_count(&cshutdn->list));
- sigpipe_restore(&pipe_st);
+ sigpipe_restore(&sigpipe_ctx);
}
int Curl_cshutdn_init(struct cshutdn *cshutdn,
conn->connection_id, Curl_llist_count(&cshutdn->list));
}
-static void cshutdn_multi_socket(struct cshutdn *cshutdn,
- struct Curl_easy *data,
- curl_socket_t s)
-{
- struct Curl_llist_node *e;
- struct connectdata *conn;
- bool done;
-
- DEBUGASSERT(cshutdn->multi->socket_cb);
- e = Curl_llist_head(&cshutdn->list);
- while(e) {
- conn = Curl_node_elem(e);
- if(s == conn->sock[FIRSTSOCKET] || s == conn->sock[SECONDARYSOCKET]) {
- Curl_cshutdn_run_once(data, conn, &done);
- if(done || cshutdn_update_ev(cshutdn, data, conn)) {
- Curl_node_remove(e);
- Curl_cshutdn_terminate(data, conn, FALSE);
- }
- break;
- }
- e = Curl_node_next(e);
- }
-}
-
void Curl_cshutdn_perform(struct cshutdn *cshutdn,
struct Curl_easy *data,
- curl_socket_t s)
+ struct Curl_sigpipe_ctx *sigpipe_ctx)
{
- if((s == CURL_SOCKET_TIMEOUT) || (!cshutdn->multi->socket_cb))
- cshutdn_perform(cshutdn, data);
- else
- cshutdn_multi_socket(cshutdn, data, s);
+ cshutdn_perform(cshutdn, data, sigpipe_ctx);
}
/* return fd_set info about the shutdown connections */
struct Curl_waitfds;
struct Curl_multi;
struct Curl_share;
+struct Curl_sigpipe_ctx;
/* Run the shutdown of the connection once.
* Will shortly attach/detach `data` to `conn` while doing so.
fd_set *read_fd_set, fd_set *write_fd_set,
int *maxfd);
-/* Run shut down connections using socket. If socket is CURL_SOCKET_TIMEOUT,
- * run maintenance on all connections. */
+/* Run maintenance on all connections. */
void Curl_cshutdn_perform(struct cshutdn *cshutdn,
struct Curl_easy *data,
- curl_socket_t s);
+ struct Curl_sigpipe_ctx *sigpipe_ctx);
#endif /* HEADER_CURL_CSHUTDN_H */
struct Curl_multi *multi;
CURLMcode mresult;
CURLcode result = CURLE_OK;
- SIGPIPE_VARIABLE(pipe_st);
+ struct Curl_sigpipe_ctx sigpipe_ctx;
if(!data)
return CURLE_BAD_FUNCTION_ARGUMENT;
/* assign this after curl_multi_add_handle() */
data->multi_easy = multi;
- sigpipe_init(&pipe_st);
- sigpipe_apply(data, &pipe_st);
+ sigpipe_init(&sigpipe_ctx);
+ sigpipe_apply(data, &sigpipe_ctx);
/* run the transfer */
result = events ? easy_events(multi) : easy_transfer(multi);
a failure here, room for future improvement! */
(void)curl_multi_remove_handle(multi, data);
- sigpipe_restore(&pipe_st);
+ sigpipe_restore(&sigpipe_ctx);
/* The multi handle is kept alive, owned by the easy handle */
return result;
{
struct Curl_easy *data = ptr;
if(GOOD_EASY_HANDLE(data)) {
- SIGPIPE_VARIABLE(pipe_st);
- sigpipe_ignore(data, &pipe_st);
+ struct Curl_sigpipe_ctx sigpipe_ctx;
+ sigpipe_ignore(data, &sigpipe_ctx);
Curl_close(&data);
- sigpipe_restore(&pipe_st);
+ sigpipe_restore(&sigpipe_ctx);
}
}
{
CURLcode result;
struct connectdata *c = NULL;
- SIGPIPE_VARIABLE(pipe_st);
+ struct Curl_sigpipe_ctx sigpipe_ctx;
*n = 0;
result = easy_connection(data, &c);
needs to be reattached */
Curl_attach_connection(data, c);
- sigpipe_ignore(data, &pipe_st);
+ sigpipe_ignore(data, &sigpipe_ctx);
result = Curl_conn_send(data, FIRSTSOCKET, buffer, buflen, FALSE, n);
- sigpipe_restore(&pipe_st);
+ sigpipe_restore(&sigpipe_ctx);
if(result && result != CURLE_AGAIN)
return CURLE_SEND_ERROR;
}
static CURLMcode multi_runsingle(struct Curl_multi *multi,
- struct Curl_easy *data)
+ struct Curl_easy *data,
+ struct Curl_sigpipe_ctx *sigpipe_ctx)
{
struct Curl_message *msg = NULL;
bool connected;
Curl_uint32_bset_remove(&multi->dirty, data->mid);
if(data == multi->admin) {
- Curl_cshutdn_perform(&multi->cshutdn, multi->admin, CURL_SOCKET_TIMEOUT);
+ Curl_cshutdn_perform(&multi->cshutdn, multi->admin, sigpipe_ctx);
return CURLM_OK;
}
+ sigpipe_apply(data, sigpipe_ctx);
do {
/* A "stream" here is a logical stream if the protocol can handle that
(HTTP/2), or the full connection for older protocols */
CURLMcode returncode = CURLM_OK;
struct curltime start = *multi_now(multi);
uint32_t mid;
- SIGPIPE_VARIABLE(pipe_st);
+ struct Curl_sigpipe_ctx sigpipe_ctx;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
if(multi->in_ntfy_callback)
return CURLM_RECURSIVE_API_CALL;
- sigpipe_init(&pipe_st);
+ sigpipe_init(&sigpipe_ctx);
+
if(Curl_uint32_bset_first(&multi->process, &mid)) {
CURL_TRC_M(multi->admin, "multi_perform(running=%u)",
Curl_multi_xfers_running(multi));
Curl_uint32_bset_remove(&multi->dirty, mid);
continue;
}
- sigpipe_apply(data, &pipe_st);
- mresult = multi_runsingle(multi, data);
+ mresult = multi_runsingle(multi, data, &sigpipe_ctx);
if(mresult)
returncode = mresult;
} while(Curl_uint32_bset_next(&multi->process, mid, &mid));
}
- sigpipe_restore(&pipe_st);
+ sigpipe_restore(&sigpipe_ctx);
if(multi_ischanged(multi, TRUE))
process_pending_handles(multi);
return CURLM_OK;
}
-struct multi_run_ctx {
- struct Curl_multi *multi;
- size_t run_xfers;
- SIGPIPE_MEMBER(pipe_st);
-};
-
-static void multi_mark_expired_as_dirty(struct multi_run_ctx *mrc,
+static void multi_mark_expired_as_dirty(struct Curl_multi *multi,
const struct curltime *ts)
{
- struct Curl_multi *multi = mrc->multi;
struct Curl_easy *data = NULL;
struct Curl_tree *t = NULL;
/*
* The loop following here will go on as long as there are expire-times left
- * to process (compared to mrc->now) in the splay and 'data' will be
+ * to process (compared to `ts`) in the splay and 'data' will be
* re-assigned for every expired handle we deal with.
*/
while(1) {
}
}
-static CURLMcode multi_run_dirty(struct multi_run_ctx *mrc)
+static CURLMcode multi_run_dirty(struct Curl_multi *multi,
+ struct Curl_sigpipe_ctx *sigpipe_ctx,
+ uint32_t *pnum)
{
- struct Curl_multi *multi = mrc->multi;
CURLMcode mresult = CURLM_OK;
uint32_t mid;
+ *pnum = 0;
if(Curl_uint32_bset_first(&multi->dirty, &mid)) {
do {
struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
continue;
}
- mrc->run_xfers++;
- sigpipe_apply(data, &mrc->pipe_st);
+ (*pnum)++;
/* runsingle() clears the dirty mid */
- mresult = multi_runsingle(multi, data);
+ mresult = multi_runsingle(multi, data, sigpipe_ctx);
if(CURLM_OK >= mresult) {
/* reassess event handling of data */
int *running_handles)
{
CURLMcode mresult = CURLM_OK;
- struct multi_run_ctx mrc;
+ struct Curl_sigpipe_ctx pipe_ctx;
+ uint32_t run_xfers;
(void)ev_bitmask;
- memset(&mrc, 0, sizeof(mrc));
- mrc.multi = multi;
- sigpipe_init(&mrc.pipe_st);
+ sigpipe_init(&pipe_ctx);
if(checkall) {
/* *perform() deals with running_handles on its own */
memset(&multi->last_expire_ts, 0, sizeof(multi->last_expire_ts));
}
- multi_mark_expired_as_dirty(&mrc, multi_now(multi));
- mresult = multi_run_dirty(&mrc);
+ multi_mark_expired_as_dirty(multi, multi_now(multi));
+ mresult = multi_run_dirty(multi, &pipe_ctx, &run_xfers);
if(mresult)
goto out;
- if(mrc.run_xfers) {
+ if(run_xfers) {
/* Running transfers takes time. With a new timestamp, we might catch
* other expires which are due now. Instead of telling the application
* to set a 0 timeout and call us again, we run them here.
* Do that only once or it might be unfair to transfers on other
* sockets. */
- multi_mark_expired_as_dirty(&mrc, &multi->now);
- mresult = multi_run_dirty(&mrc);
+ multi_mark_expired_as_dirty(multi, &multi->now);
+ mresult = multi_run_dirty(multi, &pipe_ctx, &run_xfers);
}
out:
- sigpipe_restore(&mrc.pipe_st);
+ sigpipe_restore(&pipe_ctx);
if(multi_ischanged(multi, TRUE))
process_pending_handles(multi);
(defined(USE_OPENSSL) || defined(USE_MBEDTLS) || defined(USE_WOLFSSL))
#include <signal.h>
-struct sigpipe_ignore {
+struct Curl_sigpipe_ctx {
struct sigaction old_pipe_act;
BIT(no_signal);
};
-#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x
-#define SIGPIPE_MEMBER(x) struct sigpipe_ignore x
-
-static void sigpipe_init(struct sigpipe_ignore *ig)
+static CURL_INLINE void sigpipe_init(struct Curl_sigpipe_ctx *ig)
{
memset(ig, 0, sizeof(*ig));
ig->no_signal = TRUE;
* internals, and then sigpipe_restore() will restore the situation when we
* return from libcurl again.
*/
-static void sigpipe_ignore(struct Curl_easy *data,
- struct sigpipe_ignore *ig)
+static CURL_INLINE void sigpipe_ignore(struct Curl_easy *data,
+ struct Curl_sigpipe_ctx *ig)
{
/* get a local copy of no_signal because the Curl_easy might not be
around when we restore */
* and SIGPIPE handling. It MUST only be called after a corresponding
* sigpipe_ignore() was used.
*/
-static void sigpipe_restore(struct sigpipe_ignore *ig)
+static CURL_INLINE void sigpipe_restore(struct Curl_sigpipe_ctx *ig)
{
if(!ig->no_signal)
/* restore the outside state */
sigaction(SIGPIPE, &ig->old_pipe_act, NULL);
}
-static void sigpipe_apply(struct Curl_easy *data,
- struct sigpipe_ignore *ig)
+static CURL_INLINE void sigpipe_apply(struct Curl_easy *data,
+ struct Curl_sigpipe_ctx *ig)
{
- if(data->set.no_signal != ig->no_signal) {
+ if(data && (data->set.no_signal != ig->no_signal)) {
sigpipe_restore(ig);
sigpipe_ignore(data, ig);
}
#else
/* for systems without sigaction */
-#define sigpipe_ignore(x, y) Curl_nop_stmt
-#define sigpipe_apply(x, y) Curl_nop_stmt
-#define sigpipe_init(x) Curl_nop_stmt
-#define sigpipe_restore(x) Curl_nop_stmt
-#define SIGPIPE_VARIABLE(x)
-#define SIGPIPE_MEMBER(x) bool x
+#define sigpipe_ignore(x, y) do { (void)x; (void)y; } while(0)
+#define sigpipe_apply(x, y) do { (void)x; (void)y; } while(0)
+#define sigpipe_init(x) do { (void)x; } while(0)
+#define sigpipe_restore(x) do { (void)x; } while(0)
+
+struct Curl_sigpipe_ctx {
+ bool dummy;
+};
+
#endif
#endif /* HEADER_CURL_SIGPIPE_H */