diff --git a/lib/asyn-thrdd.c b/lib/asyn-thrdd.c index 448487db8f..e70893ddc5 100644 --- a/lib/asyn-thrdd.c +++ b/lib/asyn-thrdd.c @@ -63,6 +63,7 @@ #include "url.h" #include "multiif.h" #include "curl_threads.h" +#include "select.h" #include "strdup.h" #ifdef USE_ARES diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index 162881b17e..781352432c 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -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 */ diff --git a/lib/cf-haproxy.c b/lib/cf-haproxy.c index 62ac89e819..a131da59a6 100644 --- a/lib/cf-haproxy.c +++ b/lib/cf-haproxy.c @@ -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" diff --git a/lib/cf-https-connect.c b/lib/cf-https-connect.c index f36d227b11..c62429a142 100644 --- a/lib/cf-https-connect.c +++ b/lib/cf-https-connect.c @@ -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 */ diff --git a/lib/cf-ip-happy.c b/lib/cf-ip-happy.c index 6dbb5c5fdc..f60f5bf611 100644 --- a/lib/cf-ip-happy.c +++ b/lib/cf-ip-happy.c @@ -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 */ diff --git a/lib/cfilters.c b/lib/cfilters.c index 424fc98c30..fda0367bb0 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -1099,142 +1099,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, - unsigned int bitmap, curl_socket_t *socks) -{ - if(bitmap) { - unsigned 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, - unsigned int (*socks_cb)(struct Curl_easy *data, - curl_socket_t *socks)) -{ - curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; - unsigned int bitmap; - - bitmap = 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; -} diff --git a/lib/cfilters.h b/lib/cfilters.h index 509063e1d8..3f3c230574 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -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, - unsigned int (*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. diff --git a/lib/select.c b/lib/select.c index 2353c474df..db1933e223 100644 --- a/lib/select.c +++ b/lib/select.c @@ -492,3 +492,142 @@ unsigned int Curl_waitfds_add_ps(struct Curl_waitfds *cwfds, } return need; } + +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, + unsigned int bitmap, curl_socket_t *socks) +{ + if(bitmap) { + unsigned 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, + unsigned int (*socks_cb)(struct Curl_easy *data, + curl_socket_t *socks)) +{ + curl_socket_t socks[MAX_SOCKSPEREASYHANDLE]; + unsigned int bitmap; + + bitmap = 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; +} diff --git a/lib/select.h b/lib/select.h index e9cec600f3..02257dcbea 100644 --- a/lib/select.h +++ b/lib/select.h @@ -110,6 +110,85 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, timediff_t timeout_ms); } while(0) #endif + +/* we support N sockets per easy handle. Set the corresponding bit to what + action we should wait for */ +#define MAX_SOCKSPEREASYHANDLE 16 + +/* the write bits start at bit 16 for the *getsock() bitmap */ +#define GETSOCK_WRITEBITSTART 16 + +#define GETSOCK_BLANK 0U /* no bits set */ + +/* set the bit for the given sock number to make the bitmap for writable */ +#define GETSOCK_WRITESOCK(x) (1U << (GETSOCK_WRITEBITSTART + (x))) + +/* set the bit for the given sock number to make the bitmap for readable */ +#define GETSOCK_READSOCK(x) (1U << (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)) + + +/* 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]; +}; + +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, + unsigned int (*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); + struct curl_pollfds { struct pollfd *pfds; unsigned int n; diff --git a/lib/smb.c b/lib/smb.c index f5235102b9..11b6e57ca0 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -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" diff --git a/lib/urldata.h b/lib/urldata.h index dcc76d222f..32ab44be98 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -471,34 +471,6 @@ struct hostname { #define FIRSTSOCKET 0 #define SECONDARYSOCKET 1 -/* we support N sockets per easy handle. Set the corresponding bit to what - action we should wait for */ -#define MAX_SOCKSPEREASYHANDLE 16 - -/* the write bits start at bit 16 for the *getsock() bitmap */ -#define GETSOCK_WRITEBITSTART 16 - -#define GETSOCK_BLANK 0U /* no bits set */ - -/* set the bit for the given sock number to make the bitmap for writable */ -#define GETSOCK_WRITESOCK(x) (1U << (GETSOCK_WRITEBITSTART + (x))) - -/* set the bit for the given sock number to make the bitmap for readable */ -#define GETSOCK_READSOCK(x) (1U << (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)) - - -/* 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. */