]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
transfer: adjust_pollset improvements
authorStefan Eissing <stefan@eissing.org>
Fri, 5 Jan 2024 11:28:09 +0000 (12:28 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Sun, 7 Jan 2024 13:36:25 +0000 (14:36 +0100)
- let `multi_getsock()` initialize the pollset in what the
  transfer state requires in regards to SEND/RECV
- change connection filters `adjust_pollset()` implementation
  to react on the presence of POLLIN/-OUT in the pollset and
  no longer check CURL_WANT_SEND/CURL_WANT_RECV
- cf-socket will no longer add POLLIN on its own
- http2 and http/3 filters will only do adjustments if the
  passed pollset wants to POLLIN/OUT for the transfer on
  the socket. This is similar to the HTTP/2 proxy filter
  and works in stacked filters.

Closes #12640

lib/cf-socket.c
lib/cfilters.c
lib/cfilters.h
lib/http2.c
lib/multi.c
lib/transfer.c
lib/transfer.h
lib/urldata.h
lib/vquic/curl_ngtcp2.c
lib/vquic/curl_quiche.c

index c86aa7e7c2a96996a56c9680a01e8aa9b1ccb2a9..2e985a77f30fb5f4857f9daef826873e551fc547 100644 (file)
@@ -1243,7 +1243,7 @@ static void cf_socket_adjust_pollset(struct Curl_cfilter *cf,
   if(ctx->sock != CURL_SOCKET_BAD) {
     if(!cf->connected)
       Curl_pollset_set_out_only(data, ps, ctx->sock);
-    else if(CURL_WANT_RECV(data))
+    else if(!ctx->active)
       Curl_pollset_add_in(data, ps, ctx->sock);
     CURL_TRC_CF(data, cf, "adjust_pollset -> %d socks", ps->num);
   }
index e78ecd71de22976031a9a1228746e381464c8822..823e90c3f2bb32b76187de04cbc37b7f6838ba30 100644 (file)
@@ -760,25 +760,11 @@ static void ps_add(struct Curl_easy *data, struct easy_pollset *ps,
 void Curl_pollset_add_socks(struct Curl_easy *data,
                             struct easy_pollset *ps,
                             int (*get_socks_cb)(struct Curl_easy *data,
-                                                struct connectdata *conn,
                                                 curl_socket_t *socks))
 {
   curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
   int bitmap;
 
-  DEBUGASSERT(data->conn);
-  bitmap = get_socks_cb(data, data->conn, socks);
-  ps_add(data, ps, bitmap, socks);
-}
-
-void Curl_pollset_add_socks2(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);
 }
index 09a3f162acfc275caf9fb03665484d5f91b2d331..f83842920bc907d104755d60aa963a89bf67e57b 100644 (file)
@@ -530,12 +530,7 @@ void Curl_pollset_set(struct Curl_easy *data,
 void Curl_pollset_add_socks(struct Curl_easy *data,
                             struct easy_pollset *ps,
                             int (*get_socks_cb)(struct Curl_easy *data,
-                                                struct connectdata *conn,
                                                 curl_socket_t *socks));
-void Curl_pollset_add_socks2(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
index b7a08607945357a63c7f157c2de912852595e48c..c3157d1ef28d1105e17cb692e004fc28c2adbda1 100644 (file)
@@ -2331,12 +2331,16 @@ static void cf_h2_adjust_pollset(struct Curl_cfilter *cf,
                                  struct easy_pollset *ps)
 {
   struct cf_h2_ctx *ctx = cf->ctx;
-  bool want_recv = CURL_WANT_RECV(data);
-  bool want_send = CURL_WANT_SEND(data);
+  curl_socket_t sock;
+  bool want_recv, want_send;
 
-  if(ctx->h2 && (want_recv || want_send)) {
+  if(!ctx->h2)
+    return;
+
+  sock = Curl_conn_cf_get_socket(cf, data);
+  Curl_pollset_check(data, ps, sock, &want_recv, &want_send);
+  if(want_recv || want_send) {
     struct stream_ctx *stream = H2_STREAM_CTX(data);
-    curl_socket_t sock = Curl_conn_cf_get_socket(cf, data);
     struct cf_call_data save;
     bool c_exhaust, s_exhaust;
 
index 9c7cde8f16ce1853282166b05be9f33048fcfdbd..e4491d912c980cfe423214f6922d9e2707344932 100644 (file)
@@ -994,31 +994,90 @@ void Curl_attach_connection(struct Curl_easy *data,
   Curl_conn_ev_data_attach(conn, data);
 }
 
-static int domore_getsock(struct Curl_easy *data,
-                          struct connectdata *conn,
-                          curl_socket_t *socks)
+static int connecting_getsock(struct Curl_easy *data, curl_socket_t *socks)
 {
+  struct connectdata *conn = data->conn;
+  (void)socks;
+  if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+    /* Default is to wait to something from the server */
+    socks[0] = conn->sockfd;
+    return GETSOCK_READSOCK(0);
+  }
+  return GETSOCK_BLANK;
+}
+
+static int protocol_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+  struct connectdata *conn = data->conn;
+  if(conn && conn->handler->proto_getsock)
+    return conn->handler->proto_getsock(data, conn, socks);
+  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+    /* Default is to wait to something from the server */
+    socks[0] = conn->sockfd;
+    return GETSOCK_READSOCK(0);
+  }
+  return GETSOCK_BLANK;
+}
+
+static int domore_getsock(struct Curl_easy *data, curl_socket_t *socks)
+{
+  struct connectdata *conn = data->conn;
   if(conn && conn->handler->domore_getsock)
     return conn->handler->domore_getsock(data, conn, socks);
+  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+    /* Default is that we want to send something to the server */
+    socks[0] = conn->sockfd;
+    return GETSOCK_WRITESOCK(0);
+  }
   return GETSOCK_BLANK;
 }
 
-static int doing_getsock(struct Curl_easy *data,
-                         struct connectdata *conn,
-                         curl_socket_t *socks)
+static int doing_getsock(struct Curl_easy *data, curl_socket_t *socks)
 {
+  struct connectdata *conn = data->conn;
   if(conn && conn->handler->doing_getsock)
     return conn->handler->doing_getsock(data, conn, socks);
+  else if(conn && conn->sockfd != CURL_SOCKET_BAD) {
+    /* Default is that we want to send something to the server */
+    socks[0] = conn->sockfd;
+    return GETSOCK_WRITESOCK(0);
+  }
   return GETSOCK_BLANK;
 }
 
-static int protocol_getsock(struct Curl_easy *data,
-                            struct connectdata *conn,
-                            curl_socket_t *socks)
+static int perform_getsock(struct Curl_easy *data, curl_socket_t *sock)
 {
-  if(conn->handler->proto_getsock)
-    return conn->handler->proto_getsock(data, conn, socks);
-  return GETSOCK_BLANK;
+  struct connectdata *conn = data->conn;
+
+  if(!conn)
+    return GETSOCK_BLANK;
+  else if(conn->handler->perform_getsock)
+    return conn->handler->perform_getsock(data, conn, sock);
+  else {
+    /* Default is to obey the data->req.keepon flags for send/recv */
+    int bitmap = GETSOCK_BLANK;
+    unsigned sockindex = 0;
+    if(CURL_WANT_RECV(data)) {
+      DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
+      bitmap |= GETSOCK_READSOCK(sockindex);
+      sock[sockindex] = conn->sockfd;
+    }
+
+    if(CURL_WANT_SEND(data)) {
+      if((conn->sockfd != conn->writesockfd) ||
+         bitmap == GETSOCK_BLANK) {
+        /* only if they are not the same socket and we have a readable
+           one, we increase index */
+        if(bitmap != GETSOCK_BLANK)
+          sockindex++; /* increase index if we need two entries */
+
+        DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
+        sock[sockindex] = conn->writesockfd;
+      }
+      bitmap |= GETSOCK_WRITESOCK(sockindex);
+    }
+    return bitmap;
+  }
 }
 
 /* Initializes `poll_set` with the current socket poll actions needed
@@ -1034,45 +1093,61 @@ static void multi_getsock(struct Curl_easy *data,
     return;
 
   switch(data->mstate) {
-  default:
+  case MSTATE_INIT:
+  case MSTATE_PENDING:
+  case MSTATE_CONNECT:
+    /* nothing to poll for yet */
     break;
 
   case MSTATE_RESOLVING:
-    Curl_pollset_add_socks2(data, ps, Curl_resolv_getsock);
+    Curl_pollset_add_socks(data, ps, Curl_resolv_getsock);
     /* connection filters are not involved in this phase */
-    return;
+    break;
+
+  case MSTATE_CONNECTING:
+  case MSTATE_TUNNELING:
+    Curl_pollset_add_socks(data, ps, connecting_getsock);
+    Curl_conn_adjust_pollset(data, ps);
+    break;
 
-  case MSTATE_PROTOCONNECTING:
   case MSTATE_PROTOCONNECT:
+  case MSTATE_PROTOCONNECTING:
     Curl_pollset_add_socks(data, ps, protocol_getsock);
+    Curl_conn_adjust_pollset(data, ps);
     break;
 
   case MSTATE_DO:
   case MSTATE_DOING:
     Curl_pollset_add_socks(data, ps, doing_getsock);
-    break;
-
-  case MSTATE_TUNNELING:
-  case MSTATE_CONNECTING:
+    Curl_conn_adjust_pollset(data, ps);
     break;
 
   case MSTATE_DOING_MORE:
     Curl_pollset_add_socks(data, ps, domore_getsock);
+    Curl_conn_adjust_pollset(data, ps);
     break;
 
-  case MSTATE_DID: /* since is set after DO is completed, we switch to
-                        waiting for the same as the PERFORMING state */
+  case MSTATE_DID: /* same as PERFORMING in regard to polling */
   case MSTATE_PERFORMING:
-    Curl_pollset_add_socks(data, ps, Curl_single_getsock);
+    Curl_pollset_add_socks(data, ps, perform_getsock);
+    Curl_conn_adjust_pollset(data, ps);
     break;
 
   case MSTATE_RATELIMITING:
-    /* nothing to wait for */
-    return;
-  }
+    /* we need to let time pass, ignore socket(s) */
+    break;
+
+  case MSTATE_DONE:
+  case MSTATE_COMPLETED:
+  case MSTATE_MSGSENT:
+    /* nothing more to poll for */
+    break;
 
-  /* Let connection filters add/remove as needed */
-  Curl_conn_adjust_pollset(data, ps);
+  default:
+    failf(data, "multi_getsock: unexpected multi state %d", data->mstate);
+    DEBUGASSERT(0);
+    break;
+  }
 }
 
 CURLMcode curl_multi_fdset(struct Curl_multi *multi,
index 59a3f05cb16484917e7db2a5f03ac6bd86ef9c5d..0d7226c8a5ed5fb07c76896f08cad4313f658088 100644 (file)
@@ -1220,52 +1220,6 @@ out:
   return result;
 }
 
-/*
- * Curl_single_getsock() gets called by the multi interface code when the app
- * has requested to get the sockets for the current connection. This function
- * will then be called once for every connection that the multi interface
- * keeps track of. This function will only be called for connections that are
- * in the proper state to have this information available.
- */
-int Curl_single_getsock(struct Curl_easy *data,
-                        struct connectdata *conn,
-                        curl_socket_t *sock)
-{
-  int bitmap = GETSOCK_BLANK;
-  unsigned sockindex = 0;
-
-  if(conn->handler->perform_getsock)
-    return conn->handler->perform_getsock(data, conn, sock);
-
-  /* don't include HOLD and PAUSE connections */
-  if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) {
-
-    DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
-
-    bitmap |= GETSOCK_READSOCK(sockindex);
-    sock[sockindex] = conn->sockfd;
-  }
-
-  /* don't include HOLD and PAUSE connections */
-  if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
-    if((conn->sockfd != conn->writesockfd) ||
-       bitmap == GETSOCK_BLANK) {
-      /* only if they are not the same socket and we have a readable
-         one, we increase index */
-      if(bitmap != GETSOCK_BLANK)
-        sockindex++; /* increase index if we need two entries */
-
-      DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
-
-      sock[sockindex] = conn->writesockfd;
-    }
-
-    bitmap |= GETSOCK_WRITESOCK(sockindex);
-  }
-
-  return bitmap;
-}
-
 /* Curl_init_CONNECT() gets called each time the handle switches to CONNECT
    which means this gets called once for each subsequent redirect etc */
 void Curl_init_CONNECT(struct Curl_easy *data)
index f1969a62a9e900034172b7c52f12d1aaa8e0d36b..b057c50d23010220b9e7a47d233098b1a0cc7e15 100644 (file)
@@ -47,8 +47,6 @@ CURLcode Curl_follow(struct Curl_easy *data, char *newurl,
                      followtype type);
 CURLcode Curl_readwrite(struct connectdata *conn,
                         struct Curl_easy *data, bool *done);
-int Curl_single_getsock(struct Curl_easy *data,
-                        struct connectdata *conn, curl_socket_t *socks);
 CURLcode Curl_fillreadbuffer(struct Curl_easy *data, size_t bytes,
                              size_t *nreadp);
 CURLcode Curl_retry_request(struct Curl_easy *data, char **url);
index 210fca76c48b08c8d3d8100be13594d1ce949b6d..de192dadeaf387a132c064a5cb6544c0d1523431 100644 (file)
@@ -583,7 +583,7 @@ struct hostname {
   (((data)->req.keepon & KEEP_SENDBITS) == KEEP_SEND)
 /* transfer receive is not on PAUSE or HOLD */
 #define CURL_WANT_RECV(data) \
-  (!((data)->req.keepon & (KEEP_RECV_PAUSE|KEEP_RECV_HOLD)))
+  (((data)->req.keepon & KEEP_RECVBITS) == KEEP_RECV)
 
 #if defined(CURLRES_ASYNCH) || !defined(CURL_DISABLE_DOH)
 #define USE_CURL_ASYNC
index 89f690462d640bd7162b5f751999aff186735f09..e391e4f421fe748b7ee3d6f996512319f03279ca 100644 (file)
@@ -1157,10 +1157,13 @@ static void cf_ngtcp2_adjust_pollset(struct Curl_cfilter *cf,
                                       struct easy_pollset *ps)
 {
   struct cf_ngtcp2_ctx *ctx = cf->ctx;
-  bool want_recv = CURL_WANT_RECV(data);
-  bool want_send = CURL_WANT_SEND(data);
+  bool want_recv, want_send;
 
-  if(ctx->qconn && (want_recv || want_send)) {
+  if(!ctx->qconn)
+    return;
+
+  Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
+  if(want_recv || want_send) {
     struct h3_stream_ctx *stream = H3_STREAM_CTX(data);
     struct cf_call_data save;
     bool c_exhaust, s_exhaust;
index 9c4df2df0f695521b76b719821361593370f9021..ed0bde367092987e3b6ff3266fb9cb78c521ebd2 100644 (file)
@@ -1180,10 +1180,13 @@ static void cf_quiche_adjust_pollset(struct Curl_cfilter *cf,
                                      struct easy_pollset *ps)
 {
   struct cf_quiche_ctx *ctx = cf->ctx;
-  bool want_recv = CURL_WANT_RECV(data);
-  bool want_send = CURL_WANT_SEND(data);
+  bool want_recv, want_send;
 
-  if(ctx->qconn && (want_recv || want_send)) {
+  if(!ctx->qconn)
+    return;
+
+  Curl_pollset_check(data, ps, ctx->q.sockfd, &want_recv, &want_send);
+  if(want_recv || want_send) {
     struct stream_ctx *stream = H3_STREAM_CTX(data);
     bool c_exhaust, s_exhaust;