lib: replace getsock() logic with pollsets

`getsock()` calls operated on a global limit that could
not be configure beyond 16 sockets. This is no longer adequate
with the new happy eyeballing strategy.

Instead, do the following:
- make `struct easy_pollset` dynamic. Starting with
  a minimal room for two sockets, the very common case,
  allow it to grow on demand.
- replace all protocol handler getsock() calls with pollsets
  and a CURLcode to return failures
- add CURLcode return for all connection filter `adjust_pollset()`
  callbacks, since they too can now fail.
- use appropriately in multi.c and multi_ev.c
- fix unit2600 to trigger pollset growth

Closes #18164
This commit is contained in:
Stefan Eissing 2025-08-04 16:17:37 +02:00 committed by Daniel Stenberg
parent c85c2b7be7
commit 5b80b4c012
No known key found for this signature in database
GPG key ID: 5CC908FDB71E12C2
54 changed files with 1002 additions and 873 deletions

View file

@ -273,15 +273,15 @@ static void async_ares_cleanup(struct Curl_easy *data)
}
/*
* Curl_async_getsock() is called when someone from the outside world
* Curl_async_pollset() is called when someone from the outside world
* (using curl_multi_fdset()) wants to get our fd_set setup.
*/
int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
{
struct async_ares_ctx *ares = &data->state.async.ares;
DEBUGASSERT(ares->channel);
return Curl_ares_getsock(data, ares->channel, socks);
return Curl_ares_pollset(data, ares->channel, ps);
}
/*

View file

@ -70,7 +70,7 @@
#endif
/*
* Curl_ares_getsock() is called when the outside world (using
* Curl_ares_pollset() is called when the outside world (using
* curl_multi_fdset()) wants to get our fd_set setup and we are talking with
* ares. The caller must make sure that this function is only called when we
* have a working ares channel.
@ -78,18 +78,38 @@
* Returns: sockets-in-use-bitmap
*/
int Curl_ares_getsock(struct Curl_easy *data,
ares_channel channel,
curl_socket_t *socks)
CURLcode Curl_ares_pollset(struct Curl_easy *data,
ares_channel channel,
struct easy_pollset *ps)
{
struct timeval maxtime = { CURL_TIMEOUT_RESOLVE, 0 };
struct timeval timebuf;
int max = ares_getsock(channel,
(ares_socket_t *)socks, MAX_SOCKSPEREASYHANDLE);
struct timeval *timeout = ares_timeout(channel, &maxtime, &timebuf);
timediff_t milli = curlx_tvtoms(timeout);
curl_socket_t sockets[16]; /* ARES documented limit */
unsigned int bitmap, i;
struct timeval *timeout;
timediff_t milli;
CURLcode result = CURLE_OK;
bitmap = ares_getsock(channel, (ares_socket_t *)sockets,
CURL_ARRAYSIZE(sockets));
for(i = 0; i < CURL_ARRAYSIZE(sockets); ++i) {
int flags = 0;
if(ARES_GETSOCK_READABLE(bitmap, i))
flags |= CURL_POLL_IN;
if(ARES_GETSOCK_WRITABLE(bitmap, i))
flags |= CURL_POLL_OUT;
if(!flags)
break;
result = Curl_pollset_change(data, ps, sockets[i], flags, 0);
if(result)
return result;
}
timeout = ares_timeout(channel, &maxtime, &timebuf);
milli = curlx_tvtoms(timeout);
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
return max;
return result;
}
/*

View file

@ -63,6 +63,7 @@
#include "url.h"
#include "multiif.h"
#include "curl_threads.h"
#include "select.h"
#include "strdup.h"
#ifdef USE_ARES
@ -629,33 +630,25 @@ CURLcode Curl_async_is_resolved(struct Curl_easy *data,
}
}
int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps)
{
struct async_thrdd_ctx *thrdd = &data->state.async.thrdd;
int ret_val = 0;
#if !defined(CURL_DISABLE_SOCKETPAIR) || defined(USE_HTTPSRR_ARES)
int socketi = 0;
#else
(void)socks;
#endif
CURLcode result = CURLE_OK;
#ifdef USE_HTTPSRR_ARES
if(thrdd->rr.channel) {
ret_val = Curl_ares_getsock(data, thrdd->rr.channel, socks);
for(socketi = 0; socketi < (MAX_SOCKSPEREASYHANDLE - 1); socketi++)
if(!ARES_GETSOCK_READABLE(ret_val, socketi) &&
!ARES_GETSOCK_WRITABLE(ret_val, socketi))
break;
result = Curl_ares_pollset(data, thrdd->rr.channel, ps);
if(result)
return result;
}
#endif
if(!thrdd->addr)
return ret_val;
return result;
#ifndef CURL_DISABLE_SOCKETPAIR
if(thrdd->addr) {
/* return read fd to client for polling the DNS resolution status */
socks[socketi] = thrdd->addr->sock_pair[0];
ret_val |= GETSOCK_READSOCK(socketi);
result = Curl_pollset_add_in(data, ps, thrdd->addr->sock_pair[0]);
}
else
#endif
@ -673,7 +666,7 @@ int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *socks)
Curl_expire(data, milli, EXPIRE_ASYNC_NAME);
}
return ret_val;
return result;
}
#ifndef HAVE_GETADDRINFO

View file

@ -37,6 +37,7 @@ struct Curl_dns_entry;
struct addrinfo;
struct hostent;
struct connectdata;
struct easy_pollset;
#if defined(CURLRES_ARES) && defined(CURLRES_THREADED)
#error cannot have both CURLRES_ARES and CURLRES_THREADED defined
@ -70,15 +71,15 @@ void Curl_async_global_cleanup(void);
*/
CURLcode Curl_async_get_impl(struct Curl_easy *easy, void **impl);
/* Curl_async_getsock()
/* Curl_async_pollset()
*
* This function is called from the Curl_multi_getsock() function. 'sock' is a
* This function is called from the Curl_multi_pollset() function. 'sock' is a
* pointer to an array to hold the file descriptors, with 'numsock' being the
* size of that array (in number of entries). This function is supposed to
* return bitmask indicating what file descriptors (referring to array indexes
* in the 'sock' array) to wait for, read/write.
*/
int Curl_async_getsock(struct Curl_easy *data, curl_socket_t *sock);
CURLcode Curl_async_pollset(struct Curl_easy *data, struct easy_pollset *ps);
/*
* Curl_async_is_resolved()
@ -127,9 +128,10 @@ struct Curl_addrinfo *Curl_async_getaddrinfo(struct Curl_easy *data,
/* common functions for c-ares and threaded resolver with HTTPSRR */
#include <ares.h>
int Curl_ares_getsock(struct Curl_easy *data,
ares_channel channel,
curl_socket_t *socks);
CURLcode Curl_ares_pollset(struct Curl_easy *data,
ares_channel channel,
struct easy_pollset *ps);
int Curl_ares_perform(ares_channel channel,
timediff_t timeout_ms);
#endif

View file

@ -682,11 +682,12 @@ out:
return result;
}
static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct h1_tunnel_state *ts = cf->ctx;
CURLcode result = CURLE_OK;
if(!cf->connected) {
/* If we are not connected, but the filter "below" is
@ -698,13 +699,14 @@ static void cf_h1_proxy_adjust_pollset(struct Curl_cfilter *cf,
response headers or if we are still sending the request, wait
for write. */
if(tunnel_want_send(ts))
Curl_pollset_set_out_only(data, ps, sock);
result = Curl_pollset_set_out_only(data, ps, sock);
else
Curl_pollset_set_in_only(data, ps, sock);
result = Curl_pollset_set_in_only(data, ps, sock);
}
else
Curl_pollset_set_out_only(data, ps, sock);
result = Curl_pollset_set_out_only(data, ps, sock);
}
return result;
}
static void cf_h1_proxy_destroy(struct Curl_cfilter *cf,

View file

@ -41,6 +41,7 @@
#include "http_proxy.h"
#include "multiif.h"
#include "sendf.h"
#include "select.h"
#include "cf-h2-proxy.h"
/* The last 3 #include files should be in this order */
@ -1202,14 +1203,15 @@ static bool cf_h2_proxy_data_pending(struct Curl_cfilter *cf,
return cf->next ? cf->next->cft->has_data_pending(cf->next, data) : FALSE;
}
static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_h2_proxy_ctx *ctx = cf->ctx;
struct cf_call_data save;
curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
bool want_recv, want_send;
CURLcode result = CURLE_OK;
if(!cf->connected && ctx->h2) {
want_send = nghttp2_session_want_write(ctx->h2) ||
@ -1234,9 +1236,9 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
!Curl_bufq_is_empty(&ctx->outbufq) ||
!Curl_bufq_is_empty(&ctx->tunnel.sendbuf);
Curl_pollset_set(data, ps, sock, want_recv, want_send);
CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d",
want_recv, want_send);
result = Curl_pollset_set(data, ps, sock, want_recv, want_send);
CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d -> %d",
want_recv, want_send, result);
CF_DATA_RESTORE(cf, save);
}
else if(ctx->sent_goaway && !cf->shutdown) {
@ -1246,11 +1248,12 @@ static void cf_h2_proxy_adjust_pollset(struct Curl_cfilter *cf,
!Curl_bufq_is_empty(&ctx->outbufq) ||
!Curl_bufq_is_empty(&ctx->tunnel.sendbuf);
want_recv = nghttp2_session_want_read(ctx->h2);
Curl_pollset_set(data, ps, sock, want_recv, want_send);
CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d",
want_recv, want_send);
result = Curl_pollset_set(data, ps, sock, want_recv, want_send);
CURL_TRC_CF(data, cf, "adjust_pollset, want_recv=%d want_send=%d -> %d",
want_recv, want_send, result);
CF_DATA_RESTORE(cf, save);
}
return result;
}
static CURLcode h2_handle_tunnel_close(struct Curl_cfilter *cf,

View file

@ -32,6 +32,7 @@
#include "cf-haproxy.h"
#include "curl_trc.h"
#include "multiif.h"
#include "select.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@ -178,15 +179,17 @@ static void cf_haproxy_close(struct Curl_cfilter *cf,
cf->next->cft->do_close(cf->next, data);
}
static void cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_haproxy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
if(cf->next->connected && !cf->connected) {
/* If we are not connected, but the filter "below" is
* and not waiting on something, we are sending. */
Curl_pollset_set_out_only(data, ps, Curl_conn_cf_get_socket(cf, data));
return Curl_pollset_set_out_only(
data, ps, Curl_conn_cf_get_socket(cf, data));
}
return CURLE_OK;
}
struct Curl_cftype Curl_cft_haproxy = {

View file

@ -35,6 +35,7 @@
#include "multiif.h"
#include "cf-https-connect.h"
#include "http2.h"
#include "select.h"
#include "vquic/vquic.h"
/* The last 3 #include files should be in this order */
@ -426,22 +427,24 @@ static CURLcode cf_hc_shutdown(struct Curl_cfilter *cf,
return result;
}
static void cf_hc_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_hc_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
CURLcode result = CURLE_OK;
if(!cf->connected) {
struct cf_hc_ctx *ctx = cf->ctx;
size_t i;
for(i = 0; i < ctx->baller_count; i++) {
for(i = 0; (i < ctx->baller_count) && !result; i++) {
struct cf_hc_baller *b = &ctx->ballers[i];
if(!cf_hc_baller_is_active(b))
continue;
Curl_conn_cf_adjust_pollset(b->cf, data, ps);
result = Curl_conn_cf_adjust_pollset(b->cf, data, ps);
}
CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %d socks", result, ps->n);
}
return result;
}
static bool cf_hc_data_pending(struct Curl_cfilter *cf,

View file

@ -60,6 +60,7 @@
#include "curl_trc.h"
#include "multiif.h"
#include "progress.h"
#include "select.h"
#include "vquic/vquic.h" /* for quic cfilters */
/* The last 3 #include files should be in this order */
@ -533,16 +534,18 @@ static CURLcode cf_ip_ballers_shutdown(struct cf_ip_ballers *bs,
return CURLE_OK;
}
static void cf_ip_ballers_pollset(struct cf_ip_ballers *bs,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_ip_ballers_pollset(struct cf_ip_ballers *bs,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_ip_attempt *a;
for(a = bs->running; a; a = a->next) {
CURLcode result = CURLE_OK;
for(a = bs->running; a && !result; a = a->next) {
if(a->result)
continue;
Curl_conn_cf_adjust_pollset(a->cf, data, ps);
result = Curl_conn_cf_adjust_pollset(a->cf, data, ps);
}
return result;
}
static bool cf_ip_ballers_pending(struct cf_ip_ballers *bs,
@ -713,16 +716,18 @@ static CURLcode cf_ip_happy_shutdown(struct Curl_cfilter *cf,
return result;
}
static void cf_ip_happy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_ip_happy_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_ip_happy_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(!cf->connected) {
cf_ip_ballers_pollset(&ctx->ballers, data, ps);
CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
result = cf_ip_ballers_pollset(&ctx->ballers, data, ps);
CURL_TRC_CF(data, cf, "adjust_pollset -> %d, %d socks", result, ps->n);
}
return result;
}
static CURLcode cf_ip_happy_connect(struct Curl_cfilter *cf,

View file

@ -1376,11 +1376,12 @@ out:
return result;
}
static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_socket_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_socket_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(ctx->sock != CURL_SOCKET_BAD) {
/* A listening socket filter needs to be connected before the accept
@ -1388,21 +1389,22 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
* FTP no longer does the socket checks and accept calls and delegates
* all that to the filter. */
if(ctx->listening) {
Curl_pollset_set_in_only(data, ps, ctx->sock);
result = Curl_pollset_set_in_only(data, ps, ctx->sock);
CURL_TRC_CF(data, cf, "adjust_pollset, listening, POLLIN fd=%"
FMT_SOCKET_T, ctx->sock);
}
else if(!cf->connected) {
Curl_pollset_set_out_only(data, ps, ctx->sock);
result = Curl_pollset_set_out_only(data, ps, ctx->sock);
CURL_TRC_CF(data, cf, "adjust_pollset, !connected, POLLOUT fd=%"
FMT_SOCKET_T, ctx->sock);
}
else if(!ctx->active) {
Curl_pollset_add_in(data, ps, ctx->sock);
result = Curl_pollset_add_in(data, ps, ctx->sock);
CURL_TRC_CF(data, cf, "adjust_pollset, !active, POLLIN fd=%"
FMT_SOCKET_T, ctx->sock);
}
}
return result;
}
#ifdef USE_WINSOCK

View file

@ -67,14 +67,15 @@ CURLcode Curl_cf_def_shutdown(struct Curl_cfilter *cf,
static void conn_report_connect_stats(struct Curl_easy *data,
struct connectdata *conn);
void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
CURLcode Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
/* NOP */
(void)cf;
(void)data;
(void)ps;
return CURLE_OK;
}
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
@ -469,6 +470,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
{
#define CF_CONN_NUM_POLLS_ON_STACK 5
struct pollfd a_few_on_stack[CF_CONN_NUM_POLLS_ON_STACK];
struct easy_pollset ps;
struct curl_pollfds cpfds;
struct Curl_cfilter *cf;
CURLcode result = CURLE_OK;
@ -486,6 +488,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
if(*done)
return CURLE_OK;
Curl_pollset_init(&ps);
Curl_pollfds_init(&cpfds, a_few_on_stack, CF_CONN_NUM_POLLS_ON_STACK);
while(!*done) {
if(Curl_conn_needs_flush(data, sockindex)) {
@ -523,7 +526,6 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
/* check allowed time left */
const timediff_t timeout_ms = Curl_timeleft(data, NULL, TRUE);
curl_socket_t sockfd = Curl_conn_cf_get_socket(cf, data);
struct easy_pollset ps;
int rc;
if(timeout_ms < 0) {
@ -534,12 +536,14 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
}
CURL_TRC_CF(data, cf, "Curl_conn_connect(block=1), do poll");
Curl_pollset_reset(&ps);
Curl_pollfds_reset(&cpfds);
memset(&ps, 0, sizeof(ps));
/* In general, we want to send after connect, wait on that. */
if(sockfd != CURL_SOCKET_BAD)
Curl_pollset_set_out_only(data, &ps, sockfd);
Curl_conn_adjust_pollset(data, data->conn, &ps);
result = Curl_conn_adjust_pollset(data, data->conn, &ps);
if(result)
goto out;
result = Curl_pollfds_add_ps(&cpfds, &ps);
if(result)
goto out;
@ -557,6 +561,7 @@ CURLcode Curl_conn_connect(struct Curl_easy *data,
}
out:
Curl_pollset_cleanup(&ps);
Curl_pollfds_cleanup(&cpfds);
return result;
}
@ -710,10 +715,11 @@ bool Curl_conn_needs_flush(struct Curl_easy *data, int sockindex)
return Curl_conn_cf_needs_flush(data->conn->cfilter[sockindex], data);
}
void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
CURLcode Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
CURLcode result = CURLE_OK;
/* Get the lowest not-connected filter, if there are any */
while(cf && !cf->connected && cf->next && !cf->next->connected)
cf = cf->next;
@ -722,23 +728,26 @@ void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
cf = cf->next;
/* From there on, give all filters a chance to adjust the pollset.
* Lower filters are called later, so they may override */
while(cf) {
cf->cft->adjust_pollset(cf, data, ps);
while(cf && !result) {
result = cf->cft->adjust_pollset(cf, data, ps);
cf = cf->next;
}
return result;
}
void Curl_conn_adjust_pollset(struct Curl_easy *data,
struct connectdata *conn,
struct easy_pollset *ps)
CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data,
struct connectdata *conn,
struct easy_pollset *ps)
{
CURLcode result = CURLE_OK;
int i;
DEBUGASSERT(data);
DEBUGASSERT(conn);
for(i = 0; i < 2; ++i) {
Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
for(i = 0; (i < 2) && !result; ++i) {
result = Curl_conn_cf_adjust_pollset(conn->cfilter[i], data, ps);
}
return result;
}
int Curl_conn_cf_poll(struct Curl_cfilter *cf,
@ -746,35 +755,18 @@ int Curl_conn_cf_poll(struct Curl_cfilter *cf,
timediff_t timeout_ms)
{
struct easy_pollset ps;
struct pollfd pfds[MAX_SOCKSPEREASYHANDLE];
unsigned int i, npfds = 0;
int result;
DEBUGASSERT(cf);
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
memset(&ps, 0, sizeof(ps));
memset(pfds, 0, sizeof(pfds));
Curl_pollset_init(&ps);
Curl_conn_cf_adjust_pollset(cf, data, &ps);
DEBUGASSERT(ps.num <= MAX_SOCKSPEREASYHANDLE);
for(i = 0; i < ps.num; ++i) {
short events = 0;
if(ps.actions[i] & CURL_POLL_IN) {
events |= POLLIN;
}
if(ps.actions[i] & CURL_POLL_OUT) {
events |= POLLOUT;
}
if(events) {
pfds[npfds].fd = ps.sockets[i];
pfds[npfds].events = events;
++npfds;
}
}
if(!npfds)
DEBUGF(infof(data, "no sockets to poll!"));
return Curl_poll(pfds, npfds, timeout_ms);
result = Curl_conn_cf_adjust_pollset(cf, data, &ps);
if(!result)
result = Curl_pollset_poll(data, &ps, timeout_ms);
Curl_pollset_cleanup(&ps);
return result;
}
void Curl_conn_get_current_host(struct Curl_easy *data, int sockindex,
@ -1099,142 +1091,3 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
*pnwritten = 0;
return CURLE_FAILED_INIT;
}
void Curl_pollset_reset(struct Curl_easy *data,
struct easy_pollset *ps)
{
size_t i;
(void)data;
memset(ps, 0, sizeof(*ps));
for(i = 0; i < MAX_SOCKSPEREASYHANDLE; i++)
ps->sockets[i] = CURL_SOCKET_BAD;
}
/**
*
*/
void Curl_pollset_change(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
int add_flags, int remove_flags)
{
unsigned int i;
(void)data;
DEBUGASSERT(VALID_SOCK(sock));
if(!VALID_SOCK(sock))
return;
DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
for(i = 0; i < ps->num; ++i) {
if(ps->sockets[i] == sock) {
ps->actions[i] &= (unsigned char)(~remove_flags);
ps->actions[i] |= (unsigned char)add_flags;
/* all gone? remove socket */
if(!ps->actions[i]) {
if((i + 1) < ps->num) {
memmove(&ps->sockets[i], &ps->sockets[i + 1],
(ps->num - (i + 1)) * sizeof(ps->sockets[0]));
memmove(&ps->actions[i], &ps->actions[i + 1],
(ps->num - (i + 1)) * sizeof(ps->actions[0]));
}
--ps->num;
}
return;
}
}
/* not present */
if(add_flags) {
/* Having more SOCKETS per easy handle than what is defined
* is a programming error. This indicates that we need
* to raise this limit, making easy_pollset larger.
* Since we use this in tight loops, we do not want to make
* the pollset dynamic unnecessarily.
* The current maximum in practise is HTTP/3 eyeballing where
* we have up to 4 sockets involved in connection setup.
*/
DEBUGASSERT(i < MAX_SOCKSPEREASYHANDLE);
if(i < MAX_SOCKSPEREASYHANDLE) {
ps->sockets[i] = sock;
ps->actions[i] = (unsigned char)add_flags;
ps->num = i + 1;
}
}
}
void Curl_pollset_set(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool do_in, bool do_out)
{
Curl_pollset_change(data, ps, sock,
(do_in ? CURL_POLL_IN : 0)|
(do_out ? CURL_POLL_OUT : 0),
(!do_in ? CURL_POLL_IN : 0)|
(!do_out ? CURL_POLL_OUT : 0));
}
static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
int bitmap, curl_socket_t *socks)
{
if(bitmap) {
int i;
for(i = 0; i < MAX_SOCKSPEREASYHANDLE; ++i) {
if(!(bitmap & GETSOCK_MASK_RW(i)) || !VALID_SOCK((socks[i]))) {
break;
}
if(bitmap & GETSOCK_READSOCK(i)) {
if(bitmap & GETSOCK_WRITESOCK(i))
Curl_pollset_add_inout(data, ps, socks[i]);
else
/* is READ, since we checked MASK_RW above */
Curl_pollset_add_in(data, ps, socks[i]);
}
else
Curl_pollset_add_out(data, ps, socks[i]);
}
}
}
void Curl_pollset_add_socks(struct Curl_easy *data,
struct easy_pollset *ps,
int (*get_socks_cb)(struct Curl_easy *data,
curl_socket_t *socks))
{
curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
int bitmap;
bitmap = get_socks_cb(data, socks);
ps_add(data, ps, bitmap, socks);
}
void Curl_pollset_check(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool *pwant_read, bool *pwant_write)
{
unsigned int i;
(void)data;
DEBUGASSERT(VALID_SOCK(sock));
for(i = 0; i < ps->num; ++i) {
if(ps->sockets[i] == sock) {
*pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
*pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
return;
}
}
*pwant_read = *pwant_write = FALSE;
}
bool Curl_pollset_want_read(struct Curl_easy *data,
struct easy_pollset *ps,
curl_socket_t sock)
{
unsigned int i;
(void)data;
for(i = 0; i < ps->num; ++i) {
if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN))
return TRUE;
}
return FALSE;
}

View file

@ -80,7 +80,7 @@ struct easy_pollset;
* @param data the easy handle the pollset is about
* @param ps the pollset (inout) for the easy handle
*/
typedef void Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
typedef CURLcode Curl_cft_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps);
@ -244,7 +244,7 @@ void Curl_cf_def_destroy_this(struct Curl_cfilter *cf,
/* Default implementations for the type functions, implementing pass-through
* the filter chain. */
void Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
CURLcode Curl_cf_def_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps);
bool Curl_cf_def_data_pending(struct Curl_cfilter *cf,
@ -477,16 +477,16 @@ void Curl_conn_forget_socket(struct Curl_easy *data, int sockindex);
/**
* Adjust the pollset for the filter chain starting at `cf`.
*/
void Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps);
CURLcode Curl_conn_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps);
/**
* Adjust pollset from filters installed at transfer's connection.
*/
void Curl_conn_adjust_pollset(struct Curl_easy *data,
struct connectdata *conn,
struct easy_pollset *ps);
CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data,
struct connectdata *conn,
struct easy_pollset *ps);
/**
* Curl_poll() the filter chain at `cf` with timeout `timeout_ms`.
@ -632,56 +632,6 @@ CURLcode Curl_conn_send(struct Curl_easy *data, int sockindex,
size_t *pnwritten);
void Curl_pollset_reset(struct Curl_easy *data,
struct easy_pollset *ps);
/* Change the poll flags (CURL_POLL_IN/CURL_POLL_OUT) to the poll set for
* socket `sock`. If the socket is not already part of the poll set, it
* will be added.
* If the socket is present and all poll flags are cleared, it will be removed.
*/
void Curl_pollset_change(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
int add_flags, int remove_flags);
void Curl_pollset_set(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool do_in, bool do_out);
#define Curl_pollset_add_in(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), CURL_POLL_IN, 0)
#define Curl_pollset_add_out(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), CURL_POLL_OUT, 0)
#define Curl_pollset_add_inout(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), \
CURL_POLL_IN|CURL_POLL_OUT, 0)
#define Curl_pollset_set_in_only(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), \
CURL_POLL_IN, CURL_POLL_OUT)
#define Curl_pollset_set_out_only(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), \
CURL_POLL_OUT, CURL_POLL_IN)
void Curl_pollset_add_socks(struct Curl_easy *data,
struct easy_pollset *ps,
int (*get_socks_cb)(struct Curl_easy *data,
curl_socket_t *socks));
/**
* Check if the pollset, as is, wants to read and/or write regarding
* the given socket.
*/
void Curl_pollset_check(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool *pwant_read, bool *pwant_write);
/**
* Return TRUE if the pollset contains socket with CURL_POLL_IN.
*/
bool Curl_pollset_want_read(struct Curl_easy *data,
struct easy_pollset *ps,
curl_socket_t sock);
/**
* Types and macros used to keep the current easy handle in filter calls,
* allowing for nested invocations. See #10336.

View file

@ -486,18 +486,24 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
{
if(Curl_llist_head(&cshutdn->list)) {
struct Curl_llist_node *e;
struct easy_pollset ps;
Curl_pollset_init(&ps);
for(e = Curl_llist_head(&cshutdn->list); e;
e = Curl_node_next(e)) {
struct easy_pollset ps;
unsigned int i;
struct connectdata *conn = Curl_node_elem(e);
memset(&ps, 0, sizeof(ps));
CURLcode result;
Curl_pollset_reset(&ps);
Curl_attach_connection(data, conn);
Curl_conn_adjust_pollset(data, conn, &ps);
result = Curl_conn_adjust_pollset(data, conn, &ps);
Curl_detach_connection(data);
for(i = 0; i < ps.num; i++) {
if(result)
continue;
for(i = 0; i < ps.n; i++) {
#ifdef __DJGPP__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Warith-conversion"
@ -514,6 +520,7 @@ void Curl_cshutdn_setfds(struct cshutdn *cshutdn,
*maxfd = (int)ps.sockets[i];
}
}
Curl_pollset_cleanup(&ps);
}
}
@ -528,17 +535,21 @@ unsigned int Curl_cshutdn_add_waitfds(struct cshutdn *cshutdn,
struct Curl_llist_node *e;
struct easy_pollset ps;
struct connectdata *conn;
CURLcode result;
Curl_pollset_init(&ps);
for(e = Curl_llist_head(&cshutdn->list); e;
e = Curl_node_next(e)) {
conn = Curl_node_elem(e);
memset(&ps, 0, sizeof(ps));
Curl_pollset_reset(&ps);
Curl_attach_connection(data, conn);
Curl_conn_adjust_pollset(data, conn, &ps);
result = Curl_conn_adjust_pollset(data, conn, &ps);
Curl_detach_connection(data);
need += Curl_waitfds_add_ps(cwfds, &ps);
if(!result)
need += Curl_waitfds_add_ps(cwfds, &ps);
}
Curl_pollset_cleanup(&ps);
}
return need;
}
@ -554,20 +565,24 @@ CURLcode Curl_cshutdn_add_pollfds(struct cshutdn *cshutdn,
struct easy_pollset ps;
struct connectdata *conn;
Curl_pollset_init(&ps);
for(e = Curl_llist_head(&cshutdn->list); e;
e = Curl_node_next(e)) {
conn = Curl_node_elem(e);
memset(&ps, 0, sizeof(ps));
Curl_pollset_reset(&ps);
Curl_attach_connection(data, conn);
Curl_conn_adjust_pollset(data, conn, &ps);
result = Curl_conn_adjust_pollset(data, conn, &ps);
Curl_detach_connection(data);
result = Curl_pollfds_add_ps(cpfds, &ps);
if(!result)
result = Curl_pollfds_add_ps(cpfds, &ps);
if(result) {
Curl_pollset_cleanup(&ps);
Curl_pollfds_cleanup(cpfds);
goto out;
}
}
Curl_pollset_cleanup(&ps);
}
out:
return result;

View file

@ -81,10 +81,10 @@ const struct Curl_handler Curl_handler_rtmp = {
rtmp_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -106,10 +106,10 @@ const struct Curl_handler Curl_handler_rtmpt = {
rtmp_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -131,10 +131,10 @@ const struct Curl_handler Curl_handler_rtmpe = {
rtmp_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -156,10 +156,10 @@ const struct Curl_handler Curl_handler_rtmpte = {
rtmp_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -181,10 +181,10 @@ const struct Curl_handler Curl_handler_rtmps = {
rtmp_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -206,10 +206,10 @@ const struct Curl_handler Curl_handler_rtmpts = {
rtmp_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
rtmp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */

View file

@ -92,10 +92,10 @@ const struct Curl_handler Curl_handler_dict = {
ZERO_NULL, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */

View file

@ -120,10 +120,10 @@ const struct Curl_handler Curl_handler_file = {
file_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
file_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */

View file

@ -214,10 +214,10 @@ static CURLcode ftp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead_connection);
static CURLcode ftp_do_more(struct Curl_easy *data, int *completed);
static CURLcode ftp_multi_statemach(struct Curl_easy *data, bool *done);
static int ftp_getsock(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks);
static int ftp_domore_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
static CURLcode ftp_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode ftp_domore_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode ftp_doing(struct Curl_easy *data,
bool *dophase_done);
static CURLcode ftp_setup_connection(struct Curl_easy *data,
@ -257,10 +257,10 @@ const struct Curl_handler Curl_handler_ftp = {
ftp_connect, /* connect_it */
ftp_multi_statemach, /* connecting */
ftp_doing, /* doing */
ftp_getsock, /* proto_getsock */
ftp_getsock, /* doing_getsock */
ftp_domore_getsock, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ftp_pollset, /* proto_pollset */
ftp_pollset, /* doing_pollset */
ftp_domore_pollset, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -290,10 +290,10 @@ const struct Curl_handler Curl_handler_ftps = {
ftp_connect, /* connect_it */
ftp_multi_statemach, /* connecting */
ftp_doing, /* doing */
ftp_getsock, /* proto_getsock */
ftp_getsock, /* doing_getsock */
ftp_domore_getsock, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ftp_pollset, /* proto_pollset */
ftp_pollset, /* doing_pollset */
ftp_domore_pollset, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -781,42 +781,39 @@ static CURLcode ftp_state_pwd(struct Curl_easy *data,
}
/* For the FTP "protocol connect" and "doing" phases only */
static int ftp_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks)
static CURLcode ftp_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN);
return ftpc ? Curl_pp_getsock(data, &ftpc->pp, socks) : GETSOCK_BLANK;
struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN);
return ftpc ? Curl_pp_pollset(data, &ftpc->pp, ps) : CURLE_OK;
}
/* For the FTP "DO_MORE" phase only */
static int ftp_domore_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks)
static CURLcode ftp_domore_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct ftp_conn *ftpc = Curl_conn_meta_get(conn, CURL_META_FTP_CONN);
(void)data;
struct ftp_conn *ftpc = Curl_conn_meta_get(data->conn, CURL_META_FTP_CONN);
if(!ftpc)
return GETSOCK_BLANK;
return CURLE_OK;
/* When in DO_MORE state, we could be either waiting for us to connect to a
* remote site, or we could wait for that site to connect to us. Or just
* handle ordinary commands.
*/
CURL_TRC_FTP(data, "[%s] ftp_domore_getsock()", FTP_CSTATE(ftpc));
CURL_TRC_FTP(data, "[%s] ftp_domore_pollset()", FTP_CSTATE(ftpc));
if(FTP_STOP == ftpc->state) {
/* if stopped and still in this state, then we are also waiting for a
connect on the secondary connection */
DEBUGASSERT(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD ||
(conn->cfilter[SECONDARYSOCKET] &&
!Curl_conn_is_connected(conn, SECONDARYSOCKET)));
socks[0] = conn->sock[FIRSTSOCKET];
DEBUGASSERT(data->conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD ||
(data->conn->cfilter[SECONDARYSOCKET] &&
!Curl_conn_is_connected(data->conn, SECONDARYSOCKET)));
/* An unconnected SECONDARY will add its socket by itself
* via its adjust_pollset() */
return GETSOCK_READSOCK(0);
return Curl_pollset_add_in(data, ps, data->conn->sock[FIRSTSOCKET]);
}
return Curl_pp_getsock(data, &ftpc->pp, socks);
return Curl_pp_pollset(data, &ftpc->pp, ps);
}
/* This is called after the FTP_QUOTE state is passed.

View file

@ -70,10 +70,10 @@ const struct Curl_handler Curl_handler_gopher = {
ZERO_NULL, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -96,10 +96,10 @@ const struct Curl_handler Curl_handler_gophers = {
gopher_connect, /* connect_it */
gopher_connecting, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */

View file

@ -1527,21 +1527,21 @@ CURLcode Curl_resolv_check(struct Curl_easy *data,
}
#endif
int Curl_resolv_getsock(struct Curl_easy *data,
curl_socket_t *socks)
CURLcode Curl_resolv_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
#ifdef CURLRES_ASYNCH
#ifndef CURL_DISABLE_DOH
if(data->conn->bits.doh)
/* nothing to wait for during DoH resolve, those handles have their own
sockets */
return GETSOCK_BLANK;
return CURLE_OK;
#endif
return Curl_async_getsock(data, socks);
return Curl_async_pollset(data, ps);
#else
(void)data;
(void)socks;
return GETSOCK_BLANK;
(void)ps;
return CURLE_OK;
#endif
}

View file

@ -53,6 +53,7 @@ struct addrinfo;
struct hostent;
struct Curl_easy;
struct connectdata;
struct easy_pollset;
enum alpnid {
ALPN_none = 0,
@ -199,8 +200,8 @@ CURLcode Curl_resolv_check(struct Curl_easy *data,
#else
#define Curl_resolv_check(x,y) CURLE_NOT_BUILT_IN
#endif
int Curl_resolv_getsock(struct Curl_easy *data,
curl_socket_t *socks);
CURLcode Curl_resolv_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
CURLcode Curl_resolver_error(struct Curl_easy *data);

View file

@ -137,10 +137,10 @@ const struct Curl_handler Curl_handler_http = {
Curl_http_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
Curl_http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
Curl_http_do_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
Curl_http_write_resp, /* write_resp */
Curl_http_write_resp_hd, /* write_resp_hd */
@ -167,10 +167,10 @@ const struct Curl_handler Curl_handler_https = {
Curl_http_connect, /* connect_it */
NULL, /* connecting */
ZERO_NULL, /* doing */
NULL, /* proto_getsock */
Curl_http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
NULL, /* proto_pollset */
Curl_http_do_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
Curl_http_write_resp, /* write_resp */
Curl_http_write_resp_hd, /* write_resp_hd */
@ -1524,14 +1524,12 @@ CURLcode Curl_http_connect(struct Curl_easy *data, bool *done)
/* this returns the socket to wait for in the DO and DOING state for the multi
interface and then we are always _sending_ a request and thus we wait for
the single socket to become writable only */
int Curl_http_getsock_do(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks)
CURLcode Curl_http_do_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
/* write mode */
(void)conn;
socks[0] = Curl_conn_get_socket(data, FIRSTSOCKET);
return GETSOCK_WRITESOCK(0);
curl_socket_t sock = Curl_conn_get_socket(data, FIRSTSOCKET);
return Curl_pollset_add_out(data, ps, sock);
}
/*

View file

@ -115,8 +115,8 @@ CURLcode Curl_http_setup_conn(struct Curl_easy *data,
CURLcode Curl_http(struct Curl_easy *data, bool *done);
CURLcode Curl_http_done(struct Curl_easy *data, CURLcode, bool premature);
CURLcode Curl_http_connect(struct Curl_easy *data, bool *done);
int Curl_http_getsock_do(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks);
CURLcode Curl_http_do_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
CURLcode Curl_http_write_resp(struct Curl_easy *data,
const char *buf, size_t blen,
bool is_eos);

View file

@ -2465,17 +2465,18 @@ out:
return result;
}
static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_h2_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_h2_ctx *ctx = cf->ctx;
struct cf_call_data save;
curl_socket_t sock;
bool want_recv, want_send;
CURLcode result = CURLE_OK;
if(!ctx->h2)
return;
return CURLE_OK;
sock = Curl_conn_cf_get_socket(cf, data);
Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
@ -2493,7 +2494,7 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
(!c_exhaust && nghttp2_session_want_write(ctx->h2)) ||
!Curl_bufq_is_empty(&ctx->outbufq);
Curl_pollset_set(data, ps, sock, want_recv, want_send);
result = Curl_pollset_set(data, ps, sock, want_recv, want_send);
CF_DATA_RESTORE(cf, save);
}
else if(ctx->sent_goaway && !cf->shutdown) {
@ -2502,9 +2503,10 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
want_send = nghttp2_session_want_write(ctx->h2) ||
!Curl_bufq_is_empty(&ctx->outbufq);
want_recv = nghttp2_session_want_read(ctx->h2);
Curl_pollset_set(data, ps, sock, want_recv, want_send);
result = Curl_pollset_set(data, ps, sock, want_recv, want_send);
CF_DATA_RESTORE(cf, save);
}
return result;
}
static CURLcode cf_h2_connect(struct Curl_cfilter *cf,

View file

@ -157,8 +157,8 @@ static CURLcode imap_connect(struct Curl_easy *data, bool *done);
static CURLcode imap_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead);
static CURLcode imap_multi_statemach(struct Curl_easy *data, bool *done);
static int imap_getsock(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks);
static CURLcode imap_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode imap_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode imap_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
@ -196,10 +196,10 @@ const struct Curl_handler Curl_handler_imap = {
imap_connect, /* connect_it */
imap_multi_statemach, /* connecting */
imap_doing, /* doing */
imap_getsock, /* proto_getsock */
imap_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
imap_pollset, /* proto_pollset */
imap_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
imap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -227,10 +227,10 @@ const struct Curl_handler Curl_handler_imaps = {
imap_connect, /* connect_it */
imap_multi_statemach, /* connecting */
imap_doing, /* doing */
imap_getsock, /* proto_getsock */
imap_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
imap_pollset, /* proto_pollset */
imap_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
imap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -1560,13 +1560,12 @@ static CURLcode imap_block_statemach(struct Curl_easy *data,
}
/* For the IMAP "protocol connect" and "doing" phases only */
static int imap_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *socks)
static CURLcode imap_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct imap_conn *imapc = Curl_conn_meta_get(conn, CURL_META_IMAP_CONN);
return imapc ?
Curl_pp_getsock(data, &imapc->pp, socks) : GETSOCK_BLANK;
struct imap_conn *imapc =
Curl_conn_meta_get(data->conn, CURL_META_IMAP_CONN);
return imapc ? Curl_pp_pollset(data, &imapc->pp, ps) : CURLE_OK;
}
/***********************************************************************

View file

@ -177,10 +177,10 @@ const struct Curl_handler Curl_handler_ldap = {
ZERO_NULL, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -207,10 +207,10 @@ const struct Curl_handler Curl_handler_ldaps = {
ZERO_NULL, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */

View file

@ -107,8 +107,8 @@ static CURLcode mqtt_do(struct Curl_easy *data, bool *done);
static CURLcode mqtt_done(struct Curl_easy *data,
CURLcode status, bool premature);
static CURLcode mqtt_doing(struct Curl_easy *data, bool *done);
static int mqtt_getsock(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *sock);
static CURLcode mqtt_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode mqtt_setup_conn(struct Curl_easy *data,
struct connectdata *conn);
@ -125,10 +125,10 @@ const struct Curl_handler Curl_handler_mqtt = {
ZERO_NULL, /* connect_it */
ZERO_NULL, /* connecting */
mqtt_doing, /* doing */
ZERO_NULL, /* proto_getsock */
mqtt_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
mqtt_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -213,13 +213,10 @@ static CURLcode mqtt_send(struct Curl_easy *data,
/* Generic function called by the multi interface to figure out what socket(s)
to wait for and for what actions during the DOING and PROTOCONNECT
states */
static int mqtt_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *sock)
static CURLcode mqtt_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
(void)data;
sock[0] = conn->sock[FIRSTSOCKET];
return GETSOCK_READSOCK(FIRSTSOCKET);
return Curl_pollset_add_in(data, ps, data->conn->sock[FIRSTSOCKET]);
}
static int mqtt_encode_len(char *buf, size_t len)

View file

@ -907,118 +907,103 @@ void Curl_attach_connection(struct Curl_easy *data,
conn->handler->attach(data, conn);
}
static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
static CURLcode mstate_connecting_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct connectdata *conn = data->conn;
curl_socket_t sockfd;
if(!conn)
return GETSOCK_BLANK;
sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
if(sockfd != CURL_SOCKET_BAD) {
/* Default is to wait to something from the server */
socks[0] = sockfd;
return GETSOCK_READSOCK(0);
if(data->conn) {
curl_socket_t sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
if(sockfd != CURL_SOCKET_BAD) {
/* Default is to wait to something from the server */
return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0);
}
}
return GETSOCK_BLANK;
return CURLE_OK;
}
static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
static CURLcode mstate_protocol_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct connectdata *conn = data->conn;
curl_socket_t sockfd;
if(!conn)
return GETSOCK_BLANK;
if(conn->handler->proto_getsock)
return conn->handler->proto_getsock(data, conn, socks);
sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
if(sockfd != CURL_SOCKET_BAD) {
/* Default is to wait to something from the server */
socks[0] = sockfd;
return GETSOCK_READSOCK(0);
if(data->conn) {
curl_socket_t sockfd;
if(data->conn->handler->proto_pollset)
return data->conn->handler->proto_pollset(data, ps);
sockfd = Curl_conn_get_socket(data, FIRSTSOCKET);
if(sockfd != CURL_SOCKET_BAD) {
/* Default is to wait to something from the server */
return Curl_pollset_change(data, ps, sockfd, CURL_POLL_IN, 0);
}
}
return GETSOCK_BLANK;
return CURLE_OK;
}
static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
static CURLcode mstate_do_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct connectdata *conn = data->conn;
if(!conn)
return GETSOCK_BLANK;
if(conn->handler->domore_getsock)
return conn->handler->domore_getsock(data, conn, socks);
else if(conn->sockfd != CURL_SOCKET_BAD) {
/* Default is that we want to send something to the server */
socks[0] = conn->sockfd;
return GETSOCK_WRITESOCK(0);
if(data->conn) {
if(data->conn->handler->doing_pollset)
return data->conn->handler->doing_pollset(data, ps);
else if(conn->sockfd != CURL_SOCKET_BAD) {
/* Default is that we want to send something to the server */
return Curl_pollset_add_out(data, ps, conn->sockfd);
}
}
return GETSOCK_BLANK;
return CURLE_OK;
}
static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
static CURLcode mstate_domore_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct connectdata *conn = data->conn;
if(!conn)
return GETSOCK_BLANK;
if(conn->handler->doing_getsock)
return conn->handler->doing_getsock(data, conn, socks);
else if(conn->sockfd != CURL_SOCKET_BAD) {
/* Default is that we want to send something to the server */
socks[0] = conn->sockfd;
return GETSOCK_WRITESOCK(0);
if(data->conn) {
if(data->conn->handler->domore_pollset)
return data->conn->handler->domore_pollset(data, ps);
else if(data->conn->sockfd != CURL_SOCKET_BAD) {
/* Default is that we want to send something to the server */
return Curl_pollset_add_out(data, ps, data->conn->sockfd);
}
}
return GETSOCK_BLANK;
return CURLE_OK;
}
static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
static CURLcode mstate_perform_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct connectdata *conn = data->conn;
if(!conn)
return GETSOCK_BLANK;
else if(conn->handler->perform_getsock)
return conn->handler->perform_getsock(data, conn, sock);
if(!data->conn)
return CURLE_OK;
else if(data->conn->handler->perform_pollset)
return data->conn->handler->perform_pollset(data, ps);
else {
/* Default is to obey the data->req.keepon flags for send/recv */
int bitmap = GETSOCK_BLANK;
unsigned sockindex = 0;
CURLcode result = CURLE_OK;
if(CURL_WANT_RECV(data)) {
DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
bitmap |= GETSOCK_READSOCK(sockindex);
sock[sockindex] = conn->sockfd;
DEBUGASSERT(data->conn->sockfd != CURL_SOCKET_BAD);
result = Curl_pollset_add_in(data, ps, data->conn->sockfd);
}
if(Curl_req_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);
if(!result && Curl_req_want_send(data)) {
DEBUGASSERT(data->conn->writesockfd != CURL_SOCKET_BAD);
result = Curl_pollset_add_out(data, ps, data->conn->writesockfd);
}
return bitmap;
return result;
}
}
/* Initializes `poll_set` with the current socket poll actions needed
* for transfer `data`. */
void Curl_multi_getsock(struct Curl_easy *data,
struct easy_pollset *ps,
const char *caller)
CURLMcode Curl_multi_pollset(struct Curl_easy *data,
struct easy_pollset *ps,
const char *caller)
{
CURLMcode mresult = CURLM_OK;
CURLcode result = CURLE_OK;
bool expect_sockets = TRUE;
/* If the transfer has no connection, this is fine. Happens when
called via curl_multi_remove_handle() => Curl_multi_ev_assess() =>
Curl_multi_getsock(). */
Curl_pollset_reset(data, ps);
Curl_multi_pollset(). */
Curl_pollset_reset(ps);
if(!data->conn)
return;
return CURLM_OK;
switch(data->mstate) {
case MSTATE_INIT:
@ -1030,7 +1015,7 @@ void Curl_multi_getsock(struct Curl_easy *data,
break;
case MSTATE_RESOLVING:
Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
result = Curl_resolv_pollset(data, ps);
/* connection filters are not involved in this phase. It's ok if we get no
* sockets to wait for. Resolving can wake up from other sources. */
expect_sockets = FALSE;
@ -1038,31 +1023,36 @@ void Curl_multi_getsock(struct Curl_easy *data,
case MSTATE_CONNECTING:
case MSTATE_TUNNELING:
Curl_pollset_add_socks(data, ps, connecting_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
result = mstate_connecting_pollset(data, ps);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_PROTOCONNECT:
case MSTATE_PROTOCONNECTING:
Curl_pollset_add_socks(data, ps, protocol_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
result = mstate_protocol_pollset(data, ps);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_DO:
case MSTATE_DOING:
Curl_pollset_add_socks(data, ps, doing_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
result = mstate_do_pollset(data, ps);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_DOING_MORE:
Curl_pollset_add_socks(data, ps, domore_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
result = mstate_domore_pollset(data, ps);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_DID: /* same as PERFORMING in regard to polling */
case MSTATE_PERFORMING:
Curl_pollset_add_socks(data, ps, perform_getsock);
Curl_conn_adjust_pollset(data, data->conn, ps);
result = mstate_perform_pollset(data, ps);
if(!result)
result = Curl_conn_adjust_pollset(data, data->conn, ps);
break;
case MSTATE_RATELIMITING:
@ -1084,6 +1074,15 @@ void Curl_multi_getsock(struct Curl_easy *data,
break;
}
if(result) {
if(result == CURLE_OUT_OF_MEMORY)
mresult = CURLM_OUT_OF_MEMORY;
else {
failf(data, "error determining pollset: %d", result);
mresult = CURLM_INTERNAL_ERROR;
}
goto out;
}
/* Unblocked and waiting to receive with buffered input.
* Make transfer run again at next opportunity. */
@ -1097,7 +1096,7 @@ void Curl_multi_getsock(struct Curl_easy *data,
Curl_multi_mark_dirty(data);
}
switch(ps->num) {
switch(ps->n) {
case 0:
CURL_TRC_M(data, "%s pollset[], timeouts=%zu, paused %d/%d (r/w)",
caller, Curl_llist_count(&data->state.timeoutlist),
@ -1124,10 +1123,10 @@ void Curl_multi_getsock(struct Curl_easy *data,
break;
default:
CURL_TRC_M(data, "%s pollset[fds=%u], timeouts=%zu",
caller, ps->num, Curl_llist_count(&data->state.timeoutlist));
caller, ps->n, Curl_llist_count(&data->state.timeoutlist));
break;
}
if(expect_sockets && !ps->num && data->multi &&
if(expect_sockets && !ps->n && data->multi &&
!Curl_uint_bset_contains(&data->multi->dirty, data->mid) &&
!Curl_llist_count(&data->state.timeoutlist) &&
!Curl_cwriter_is_paused(data) && !Curl_creader_is_paused(data) &&
@ -1140,6 +1139,8 @@ void Curl_multi_getsock(struct Curl_easy *data,
infof(data, "WARNING: no socket in pollset or timer, transfer may stall!");
DEBUGASSERT(0);
}
out:
return mresult;
}
CURLMcode curl_multi_fdset(CURLM *m,
@ -1151,6 +1152,7 @@ CURLMcode curl_multi_fdset(CURLM *m,
and then we must make sure that is done. */
int this_max_fd = -1;
struct Curl_multi *multi = m;
struct easy_pollset ps;
unsigned int i, mid;
(void)exc_fd_set; /* not used */
@ -1160,18 +1162,18 @@ CURLMcode curl_multi_fdset(CURLM *m,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
Curl_pollset_init(&ps);
if(Curl_uint_bset_first(&multi->process, &mid)) {
do {
struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
struct easy_pollset ps;
if(!data) {
DEBUGASSERT(0);
continue;
}
Curl_multi_getsock(data, &ps, "curl_multi_fdset");
for(i = 0; i < ps.num; i++) {
Curl_multi_pollset(data, &ps, "curl_multi_fdset");
for(i = 0; i < ps.n; i++) {
if(!FDSET_SOCK(ps.sockets[i]))
/* pretend it does not exist */
continue;
@ -1197,6 +1199,7 @@ CURLMcode curl_multi_fdset(CURLM *m,
read_fd_set, write_fd_set, &this_max_fd);
*max_fd = this_max_fd;
Curl_pollset_cleanup(&ps);
return CURLM_OK;
}
@ -1209,6 +1212,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
struct Curl_waitfds cwfds;
CURLMcode result = CURLM_OK;
struct Curl_multi *multi = m;
struct easy_pollset ps;
unsigned int need = 0, mid;
if(!ufds && (size || !fd_count))
@ -1220,18 +1224,18 @@ CURLMcode curl_multi_waitfds(CURLM *m,
if(multi->in_callback)
return CURLM_RECURSIVE_API_CALL;
Curl_pollset_init(&ps);
Curl_waitfds_init(&cwfds, ufds, size);
if(Curl_uint_bset_first(&multi->process, &mid)) {
do {
struct Curl_easy *data = Curl_multi_get_easy(multi, mid);
struct easy_pollset ps;
if(!data) {
DEBUGASSERT(0);
Curl_uint_bset_remove(&multi->process, mid);
Curl_uint_bset_remove(&multi->dirty, mid);
continue;
}
Curl_multi_getsock(data, &ps, "curl_multi_waitfds");
Curl_multi_pollset(data, &ps, "curl_multi_waitfds");
need += Curl_waitfds_add_ps(&cwfds, &ps);
}
while(Curl_uint_bset_next(&multi->process, mid, &mid));
@ -1245,6 +1249,7 @@ CURLMcode curl_multi_waitfds(CURLM *m,
if(fd_count)
*fd_count = need;
Curl_pollset_cleanup(&ps);
return result;
}
@ -1278,6 +1283,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
struct curltime expire_time;
long timeout_internal;
int retcode = 0;
struct easy_pollset ps;
struct pollfd a_few_on_stack[NUM_POLLS_ON_STACK];
struct curl_pollfds cpfds;
unsigned int curl_nfds = 0; /* how many pfds are for curl transfers */
@ -1302,12 +1308,12 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
if(timeout_ms < 0)
return CURLM_BAD_FUNCTION_ARGUMENT;
Curl_pollset_init(&ps);
Curl_pollfds_init(&cpfds, a_few_on_stack, NUM_POLLS_ON_STACK);
/* Add the curl handles to our pollfds first */
if(Curl_uint_bset_first(&multi->process, &mid)) {
do {
struct easy_pollset ps;
data = Curl_multi_get_easy(multi, mid);
if(!data) {
DEBUGASSERT(0);
@ -1315,7 +1321,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
Curl_uint_bset_remove(&multi->dirty, mid);
continue;
}
Curl_multi_getsock(data, &ps, "multi_wait");
Curl_multi_pollset(data, &ps, "multi_wait");
if(Curl_pollfds_add_ps(&cpfds, &ps)) {
result = CURLM_OUT_OF_MEMORY;
goto out;
@ -1514,6 +1520,7 @@ static CURLMcode multi_wait(struct Curl_multi *multi,
}
out:
Curl_pollset_cleanup(&ps);
Curl_pollfds_cleanup(&cpfds);
return result;
}

View file

@ -317,7 +317,7 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
DEBUGASSERT(prev_ps);
/* Handle changes to sockets the transfer is interested in. */
for(i = 0; i < ps->num; i++) {
for(i = 0; i < ps->n; i++) {
unsigned char last_action;
bool first_time = FALSE; /* data/conn appears first time on socket */
@ -362,7 +362,7 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
entry->conn ? 1 : 0);
}
else {
for(j = 0; j < prev_ps->num; j++) {
for(j = 0; j < prev_ps->n; j++) {
if(s == prev_ps->sockets[j]) {
last_action = prev_ps->actions[j];
break;
@ -377,11 +377,11 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
}
/* Handle changes to sockets the transfer is NO LONGER interested in. */
for(i = 0; i < prev_ps->num; i++) {
for(i = 0; i < prev_ps->n; i++) {
bool stillused = FALSE;
s = prev_ps->sockets[i];
for(j = 0; j < ps->num; j++) {
for(j = 0; j < ps->n; j++) {
if(s == ps->sockets[j]) {
/* socket is still supervised */
stillused = TRUE;
@ -437,15 +437,19 @@ static CURLMcode mev_pollset_diff(struct Curl_multi *multi,
} /* for loop over num */
/* Remember for next time */
memcpy(prev_ps, ps, sizeof(*prev_ps));
Curl_pollset_move(prev_ps, ps);
return CURLM_OK;
}
static void mev_pollset_dtor(void *key, size_t klen, void *entry)
{
struct easy_pollset *ps = entry;
(void)key;
(void)klen;
free(entry);
if(ps) {
Curl_pollset_cleanup(ps);
free(ps);
}
}
static struct easy_pollset*
@ -453,7 +457,7 @@ mev_add_new_conn_pollset(struct connectdata *conn)
{
struct easy_pollset *ps;
ps = calloc(1, sizeof(*ps));
ps = Curl_pollset_create();
if(!ps)
return NULL;
if(Curl_conn_meta_set(conn, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor))
@ -466,7 +470,7 @@ mev_add_new_xfer_pollset(struct Curl_easy *data)
{
struct easy_pollset *ps;
ps = calloc(1, sizeof(*ps));
ps = Curl_pollset_create();
if(!ps)
return NULL;
if(Curl_meta_set(data, CURL_META_MEV_POLLSET, ps, mev_pollset_dtor))
@ -486,42 +490,47 @@ mev_get_last_pollset(struct Curl_easy *data,
return NULL;
}
static void mev_init_cur_pollset(struct easy_pollset *ps,
struct Curl_easy *data,
struct connectdata *conn)
{
memset(ps, 0, sizeof(*ps));
if(conn)
Curl_conn_adjust_pollset(data, conn, ps);
else if(data)
Curl_multi_getsock(data, ps, "ev assess");
}
static CURLMcode mev_assess(struct Curl_multi *multi,
struct Curl_easy *data,
struct connectdata *conn)
{
if(multi && multi->socket_cb) {
struct easy_pollset ps, *last_ps;
struct easy_pollset ps, *last_ps;
CURLMcode res = CURLM_OK;
mev_init_cur_pollset(&ps, data, conn);
last_ps = mev_get_last_pollset(data, conn);
if(!multi || !multi->socket_cb)
return CURLM_OK;
if(!last_ps && ps.num) {
if(conn)
last_ps = mev_add_new_conn_pollset(conn);
else
last_ps = mev_add_new_xfer_pollset(data);
if(!last_ps)
return CURLM_OUT_OF_MEMORY;
Curl_pollset_init(&ps);
if(conn) {
CURLcode r = Curl_conn_adjust_pollset(data, conn, &ps);
if(r) {
res = (r == CURLE_OUT_OF_MEMORY) ?
CURLM_OUT_OF_MEMORY : CURLM_INTERNAL_ERROR;
goto out;
}
if(last_ps)
return mev_pollset_diff(multi, data, conn, &ps, last_ps);
else
DEBUGASSERT(!ps.num);
}
return CURLM_OK;
else if(data)
Curl_multi_pollset(data, &ps, "ev assess");
last_ps = mev_get_last_pollset(data, conn);
if(!last_ps && ps.n) {
if(conn)
last_ps = mev_add_new_conn_pollset(conn);
else
last_ps = mev_add_new_xfer_pollset(data);
if(!last_ps) {
res = CURLM_OUT_OF_MEMORY;
goto out;
}
}
if(last_ps)
res = mev_pollset_diff(multi, data, conn, &ps, last_ps);
else
DEBUGASSERT(!ps.n);
out:
Curl_pollset_cleanup(&ps);
return res;
}
CURLMcode Curl_multi_ev_assess_xfer(struct Curl_multi *multi,

View file

@ -72,12 +72,6 @@ typedef enum {
MSTATE_LAST /* 18 - not a true state, never use this */
} CURLMstate;
/* we support N sockets per easy handle. Set the corresponding bit to what
action we should wait for */
#define MAX_SOCKSPEREASYHANDLE 5
#define GETSOCK_READABLE (0x00ff)
#define GETSOCK_WRITABLE (0xff00)
#define CURLPIPE_ANY (CURLPIPE_MULTIPLEX)
#ifndef CURL_DISABLE_SOCKETPAIR

View file

@ -53,20 +53,6 @@ struct Curl_multi *Curl_multi_handle(unsigned int xfer_table_size,
size_t dnssize,
size_t sesssize);
/* the write bits start at bit 16 for the *getsock() bitmap */
#define GETSOCK_WRITEBITSTART 16
#define GETSOCK_BLANK 0 /* no bits set */
/* set the bit for the given sock number to make the bitmap for writable */
#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x)))
/* set the bit for the given sock number to make the bitmap for readable */
#define GETSOCK_READSOCK(x) (1 << (x))
/* mask for checking if read and/or write is set for index x */
#define GETSOCK_MASK_RW(x) (GETSOCK_READSOCK(x)|GETSOCK_WRITESOCK(x))
/**
* Let the multi handle know that the socket is about to be closed.
* The multi will then remove anything it knows about the socket, so
@ -86,9 +72,9 @@ CURLMcode Curl_multi_add_perform(struct Curl_multi *multi,
/* Return the value of the CURLMOPT_MAX_CONCURRENT_STREAMS option */
unsigned int Curl_multi_max_concurrent_streams(struct Curl_multi *multi);
void Curl_multi_getsock(struct Curl_easy *data,
struct easy_pollset *ps,
const char *caller);
CURLMcode Curl_multi_pollset(struct Curl_easy *data,
struct easy_pollset *ps,
const char *caller);
/**
* Borrow the transfer buffer from the multi, suitable

View file

@ -126,10 +126,10 @@ const struct Curl_handler Curl_handler_ldap = {
oldap_connect, /* connect_it */
oldap_connecting, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
oldap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -156,10 +156,10 @@ const struct Curl_handler Curl_handler_ldaps = {
oldap_connect, /* connect_it */
oldap_connecting, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
oldap_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */

View file

@ -397,19 +397,13 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
return result;
}
int Curl_pp_getsock(struct Curl_easy *data,
struct pingpong *pp, curl_socket_t *socks)
CURLcode Curl_pp_pollset(struct Curl_easy *data,
struct pingpong *pp,
struct easy_pollset *ps)
{
struct connectdata *conn = data->conn;
socks[0] = conn->sock[FIRSTSOCKET];
if(pp->sendleft) {
/* write mode */
return GETSOCK_WRITESOCK(0);
}
/* read mode */
return GETSOCK_READSOCK(0);
int flags = pp->sendleft ? CURL_POLL_OUT : CURL_POLL_IN;
return Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET],
flags, 0);
}
bool Curl_pp_needs_flush(struct Curl_easy *data,

View file

@ -147,8 +147,9 @@ CURLcode Curl_pp_flushsend(struct Curl_easy *data,
/* call this when a pingpong connection is disconnected */
CURLcode Curl_pp_disconnect(struct pingpong *pp);
int Curl_pp_getsock(struct Curl_easy *data, struct pingpong *pp,
curl_socket_t *socks);
CURLcode Curl_pp_pollset(struct Curl_easy *data,
struct pingpong *pp,
struct easy_pollset *ps);
/***********************************************************************

View file

@ -153,8 +153,8 @@ static CURLcode pop3_connect(struct Curl_easy *data, bool *done);
static CURLcode pop3_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead);
static CURLcode pop3_multi_statemach(struct Curl_easy *data, bool *done);
static int pop3_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
static CURLcode pop3_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode pop3_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode pop3_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
@ -186,10 +186,10 @@ const struct Curl_handler Curl_handler_pop3 = {
pop3_connect, /* connect_it */
pop3_multi_statemach, /* connecting */
pop3_doing, /* doing */
pop3_getsock, /* proto_getsock */
pop3_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
pop3_pollset, /* proto_pollset */
pop3_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
pop3_disconnect, /* disconnect */
pop3_write, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -217,10 +217,10 @@ const struct Curl_handler Curl_handler_pop3s = {
pop3_connect, /* connect_it */
pop3_multi_statemach, /* connecting */
pop3_doing, /* doing */
pop3_getsock, /* proto_getsock */
pop3_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
pop3_pollset, /* proto_pollset */
pop3_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
pop3_disconnect, /* disconnect */
pop3_write, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -1269,13 +1269,12 @@ static CURLcode pop3_block_statemach(struct Curl_easy *data,
}
/* For the POP3 "protocol connect" and "doing" phases only */
static int pop3_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks)
static CURLcode pop3_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct pop3_conn *pop3c = Curl_conn_meta_get(conn, CURL_META_POP3_CONN);
if(pop3c)
return Curl_pp_getsock(data, &pop3c->pp, socks);
return GETSOCK_BLANK;
struct pop3_conn *pop3c =
Curl_conn_meta_get(data->conn, CURL_META_POP3_CONN);
return pop3c ? Curl_pp_pollset(data, &pop3c->pp, ps) : CURLE_OK;
}
/***********************************************************************

View file

@ -83,8 +83,8 @@ struct RTSP {
static CURLcode rtsp_do(struct Curl_easy *data, bool *done);
static CURLcode rtsp_done(struct Curl_easy *data, CURLcode, bool premature);
static CURLcode rtsp_connect(struct Curl_easy *data, bool *done);
static int rtsp_getsock_do(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
static CURLcode rtsp_do_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
/*
* Parse and write out an RTSP response.
@ -110,13 +110,11 @@ static unsigned int rtsp_conncheck(struct Curl_easy *data,
/* this returns the socket to wait for in the DO and DOING state for the multi
interface and then we are always _sending_ a request and thus we wait for
the single socket to become writable only */
static int rtsp_getsock_do(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks)
static CURLcode rtsp_do_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
/* write mode */
(void)data;
socks[0] = conn->sock[FIRSTSOCKET];
return GETSOCK_WRITESOCK(0);
return Curl_pollset_add_out(data, ps, data->conn->sock[FIRSTSOCKET]);
}
static
@ -137,10 +135,10 @@ const struct Curl_handler Curl_handler_rtsp = {
rtsp_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
rtsp_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
rtsp_do_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
rtsp_rtp_write_resp, /* write_resp */
ZERO_NULL, /* write_resp_hd */

View file

@ -41,6 +41,7 @@
#include "urldata.h"
#include "connect.h"
#include "select.h"
#include "curl_trc.h"
#include "curlx/timediff.h"
#include "curlx/wait.h"
#include "curlx/warnless.h"
@ -423,7 +424,7 @@ CURLcode Curl_pollfds_add_ps(struct curl_pollfds *cpfds,
DEBUGASSERT(cpfds);
DEBUGASSERT(ps);
for(i = 0; i < ps->num; i++) {
for(i = 0; i < ps->n; i++) {
short events = 0;
if(ps->actions[i] & CURL_POLL_IN)
events |= POLLIN;
@ -481,7 +482,7 @@ unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds,
DEBUGASSERT(cwfds);
DEBUGASSERT(ps);
for(i = 0; i < ps->num; i++) {
for(i = 0; i < ps->n; i++) {
short events = 0;
if(ps->actions[i] & CURL_POLL_IN)
events |= CURL_WAIT_POLLIN;
@ -492,3 +493,233 @@ unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds,
}
return need;
}
void Curl_pollset_reset(struct easy_pollset *ps)
{
unsigned int i;
ps->n = 0;
#ifdef DEBUGBUILD
DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
#endif
DEBUGASSERT(ps->count);
for(i = 0; i < ps->count; i++)
ps->sockets[i] = CURL_SOCKET_BAD;
memset(ps->actions, 0, ps->count * sizeof(ps->actions[0]));
}
void Curl_pollset_init(struct easy_pollset *ps)
{
#ifdef DEBUGBUILD
ps->init = CURL_EASY_POLLSET_MAGIC;
#endif
ps->sockets = ps->def_sockets;
ps->actions = ps->def_actions;
ps->count = CURL_ARRAYSIZE(ps->def_sockets);
ps->n = 0;
Curl_pollset_reset(ps);
}
struct easy_pollset *Curl_pollset_create(void)
{
struct easy_pollset *ps = calloc(1, sizeof(*ps));
if(ps)
Curl_pollset_init(ps);
return ps;
}
void Curl_pollset_cleanup(struct easy_pollset *ps)
{
#ifdef DEBUGBUILD
DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
#endif
if(ps->sockets != ps->def_sockets) {
free(ps->sockets);
ps->sockets = ps->def_sockets;
}
if(ps->actions != ps->def_actions) {
free(ps->actions);
ps->actions = ps->def_actions;
}
ps->count = CURL_ARRAYSIZE(ps->def_sockets);
Curl_pollset_reset(ps);
}
void Curl_pollset_move(struct easy_pollset *to, struct easy_pollset *from)
{
Curl_pollset_cleanup(to); /* deallocate anything in to */
if(from->sockets != from->def_sockets) {
DEBUGASSERT(from->actions != from->def_actions);
to->sockets = from->sockets;
to->actions = from->actions;
to->count = from->count;
to->n = from->n;
Curl_pollset_init(from);
}
else {
DEBUGASSERT(to->sockets == to->def_sockets);
DEBUGASSERT(to->actions == to->def_actions);
memcpy(to->sockets, from->sockets, to->count * sizeof(to->sockets[0]));
memcpy(to->actions, from->actions, to->count * sizeof(to->actions[0]));
to->n = from->n;
Curl_pollset_init(from);
}
}
/**
*
*/
CURLcode Curl_pollset_change(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
int add_flags, int remove_flags)
{
unsigned int i;
#ifdef DEBUGBUILD
DEBUGASSERT(ps->init == CURL_EASY_POLLSET_MAGIC);
#endif
(void)data;
DEBUGASSERT(VALID_SOCK(sock));
if(!VALID_SOCK(sock))
return CURLE_BAD_FUNCTION_ARGUMENT;
DEBUGASSERT(add_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
DEBUGASSERT(remove_flags <= (CURL_POLL_IN|CURL_POLL_OUT));
DEBUGASSERT((add_flags&remove_flags) == 0); /* no overlap */
for(i = 0; i < ps->n; ++i) {
if(ps->sockets[i] == sock) {
ps->actions[i] &= (unsigned char)(~remove_flags);
ps->actions[i] |= (unsigned char)add_flags;
/* all gone? remove socket */
if(!ps->actions[i]) {
if((i + 1) < ps->n) {
memmove(&ps->sockets[i], &ps->sockets[i + 1],
(ps->n - (i + 1)) * sizeof(ps->sockets[0]));
memmove(&ps->actions[i], &ps->actions[i + 1],
(ps->n - (i + 1)) * sizeof(ps->actions[0]));
}
--ps->n;
}
return CURLE_OK;
}
}
/* not present */
if(add_flags) {
if(i >= ps->count) { /* need to grow */
unsigned int new_count = CURLMAX(ps->count * 2, 8);
curl_socket_t *nsockets;
unsigned char *nactions;
CURL_TRC_M(data, "growing pollset capacity from %u to %u",
ps->count, new_count);
if(new_count <= ps->count)
return CURLE_OUT_OF_MEMORY;
nsockets = calloc(new_count, sizeof(nsockets[0]));
if(!nsockets)
return CURLE_OUT_OF_MEMORY;
nactions = calloc(new_count, sizeof(nactions[0]));
if(!nactions) {
free(nsockets);
return CURLE_OUT_OF_MEMORY;
}
memcpy(nsockets, ps->sockets, ps->count * sizeof(ps->sockets[0]));
memcpy(nactions, ps->actions, ps->count * sizeof(ps->actions[0]));
if(ps->sockets != ps->def_sockets)
free(ps->sockets);
ps->sockets = nsockets;
if(ps->actions != ps->def_actions)
free(ps->actions);
ps->actions = nactions;
ps->count = new_count;
}
DEBUGASSERT(i < ps->count);
if(i < ps->count) {
ps->sockets[i] = sock;
ps->actions[i] = (unsigned char)add_flags;
ps->n = i + 1;
}
}
return CURLE_OK;
}
CURLcode Curl_pollset_set(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool do_in, bool do_out)
{
return Curl_pollset_change(data, ps, sock,
(do_in ? CURL_POLL_IN : 0)|
(do_out ? CURL_POLL_OUT : 0),
(!do_in ? CURL_POLL_IN : 0)|
(!do_out ? CURL_POLL_OUT : 0));
}
int Curl_pollset_poll(struct Curl_easy *data,
struct easy_pollset *ps,
timediff_t timeout_ms)
{
struct pollfd *pfds;
unsigned int i, npfds;
int result;
(void)data;
DEBUGASSERT(data);
DEBUGASSERT(data->conn);
if(!ps->n)
return curlx_wait_ms(timeout_ms);
pfds = calloc(ps->n, sizeof(*pfds));
if(!pfds)
return -1;
npfds = 0;
for(i = 0; i < ps->n; ++i) {
short events = 0;
if(ps->actions[i] & CURL_POLL_IN) {
events |= POLLIN;
}
if(ps->actions[i] & CURL_POLL_OUT) {
events |= POLLOUT;
}
if(events) {
pfds[npfds].fd = ps->sockets[i];
pfds[npfds].events = events;
++npfds;
}
}
result = Curl_poll(pfds, npfds, timeout_ms);
free(pfds);
return result;
}
void Curl_pollset_check(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool *pwant_read, bool *pwant_write)
{
unsigned int i;
(void)data;
DEBUGASSERT(VALID_SOCK(sock));
for(i = 0; i < ps->n; ++i) {
if(ps->sockets[i] == sock) {
*pwant_read = !!(ps->actions[i] & CURL_POLL_IN);
*pwant_write = !!(ps->actions[i] & CURL_POLL_OUT);
return;
}
}
*pwant_read = *pwant_write = FALSE;
}
bool Curl_pollset_want_read(struct Curl_easy *data,
struct easy_pollset *ps,
curl_socket_t sock)
{
unsigned int i;
(void)data;
for(i = 0; i < ps->n; ++i) {
if((ps->sockets[i] == sock) && (ps->actions[i] & CURL_POLL_IN))
return TRUE;
}
return FALSE;
}

View file

@ -110,6 +110,90 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms);
} while(0)
#endif
/* Keep the sockets to poll for an easy handle.
* `actions` are bitmaps of CURL_POLL_IN and CURL_POLL_OUT.
* Starts with small capacity, grows on demand.
*/
#define EZ_POLLSET_DEF_COUNT 2
struct easy_pollset {
curl_socket_t *sockets;
unsigned char *actions;
unsigned int n;
unsigned int count;
#ifdef DEBUGBUILD
int init;
#endif
curl_socket_t def_sockets[EZ_POLLSET_DEF_COUNT];
unsigned char def_actions[EZ_POLLSET_DEF_COUNT];
};
#ifdef DEBUGBUILD
#define CURL_EASY_POLLSET_MAGIC 0x7a657370
#endif
/* allocate and initialise */
struct easy_pollset *Curl_pollset_create(void);
/* Initialize before first use */
void Curl_pollset_init(struct easy_pollset *ps);
/* Free any allocated resources */
void Curl_pollset_cleanup(struct easy_pollset *ps);
/* Reset to an empty pollset */
void Curl_pollset_reset(struct easy_pollset *ps);
/* Move pollset from to pollset to, replacing all in to,
* leaving from empty. */
void Curl_pollset_move(struct easy_pollset *to, struct easy_pollset *from);
/* Change the poll flags (CURL_POLL_IN/CURL_POLL_OUT) to the poll set for
* socket `sock`. If the socket is not already part of the poll set, it
* will be added.
* If the socket is present and all poll flags are cleared, it will be removed.
*/
CURLcode Curl_pollset_change(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
int add_flags, int remove_flags);
CURLcode Curl_pollset_set(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool do_in, bool do_out);
#define Curl_pollset_add_in(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), CURL_POLL_IN, 0)
#define Curl_pollset_add_out(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), CURL_POLL_OUT, 0)
#define Curl_pollset_add_inout(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), \
CURL_POLL_IN|CURL_POLL_OUT, 0)
#define Curl_pollset_set_in_only(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), \
CURL_POLL_IN, CURL_POLL_OUT)
#define Curl_pollset_set_out_only(data, ps, sock) \
Curl_pollset_change((data), (ps), (sock), \
CURL_POLL_OUT, CURL_POLL_IN)
/* return < = on error, 0 on timeout or how many sockets are ready */
int Curl_pollset_poll(struct Curl_easy *data,
struct easy_pollset *ps,
timediff_t timeout_ms);
/**
* Check if the pollset, as is, wants to read and/or write regarding
* the given socket.
*/
void Curl_pollset_check(struct Curl_easy *data,
struct easy_pollset *ps, curl_socket_t sock,
bool *pwant_read, bool *pwant_write);
/**
* Return TRUE if the pollset contains socket with CURL_POLL_IN.
*/
bool Curl_pollset_want_read(struct Curl_easy *data,
struct easy_pollset *ps,
curl_socket_t sock);
struct curl_pollfds {
struct pollfd *pfds;
unsigned int n;

View file

@ -36,6 +36,7 @@
#include "connect.h"
#include "progress.h"
#include "transfer.h"
#include "select.h"
#include "vtls/vtls.h"
#include "curl_ntlm_core.h"
#include "escape.h"
@ -298,8 +299,8 @@ static CURLcode smb_connect(struct Curl_easy *data, bool *done);
static CURLcode smb_connection_state(struct Curl_easy *data, bool *done);
static CURLcode smb_do(struct Curl_easy *data, bool *done);
static CURLcode smb_request_state(struct Curl_easy *data, bool *done);
static int smb_getsock(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks);
static CURLcode smb_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode smb_parse_url_path(struct Curl_easy *data,
struct smb_conn *smbc,
struct smb_request *req);
@ -316,10 +317,10 @@ const struct Curl_handler Curl_handler_smb = {
smb_connect, /* connect_it */
smb_connection_state, /* connecting */
smb_request_state, /* doing */
smb_getsock, /* proto_getsock */
smb_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smb_pollset, /* proto_pollset */
smb_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -345,10 +346,10 @@ const struct Curl_handler Curl_handler_smbs = {
smb_connect, /* connect_it */
smb_connection_state, /* connecting */
smb_request_state, /* doing */
smb_getsock, /* proto_getsock */
smb_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smb_pollset, /* proto_pollset */
smb_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -1204,12 +1205,10 @@ static CURLcode smb_request_state(struct Curl_easy *data, bool *done)
return CURLE_OK;
}
static int smb_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks)
static CURLcode smb_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
(void)data;
socks[0] = conn->sock[FIRSTSOCKET];
return GETSOCK_READSOCK(0) | GETSOCK_WRITESOCK(0);
return Curl_pollset_add_inout(data, ps, data->conn->sock[FIRSTSOCKET]);
}
static CURLcode smb_do(struct Curl_easy *data, bool *done)

View file

@ -157,8 +157,8 @@ static CURLcode smtp_connect(struct Curl_easy *data, bool *done);
static CURLcode smtp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead);
static CURLcode smtp_multi_statemach(struct Curl_easy *data, bool *done);
static int smtp_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
static CURLcode smtp_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode smtp_doing(struct Curl_easy *data, bool *dophase_done);
static CURLcode smtp_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
@ -192,10 +192,10 @@ const struct Curl_handler Curl_handler_smtp = {
smtp_connect, /* connect_it */
smtp_multi_statemach, /* connecting */
smtp_doing, /* doing */
smtp_getsock, /* proto_getsock */
smtp_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smtp_pollset, /* proto_pollset */
smtp_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
smtp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -223,10 +223,10 @@ const struct Curl_handler Curl_handler_smtps = {
smtp_connect, /* connect_it */
smtp_multi_statemach, /* connecting */
smtp_doing, /* doing */
smtp_getsock, /* proto_getsock */
smtp_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
smtp_pollset, /* proto_pollset */
smtp_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
smtp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -1413,12 +1413,12 @@ static CURLcode smtp_block_statemach(struct Curl_easy *data,
}
/* For the SMTP "protocol connect" and "doing" phases only */
static int smtp_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks)
static CURLcode smtp_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
struct smtp_conn *smtpc = Curl_conn_meta_get(conn, CURL_META_SMTP_CONN);
return smtpc ?
Curl_pp_getsock(data, &smtpc->pp, socks) : GETSOCK_BLANK;
struct smtp_conn *smtpc =
Curl_conn_meta_get(data->conn, CURL_META_SMTP_CONN);
return smtpc ? Curl_pp_pollset(data, &smtpc->pp, ps) : CURLE_OK;
}
/***********************************************************************

View file

@ -1161,11 +1161,12 @@ static CURLcode socks_proxy_cf_connect(struct Curl_cfilter *cf,
return result;
}
static void socks_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode socks_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct socks_state *sx = cf->ctx;
CURLcode result = CURLE_OK;
if(!cf->connected && sx) {
/* If we are not connected, the filter below is and has nothing
@ -1177,13 +1178,14 @@ static void socks_cf_adjust_pollset(struct Curl_cfilter *cf,
case CONNECT_AUTH_READ:
case CONNECT_REQ_READ:
case CONNECT_REQ_READ_MORE:
Curl_pollset_set_in_only(data, ps, sock);
result = Curl_pollset_set_in_only(data, ps, sock);
break;
default:
Curl_pollset_set_out_only(data, ps, sock);
result = Curl_pollset_set_out_only(data, ps, sock);
break;
}
}
return result;
}
static void socks_proxy_cf_close(struct Curl_cfilter *cf,

View file

@ -188,10 +188,10 @@ const struct Curl_handler Curl_handler_telnet = {
ZERO_NULL, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
ZERO_NULL, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
ZERO_NULL, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */

View file

@ -160,8 +160,8 @@ static CURLcode tftp_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static CURLcode tftp_multi_statemach(struct Curl_easy *data, bool *done);
static CURLcode tftp_doing(struct Curl_easy *data, bool *dophase_done);
static int tftp_getsock(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *socks);
static CURLcode tftp_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode tftp_translate_code(tftp_error_t error);
@ -178,10 +178,10 @@ const struct Curl_handler Curl_handler_tftp = {
tftp_connect, /* connect_it */
tftp_multi_statemach, /* connecting */
tftp_doing, /* doing */
tftp_getsock, /* proto_getsock */
tftp_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
tftp_pollset, /* proto_pollset */
tftp_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -1074,19 +1074,10 @@ static CURLcode tftp_done(struct Curl_easy *data, CURLcode status,
return result;
}
/**********************************************************
*
* tftp_getsock
*
* The getsock callback
*
**********************************************************/
static int tftp_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks)
static CURLcode tftp_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
(void)data;
socks[0] = conn->sock[FIRSTSOCKET];
return GETSOCK_READSOCK(0);
return Curl_pollset_add_in(data, ps, data->conn->sock[FIRSTSOCKET]);
}
/**********************************************************

View file

@ -34,8 +34,6 @@ void Curl_init_CONNECT(struct Curl_easy *data);
CURLcode Curl_pretransfer(struct Curl_easy *data);
CURLcode Curl_sendrecv(struct Curl_easy *data, struct curltime *nowp);
int Curl_single_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
bool Curl_meets_timecondition(struct Curl_easy *data, time_t timeofdoc);

View file

@ -471,15 +471,6 @@ struct hostname {
#define FIRSTSOCKET 0
#define SECONDARYSOCKET 1
/* Polling requested by an easy handle.
* `action` is CURL_POLL_IN, CURL_POLL_OUT or CURL_POLL_INOUT.
*/
struct easy_pollset {
curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
unsigned int num;
unsigned char actions[MAX_SOCKSPEREASYHANDLE];
};
/*
* Specific protocol handler.
*/
@ -516,24 +507,24 @@ struct Curl_handler {
/* Called from the multi interface during the PROTOCONNECT phase, and it
should then return a proper fd set */
int (*proto_getsock)(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
CURLcode (*proto_pollset)(struct Curl_easy *data,
struct easy_pollset *ps);
/* Called from the multi interface during the DOING phase, and it should
then return a proper fd set */
int (*doing_getsock)(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
CURLcode (*doing_pollset)(struct Curl_easy *data,
struct easy_pollset *ps);
/* Called from the multi interface during the DO_MORE phase, and it should
then return a proper fd set */
int (*domore_getsock)(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
CURLcode (*domore_pollset)(struct Curl_easy *data,
struct easy_pollset *ps);
/* Called from the multi interface during the DO_DONE, PERFORM and
WAITPERFORM phases, and it should then return a proper fd set. Not setting
this will make libcurl use the generic default one. */
int (*perform_getsock)(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *socks);
CURLcode (*perform_pollset)(struct Curl_easy *data,
struct easy_pollset *ps);
/* This function *MAY* be set to a protocol-dependent function that is run
* by the curl_disconnect(), as a step in the disconnection. If the handler

View file

@ -898,15 +898,16 @@ static CURLcode check_and_set_expiry(struct Curl_cfilter *cf,
return CURLE_OK;
}
static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_ngtcp2_ctx *ctx = cf->ctx;
bool want_recv, want_send;
CURLcode result = CURLE_OK;
if(!ctx->qconn)
return;
return CURLE_OK;
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
if(!want_send && !Curl_bufq_is_empty(&ctx->q.sendbuf))
@ -926,9 +927,10 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
want_send = (!s_exhaust && want_send) ||
!Curl_bufq_is_empty(&ctx->q.sendbuf);
Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
result = Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
CF_DATA_RESTORE(cf, save);
}
return result;
}
static int cb_h3_stream_close(nghttp3_conn *conn, int64_t sid,

View file

@ -2266,11 +2266,12 @@ out:
return alive;
}
static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_osslq_ctx *ctx = cf->ctx;
CURLcode result = CURLE_OK;
if(!ctx->tls.ossl.ssl) {
/* NOP */
@ -2278,9 +2279,9 @@ static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
else if(!cf->connected) {
/* during handshake, transfer has not started yet. we always
* add our socket for polling if SSL wants to send/recv */
Curl_pollset_set(data, ps, ctx->q.sockfd,
SSL_net_read_desired(ctx->tls.ossl.ssl),
SSL_net_write_desired(ctx->tls.ossl.ssl));
result = Curl_pollset_set(data, ps, ctx->q.sockfd,
SSL_net_read_desired(ctx->tls.ossl.ssl),
SSL_net_write_desired(ctx->tls.ossl.ssl));
}
else {
/* once connected, we only modify the socket if it is present.
@ -2288,15 +2289,16 @@ static void cf_osslq_adjust_pollset(struct Curl_cfilter *cf,
bool want_recv, want_send;
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
if(want_recv || want_send) {
Curl_pollset_set(data, ps, ctx->q.sockfd,
SSL_net_read_desired(ctx->tls.ossl.ssl),
SSL_net_write_desired(ctx->tls.ossl.ssl));
result = Curl_pollset_set(data, ps, ctx->q.sockfd,
SSL_net_read_desired(ctx->tls.ossl.ssl),
SSL_net_write_desired(ctx->tls.ossl.ssl));
}
else if(ctx->need_recv || ctx->need_send) {
Curl_pollset_set(data, ps, ctx->q.sockfd,
ctx->need_recv, ctx->need_send);
result = Curl_pollset_set(data, ps, ctx->q.sockfd,
ctx->need_recv, ctx->need_send);
}
}
return result;
}
static CURLcode cf_osslq_query(struct Curl_cfilter *cf,

View file

@ -1142,15 +1142,16 @@ static bool stream_is_writeable(struct Curl_cfilter *cf,
ctx->qconn, (curl_uint64_t)stream->id, 1) > 0);
}
static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_quiche_ctx *ctx = cf->ctx;
bool want_recv, want_send;
CURLcode result = CURLE_OK;
if(!ctx->qconn)
return;
return CURLE_OK;
Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
if(want_recv || want_send) {
@ -1165,8 +1166,9 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
want_send = (!s_exhaust && want_send) ||
!Curl_bufq_is_empty(&ctx->q.sendbuf);
Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
result = Curl_pollset_set(data, ps, ctx->q.sockfd, want_recv, want_send);
}
return result;
}
/*

View file

@ -125,8 +125,8 @@ CURLcode sftp_perform(struct Curl_easy *data,
bool *connected,
bool *dophase_done);
static int myssh_getsock(struct Curl_easy *data,
struct connectdata *conn, curl_socket_t *sock);
static CURLcode myssh_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static void myssh_block2waitfor(struct connectdata *conn,
struct ssh_conn *sshc,
bool block);
@ -148,10 +148,10 @@ const struct Curl_handler Curl_handler_scp = {
myssh_connect, /* connect_it */
myssh_multi_statemach, /* connecting */
scp_doing, /* doing */
myssh_getsock, /* proto_getsock */
myssh_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
myssh_getsock, /* perform_getsock */
myssh_pollset, /* proto_pollset */
myssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
myssh_pollset, /* perform_pollset */
scp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -177,10 +177,10 @@ const struct Curl_handler Curl_handler_sftp = {
myssh_connect, /* connect_it */
myssh_multi_statemach, /* connecting */
sftp_doing, /* doing */
myssh_getsock, /* proto_getsock */
myssh_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
myssh_getsock, /* perform_getsock */
myssh_pollset, /* proto_pollset */
myssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
myssh_pollset, /* perform_pollset */
sftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -2390,25 +2390,19 @@ static CURLcode myssh_statemach_act(struct Curl_easy *data,
/* called by the multi interface to figure out what socket(s) to wait for and
for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
static int myssh_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *sock)
static CURLcode myssh_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
int bitmap = GETSOCK_BLANK;
(void)data;
sock[0] = conn->sock[FIRSTSOCKET];
if(conn->waitfor & KEEP_RECV)
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
if(conn->waitfor & KEEP_SEND)
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
if(!conn->waitfor)
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
DEBUGF(infof(data, "ssh_getsock -> %x", bitmap));
return bitmap;
int flags = 0;
if(data->conn->waitfor & KEEP_RECV)
flags |= CURL_POLL_IN;
if(data->conn->waitfor & KEEP_SEND)
flags |= CURL_POLL_OUT;
if(!data->conn->waitfor)
flags |= CURL_POLL_OUT;
return flags ?
Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) :
CURLE_OK;
}
static void myssh_block2waitfor(struct connectdata *conn,
@ -2437,7 +2431,7 @@ static CURLcode myssh_multi_statemach(struct Curl_easy *data,
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
bool block; /* we store the status and use that to provide a ssh_getsock()
bool block; /* we store the status and use that to provide a ssh_pollset()
implementation */
CURLcode result;

View file

@ -99,8 +99,8 @@ static CURLcode sftp_disconnect(struct Curl_easy *data,
struct connectdata *conn, bool dead);
static CURLcode sftp_perform(struct Curl_easy *data, bool *connected,
bool *dophase_done);
static int ssh_getsock(struct Curl_easy *data, struct connectdata *conn,
curl_socket_t *sock);
static CURLcode ssh_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode ssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static void ssh_attach(struct Curl_easy *data, struct connectdata *conn);
@ -119,10 +119,10 @@ const struct Curl_handler Curl_handler_scp = {
ssh_connect, /* connect_it */
ssh_multi_statemach, /* connecting */
scp_doing, /* doing */
ssh_getsock, /* proto_getsock */
ssh_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ssh_getsock, /* perform_getsock */
ssh_pollset, /* proto_pollset */
ssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ssh_pollset, /* perform_pollset */
scp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -150,10 +150,10 @@ const struct Curl_handler Curl_handler_sftp = {
ssh_connect, /* connect_it */
ssh_multi_statemach, /* connecting */
sftp_doing, /* doing */
ssh_getsock, /* proto_getsock */
ssh_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ssh_getsock, /* perform_getsock */
ssh_pollset, /* proto_pollset */
ssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ssh_pollset, /* perform_pollset */
sftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -3087,22 +3087,17 @@ static CURLcode ssh_statemachine(struct Curl_easy *data,
/* called by the multi interface to figure out what socket(s) to wait for and
for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
static int ssh_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *sock)
static CURLcode ssh_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
int bitmap = GETSOCK_BLANK;
(void)data;
sock[0] = conn->sock[FIRSTSOCKET];
if(conn->waitfor & KEEP_RECV)
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
if(conn->waitfor & KEEP_SEND)
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
return bitmap;
int flags = 0;
if(data->conn->waitfor & KEEP_RECV)
flags |= CURL_POLL_IN;
if(data->conn->waitfor & KEEP_SEND)
flags |= CURL_POLL_OUT;
return flags ?
Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) :
CURLE_OK;
}
/*
@ -3139,7 +3134,7 @@ static CURLcode ssh_multi_statemach(struct Curl_easy *data, bool *done)
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
struct SSHPROTO *sshp = Curl_meta_get(data, CURL_META_SSH_EASY);
CURLcode result = CURLE_OK;
bool block; /* we store the status and use that to provide a ssh_getsock()
bool block; /* we store the status and use that to provide a ssh_pollset()
implementation */
if(!sshc || !sshp)
return CURLE_FAILED_INIT;

View file

@ -66,9 +66,8 @@ static CURLcode wsftp_doing(struct Curl_easy *data,
static CURLcode wsftp_disconnect(struct Curl_easy *data,
struct connectdata *conn,
bool dead);
static int wssh_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *sock);
static CURLcode wssh_pollset(struct Curl_easy *data,
struct easy_pollset *ps);
static CURLcode wssh_setup_connection(struct Curl_easy *data,
struct connectdata *conn);
static void wssh_sshc_cleanup(struct ssh_conn *sshc);
@ -87,10 +86,10 @@ const struct Curl_handler Curl_handler_scp = {
wssh_connect, /* connect_it */
wssh_multi_statemach, /* connecting */
wscp_doing, /* doing */
wssh_getsock, /* proto_getsock */
wssh_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
wssh_getsock, /* perform_getsock */
wssh_pollset, /* proto_pollset */
wssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
wssh_pollset, /* perform_pollset */
wscp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -118,10 +117,10 @@ const struct Curl_handler Curl_handler_sftp = {
wssh_connect, /* connect_it */
wssh_multi_statemach, /* connecting */
wsftp_doing, /* doing */
wssh_getsock, /* proto_getsock */
wssh_getsock, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
wssh_getsock, /* perform_getsock */
wssh_pollset, /* proto_pollset */
wssh_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
wssh_pollset, /* perform_pollset */
wsftp_disconnect, /* disconnect */
ZERO_NULL, /* write_resp */
ZERO_NULL, /* write_resp_hd */
@ -932,7 +931,7 @@ static CURLcode wssh_multi_statemach(struct Curl_easy *data, bool *done)
struct connectdata *conn = data->conn;
struct ssh_conn *sshc = Curl_conn_meta_get(conn, CURL_META_SSH_CONN);
CURLcode result = CURLE_OK;
bool block; /* we store the status and use that to provide a ssh_getsock()
bool block; /* we store the status and use that to provide a ssh_pollset()
implementation */
if(!sshc)
return CURLE_FAILED_INIT;
@ -1185,21 +1184,17 @@ static CURLcode wsftp_disconnect(struct Curl_easy *data,
return result;
}
static int wssh_getsock(struct Curl_easy *data,
struct connectdata *conn,
curl_socket_t *sock)
static CURLcode wssh_pollset(struct Curl_easy *data,
struct easy_pollset *ps)
{
int bitmap = GETSOCK_BLANK;
int dir = conn->waitfor;
(void)data;
sock[0] = conn->sock[FIRSTSOCKET];
if(dir == KEEP_RECV)
bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
else if(dir == KEEP_SEND)
bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
return bitmap;
int flags = 0;
if(data->conn->waitfor & KEEP_RECV)
flags |= CURL_POLL_IN;
if(data->conn->waitfor & KEEP_SEND)
flags |= CURL_POLL_OUT;
return flags ?
Curl_pollset_change(data, ps, data->conn->sock[FIRSTSOCKET], flags, 0) :
CURLE_OK;
}
void Curl_ssh_version(char *buffer, size_t buflen)

View file

@ -503,26 +503,30 @@ void Curl_ssl_close_all(struct Curl_easy *data)
Curl_ssl->close_all(data);
}
void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps)
CURLcode Curl_ssl_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct ssl_connect_data *connssl = cf->ctx;
if(connssl->io_need) {
curl_socket_t sock = Curl_conn_cf_get_socket(cf->next, data);
CURLcode result = CURLE_OK;
if(sock != CURL_SOCKET_BAD) {
if(connssl->io_need & CURL_SSL_IO_NEED_SEND) {
Curl_pollset_set_out_only(data, ps, sock);
result = Curl_pollset_set_out_only(data, ps, sock);
CURL_TRC_CF(data, cf, "adjust_pollset, POLLOUT fd=%" FMT_SOCKET_T,
sock);
}
else {
Curl_pollset_set_in_only(data, ps, sock);
result = Curl_pollset_set_in_only(data, ps, sock);
CURL_TRC_CF(data, cf, "adjust_pollset, POLLIN fd=%" FMT_SOCKET_T,
sock);
}
}
return result;
}
return CURLE_OK;
}
/* Selects an SSL crypto engine
@ -902,13 +906,13 @@ static CURLcode multissl_connect(struct Curl_cfilter *cf,
return Curl_ssl->do_connect(cf, data, done);
}
static void multissl_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode multissl_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
if(multissl_setup(NULL))
return;
Curl_ssl->adjust_pollset(cf, data, ps);
return CURLE_OK;
return Curl_ssl->adjust_pollset(cf, data, ps);
}
static void *multissl_get_internals(struct ssl_connect_data *connssl,
@ -1545,16 +1549,18 @@ static CURLcode ssl_cf_shutdown(struct Curl_cfilter *cf,
return result;
}
static void ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode ssl_cf_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct ssl_connect_data *connssl = cf->ctx;
struct cf_call_data save;
CURLcode result;
CF_DATA_SAVE(save, cf, data);
connssl->ssl_impl->adjust_pollset(cf, data, ps);
result = connssl->ssl_impl->adjust_pollset(cf, data, ps);
CF_DATA_RESTORE(cf, save);
return result;
}
static CURLcode ssl_cf_query(struct Curl_cfilter *cf,

View file

@ -166,8 +166,8 @@ struct Curl_ssl {
/* During handshake/shutdown, adjust the pollset to include the socket
* for POLLOUT or POLLIN as needed. Mandatory. */
void (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps);
CURLcode (*adjust_pollset)(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps);
void *(*get_internals)(struct ssl_connect_data *connssl, CURLINFO info);
void (*close)(struct Curl_cfilter *cf, struct Curl_easy *data);
void (*close_all)(struct Curl_easy *data);
@ -190,8 +190,9 @@ struct Curl_ssl {
extern const struct Curl_ssl *Curl_ssl;
void Curl_ssl_adjust_pollset(struct Curl_cfilter *cf, struct Curl_easy *data,
struct easy_pollset *ps);
CURLcode Curl_ssl_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps);
/**
* Get the SSL filter below the given one or NULL if there is none.

View file

@ -1552,10 +1552,10 @@ const struct Curl_handler Curl_handler_ws = {
Curl_http_connect, /* connect_it */
ZERO_NULL, /* connecting */
ZERO_NULL, /* doing */
ZERO_NULL, /* proto_getsock */
Curl_http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
ZERO_NULL, /* proto_pollset */
Curl_http_do_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
Curl_http_write_resp, /* write_resp */
Curl_http_write_resp_hd, /* write_resp_hd */
@ -1579,10 +1579,10 @@ const struct Curl_handler Curl_handler_wss = {
Curl_http_connect, /* connect_it */
NULL, /* connecting */
ZERO_NULL, /* doing */
NULL, /* proto_getsock */
Curl_http_getsock_do, /* doing_getsock */
ZERO_NULL, /* domore_getsock */
ZERO_NULL, /* perform_getsock */
NULL, /* proto_pollset */
Curl_http_do_pollset, /* doing_pollset */
ZERO_NULL, /* domore_pollset */
ZERO_NULL, /* perform_pollset */
ZERO_NULL, /* disconnect */
Curl_http_write_resp, /* write_resp */
Curl_http_write_resp_hd, /* write_resp_hd */

View file

@ -105,8 +105,10 @@ struct test_result {
static const struct test_case *current_tc;
static struct test_result *current_tr;
static int test_idx;
struct cf_test_ctx {
int idx;
int ai_family;
int transport;
char id[16];
@ -151,13 +153,13 @@ static CURLcode cf_test_connect(struct Curl_cfilter *cf,
return CURLE_OK;
}
static void cf_test_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
static CURLcode cf_test_adjust_pollset(struct Curl_cfilter *cf,
struct Curl_easy *data,
struct easy_pollset *ps)
{
struct cf_test_ctx *ctx = cf->ctx;
/* just for testing, give one socket with events back */
(void)cf;
Curl_pollset_set(data, ps, 1, TRUE, TRUE);
return Curl_pollset_set(data, ps, ctx->idx, TRUE, TRUE);
}
static CURLcode cf_test_create(struct Curl_cfilter **pcf,
@ -196,6 +198,7 @@ static CURLcode cf_test_create(struct Curl_cfilter **pcf,
result = CURLE_OUT_OF_MEMORY;
goto out;
}
ctx->idx = test_idx++;
ctx->ai_family = ai->ai_family;
ctx->transport = transport;
ctx->started = curlx_now();