From 7008fe16b4c2432bcf926cc6aa10eb97dc486f9d Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Thu, 26 Feb 2026 16:22:14 +0900 Subject: [PATCH 1/4] io: Implement batch write API Signed-off-by: Hiroshi Hatake --- include/fluent-bit/flb_io.h | 10 ++++ src/flb_io.c | 93 +++++++++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+) diff --git a/include/fluent-bit/flb_io.h b/include/fluent-bit/flb_io.h index 9a6afd1e0cd..272d9f1adf4 100644 --- a/include/fluent-bit/flb_io.h +++ b/include/fluent-bit/flb_io.h @@ -20,6 +20,7 @@ #ifndef FLB_IO_H #define FLB_IO_H +#include #include #include @@ -40,6 +41,10 @@ #define FLB_IO_IPV6 32 /* network I/O uses IPv6 */ struct flb_connection; +struct flb_iovec { + void *iov_base; + size_t iov_len; +}; int flb_io_net_accept(struct flb_connection *connection, struct flb_coro *th); @@ -50,6 +55,11 @@ int flb_io_net_connect(struct flb_connection *u_conn, int flb_io_net_write(struct flb_connection *connection, const void *data, size_t len, size_t *out_len); +int flb_io_net_writev(struct flb_connection *connection, + const struct flb_iovec *iov, + int iovcnt, + size_t *out_len); + ssize_t flb_io_net_read(struct flb_connection *connection, void *buf, size_t len); int flb_io_fd_write(int fd, const void *data, size_t len, size_t *out_len); diff --git a/src/flb_io.c b/src/flb_io.c index 38fbb3eed4b..24e06ea3484 100644 --- a/src/flb_io.c +++ b/src/flb_io.c @@ -46,6 +46,11 @@ #include #include #include +#include +#include +#ifndef FLB_SYSTEM_WINDOWS +#include +#endif #include #include @@ -63,6 +68,36 @@ #include #include + +static int flb_io_get_iov_max() +{ + long limit; + +#ifdef IOV_MAX + limit = IOV_MAX; +#else + limit = -1; +#endif + +#ifdef _SC_IOV_MAX + { + long sys_limit; + + sys_limit = sysconf(_SC_IOV_MAX); + + if (sys_limit > 0) { + limit = sys_limit; + } + } +#endif + + if (limit <= 0 || limit > INT_MAX) { + limit = 1024; + } + + return (int) limit; +} + int flb_io_net_accept(struct flb_connection *connection, struct flb_coro *coro) { @@ -664,6 +699,64 @@ static FLB_INLINE ssize_t net_io_read_async(struct flb_coro *co, return ret; } + +int flb_io_net_writev(struct flb_connection *connection, + const struct flb_iovec *iov, + int iovcnt, + size_t *out_len) +{ + int result; + int index; + size_t total; + size_t total_length; + char *temporary_buffer; + + if (iov == NULL || iovcnt <= 0 || out_len == NULL) { + errno = EINVAL; + + return -1; + } + + if (iovcnt > flb_io_get_iov_max()) { + errno = EINVAL; + + return -1; + } + + total_length = 0; + + for (index = 0 ; index < iovcnt ; index++) { + total_length += iov[index].iov_len; + } + + if (total_length == 0) { + *out_len = 0; + + return 0; + } + + temporary_buffer = flb_malloc(total_length); + + if (temporary_buffer == NULL) { + flb_errno(); + + return -1; + } + + total = 0; + + for (index = 0 ; index < iovcnt ; index++) { + memcpy(&temporary_buffer[total], iov[index].iov_base, iov[index].iov_len); + total += iov[index].iov_len; + } + + result = flb_io_net_write(connection, temporary_buffer, total_length, out_len); + + flb_free(temporary_buffer); + + return result; +} + /* Write data to fd. For unix socket. */ int flb_io_fd_write(int fd, const void *data, size_t len, size_t *out_len) { From e8bfd848d770d4a803ff2c881ebc83abc8908395 Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Thu, 26 Feb 2026 16:24:24 +0900 Subject: [PATCH 2/4] http_client: Implement batch writing Signed-off-by: Hiroshi Hatake --- src/flb_http_client.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/src/flb_http_client.c b/src/flb_http_client.c index 7a267d750f6..8c4a9a011dc 100644 --- a/src/flb_http_client.c +++ b/src/flb_http_client.c @@ -1491,24 +1491,36 @@ int flb_http_do_request(struct flb_http_client *c, size_t *bytes) } #endif - /* Write the header */ - ret = flb_io_net_write(c->u_conn, - c->header_buf, c->header_len, - &bytes_header); - if (ret == -1) { - /* errno might be changed from the original call */ - if (errno != 0) { + if (c->body_len > 0) { + struct flb_iovec io_vector[2]; + + io_vector[0].iov_base = c->header_buf; + io_vector[0].iov_len = c->header_len; + io_vector[1].iov_base = c->body_buf; + io_vector[1].iov_len = c->body_len; + + ret = flb_io_net_writev(c->u_conn, + io_vector, + 2, + &bytes_header); + if (ret == -1) { flb_errno(); + return FLB_HTTP_ERROR; } - return FLB_HTTP_ERROR; - } - if (c->body_len > 0) { + bytes_body = bytes_header - c->header_len; + bytes_header = c->header_len; + } + else { + /* Write the header */ ret = flb_io_net_write(c->u_conn, - c->body_buf, c->body_len, - &bytes_body); + c->header_buf, c->header_len, + &bytes_header); if (ret == -1) { - flb_errno(); + /* errno might be changed from the original call */ + if (errno != 0) { + flb_errno(); + } return FLB_HTTP_ERROR; } } From e22ebc8c0892955af2d701866cf306fc283d8e1c Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 27 Feb 2026 11:20:52 +0900 Subject: [PATCH 3/4] io: Add crash guards Signed-off-by: Hiroshi Hatake --- src/flb_io.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/src/flb_io.c b/src/flb_io.c index 24e06ea3484..7a96a202704 100644 --- a/src/flb_io.c +++ b/src/flb_io.c @@ -726,6 +726,17 @@ int flb_io_net_writev(struct flb_connection *connection, total_length = 0; for (index = 0 ; index < iovcnt ; index++) { + /* Overflow guard */ + if (iov[index].iov_len > SIZE_MAX - total_length) { + errno = EOVERFLOW; + return -1; + } + + if (iov[index].iov_len > 0 && iov[index].iov_base == NULL) { + errno = EINVAL; + return -1; + } + total_length += iov[index].iov_len; } @@ -746,7 +757,9 @@ int flb_io_net_writev(struct flb_connection *connection, total = 0; for (index = 0 ; index < iovcnt ; index++) { - memcpy(&temporary_buffer[total], iov[index].iov_base, iov[index].iov_len); + if (iov[index].iov_len > 0) { + memcpy(&temporary_buffer[total], iov[index].iov_base, iov[index].iov_len); + } total += iov[index].iov_len; } From 7ebff7b9b40802eca858e3d54329cc763a1b60fb Mon Sep 17 00:00:00 2001 From: Hiroshi Hatake Date: Fri, 27 Feb 2026 11:34:03 +0900 Subject: [PATCH 4/4] http_client: Add a fallback for writev Signed-off-by: Hiroshi Hatake --- src/flb_http_client.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/flb_http_client.c b/src/flb_http_client.c index 8c4a9a011dc..a2d5e9ae5ef 100644 --- a/src/flb_http_client.c +++ b/src/flb_http_client.c @@ -1504,12 +1504,44 @@ int flb_http_do_request(struct flb_http_client *c, size_t *bytes) 2, &bytes_header); if (ret == -1) { - flb_errno(); - return FLB_HTTP_ERROR; + if (errno == ENOMEM && bytes_header == 0) { + ret = flb_io_net_write(c->u_conn, + c->header_buf, c->header_len, + &bytes_header); + if (ret == -1) { + if (errno != 0) { + flb_errno(); + } + return FLB_HTTP_ERROR; + } + + ret = flb_io_net_write(c->u_conn, + c->body_buf, c->body_len, + &bytes_body); + if (ret == -1) { + if (errno != 0) { + flb_errno(); + } + return FLB_HTTP_ERROR; + } + } + else { + if (errno != 0) { + flb_errno(); + } + return FLB_HTTP_ERROR; + } } + else { + if (bytes_header < c->header_len) { + flb_error("[http_client] invalid write accounting: total=%zu header=%zu", + bytes_header, c->header_len); + return FLB_HTTP_ERROR; + } - bytes_body = bytes_header - c->header_len; - bytes_header = c->header_len; + bytes_body = bytes_header - c->header_len; + bytes_header = c->header_len; + } } else { /* Write the header */