gregames 2002/07/02 14:33:43
Modified: . configure.in
network_io/unix sendrecv.c
Log:
FreeBSD apr_sendfile: test for kernel version to determine whether to
include headers in length due to 4.6-STABLE kernel patch.
a few minor changes from what I posted due to feedback from Cliff & Jeff:
* provide a URL to the kernel CVS for their sendfile patch
* get rid of the 4.4 comment - the header & syscall exist in 3.4 FreeBSD :-)
* initialize slow path variables explicitly after fast path test
Revision Changes Path
1.460 +1 -0 apr/configure.in
Index: configure.in
===================================================================
RCS file: /home/cvs/apr/configure.in,v
retrieving revision 1.459
retrieving revision 1.460
diff -u -r1.459 -r1.460
--- configure.in 1 Jul 2002 14:50:46 -0000 1.459
+++ configure.in 2 Jul 2002 21:33:43 -0000 1.460
@@ -934,6 +934,7 @@
sys/signal.h \
sys/socket.h \
sys/stat.h \
+ sys/sysctl.h \
sys/syslimits.h \
sys/time.h \
sys/types.h \
1.85 +66 -9 apr/network_io/unix/sendrecv.c
Index: sendrecv.c
===================================================================
RCS file: /home/cvs/apr/network_io/unix/sendrecv.c,v
retrieving revision 1.84
retrieving revision 1.85
diff -u -r1.84 -r1.85
--- sendrecv.c 17 May 2002 21:19:45 -0000 1.84
+++ sendrecv.c 2 Jul 2002 21:33:43 -0000 1.85
@@ -59,6 +59,10 @@
#include "fileio.h"
#endif /* APR_HAS_SENDFILE */
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
apr_status_t apr_wait_for_io_or_timeout(apr_socket_t *sock, int for_read)
{
struct timeval tv, *tvptr;
@@ -435,6 +439,54 @@
#elif defined(__FreeBSD__)
+static int include_hdrs_in_length(void)
+{
+#ifdef HAVE_SYS_SYSCTL_H
+/* this assumes:
+ * if the header exits, so does the sysctlbyname() syscall, and
+ * if the header doesn't exist, the kernel is really old
+ */
+
+/* see
+ * http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/sys/param.h#rev1.61.2.29
+ * for kernel version number
+ *
+ *
http://www.freebsd.org/cgi/cvsweb.cgi/src/sys/kern/uipc_syscalls.c#rev1.65.2.10
+ * for the sendfile patch
+ */
+#define KERNEL_WITH_SENDFILE_LENGTH_FIX 460001
+
+ typedef enum { UNKNOWN = 0,
+ NEW,
+ OLD
+ } api_e;
+
+ static api_e api;
+ int kernel_version;
+ size_t kernel_version_size;
+
+ if (api != UNKNOWN) {
+ return (api == OLD);
+ }
+ kernel_version = 0; /* silence compiler warning */
+ kernel_version_size = sizeof(kernel_version);
+ if (sysctlbyname("kern.osreldate", &kernel_version,
+ &kernel_version_size, NULL, NULL) == 0 &&
+ kernel_version < KERNEL_WITH_SENDFILE_LENGTH_FIX) {
+ api = OLD;
+ return 1;
+ }
+ /* size of kern.osreldate's output might change in the future
+ * causing the sysctlbyname to fail,
+ * but if it's the future, we should use the newer API
+ */
+ api = NEW;
+ return 0;
+#elif
+ /* the build system's kernel is older than 3.4. Use the old API */
+ return 1;
+#endif
+}
/* Release 3.1 or greater */
apr_status_t apr_sendfile(apr_socket_t * sock, apr_file_t * file,
apr_hdtr_t * hdtr, apr_off_t * offset, apr_size_t * len,
@@ -445,20 +497,25 @@
struct sf_hdtr headerstruct;
size_t bytes_to_send = *len;
+ /* Ignore flags for now. */
+ flags = 0;
+
if (!hdtr) {
hdtr = &no_hdtr;
}
- /* Ignore flags for now. */
- flags = 0;
+ else if (hdtr->numheaders && include_hdrs_in_length()) {
- /* On FreeBSD, the number of bytes to send must include the length of
- * the headers. Don't look at the man page for this :( Instead, look
- * at the the logic in src/sys/kern/uipc_syscalls::sendfile().
- */
-
- for (i = 0; i < hdtr->numheaders; i++) {
- bytes_to_send += hdtr->headers[i].iov_len;
+ /* On early versions of FreeBSD sendfile, the number of bytes to
send
+ * must include the length of the headers. Don't look at the man
page
+ * for this :( Instead, look at the the logic in
+ * src/sys/kern/uipc_syscalls::sendfile().
+ *
+ * This was fixed in the middle of 4.6-STABLE
+ */
+ for (i = 0; i < hdtr->numheaders; i++) {
+ bytes_to_send += hdtr->headers[i].iov_len;
+ }
}
headerstruct.headers = hdtr->headers;