]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MEDIUM: splice: Don't consider EINVAL to be a fatal error
authorOlivier Houchard <ohouchard@haproxy.com>
Wed, 9 Jul 2025 17:05:23 +0000 (19:05 +0200)
committerOlivier Houchard <cognet@ci0.org>
Wed, 20 Aug 2025 16:33:11 +0000 (18:33 +0200)
Don't consider that EINVAL is a fatal error, when calling splice().
When doing splicing from a kTLS socket, splice() will set errno to
EINVAL if the next record to be read is not an application data record.
This is not a fatal error, it just means we have to use recvmsg() to
read it, and potentially we can then resume using splicing.
It is unfortunate that EINVAL was used for that case, but we should
never get any other case of receiving EINVAL from splice(), so it should
be safe to treat it as non-fatal.

src/raw_sock.c

index ddfe0e464d89d8e52e88f963e434693fc88f1f26..5ef904d746109689b16141c4faa083c5ab5f43bf 100644 (file)
@@ -123,8 +123,20 @@ int raw_sock_to_pipe(struct connection *conn, void *xprt_ctx, struct pipe *pipe,
                                /* splice not supported on this end, disable it.
                                 * We can safely return -1 since there is no
                                 * chance that any data has been piped yet.
+                                * EINVAL, however, is a bit special.
+                                * If we're trying to splice from a KTLS
+                                * socket, the kernel may return EINVAL
+                                * to signal that the current TLS record
+                                * is not application data, and that we
+                                * have to call recvmsg() to get it.
+                                * This is not really an error, and doesn't
+                                * mean we won't be able to splice later.
+                                * Choosing EINVAL there is a bit unfortunate,
+                                * because it can mean many things, but we
+                                * should not get it for any other reason.
                                 */
-                               retval = -1;
+                               if (errno != EINVAL)
+                                       retval = -1;
                                goto leave;
                        }
                        else if (errno == EINTR) {
@@ -132,9 +144,11 @@ int raw_sock_to_pipe(struct connection *conn, void *xprt_ctx, struct pipe *pipe,
                                continue;
                        }
                        /* here we have another error */
-                       conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_rcv_err);
-                       conn->flags |= CO_FL_ERROR;
-                       conn_set_errno(conn, errno);
+                       if (errno != EINVAL) {
+                               conn_report_term_evt(conn, tevt_loc_fd, fd_tevt_type_rcv_err);
+                               conn->flags |= CO_FL_ERROR;
+                               conn_set_errno(conn, errno);
+                       }
                        break;
                } /* ret <= 0 */