diff --git a/Makefile b/Makefile index 653c083ce..5652d59be 100644 --- a/Makefile +++ b/Makefile @@ -28,6 +28,8 @@ # USE_GETADDRINFO : use getaddrinfo() to resolve IPv6 host names. # USE_OPENSSL : enable use of OpenSSL. Recommended, but see below. # USE_FUTEX : enable use of futex on kernel 2.6. Automatic. +# USE_ACCEPT4 : enable use of accept4() on linux. Automatic. +# USE_MY_ACCEPT4 : use own implemention of accept4() if glibc < 2.10. # # Options can be forced by specifying "USE_xxx=1" or can be disabled by using # "USE_xxx=" (empty string). @@ -240,6 +242,7 @@ ifeq ($(TARGET),linux2628) USE_LIBCRYPT = implicit USE_LINUX_SPLICE= implicit USE_LINUX_TPROXY= implicit + USE_ACCEPT4 = implicit USE_FUTEX = implicit else ifeq ($(TARGET),solaris) @@ -439,6 +442,16 @@ OPTIONS_CFLAGS += -DUSE_MY_SPLICE BUILD_OPTIONS += $(call ignore_implicit,USE_MY_SPLICE) endif +ifneq ($(USE_ACCEPT4),) +OPTIONS_CFLAGS += -DUSE_ACCEPT4 +BUILD_OPTIONS += $(call ignore_implicit,USE_ACCEPT4) +endif + +ifneq ($(USE_MY_ACCEPT4),) +OPTIONS_CFLAGS += -DUSE_MY_ACCEPT4 +BUILD_OPTIONS += $(call ignore_implicit,USE_MY_ACCEPT4) +endif + ifneq ($(USE_NETFILTER),) OPTIONS_CFLAGS += -DNETFILTER BUILD_OPTIONS += $(call ignore_implicit,USE_NETFILTER) diff --git a/include/common/accept4.h b/include/common/accept4.h new file mode 100644 index 000000000..9c81b80a9 --- /dev/null +++ b/include/common/accept4.h @@ -0,0 +1,72 @@ +/* + * include/common/accept4.h + * Definition of the accept4 system call for older Linux libc. + * + * Copyright 2000-2012 Willy Tarreau + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation, version 2.1 + * exclusively. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + */ + +#ifndef _COMMON_ACCEPT4_H +#define _COMMON_ACCEPT4_H + +#if defined (__linux__) && defined(USE_ACCEPT4) + +#include +#include +#include +#include +#include +#include +#include + +/* On recent Linux kernels, the accept4() syscall may be used to avoid an fcntl() + * call to set O_NONBLOCK on the resulting socket. It was introduced in Linux + * 2.6.28 and is not present in older libcs. + */ +#ifndef SOCK_NONBLOCK +#define SOCK_NONBLOCK O_NONBLOCK +#endif + +#if defined(USE_MY_ACCEPT4) || !defined(SYS_ACCEPT4) +#if defined(CONFIG_HAP_LINUX_VSYSCALL) && defined(__linux__) && defined(__i386__) +/* The syscall is redefined somewhere else */ +extern int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags); +#elif ACCEPT4_USE_SOCKETCALL +static int accept4(int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags) +{ + unsigned long args[4]; + static _syscall2(int, socketcall, int, call, unsigned long *, args); + + args[0] = (unsigned long)sockfd; + args[1] = (unsigned long)addr; + args[2] = (unsigned long)addrlen; + args[3] = (unsigned long)flags; + return socketcall(SYS_ACCEPT4, args); +} +#else +static _syscall4(int, accept4, int, sockfd, struct sockaddr *, addr, socklen_t *, addrlen, int, flags); +#endif /* VSYSCALL etc... */ +#endif /* USE_MY_ACCEPT4 */ +#endif /* __linux__ && USE_ACCEPT4 */ +#endif /* _COMMON_ACCEPT4_H */ + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * End: + */ diff --git a/include/common/syscall.h b/include/common/syscall.h index a3b27eb16..3ccbf5a8d 100644 --- a/include/common/syscall.h +++ b/include/common/syscall.h @@ -2,7 +2,7 @@ * include/common/syscall.h * Redefinition of some missing OS-specific system calls. * - * Copyright 2000-2011 Willy Tarreau + * Copyright 2000-2012 Willy Tarreau * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -124,6 +124,21 @@ #endif /* $arch */ #endif /* __NR_splice */ +/* accept4() appeared in Linux 2.6.28, but it might not be in all libcs. Some + * archs have it as a native syscall, other ones use the socketcall instead. + */ +#ifndef __NR_accept4 +#if defined(__x86_64__) +#define __NR_accept4 288 +#elif defined(__sparc__) || defined(__sparc64__) +#define __NR_splice 323 +#else +#define ACCEPT4_USE_SOCKETCALL 1 +#ifndef SYS_ACCEPT4 +#define SYS_ACCEPT4 18 +#endif /* SYS_ACCEPT4 */ +#endif /* $arch */ +#endif /* __NR_accept4 */ #endif /* __linux__ */ #endif /* _COMMON_SYSCALL_H */ diff --git a/src/i386-linux-vsys.c b/src/i386-linux-vsys.c index 1bdd9e9d7..9d3033461 100644 --- a/src/i386-linux-vsys.c +++ b/src/i386-linux-vsys.c @@ -120,6 +120,10 @@ asm " mov $0x05, %eax\n" " jmp socketcall\n" + "accept4: .GLOBL accept4\n" + " mov $0x12, %eax\n" + " jmp socketcall\n" + "getsockname: .GLOBL getsockname\n" " mov $0x06, %eax\n" " jmp socketcall\n" diff --git a/src/listener.c b/src/listener.c index 7c21b9db2..c4259bcd5 100644 --- a/src/listener.c +++ b/src/listener.c @@ -14,6 +14,7 @@ #include #include +#include #include #include #include @@ -308,7 +309,11 @@ void listener_accept(int fd) return; } +#ifdef USE_ACCEPT4 + cfd = accept4(fd, (struct sockaddr *)&addr, &laddr, SOCK_NONBLOCK); +#else cfd = accept(fd, (struct sockaddr *)&addr, &laddr); +#endif if (unlikely(cfd == -1)) { switch (errno) { case EAGAIN: diff --git a/src/session.c b/src/session.c index b5dfd2bb9..3fcce844a 100644 --- a/src/session.c +++ b/src/session.c @@ -126,9 +126,13 @@ int session_accept(struct listener *l, int cfd, struct sockaddr_storage *addr) goto out_free_session; } - /* Adjust some socket options */ +#ifndef USE_ACCEPT4 + /* Adjust some socket options if the connection was accepted by a plain + * accept() syscall. + */ if (unlikely(fcntl(cfd, F_SETFL, O_NONBLOCK) == -1)) goto out_free_session; +#endif /* monitor-net and health mode are processed immediately after TCP * connection rules. This way it's possible to block them, but they