summaryrefslogtreecommitdiff
path: root/libs/libcurl/src/multi.c
diff options
context:
space:
mode:
Diffstat (limited to 'libs/libcurl/src/multi.c')
-rw-r--r--libs/libcurl/src/multi.c172
1 files changed, 149 insertions, 23 deletions
diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c
index be3e41f8bb..1b3e261c68 100644
--- a/libs/libcurl/src/multi.c
+++ b/libs/libcurl/src/multi.c
@@ -381,6 +381,11 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
multi->max_concurrent_streams = 100;
multi->ipv6_works = Curl_ipv6works(NULL);
+#ifdef USE_WINSOCK
+ multi->wsa_event = WSACreateEvent();
+ if(multi->wsa_event == WSA_INVALID_EVENT)
+ goto error;
+#else
#ifdef ENABLE_WAKEUP
if(Curl_socketpair(AF_UNIX, SOCK_STREAM, 0, multi->wakeup_pair) < 0) {
multi->wakeup_pair[0] = CURL_SOCKET_BAD;
@@ -394,6 +399,7 @@ struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
multi->wakeup_pair[1] = CURL_SOCKET_BAD;
}
#endif
+#endif
return multi;
@@ -872,8 +878,10 @@ bool Curl_multiplex_wanted(const struct Curl_multi *multi)
void Curl_detach_connnection(struct Curl_easy *data)
{
struct connectdata *conn = data->conn;
- if(conn)
+ if(conn) {
Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL);
+ Curl_ssl_detach_conn(data, conn);
+ }
data->conn = NULL;
}
@@ -890,6 +898,9 @@ void Curl_attach_connnection(struct Curl_easy *data,
data->conn = conn;
Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data,
&data->conn_queue);
+ if(conn->handler->attach)
+ conn->handler->attach(data, conn);
+ Curl_ssl_associate_conn(data, conn);
}
static int waitconnect_getsock(struct connectdata *conn,
@@ -930,10 +941,8 @@ static int waitproxyconnect_getsock(struct connectdata *conn,
{
sock[0] = conn->sock[FIRSTSOCKET];
- /* when we've sent a CONNECT to a proxy, we should rather wait for the
- socket to become readable to be able to get the response headers */
if(conn->connect_state)
- return GETSOCK_READSOCK(0);
+ return Curl_connect_getsock(conn);
return GETSOCK_WRITESOCK(0);
}
@@ -1083,6 +1092,10 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
struct pollfd *ufds = &a_few_on_stack[0];
bool ufds_malloc = FALSE;
+#ifdef USE_WINSOCK
+ WSANETWORKEVENTS wsa_events;
+ DEBUGASSERT(multi->wsa_event != WSA_INVALID_EVENT);
+#endif
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
@@ -1101,11 +1114,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
for(i = 0; i< MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
- if(bitmap & GETSOCK_READSOCK(i)) {
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
++nfds;
s = sockbunch[i];
}
- if(bitmap & GETSOCK_WRITESOCK(i)) {
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
++nfds;
s = sockbunch[i];
}
@@ -1128,7 +1141,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
nfds += extra_nfds; /* add the externally provided ones */
#ifdef ENABLE_WAKEUP
+#ifdef USE_WINSOCK
+ if(use_wakeup) {
+#else
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
+#endif
++nfds;
}
#endif
@@ -1156,22 +1173,40 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
curl_socket_t s = CURL_SOCKET_BAD;
-
+#ifdef USE_WINSOCK
+ long mask = 0;
+#endif
if(bitmap & GETSOCK_READSOCK(i)) {
- ufds[nfds].fd = sockbunch[i];
+ s = sockbunch[i];
+#ifdef USE_WINSOCK
+ mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+#endif
+ ufds[nfds].fd = s;
ufds[nfds].events = POLLIN;
++nfds;
- s = sockbunch[i];
}
if(bitmap & GETSOCK_WRITESOCK(i)) {
- ufds[nfds].fd = sockbunch[i];
+ s = sockbunch[i];
+#ifdef USE_WINSOCK
+ mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+ send(s, NULL, 0, 0); /* reset FD_WRITE */
+#endif
+ ufds[nfds].fd = s;
ufds[nfds].events = POLLOUT;
++nfds;
- s = sockbunch[i];
}
+ /* s is only set if either being readable or writable is checked */
if(s == CURL_SOCKET_BAD) {
+ /* break on entry not checked for being readable or writable */
break;
}
+#ifdef USE_WINSOCK
+ if(WSAEventSelect(s, multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
+ return CURLM_INTERNAL_ERROR;
+ }
+#endif
}
data = data->next; /* check next handle */
@@ -1180,6 +1215,22 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
/* Add external file descriptions from poll-like struct curl_waitfd */
for(i = 0; i < extra_nfds; i++) {
+#ifdef USE_WINSOCK
+ long mask = 0;
+ if(extra_fds[i].events & CURL_WAIT_POLLIN)
+ mask |= FD_READ|FD_ACCEPT|FD_CLOSE;
+ if(extra_fds[i].events & CURL_WAIT_POLLPRI)
+ mask |= FD_OOB;
+ if(extra_fds[i].events & CURL_WAIT_POLLOUT) {
+ mask |= FD_WRITE|FD_CONNECT|FD_CLOSE;
+ send(extra_fds[i].fd, NULL, 0, 0); /* reset FD_WRITE */
+ }
+ if(WSAEventSelect(extra_fds[i].fd, multi->wsa_event, mask) != 0) {
+ if(ufds_malloc)
+ free(ufds);
+ return CURLM_INTERNAL_ERROR;
+ }
+#endif
ufds[nfds].fd = extra_fds[i].fd;
ufds[nfds].events = 0;
if(extra_fds[i].events & CURL_WAIT_POLLIN)
@@ -1192,25 +1243,62 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
}
#ifdef ENABLE_WAKEUP
+#ifndef USE_WINSOCK
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
ufds[nfds].fd = multi->wakeup_pair[0];
ufds[nfds].events = POLLIN;
++nfds;
}
#endif
+#endif
+#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
+ if(nfds || use_wakeup) {
+#else
if(nfds) {
- /* wait... */
- int pollrc = Curl_poll(ufds, nfds, timeout_ms);
+#endif
+ int pollrc;
+#ifdef USE_WINSOCK
+ if(nfds)
+ pollrc = Curl_poll(ufds, nfds, 0); /* just pre-check with WinSock */
+ else
+ pollrc = 0;
+ if(pollrc <= 0) /* now wait... if not ready during the pre-check above */
+ WSAWaitForMultipleEvents(1, &multi->wsa_event, FALSE, timeout_ms, FALSE);
+#else
+ pollrc = Curl_poll(ufds, nfds, timeout_ms); /* wait... */
+#endif
+
if(pollrc > 0) {
retcode = pollrc;
+#ifdef USE_WINSOCK
+ }
+ /* With WinSock, we have to run the following section unconditionally
+ to call WSAEventSelect(fd, event, 0) on all the sockets */
+ {
+#endif
/* copy revents results from the poll to the curl_multi_wait poll
struct, the bit values of the actual underlying poll() implementation
may not be the same as the ones in the public libcurl API! */
for(i = 0; i < extra_nfds; i++) {
- unsigned short mask = 0;
unsigned r = ufds[curlfds + i].revents;
-
+ unsigned short mask = 0;
+#ifdef USE_WINSOCK
+ wsa_events.lNetworkEvents = 0;
+ if(WSAEnumNetworkEvents(extra_fds[i].fd, NULL, &wsa_events) == 0) {
+ if(wsa_events.lNetworkEvents & (FD_READ|FD_ACCEPT|FD_CLOSE))
+ mask |= CURL_WAIT_POLLIN;
+ if(wsa_events.lNetworkEvents & (FD_WRITE|FD_CONNECT|FD_CLOSE))
+ mask |= CURL_WAIT_POLLOUT;
+ if(wsa_events.lNetworkEvents & FD_OOB)
+ mask |= CURL_WAIT_POLLPRI;
+ if(ret && pollrc <= 0 && wsa_events.lNetworkEvents)
+ retcode++;
+ }
+ WSAEventSelect(extra_fds[i].fd, multi->wsa_event, 0);
+ if(pollrc <= 0)
+ continue;
+#endif
if(r & POLLIN)
mask |= CURL_WAIT_POLLIN;
if(r & POLLOUT)
@@ -1220,6 +1308,35 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
extra_fds[i].revents = mask;
}
+#ifdef USE_WINSOCK
+ /* Count up all our own sockets that had activity,
+ and remove them from the event. */
+ if(curlfds) {
+ data = multi->easyp;
+ while(data) {
+ bitmap = multi_getsock(data, sockbunch);
+
+ for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++) {
+ if(bitmap & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i))) {
+ wsa_events.lNetworkEvents = 0;
+ if(WSAEnumNetworkEvents(sockbunch[i], NULL, &wsa_events) == 0) {
+ if(ret && pollrc <= 0 && wsa_events.lNetworkEvents)
+ retcode++;
+ }
+ WSAEventSelect(sockbunch[i], multi->wsa_event, 0);
+ }
+ else {
+ /* break on entry not checked for being readable or writable */
+ break;
+ }
+ }
+
+ data = data->next;
+ }
+ }
+
+ WSAResetEvent(multi->wsa_event);
+#else
#ifdef ENABLE_WAKEUP
if(use_wakeup && multi->wakeup_pair[0] != CURL_SOCKET_BAD) {
if(ufds[curlfds + extra_nfds].revents & POLLIN) {
@@ -1232,10 +1349,8 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
when there is no more data, breaking the loop. */
nread = sread(multi->wakeup_pair[0], buf, sizeof(buf));
if(nread <= 0) {
-#ifndef USE_WINSOCK
if(nread < 0 && EINTR == SOCKERRNO)
continue;
-#endif
break;
}
}
@@ -1244,6 +1359,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
}
}
#endif
+#endif
}
}
@@ -1251,10 +1367,11 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
free(ufds);
if(ret)
*ret = retcode;
- if(!extrawait || nfds)
- /* if any socket was checked */
- ;
- else {
+#if defined(ENABLE_WAKEUP) && defined(USE_WINSOCK)
+ if(extrawait && !nfds && !use_wakeup) {
+#else
+ if(extrawait && !nfds) {
+#endif
long sleep_ms = 0;
/* Avoid busy-looping when there's nothing particular to wait for */
@@ -1303,6 +1420,10 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
return CURLM_BAD_HANDLE;
#ifdef ENABLE_WAKEUP
+#ifdef USE_WINSOCK
+ if(WSASetEvent(multi->wsa_event))
+ return CURLM_OK;
+#else
/* the wakeup_pair variable is only written during init and cleanup,
making it safe to access from another thread after the init part
and before cleanup */
@@ -1336,6 +1457,7 @@ CURLMcode curl_multi_wakeup(struct Curl_multi *multi)
}
}
#endif
+#endif
return CURLM_WAKEUP_FAILURE;
}
@@ -2153,12 +2275,12 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi,
}
}
else if((CURLE_HTTP2_STREAM == result) &&
- Curl_h2_http_1_1_error(data->conn)) {
+ Curl_h2_http_1_1_error(data)) {
CURLcode ret = Curl_retry_request(data, &newurl);
if(!ret) {
infof(data, "Downgrades to HTTP/1.1!\n");
- connclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
+ streamclose(data->conn, "Disconnect HTTP/2 for HTTP/1");
data->state.httpwant = CURL_HTTP_VERSION_1_1;
/* clear the error message bit too as we ignore the one we got */
data->state.errorbuf = FALSE;
@@ -2478,10 +2600,14 @@ CURLMcode curl_multi_cleanup(struct Curl_multi *multi)
Curl_hash_destroy(&multi->hostcache);
Curl_psl_destroy(&multi->psl);
+#ifdef USE_WINSOCK
+ WSACloseEvent(multi->wsa_event);
+#else
#ifdef ENABLE_WAKEUP
sclose(multi->wakeup_pair[0]);
sclose(multi->wakeup_pair[1]);
#endif
+#endif
free(multi);
return CURLM_OK;