summaryrefslogtreecommitdiffstats
path: root/lib/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/multi.c')
-rw-r--r--lib/multi.c146
1 files changed, 112 insertions, 34 deletions
diff --git a/lib/multi.c b/lib/multi.c
index 5456113..0926b0d 100644
--- a/lib/multi.c
+++ b/lib/multi.c
@@ -672,6 +672,7 @@ static CURLcode multi_done(struct Curl_easy *data,
many callbacks and protocols work differently, we could potentially do
this more fine-grained in the future. */
premature = TRUE;
+ FALLTHROUGH();
default:
break;
}
@@ -993,31 +994,92 @@ void Curl_attach_connection(struct Curl_easy *data,
Curl_conn_ev_data_attach(conn, data);
}
-static int domore_getsock(struct Curl_easy *data,
- struct connectdata *conn,
- curl_socket_t *socks)
+static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
+ struct connectdata *conn = data->conn;
+ (void)socks;
+ /* Not using `conn->sockfd` as `Curl_setup_transfer()` initializes
+ * that *after* the connect. */
+ if(conn && conn->sock[FIRSTSOCKET] != CURL_SOCKET_BAD) {
+ /* Default is to wait to something from the server */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_READSOCK(0);
+ }
+ return GETSOCK_BLANK;
+}
+
+static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+ struct connectdata *conn = data->conn;
+ if(conn && conn->handler->proto_getsock)
+ return conn->handler->proto_getsock(data, conn, socks);
+ else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+ /* Default is to wait to something from the server */
+ socks[0] = conn->sockfd;
+ return GETSOCK_READSOCK(0);
+ }
+ return GETSOCK_BLANK;
+}
+
+static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+ struct connectdata *conn = data->conn;
if(conn && conn->handler->domore_getsock)
return conn->handler->domore_getsock(data, conn, socks);
+ else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+ /* Default is that we want to send something to the server */
+ socks[0] = conn->sockfd;
+ return GETSOCK_WRITESOCK(0);
+ }
return GETSOCK_BLANK;
}
-static int doing_getsock(struct Curl_easy *data,
- struct connectdata *conn,
- curl_socket_t *socks)
+static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
{
+ struct connectdata *conn = data->conn;
if(conn && conn->handler->doing_getsock)
return conn->handler->doing_getsock(data, conn, socks);
+ else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+ /* Default is that we want to send something to the server */
+ socks[0] = conn->sockfd;
+ return GETSOCK_WRITESOCK(0);
+ }
return GETSOCK_BLANK;
}
-static int protocol_getsock(struct Curl_easy *data,
- struct connectdata *conn,
- curl_socket_t *socks)
+static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
{
- if(conn->handler->proto_getsock)
- return conn->handler->proto_getsock(data, conn, socks);
- return GETSOCK_BLANK;
+ struct connectdata *conn = data->conn;
+
+ if(!conn)
+ return GETSOCK_BLANK;
+ else if(conn->handler->perform_getsock)
+ return conn->handler->perform_getsock(data, conn, sock);
+ else {
+ /* Default is to obey the data->req.keepon flags for send/recv */
+ int bitmap = GETSOCK_BLANK;
+ unsigned sockindex = 0;
+ if(CURL_WANT_RECV(data)) {
+ DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
+ bitmap |= GETSOCK_READSOCK(sockindex);
+ sock[sockindex] = conn->sockfd;
+ }
+
+ if(CURL_WANT_SEND(data)) {
+ if((conn->sockfd != conn->writesockfd) ||
+ bitmap == GETSOCK_BLANK) {
+ /* only if they are not the same socket and we have a readable
+ one, we increase index */
+ if(bitmap != GETSOCK_BLANK)
+ sockindex++; /* increase index if we need two entries */
+
+ DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
+ sock[sockindex] = conn->writesockfd;
+ }
+ bitmap |= GETSOCK_WRITESOCK(sockindex);
+ }
+ return bitmap;
+ }
}
/* Initializes `poll_set` with the current socket poll actions needed
@@ -1033,45 +1095,61 @@ static void multi_getsock(struct Curl_easy *data,
return;
switch(data->mstate) {
- default:
+ case MSTATE_INIT:
+ case MSTATE_PENDING:
+ case MSTATE_CONNECT:
+ /* nothing to poll for yet */
break;
case MSTATE_RESOLVING:
- Curl_pollset_add_socks2(data, ps, Curl_resolv_getsock);
+ Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
/* connection filters are not involved in this phase */
- return;
+ break;
+
+ case MSTATE_CONNECTING:
+ case MSTATE_TUNNELING:
+ Curl_pollset_add_socks(data, ps, connecting_getsock);
+ Curl_conn_adjust_pollset(data, ps);
+ break;
- case MSTATE_PROTOCONNECTING:
case MSTATE_PROTOCONNECT:
+ case MSTATE_PROTOCONNECTING:
Curl_pollset_add_socks(data, ps, protocol_getsock);
+ Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DO:
case MSTATE_DOING:
Curl_pollset_add_socks(data, ps, doing_getsock);
- break;
-
- case MSTATE_TUNNELING:
- case MSTATE_CONNECTING:
+ Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_DOING_MORE:
Curl_pollset_add_socks(data, ps, domore_getsock);
+ Curl_conn_adjust_pollset(data, ps);
break;
- case MSTATE_DID: /* since is set after DO is completed, we switch to
- waiting for the same as the PERFORMING state */
+ case MSTATE_DID: /* same as PERFORMING in regard to polling */
case MSTATE_PERFORMING:
- Curl_pollset_add_socks(data, ps, Curl_single_getsock);
+ Curl_pollset_add_socks(data, ps, perform_getsock);
+ Curl_conn_adjust_pollset(data, ps);
break;
case MSTATE_RATELIMITING:
- /* nothing to wait for */
- return;
- }
+ /* we need to let time pass, ignore socket(s) */
+ break;
+
+ case MSTATE_DONE:
+ case MSTATE_COMPLETED:
+ case MSTATE_MSGSENT:
+ /* nothing more to poll for */
+ break;
- /* Let connection filters add/remove as needed */
- Curl_conn_adjust_pollset(data, ps);
+ default:
+ failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
+ DEBUGASSERT(0);
+ break;
+ }
}
CURLMcode curl_multi_fdset(struct Curl_multi *multi,
@@ -1942,6 +2020,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
if(!result) {
+ *nowp = Curl_pgrsTime(data, TIMER_POSTQUEUE);
if(async)
/* We're now waiting for an asynchronous name lookup */
multistate(data, MSTATE_RESOLVING);
@@ -1983,8 +2062,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
if(dns) {
#ifdef CURLRES_ASYNCH
- conn->resolve_async.dns = dns;
- conn->resolve_async.done = TRUE;
+ data->state.async.dns = dns;
+ data->state.async.done = TRUE;
#endif
result = CURLE_OK;
infof(data, "Hostname '%s' was found in DNS cache", hostname);
@@ -2371,7 +2450,6 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
{
char *newurl = NULL;
bool retry = FALSE;
- bool comeback = FALSE;
DEBUGASSERT(data->state.buffer);
/* check if over send speed */
send_timeout_ms = 0;
@@ -2402,7 +2480,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
/* read/write data if it is ready to do so */
- result = Curl_readwrite(data->conn, data, &done, &comeback);
+ result = Curl_readwrite(data, &done);
if(done || (result == CURLE_RECV_ERROR)) {
/* If CURLE_RECV_ERROR happens early enough, we assume it was a race
@@ -2512,7 +2590,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
}
- else if(comeback) {
+ else if(data->state.select_bits) {
/* 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 */
@@ -3164,7 +3242,7 @@ static CURLMcode multi_socket(struct Curl_multi *multi,
if(data->conn && !(data->conn->handler->flags & PROTOPT_DIRLOCK))
/* set socket event bitmask if they're not locked */
- data->conn->cselect_bits = (unsigned char)ev_bitmask;
+ data->state.select_bits = (unsigned char)ev_bitmask;
Curl_expire(data, 0, EXPIRE_RUN_NOW);
}