aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>2008-07-24 00:29:20 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2008-07-24 13:47:27 -0400
commitaaca0bdca573f3f51ea03139f9c7289541e7bca3 (patch)
treed25b0baa73b5301d91a5c848a896bad0fb719acc /include/linux
parenta677a039be7243357d93502bff2b40850c942e2d (diff)
flag parameters: paccept
This patch is by far the most complex in the series. It adds a new syscall paccept. This syscall differs from accept in that it adds (at the userlevel) two additional parameters: - a signal mask - a flags value The flags parameter can be used to set flag like SOCK_CLOEXEC. This is imlpemented here as well. Some people argued that this is a property which should be inherited from the file desriptor for the server but this is against POSIX. Additionally, we really want the signal mask parameter as well (similar to pselect, ppoll, etc). So an interface change in inevitable. The flag value is the same as for socket and socketpair. I think diverging here will only create confusion. Similar to the filesystem interfaces where the use of the O_* constants differs, it is acceptable here. The signal mask is handled as for pselect etc. The mask is temporarily installed for the thread and removed before the call returns. I modeled the code after pselect. If there is a problem it's likely also in pselect. For architectures which use socketcall I maintained this interface instead of adding a system call. The symmetry shouldn't be broken. The following test must be adjusted for architectures other than x86 and x86-64 and in case the syscall numbers changed. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #include <errno.h> #include <fcntl.h> #include <pthread.h> #include <signal.h> #include <stdio.h> #include <unistd.h> #include <netinet/in.h> #include <sys/socket.h> #include <sys/syscall.h> #ifndef __NR_paccept # ifdef __x86_64__ # define __NR_paccept 288 # elif defined __i386__ # define SYS_PACCEPT 18 # define USE_SOCKETCALL 1 # else # error "need __NR_paccept" # endif #endif #ifdef USE_SOCKETCALL # define paccept(fd, addr, addrlen, mask, flags) \ ({ long args[6] = { \ (long) fd, (long) addr, (long) addrlen, (long) mask, 8, (long) flags }; \ syscall (__NR_socketcall, SYS_PACCEPT, args); }) #else # define paccept(fd, addr, addrlen, mask, flags) \ syscall (__NR_paccept, fd, addr, addrlen, mask, 8, flags) #endif #define PORT 57392 #define SOCK_CLOEXEC O_CLOEXEC static pthread_barrier_t b; static void * tf (void *arg) { pthread_barrier_wait (&b); int s = socket (AF_INET, SOCK_STREAM, 0); struct sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); sin.sin_port = htons (PORT); connect (s, (const struct sockaddr *) &sin, sizeof (sin)); close (s); pthread_barrier_wait (&b); s = socket (AF_INET, SOCK_STREAM, 0); sin.sin_port = htons (PORT); connect (s, (const struct sockaddr *) &sin, sizeof (sin)); close (s); pthread_barrier_wait (&b); pthread_barrier_wait (&b); sleep (2); pthread_kill ((pthread_t) arg, SIGUSR1); return NULL; } static void handler (int s) { } int main (void) { pthread_barrier_init (&b, NULL, 2); struct sockaddr_in sin; pthread_t th; if (pthread_create (&th, NULL, tf, (void *) pthread_self ()) != 0) { puts ("pthread_create failed"); return 1; } int s = socket (AF_INET, SOCK_STREAM, 0); int reuse = 1; setsockopt (s, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof (reuse)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = htonl (INADDR_LOOPBACK); sin.sin_port = htons (PORT); bind (s, (struct sockaddr *) &sin, sizeof (sin)); listen (s, SOMAXCONN); pthread_barrier_wait (&b); int s2 = paccept (s, NULL, 0, NULL, 0); if (s2 < 0) { puts ("paccept(0) failed"); return 1; } int coe = fcntl (s2, F_GETFD); if (coe & FD_CLOEXEC) { puts ("paccept(0) set close-on-exec-flag"); return 1; } close (s2); pthread_barrier_wait (&b); s2 = paccept (s, NULL, 0, NULL, SOCK_CLOEXEC); if (s2 < 0) { puts ("paccept(SOCK_CLOEXEC) failed"); return 1; } coe = fcntl (s2, F_GETFD); if ((coe & FD_CLOEXEC) == 0) { puts ("paccept(SOCK_CLOEXEC) does not set close-on-exec flag"); return 1; } close (s2); pthread_barrier_wait (&b); struct sigaction sa; sa.sa_handler = handler; sa.sa_flags = 0; sigemptyset (&sa.sa_mask); sigaction (SIGUSR1, &sa, NULL); sigset_t ss; pthread_sigmask (SIG_SETMASK, NULL, &ss); sigaddset (&ss, SIGUSR1); pthread_sigmask (SIG_SETMASK, &ss, NULL); sigdelset (&ss, SIGUSR1); alarm (4); pthread_barrier_wait (&b); errno = 0 ; s2 = paccept (s, NULL, 0, &ss, 0); if (s2 != -1 || errno != EINTR) { puts ("paccept did not fail with EINTR"); return 1; } close (s); puts ("OK"); return 0; } ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ [akpm@linux-foundation.org: make it compile] [akpm@linux-foundation.org: add sys_ni stub] Signed-off-by: Ulrich Drepper <drepper@redhat.com> Acked-by: Davide Libenzi <davidel@xmailserver.org> Cc: Michael Kerrisk <mtk.manpages@googlemail.com> Cc: <linux-arch@vger.kernel.org> Cc: "David S. Miller" <davem@davemloft.net> Cc: Roland McGrath <roland@redhat.com> Cc: Kyle McMartin <kyle@mcmartin.ca> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/net.h3
-rw-r--r--include/linux/syscalls.h2
2 files changed, 5 insertions, 0 deletions
diff --git a/include/linux/net.h b/include/linux/net.h
index 8b5383c45b45..3a9b06d4d0fe 100644
--- a/include/linux/net.h
+++ b/include/linux/net.h
@@ -47,6 +47,7 @@ struct net;
47#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */ 47#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */
48#define SYS_SENDMSG 16 /* sys_sendmsg(2) */ 48#define SYS_SENDMSG 16 /* sys_sendmsg(2) */
49#define SYS_RECVMSG 17 /* sys_recvmsg(2) */ 49#define SYS_RECVMSG 17 /* sys_recvmsg(2) */
50#define SYS_PACCEPT 18 /* sys_paccept(2) */
50 51
51typedef enum { 52typedef enum {
52 SS_FREE = 0, /* not allocated */ 53 SS_FREE = 0, /* not allocated */
@@ -219,6 +220,8 @@ extern int sock_map_fd(struct socket *sock, int flags);
219extern struct socket *sockfd_lookup(int fd, int *err); 220extern struct socket *sockfd_lookup(int fd, int *err);
220#define sockfd_put(sock) fput(sock->file) 221#define sockfd_put(sock) fput(sock->file)
221extern int net_ratelimit(void); 222extern int net_ratelimit(void);
223extern long do_accept(int fd, struct sockaddr __user *upeer_sockaddr,
224 int __user *upeer_addrlen, int flags);
222 225
223#define net_random() random32() 226#define net_random() random32()
224#define net_srandom(seed) srandom32((__force u32)seed) 227#define net_srandom(seed) srandom32((__force u32)seed)
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h
index 4394dadff813..2a2a40af6b2c 100644
--- a/include/linux/syscalls.h
+++ b/include/linux/syscalls.h
@@ -409,6 +409,8 @@ asmlinkage long sys_getsockopt(int fd, int level, int optname,
409asmlinkage long sys_bind(int, struct sockaddr __user *, int); 409asmlinkage long sys_bind(int, struct sockaddr __user *, int);
410asmlinkage long sys_connect(int, struct sockaddr __user *, int); 410asmlinkage long sys_connect(int, struct sockaddr __user *, int);
411asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *); 411asmlinkage long sys_accept(int, struct sockaddr __user *, int __user *);
412asmlinkage long sys_paccept(int, struct sockaddr __user *, int __user *,
413 const sigset_t *, size_t, int);
412asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *); 414asmlinkage long sys_getsockname(int, struct sockaddr __user *, int __user *);
413asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *); 415asmlinkage long sys_getpeername(int, struct sockaddr __user *, int __user *);
414asmlinkage long sys_send(int, void __user *, size_t, unsigned); 416asmlinkage long sys_send(int, void __user *, size_t, unsigned);