sys_stat: Fix 'implicit declaration of function' warning on OS/2 kLIBC.
[gnulib.git] / lib / accept4.c
blob4436bdc27ccecda18130268150642247b68a365e
1 /* Accept a connection on a socket, with specific opening flags.
2 Copyright (C) 2009-2019 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License along
15 with this program; if not, see <https://www.gnu.org/licenses/>. */
17 #include <config.h>
19 /* Specification. */
20 #include <sys/socket.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include "binary-io.h"
25 #if GNULIB_MSVC_NOTHROW
26 # include "msvc-nothrow.h"
27 #else
28 # include <io.h>
29 #endif
31 #ifndef SOCK_CLOEXEC
32 # define SOCK_CLOEXEC 0
33 #endif
35 int
36 accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
38 int fd;
40 #if HAVE_ACCEPT4
41 # undef accept4
42 /* Try the system call first, if it exists. (We may be running with a glibc
43 that has the function but with an older kernel that lacks it.) */
45 /* Cache the information whether the system call really exists. */
46 static int have_accept4_really; /* 0 = unknown, 1 = yes, -1 = no */
47 if (have_accept4_really >= 0)
49 int result = accept4 (sockfd, addr, addrlen, flags);
50 if (!(result < 0 && errno == ENOSYS))
52 have_accept4_really = 1;
53 return result;
55 have_accept4_really = -1;
58 #endif
60 /* Check the supported flags. */
61 if ((flags & ~(SOCK_CLOEXEC | O_TEXT | O_BINARY)) != 0)
63 errno = EINVAL;
64 return -1;
67 fd = accept (sockfd, addr, addrlen);
68 if (fd < 0)
69 return -1;
71 #if SOCK_CLOEXEC
72 # if defined _WIN32 && ! defined __CYGWIN__
73 /* Native Windows API. */
74 if (flags & SOCK_CLOEXEC)
76 HANDLE curr_process = GetCurrentProcess ();
77 HANDLE old_handle = (HANDLE) _get_osfhandle (fd);
78 HANDLE new_handle;
79 int nfd;
81 if (!DuplicateHandle (curr_process, /* SourceProcessHandle */
82 old_handle, /* SourceHandle */
83 curr_process, /* TargetProcessHandle */
84 (PHANDLE) &new_handle, /* TargetHandle */
85 (DWORD) 0, /* DesiredAccess */
86 FALSE, /* InheritHandle */
87 DUPLICATE_SAME_ACCESS)) /* Options */
89 close (fd);
90 errno = EBADF; /* arbitrary */
91 return -1;
94 /* Closing fd before allocating the new fd ensures that the new fd will
95 have the minimum possible value. */
96 close (fd);
97 nfd = _open_osfhandle ((intptr_t) new_handle,
98 O_NOINHERIT | (flags & (O_TEXT | O_BINARY)));
99 if (nfd < 0)
101 CloseHandle (new_handle);
102 return -1;
104 return nfd;
106 # else
107 /* Unix API. */
108 if (flags & SOCK_CLOEXEC)
110 int fcntl_flags;
112 if ((fcntl_flags = fcntl (fd, F_GETFD, 0)) < 0
113 || fcntl (fd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
115 int saved_errno = errno;
116 close (fd);
117 errno = saved_errno;
118 return -1;
121 # endif
122 #endif
124 #if O_BINARY
125 if (flags & O_BINARY)
126 set_binary_mode (fd, O_BINARY);
127 else if (flags & O_TEXT)
128 set_binary_mode (fd, O_TEXT);
129 #endif
131 return fd;