New module 'accept4'.
[gnulib.git] / lib / accept4.c
1 /* Accept a connection on a socket, with specific opening flags.
2    Copyright (C) 2009 Free Software Foundation, Inc.
3
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.
8
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.
13
14    You should have received a copy of the GNU General Public License along
15    with this program; if not, write to the Free Software Foundation,
16    Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.  */
17
18 #include <config.h>
19
20 /* Specification.  */
21 #include <sys/socket.h>
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include "binary-io.h"
26
27 #ifndef SOCK_CLOEXEC
28 # define SOCK_CLOEXEC 0
29 #endif
30
31 int
32 accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
33 {
34   int fd;
35
36   /* Check the supported flags.  */
37   if ((flags & ~(SOCK_CLOEXEC | O_TEXT | O_BINARY)) != 0)
38     {
39       errno = EINVAL;
40       return -1;
41     }
42
43   fd = accept (sockfd, addr, addrlen);
44   if (fd < 0)
45     return -1;
46
47 #if SOCK_CLOEXEC
48 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
49 /* Native Woe32 API.  */
50   if (flags & SOCK_CLOEXEC)
51     {
52       HANDLE curr_process = GetCurrentProcess ();
53       HANDLE old_handle = (HANDLE) _get_osfhandle (fd);
54       HANDLE new_handle;
55       int nfd;
56
57       if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
58                             old_handle,             /* SourceHandle */
59                             curr_process,           /* TargetProcessHandle */
60                             (PHANDLE) &new_handle,  /* TargetHandle */
61                             (DWORD) 0,              /* DesiredAccess */
62                             FALSE,                  /* InheritHandle */
63                             DUPLICATE_SAME_ACCESS)) /* Options */
64         {
65           close (fd);
66           errno = EBADF; /* arbitrary */
67           return -1;
68         }
69
70       /* Closing fd before allocating the new fd ensures that the new fd will
71          have the minimum possible value.  */
72       close (fd);
73       nfd = _open_osfhandle ((long) new_handle,
74                              O_NOINHERIT | (flags & (O_TEXT | O_BINARY)));
75       if (nfd < 0)
76         {
77           CloseHandle (new_handle);
78           return -1;
79         }
80       return nfd;
81     }
82 # else
83 /* Unix API.  */
84   if (flags & SOCK_CLOEXEC)
85     {
86       int fcntl_flags;
87
88       if ((fcntl_flags = fcntl (fd, F_GETFD, 0)) < 0
89           || fcntl (fd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
90         {
91           int saved_errno = errno;
92           close (fd);
93           errno = saved_errno;
94           return -1;
95         }
96     }
97 # endif
98 #endif
99
100 #if O_BINARY
101   if (flags & O_BINARY)
102     setmode (fd, O_BINARY);
103   else if (flags & O_TEXT)
104     setmode (fd, O_TEXT);
105 #endif
106
107   return fd;
108 }