return;
/* Move all connections to the shutdown list */
+ sigpipe_init(&pipe_st);
conn = connc_find_first_connection(connc);
while(conn) {
connc_remove_conn(connc, conn);
- sigpipe_ignore(data, &pipe_st);
+ sigpipe_apply(data, &pipe_st);
/* This will remove the connection from the cache */
connclose(conn, "kill all");
Curl_conncache_remove_conn(connc->closure_handle, conn, TRUE);
connc_discard_conn(connc, connc->closure_handle, conn, FALSE);
- sigpipe_restore(&pipe_st);
conn = connc_find_first_connection(connc);
}
/* discard all connections in the shutdown list */
connc_shutdown_discard_all(connc);
- sigpipe_ignore(data, &pipe_st);
+ sigpipe_apply(data, &pipe_st);
Curl_hostcache_clean(data, data->dns.hostcache);
Curl_close(&data);
sigpipe_restore(&pipe_st);
{
struct Curl_llist_element *e;
struct connectdata *conn;
- SIGPIPE_VARIABLE(pipe_st);
DEBUGASSERT(!connc->shutdowns.iter_locked);
if(connc->shutdowns.iter_locked)
e = connc->shutdowns.conn_list.head;
if(e) {
+ SIGPIPE_VARIABLE(pipe_st);
conn = e->ptr;
Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
- sigpipe_ignore(connc->closure_handle, &pipe_st);
+ sigpipe_init(&pipe_st);
+ sigpipe_apply(connc->closure_handle, &pipe_st);
connc_disconnect(NULL, conn, connc, FALSE);
sigpipe_restore(&pipe_st);
}
struct Curl_llist_element *e = connc->shutdowns.conn_list.head;
struct Curl_llist_element *enext;
struct connectdata *conn;
+ struct curltime *nowp = NULL;
+ struct curltime now;
+ timediff_t next_from_now_ms = 0, ms;
bool done;
if(!e)
Curl_llist_remove(&connc->shutdowns.conn_list, e, NULL);
connc_disconnect(NULL, conn, connc, FALSE);
}
+ else {
+ /* Not done, when does this connection time out? */
+ if(!nowp) {
+ now = Curl_now();
+ nowp = &now;
+ }
+ ms = Curl_conn_shutdown_timeleft(conn, nowp);
+ if(ms && ms < next_from_now_ms)
+ next_from_now_ms = ms;
+ }
e = enext;
}
connc->shutdowns.iter_locked = FALSE;
+
+ if(next_from_now_ms)
+ Curl_expire(data, next_from_now_ms, EXPIRE_RUN_NOW);
}
void Curl_conncache_multi_perform(struct Curl_multi *multi)
struct curltime *nowp)
{
struct curltime now;
+ timediff_t left_ms;
if(!conn->shutdown.start[sockindex].tv_sec || !conn->shutdown.timeout_ms)
return 0; /* not started or no limits */
now = Curl_now();
nowp = &now;
}
- return conn->shutdown.timeout_ms -
- Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
+ left_ms = conn->shutdown.timeout_ms -
+ Curl_timediff(*nowp, conn->shutdown.start[sockindex]);
+ return left_ms? left_ms : -1;
+}
+
+timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
+ struct curltime *nowp)
+{
+ timediff_t left_ms = 0, ms;
+ struct curltime now;
+ int i;
+
+ for(i = 0; conn->shutdown.timeout_ms && (i < 2); ++i) {
+ if(!conn->shutdown.start[i].tv_sec)
+ continue;
+ if(!nowp) {
+ now = Curl_now();
+ nowp = &now;
+ }
+ ms = Curl_shutdown_timeleft(conn, i, nowp);
+ if(ms && (!left_ms || ms < left_ms))
+ left_ms = ms;
+ }
+ return left_ms;
}
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex)
struct curltime *nowp);
/* return how much time there is left to shutdown the connection at
- * sockindex. */
+ * sockindex. Returns 0 if there is no limit or shutdown has not started. */
timediff_t Curl_shutdown_timeleft(struct connectdata *conn, int sockindex,
struct curltime *nowp);
+/* return how much time there is left to shutdown the connection.
+ * Returns 0 if there is no limit or shutdown has not started. */
+timediff_t Curl_conn_shutdown_timeleft(struct connectdata *conn,
+ struct curltime *nowp);
+
void Curl_shutdown_clear(struct Curl_easy *data, int sockindex);
/* TRUE iff shutdown has been started */
/* assign this after curl_multi_add_handle() */
data->multi_easy = multi;
- sigpipe_ignore(data, &pipe_st);
+ sigpipe_init(&pipe_st);
+ sigpipe_apply(data, &pipe_st);
/* run the transfer */
result = events ? easy_events(multi) : easy_transfer(multi);
CURLMcode returncode = CURLM_OK;
struct Curl_tree *t;
struct curltime now = Curl_now();
+ SIGPIPE_VARIABLE(pipe_st);
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
+ sigpipe_init(&pipe_st);
data = multi->easyp;
if(data) {
CURLMcode result;
- bool nosig = data->set.no_signal;
- SIGPIPE_VARIABLE(pipe_st);
- sigpipe_ignore(data, &pipe_st);
/* Do the loop and only alter the signal ignore state if the next handle
has a different NO_SIGNAL state than the previous */
do {
pointer now */
struct Curl_easy *datanext = data->next;
- if(data->set.no_signal != nosig) {
- sigpipe_restore(&pipe_st);
- sigpipe_ignore(data, &pipe_st);
- nosig = data->set.no_signal;
+ if(data != multi->conn_cache.closure_handle) {
+ /* connection cache handle is processed below */
+ sigpipe_apply(data, &pipe_st);
+ result = multi_runsingle(multi, &now, data);
+ if(result)
+ returncode = result;
}
- result = multi_runsingle(multi, &now, data);
- if(result)
- returncode = result;
data = datanext; /* operate on next handle */
} while(data);
- sigpipe_restore(&pipe_st);
}
+ sigpipe_apply(multi->conn_cache.closure_handle, &pipe_st);
Curl_conncache_multi_perform(multi);
+ sigpipe_restore(&pipe_st);
+
/*
* Simply remove all expired timers from the splay since handles are dealt
* with unconditionally by this function and curl_multi_timeout() requires
struct Curl_easy *data = NULL;
struct Curl_tree *t;
struct curltime now = Curl_now();
- bool first = FALSE;
- bool nosig = FALSE;
+ bool run_conn_cache = FALSE;
SIGPIPE_VARIABLE(pipe_st);
if(checkall) {
DEBUGASSERT(data);
DEBUGASSERT(data->magic == CURLEASY_MAGIC_NUMBER);
- if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
- /* set socket event bitmask if they are not locked */
- data->state.select_bits |= (unsigned char)ev_bitmask;
+ if(data == multi->conn_cache.closure_handle)
+ run_conn_cache = TRUE;
+ else {
+ if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
+ /* set socket event bitmask if they are not locked */
+ data->state.select_bits |= (unsigned char)ev_bitmask;
- Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
+ }
}
/* Now we fall-through and do the timer-based stuff, since we do not want
* to process in the splay and 'data' will be re-assigned for every expired
* handle we deal with.
*/
+ sigpipe_init(&pipe_st);
do {
+ if(data == multi->conn_cache.closure_handle)
+ run_conn_cache = TRUE;
/* the first loop lap 'data' can be NULL */
- if(data) {
- if(!first) {
- first = TRUE;
- nosig = data->set.no_signal; /* initial state */
- sigpipe_ignore(data, &pipe_st);
- }
- else if(data->set.no_signal != nosig) {
- sigpipe_restore(&pipe_st);
- sigpipe_ignore(data, &pipe_st);
- nosig = data->set.no_signal; /* remember new state */
- }
+ else if(data) {
+ sigpipe_apply(data, &pipe_st);
result = multi_runsingle(multi, &now, data);
if(CURLM_OK >= result) {
}
} while(t);
- if(first)
- sigpipe_restore(&pipe_st);
+
+ if(run_conn_cache) {
+ sigpipe_apply(multi->conn_cache.closure_handle, &pipe_st);
+ Curl_conncache_multi_perform(multi);
+ }
+
+ sigpipe_restore(&pipe_st);
if(running_handles)
*running_handles = (int)multi->num_alive;
#define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x
+static void sigpipe_init(struct sigpipe_ignore *ig)
+{
+ memset(ig, 0, sizeof(*ig));
+}
+
/*
* sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl
* internals, and then sigpipe_restore() will restore the situation when we
sigaction(SIGPIPE, &ig->old_pipe_act, NULL);
}
+static void sigpipe_apply(struct Curl_easy *data,
+ struct sigpipe_ignore *ig)
+{
+ if(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)
#endif