Update copyright notices with scripts/update-copyrights.
[jlayton/glibc.git] / sysdeps / unix / sysv / linux / accept4.c
1 /* Copyright (C) 2008-2013 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3    Contributed by Ulrich Drepper <drepper@redhat.com>, 2008.
4
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <http://www.gnu.org/licenses/>.  */
18
19 #include <errno.h>
20 #include <signal.h>
21 #include <sys/socket.h>
22
23 #include <sysdep-cancel.h>
24 #include <sys/syscall.h>
25 #include <kernel-features.h>
26
27
28 #ifdef __NR_accept4
29 int
30 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
31 {
32   if (SINGLE_THREAD_P)
33     return INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len, flags);
34
35   int oldtype = LIBC_CANCEL_ASYNC ();
36
37   int result = INLINE_SYSCALL (accept4, 4, fd, addr.__sockaddr__, addr_len,
38                                flags);
39
40   LIBC_CANCEL_RESET (oldtype);
41
42   return result;
43 }
44 #elif defined __NR_socketcall
45 # ifndef __ASSUME_ACCEPT4
46 extern int __internal_accept4 (int fd, __SOCKADDR_ARG addr,
47                                socklen_t *addr_len, int flags)
48      attribute_hidden;
49
50 static int have_accept4;
51
52 int
53 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
54 {
55   if (__builtin_expect (have_accept4 >= 0, 1))
56     {
57       int ret = __internal_accept4 (fd, addr, addr_len, flags);
58       /* The kernel returns -EINVAL for unknown socket operations.
59          We need to convert that error to an ENOSYS error.  */
60       if (__builtin_expect (ret < 0, 0)
61           && have_accept4 == 0
62           && errno == EINVAL)
63         {
64           /* Try another call, this time with the FLAGS parameter
65              cleared and an invalid file descriptor.  This call will not
66              cause any harm and it will return immediately.  */
67           ret = __internal_accept4 (-1, addr, addr_len, 0);
68           if (errno == EINVAL)
69             {
70               have_accept4 = -1;
71               __set_errno (ENOSYS);
72             }
73           else
74             {
75               have_accept4 = 1;
76               __set_errno (EINVAL);
77             }
78           return -1;
79         }
80       return ret;
81     }
82   __set_errno (ENOSYS);
83   return -1;
84 }
85 # else
86 /* When __ASSUME_ACCEPT4 accept4 is defined in internal_accept4.S.  */
87 # endif
88 #else
89 int
90 accept4 (int fd, __SOCKADDR_ARG addr, socklen_t *addr_len, int flags)
91 {
92   __set_errno (ENOSYS);
93   return -1;
94 }
95 stub_warning (accept4)
96 #endif