Hi all, Various platforms have richer support for zero copy than they used to, no longer are we limited to just “send file to socket”.
In order to support this portably, I propose the following API, with 4 simple function calls covering the 4 possible combinations of apr_file_t and apr_socket_t. This allows us to ultimately deprecate and replace apr_socket_sendfile() with something more flexible. In httpd it will allow us to form creative use of pipes in addition to just sockets. Regards, Graham -- Index: include/apr_splice_io.h =================================================================== --- include/apr_splice_io.h (revision 0) +++ include/apr_splice_io.h (working copy) @@ -0,0 +1,121 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef APR_SPLICE_IO_H +#define APR_SPLICE_IO_H +/** + * @file apr_splice_io.h + * @brief APR File/Network splice library + */ + +#include "apr.h" +#include "apr_pools.h" +#include "apr_file_io.h" +#include "apr_network_io.h" +#include "apr_errno.h" + +/** + * Send from an open socket to a socket, along with optional headers and trailers. + * @param dest The socket to which we're writing + * @param src The socket from which to read + * @param hdtr A structure containing the headers and trailers to send + * @param offset Offset into the file where we should begin writing + * @param len (input) - Number of bytes to send from the file + * (output) - Number of bytes actually sent, + * including headers, file, and trailers + * @param flags APR flags that are mapped to OS specific flags + * @remark This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the + * APR_SO_NONBLOCK socket option. + * The number of bytes actually sent is stored in the len parameter. + * + * On platforms where this is supported, this function will be handled + * using splice or sendfile. If neither splice nor sendfile are available, + * APR_ENOTIMPL is returned. + */ +APR_DECLARE(apr_status_t) apr_splice_socket(apr_socket_t *dest, + apr_socket_t *src, apr_hdtr_t *hdtr, apr_off_t offset, apr_size_t *len, + apr_int32_t flags); + +/** + * Send from an open file/pipe to a socket, along with optional headers and trailers. + * @param dest The socket to which we're writing + * @param src The file/pipe from which to read + * @param hdtr A structure containing the headers and trailers to send + * @param offset Offset into the file where we should begin writing + * @param len (input) - Number of bytes to send from the file + * (output) - Number of bytes actually sent, + * including headers, file, and trailers + * @param flags APR flags that are mapped to OS specific flags + * @remark This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the + * APR_SO_NONBLOCK socket option. + * The number of bytes actually sent is stored in the len parameter. + * + * On platforms where this is supported, this function will be handled + * using splice or sendfile. If neither splice nor sendfile are available, + * APR_ENOTIMPL is returned. + */ +APR_DECLARE(apr_status_t) apr_splice_socket_file(apr_socket_t *dest, + apr_file_t *src, apr_hdtr_t *hdtr, apr_off_t offset, apr_size_t *len, + apr_int32_t flags); + +/** + * Send from one file or pipe to another file or pipe, along with optional + * headers and trailers. + * @param dest The file/pipe to which we're writing + * @param src The source file/pipe from which to read + * @param hdtr A structure containing the headers and trailers to send + * @param offset Offset into the file where we should begin writing + * @param len (input) - Number of bytes to send from the file + * (output) - Number of bytes actually sent, + * including headers, file, and trailers + * @param flags APR flags that are mapped to OS specific flags + * @remark This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the + * APR_SO_NONBLOCK socket option. + * The number of bytes actually sent is stored in the len parameter. + * + * On platforms where this is supported, this function will be handled + * using splice or sendfile. If neither splice nor sendfile are available, + * APR_ENOTIMPL is returned. + */ +APR_DECLARE(apr_status_t) apr_splice_file(apr_file_t *dest, apr_file_t *src, + apr_hdtr_t *hdtr, apr_off_t offset, apr_size_t *len, apr_int32_t flags); + +/** + * Send from a socket to a file or pipe, along with optional headers and trailers. + * @param dest The file/pipe to which we're writing + * @param src The source socket from which to read + * @param hdtr A structure containing the headers and trailers to send + * @param offset Offset into the file where we should begin writing + * @param len (input) - Number of bytes to send from the file + * (output) - Number of bytes actually sent, + * including headers, file, and trailers + * @param flags APR flags that are mapped to OS specific flags + * @remark This functions acts like a blocking write by default. To change + * this behavior, use apr_socket_timeout_set() or the + * APR_SO_NONBLOCK socket option. + * The number of bytes actually sent is stored in the len parameter. + * + * On platforms where this is supported, this function will be handled + * using splice or sendfile. If neither splice nor sendfile are available, + * APR_ENOTIMPL is returned. + */ +APR_DECLARE(apr_status_t) apr_splice_file_socket(apr_file_t *dest, apr_socket_t *src, + apr_hdtr_t *hdtr, apr_off_t offset, apr_size_t *len, apr_int32_t flags); + +#endif /* ! APR_SPLICE_IO_H */