You are viewing a plain text version of this content. The canonical link for it is here.
Posted to c-commits@axis.apache.org by ro...@apache.org on 2026/09/25 15:39:13 UTC

(axis-axis2-c-core) branch master updated (a0c52b3b0 -> f683b78e5)

This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git


    from a0c52b3b0 Note that a long-running h2 client call needs both timeouts raised
     new f92cc7300 Correct the h2 client comment on a server that stops reading
     new b6993d43f Move request_timeout_ms to the end of the h2 client options
     new f7e6b224d State that the h2 client's connect timeout starts after DNS resolution
     new f683b78e5 Start the h2 client's connect deadline after DNS resolution

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 docs/HTTP2_JSON_CLIENT.md                          |  2 +-
 include/axis2_h2_json_client.h                     | 33 +++++++++++++++++-----
 .../transport/h2/sender/axis2_h2_json_client.c     | 30 +++++++++++++-------
 3 files changed, 47 insertions(+), 18 deletions(-)


(axis-axis2-c-core) 04/04: Start the h2 client's connect deadline after DNS resolution

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git

commit f683b78e5a6b63db555cb040aa3b41874125bc0d
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Fri Sep 25 05:22:14 2026 -1000

    Start the h2 client's connect deadline after DNS resolution
    
    The deadline was taken before getaddrinfo, so a slow lookup used up
    connect_timeout_ms and failed the connect at once, contrary to the
    header. It is now set once the host has resolved.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <no...@anthropic.com>
---
 .../transport/h2/sender/axis2_h2_json_client.c     | 29 +++++++++++++---------
 1 file changed, 17 insertions(+), 12 deletions(-)

diff --git a/src/core/transport/h2/sender/axis2_h2_json_client.c b/src/core/transport/h2/sender/axis2_h2_json_client.c
index 68b406d25..65bf91e25 100644
--- a/src/core/transport/h2/sender/axis2_h2_json_client.c
+++ b/src/core/transport/h2/sender/axis2_h2_json_client.c
@@ -556,12 +556,15 @@ h2c_disconnect(axis2_h2_json_client_t *c, const axutil_env_t *env, int graceful)
     }
 }
 
-/* Try each address getaddrinfo returns (IPv6 and IPv4, in its order) until
- * one connects. The socket is non-blocking from the start so the connect
- * itself honours the deadline; it stays non-blocking for the connection's
- * life, which is what lets every later wait go through h2c_wait. */
+/* Resolve host, then start the connect_timeout_ms clock: *deadline is set
+ * here, after the lookup, and h2c_connect uses the same deadline for the TLS
+ * handshake. Then try each address getaddrinfo returned (IPv6 and IPv4, in
+ * its order) until one connects. The socket is non-blocking from the start
+ * so the connect itself honours the deadline; it stays non-blocking for the
+ * connection's life, which is what lets every later wait go through
+ * h2c_wait. */
 static axis2_status_t
-h2c_tcp_connect(axis2_h2_json_client_t *c, const axutil_env_t *env, int64_t deadline)
+h2c_tcp_connect(axis2_h2_json_client_t *c, const axutil_env_t *env, int64_t *deadline)
 {
     struct addrinfo hints, *res = NULL, *ai;
     char port[16];
@@ -572,16 +575,18 @@ h2c_tcp_connect(axis2_h2_json_client_t *c, const axutil_env_t *env, int64_t dead
     hints.ai_socktype = SOCK_STREAM;
     snprintf(port, sizeof(port), "%d", c->port);
     /* getaddrinfo blocks, bounded only by the system resolver's own timeout,
-     * so the deadline does not cover it -- as the header says. Bounding it
-     * would need a resolver thread or an async resolver (c-ares); an IP
-     * literal skips the lookup, and that is the documented way to a hard
-     * bound. */
+     * so the connect deadline starts after it, as the header says. Starting
+     * it before would let a slow lookup use up the connect time and fail
+     * the connect instantly. Bounding the lookup itself would need a
+     * resolver thread or an async resolver (c-ares); an IP literal skips
+     * it, and that is the documented way to a hard bound. */
     rc = getaddrinfo(c->host, port, &hints, &res);
     if (rc != 0)
     {
         h2c_fail(c, env, "cannot resolve %s: %s", c->host, gai_strerror(rc));
         return AXIS2_FAILURE;
     }
+    *deadline = h2c_now_ms() + c->connect_timeout_ms;
 
     for (ai = res; ai; ai = ai->ai_next)
     {
@@ -604,7 +609,7 @@ h2c_tcp_connect(axis2_h2_json_client_t *c, const axutil_env_t *env, int64_t dead
             err = errno;
         else
         {
-            left = deadline - h2c_now_ms();
+            left = *deadline - h2c_now_ms();
             rc = h2c_wait(fd, POLLOUT, left > 0 ? (int)left : 0);
             if (rc == 0)
                 err = ETIMEDOUT;
@@ -631,7 +636,7 @@ h2c_tcp_connect(axis2_h2_json_client_t *c, const axutil_env_t *env, int64_t dead
 static axis2_status_t
 h2c_connect(axis2_h2_json_client_t *c, const axutil_env_t *env)
 {
-    int64_t deadline = h2c_now_ms() + c->connect_timeout_ms;
+    int64_t deadline;           /* set by h2c_tcp_connect, after DNS */
     const unsigned char *alpn = NULL;
     unsigned int alpn_len = 0;
     nghttp2_session_callbacks *cbs = NULL;
@@ -639,7 +644,7 @@ h2c_connect(axis2_h2_json_client_t *c, const axutil_env_t *env)
     char why[160];
     int rv;
 
-    if (h2c_tcp_connect(c, env, deadline) != AXIS2_SUCCESS)
+    if (h2c_tcp_connect(c, env, &deadline) != AXIS2_SUCCESS)
         return AXIS2_FAILURE;
 
     c->ssl = SSL_new(c->ctx);


(axis-axis2-c-core) 01/04: Correct the h2 client comment on a server that stops reading

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git

commit f92cc730034b0ec223372138c6b61e7927f61764
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Fri Sep 25 03:27:04 2026 -1000

    Correct the h2 client comment on a server that stops reading
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <no...@anthropic.com>
---
 src/core/transport/h2/sender/axis2_h2_json_client.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/core/transport/h2/sender/axis2_h2_json_client.c b/src/core/transport/h2/sender/axis2_h2_json_client.c
index 1ae794a16..9ad051c4d 100644
--- a/src/core/transport/h2/sender/axis2_h2_json_client.c
+++ b/src/core/transport/h2/sender/axis2_h2_json_client.c
@@ -1033,8 +1033,8 @@ axis2_h2_json_client_post(
      * frames. A server that answers early (a 413 before the body is all
      * sent) sends its response and RST_STREAM(NO_ERROR) (RFC 9113 8.1);
      * the next h2c_pump_recv takes both, and nghttp2 sends no more body. A
-     * server that stops reading altogether blocks a send only until
-     * request_deadline. */
+     * server that stops reading altogether fails the send after
+     * io_timeout_ms, or sooner if request_deadline comes first. */
     while (!c->stream_closed)
     {
         if (h2c_pump_send(c, env) != AXIS2_SUCCESS)


(axis-axis2-c-core) 03/04: State that the h2 client's connect timeout starts after DNS resolution

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git

commit f7e6b224df09f424cc31b9cc6dd4b848b72ef41b
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Fri Sep 25 03:49:57 2026 -1000

    State that the h2 client's connect timeout starts after DNS resolution
    
    getaddrinfo blocks under the system resolver's own timeout. The header,
    docs and call site now say so, and name an IP literal host with
    verify_name as the way to a hard connect bound.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <no...@anthropic.com>
---
 docs/HTTP2_JSON_CLIENT.md                           | 2 +-
 include/axis2_h2_json_client.h                      | 8 +++++++-
 src/core/transport/h2/sender/axis2_h2_json_client.c | 5 +++++
 3 files changed, 13 insertions(+), 2 deletions(-)

diff --git a/docs/HTTP2_JSON_CLIENT.md b/docs/HTTP2_JSON_CLIENT.md
index 94f46e99b..48f664728 100644
--- a/docs/HTTP2_JSON_CLIENT.md
+++ b/docs/HTTP2_JSON_CLIENT.md
@@ -63,7 +63,7 @@ kept for that operation; other clients keep the short defaults.
 | TLS 1.2 or later, no compression, no renegotiation | RFC 9113 §9.2. |
 | The server certificate is always verified, including its name | There is no option to skip it. |
 | `verify_name` is separate from `host` | Connecting by IP to a server whose certificate names it by DNS name — the equivalent of `curl --resolve`. An IP-literal `verify_name` is matched against IP SANs and never sent as SNI. |
-| Every wait has a deadline | Connect + handshake share `connect_timeout_ms` (default 5 s); each wait for the server is bounded by `io_timeout_ms` (default 30 s), and the whole request and response by `request_timeout_ms` (default 120 s), so a server trickling bytes cannot hold a post. |
+| Every wait has a deadline | Connect + handshake share `connect_timeout_ms` (default 5 s), counted from after the DNS lookup, which the system resolver bounds; pass an IP as `host` with `verify_name` set for a hard bound; each wait for the server is bounded by `io_timeout_ms` (default 30 s), and the whole request and response by `request_timeout_ms` (default 120 s), so a server trickling bytes cannot hold a post. |
 | A response over `max_response_bytes` is abandoned, not truncated | Default 16 MB, the server's JSON transport buffer. The stream is reset. |
 | Nothing is retried | A POST may not be safe to repeat. After a failure the connection is dropped and the next post opens a new one. |
 | A connection the server closed while idle is replaced before the next request | Servers close idle HTTP/2 connections (httpd's keep-alive timeout is 5 s by default). The client checks, without waiting, for a GOAWAY or FIN before it sends; nothing has been sent, so a new connection is not a retry. |
diff --git a/include/axis2_h2_json_client.h b/include/axis2_h2_json_client.h
index 275f49be0..9d1c7e22b 100644
--- a/include/axis2_h2_json_client.h
+++ b/include/axis2_h2_json_client.h
@@ -88,7 +88,13 @@ extern "C"
         /** PEM private key for cert_file. Required when cert_file is set. */
         const axis2_char_t *key_file;
 
-        /** TCP connect and TLS handshake limit. 0 means 5000 ms. */
+        /**
+         * TCP connect and TLS handshake limit. 0 means 5000 ms. It starts
+         * after host is resolved: a DNS lookup blocks for as long as the
+         * system resolver allows (resolv.conf timeout and attempts). For a
+         * hard bound, pass an IP literal as host and the certificate's name
+         * as verify_name.
+         */
         int connect_timeout_ms;
 
         /** Longest wait for the server to make progress. 0 means 30000 ms. */
diff --git a/src/core/transport/h2/sender/axis2_h2_json_client.c b/src/core/transport/h2/sender/axis2_h2_json_client.c
index 9ad051c4d..68b406d25 100644
--- a/src/core/transport/h2/sender/axis2_h2_json_client.c
+++ b/src/core/transport/h2/sender/axis2_h2_json_client.c
@@ -571,6 +571,11 @@ h2c_tcp_connect(axis2_h2_json_client_t *c, const axutil_env_t *env, int64_t dead
     hints.ai_family = AF_UNSPEC;
     hints.ai_socktype = SOCK_STREAM;
     snprintf(port, sizeof(port), "%d", c->port);
+    /* getaddrinfo blocks, bounded only by the system resolver's own timeout,
+     * so the deadline does not cover it -- as the header says. Bounding it
+     * would need a resolver thread or an async resolver (c-ares); an IP
+     * literal skips the lookup, and that is the documented way to a hard
+     * bound. */
     rc = getaddrinfo(c->host, port, &hints, &res);
     if (rc != 0)
     {


(axis-axis2-c-core) 02/04: Move request_timeout_ms to the end of the h2 client options

Posted by ro...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

robertlazarski pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/axis-axis2-c-core.git

commit b6993d43ffe9e3f04a1978184ef6aa6d7a7a5c8c
Author: Robert Lazarski <ro...@gmail.com>
AuthorDate: Fri Sep 25 03:47:53 2026 -1000

    Move request_timeout_ms to the end of the h2 client options
    
    New options are appended so existing fields keep their offsets. The
    header now states that rule and that it does not remove the need to
    rebuild against the header the program links with.
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <no...@anthropic.com>
---
 include/axis2_h2_json_client.h | 25 +++++++++++++++++++------
 1 file changed, 19 insertions(+), 6 deletions(-)

diff --git a/include/axis2_h2_json_client.h b/include/axis2_h2_json_client.h
index 4d9e7ea80..275f49be0 100644
--- a/include/axis2_h2_json_client.h
+++ b/include/axis2_h2_json_client.h
@@ -52,6 +52,16 @@ extern "C"
 
     /**
      * Connection and TLS settings. Strings are copied at create time.
+     *
+     * Zero-initialise the struct and set what you need: every field left 0
+     * or NULL takes its documented default.
+     *
+     * New fields are only ever added at the end. That keeps every existing
+     * field at the offset it has always had, so a field is never read as a
+     * different one after the struct grows. It does not let a program built
+     * against an older copy of this header run against a newer library: the
+     * library reads the whole struct, and the older program passes a shorter
+     * one. Rebuild against the header you link with.
      */
     typedef struct axis2_h2_json_client_options
     {
@@ -84,18 +94,21 @@ extern "C"
         /** Longest wait for the server to make progress. 0 means 30000 ms. */
         int io_timeout_ms;
 
+        /**
+         * Largest response body accepted. 0 means 16 MB, the size of the
+         * server's JSON transport buffer; a larger response is abandoned.
+         */
+        size_t max_response_bytes;
+
+        /* Fields added after the struct was first published go below, in
+         * the order they were added. See the note on the struct. */
+
         /**
          * Longest a post may take from sending the request to receiving the
          * whole response, however steadily the server makes progress.
          * Connecting is bounded separately. 0 means 120000 ms.
          */
         int request_timeout_ms;
-
-        /**
-         * Largest response body accepted. 0 means 16 MB, the size of the
-         * server's JSON transport buffer; a larger response is abandoned.
-         */
-        size_t max_response_bytes;
     } axis2_h2_json_client_options_t;
 
     /**