maint: update copyright
[gnulib.git] / lib / accept4.c
1 /* Accept a connection on a socket, with specific opening flags.
2    Copyright (C) 2009-2014 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, see <http://www.gnu.org/licenses/>.  */
16
17 #include <config.h>
18
19 /* Specification.  */
20 #include <sys/socket.h>
21
22 #include <errno.h>
23 #include <fcntl.h>
24 #include "binary-io.h"
25 #include "msvc-nothrow.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 #if HAVE_ACCEPT4
37 # undef accept4
38   /* Try the system call first, if it exists.  (We may be running with a glibc
39      that has the function but with an older kernel that lacks it.)  */
40   {
41     /* Cache the information whether the system call really exists.  */
42     static int have_accept4_really; /* 0 = unknown, 1 = yes, -1 = no */
43     if (have_accept4_really >= 0)
44       {
45         int result = accept4 (sockfd, addr, addrlen, flags);
46         if (!(result < 0 && errno == ENOSYS))
47           {
48             have_accept4_really = 1;
49             return result;
50           }
51         have_accept4_really = -1;
52       }
53   }
54 #endif
55
56   /* Check the supported flags.  */
57   if ((flags & ~(SOCK_CLOEXEC | O_TEXT | O_BINARY)) != 0)
58     {
59       errno = EINVAL;
60       return -1;
61     }
62
63   fd = accept (sockfd, addr, addrlen);
64   if (fd < 0)
65     return -1;
66
67 #if SOCK_CLOEXEC
68 # if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
69 /* Native Windows API.  */
70   if (flags & SOCK_CLOEXEC)
71     {
72       HANDLE curr_process = GetCurrentProcess ();
73       HANDLE old_handle = (HANDLE) _get_osfhandle (fd);
74       HANDLE new_handle;
75       int nfd;
76
77       if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
78                             old_handle,             /* SourceHandle */
79                             curr_process,           /* TargetProcessHandle */
80                             (PHANDLE) &new_handle,  /* TargetHandle */
81                             (DWORD) 0,              /* DesiredAccess */
82                             FALSE,                  /* InheritHandle */
83                             DUPLICATE_SAME_ACCESS)) /* Options */
84         {
85           close (fd);
86           errno = EBADF; /* arbitrary */
87           return -1;
88         }
89
90       /* Closing fd before allocating the new fd ensures that the new fd will
91          have the minimum possible value.  */
92       close (fd);
93       nfd = _open_osfhandle ((intptr_t) new_handle,
94                              O_NOINHERIT | (flags & (O_TEXT | O_BINARY)));
95       if (nfd < 0)
96         {
97           CloseHandle (new_handle);
98           return -1;
99         }
100       return nfd;
101     }
102 # else
103 /* Unix API.  */
104   if (flags & SOCK_CLOEXEC)
105     {
106       int fcntl_flags;
107
108       if ((fcntl_flags = fcntl (fd, F_GETFD, 0)) < 0
109           || fcntl (fd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
110         {
111           int saved_errno = errno;
112           close (fd);
113           errno = saved_errno;
114           return -1;
115         }
116     }
117 # endif
118 #endif
119
120 #if O_BINARY
121   if (flags & O_BINARY)
122     set_binary_mode (fd, O_BINARY);
123   else if (flags & O_TEXT)
124     set_binary_mode (fd, O_TEXT);
125 #endif
126
127   return fd;
128 }