summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorjilles <jilles@FreeBSD.org>2013-05-01 20:10:21 +0000
committerjilles <jilles@FreeBSD.org>2013-05-01 20:10:21 +0000
commit299afd25fd6dead39bf5c78572782db885579911 (patch)
treec530c7ecc418cacfa14b49c004393242e6613d6b /lib
parent19e5409088a95e1f704e9a1b2e7737b3e76608e9 (diff)
downloadFreeBSD-src-299afd25fd6dead39bf5c78572782db885579911.zip
FreeBSD-src-299afd25fd6dead39bf5c78572782db885579911.tar.gz
Add accept4() system call.
The accept4() function, compared to accept(), allows setting the new file descriptor atomically close-on-exec and explicitly controlling the non-blocking status on the new socket. (Note that the latter point means that accept() is not equivalent to any form of accept4().) The linuxulator's accept4 implementation leaves a race window where the new file descriptor is not close-on-exec because it calls sys_accept(). This implementation leaves no such race window (by using falloc() flags). The linuxulator could be fixed and simplified by using the new code. Like accept(), accept4() is async-signal-safe, a cancellation point and permitted in capability mode.
Diffstat (limited to 'lib')
-rw-r--r--lib/libc/sys/Makefile.inc1
-rw-r--r--lib/libc/sys/Symbol.map3
-rw-r--r--lib/libc/sys/accept.245
-rw-r--r--lib/libthr/pthread.map5
-rw-r--r--lib/libthr/thread/thr_syscalls.c22
5 files changed, 73 insertions, 3 deletions
diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc
index fef0f3c..105f469 100644
--- a/lib/libc/sys/Makefile.inc
+++ b/lib/libc/sys/Makefile.inc
@@ -270,6 +270,7 @@ MAN+= sctp_generic_recvmsg.2 \
wait.2 \
write.2
+MLINKS+=accept.2 accept4.2
MLINKS+=access.2 eaccess.2 \
access.2 faccessat.2
MLINKS+=brk.2 sbrk.2
diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map
index 6faa0af..149fa41 100644
--- a/lib/libc/sys/Symbol.map
+++ b/lib/libc/sys/Symbol.map
@@ -378,6 +378,7 @@ FBSD_1.2 {
};
FBSD_1.3 {
+ accept4;
bindat;
cap_fcntls_get;
cap_fcntls_limit;
@@ -461,6 +462,8 @@ FBSDprivate_1.0 {
__sys_abort2;
_accept;
__sys_accept;
+ _accept4;
+ __sys_accept4;
_access;
__sys_access;
_acct;
diff --git a/lib/libc/sys/accept.2 b/lib/libc/sys/accept.2
index d27bce3..8353ecf 100644
--- a/lib/libc/sys/accept.2
+++ b/lib/libc/sys/accept.2
@@ -41,6 +41,8 @@
.In sys/socket.h
.Ft int
.Fn accept "int s" "struct sockaddr * restrict addr" "socklen_t * restrict addrlen"
+.Ft int
+.Fn accept4 "int s" "struct sockaddr * restrict addr" "socklen_t * restrict addrlen" "int flags"
.Sh DESCRIPTION
The argument
.Fa s
@@ -66,6 +68,26 @@ and
signals from the original socket
.Fa s .
.Pp
+The
+.Fn accept4
+system call is similar,
+but the
+.Dv O_NONBLOCK
+property of the new socket is instead determined by the
+.Dv SOCK_NONBLOCK
+flag in the
+.Fa flags
+argument,
+the
+.Dv O_ASYNC
+property is cleared,
+the signal destination is cleared
+and the close-on-exec flag on the new file descriptor can be set via the
+.Dv SOCK_CLOEXEC
+flag in the
+.Fa flags
+argument.
+.Pp
If no pending connections are
present on the queue, and the original socket
is not marked as non-blocking,
@@ -141,13 +163,15 @@ properties and the signal destination being inherited,
but should set them explicitly using
.Xr fcntl 2 .
.Sh RETURN VALUES
-The call returns \-1 on error.
-If it succeeds, it returns a non-negative
+These calls return \-1 on error.
+If they succeed, they return a non-negative
integer that is a descriptor for the accepted socket.
.Sh ERRORS
The
.Fn accept
-system call will fail if:
+and
+.Fn accept4
+system calls will fail if:
.Bl -tag -width Er
.It Bq Er EBADF
The descriptor is invalid.
@@ -176,6 +200,16 @@ are present to be accepted.
A connection arrived, but it was closed while waiting
on the listen queue.
.El
+.Pp
+The
+.Fn accept4
+system call will also fail if:
+.Bl -tag -width Er
+.It Bq Er EINVAL
+The
+.Fa flags
+argument is invalid.
+.El
.Sh SEE ALSO
.Xr bind 2 ,
.Xr connect 2 ,
@@ -190,3 +224,8 @@ The
.Fn accept
system call appeared in
.Bx 4.2 .
+.Pp
+The
+.Fn accept4
+system call appeared in
+.Fx 10.0 .
diff --git a/lib/libthr/pthread.map b/lib/libthr/pthread.map
index 355edea..bbbd930e 100644
--- a/lib/libthr/pthread.map
+++ b/lib/libthr/pthread.map
@@ -181,6 +181,7 @@ FBSDprivate_1.0 {
___wait;
___waitpid;
__accept;
+ __accept4;
__aio_suspend;
__close;
__connect;
@@ -408,3 +409,7 @@ FBSD_1.2 {
setcontext;
swapcontext;
};
+
+FBSD_1.3 {
+ accept4;
+};
diff --git a/lib/libthr/thread/thr_syscalls.c b/lib/libthr/thread/thr_syscalls.c
index 2327d74..7a08302 100644
--- a/lib/libthr/thread/thr_syscalls.c
+++ b/lib/libthr/thread/thr_syscalls.c
@@ -101,6 +101,7 @@ extern pid_t __waitpid(pid_t, int *, int);
extern int __sys_aio_suspend(const struct aiocb * const[], int,
const struct timespec *);
extern int __sys_accept(int, struct sockaddr *, socklen_t *);
+extern int __sys_accept4(int, struct sockaddr *, socklen_t *, int);
extern int __sys_connect(int, const struct sockaddr *, socklen_t);
extern int __sys_fsync(int);
extern int __sys_msync(void *, size_t, int);
@@ -129,6 +130,7 @@ int ___usleep(useconds_t useconds);
pid_t ___wait(int *);
pid_t ___waitpid(pid_t, int *, int);
int __accept(int, struct sockaddr *, socklen_t *);
+int __accept4(int, struct sockaddr *, socklen_t *, int);
int __aio_suspend(const struct aiocb * const iocbs[], int,
const struct timespec *);
int __close(int);
@@ -176,6 +178,26 @@ __accept(int s, struct sockaddr *addr, socklen_t *addrlen)
return (ret);
}
+__weak_reference(__accept4, accept4);
+
+/*
+ * Cancellation behavior:
+ * If thread is canceled, no socket is created.
+ */
+int
+__accept4(int s, struct sockaddr *addr, socklen_t *addrlen, int flags)
+{
+ struct pthread *curthread;
+ int ret;
+
+ curthread = _get_curthread();
+ _thr_cancel_enter(curthread);
+ ret = __sys_accept4(s, addr, addrlen, flags);
+ _thr_cancel_leave(curthread, ret == -1);
+
+ return (ret);
+}
+
__weak_reference(__aio_suspend, aio_suspend);
int
OpenPOWER on IntegriCloud