root/maint/gnulib/lib/accept4.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. accept4

   1 /* Accept a connection on a socket, with specific opening flags.
   2    Copyright (C) 2009-2021 Free Software Foundation, Inc.
   3 
   4    This file is free software: you can redistribute it and/or modify
   5    it under the terms of the GNU Lesser General Public License as
   6    published by the Free Software Foundation; either version 3 of the
   7    License, or (at your option) any later version.
   8 
   9    This file 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 Lesser General Public License for more details.
  13 
  14    You should have received a copy of the GNU Lesser General Public License
  15    along with this program.  If not, see <https://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 #if GNULIB_MSVC_NOTHROW
  26 # include "msvc-nothrow.h"
  27 #else
  28 # include <io.h>
  29 #endif
  30 
  31 #ifndef SOCK_CLOEXEC
  32 # define SOCK_CLOEXEC 0
  33 #endif
  34 #ifndef SOCK_NONBLOCK
  35 # define SOCK_NONBLOCK 0
  36 #endif
  37 
  38 int
  39 accept4 (int sockfd, struct sockaddr *addr, socklen_t *addrlen, int flags)
     /* [previous][next][first][last][top][bottom][index][help] */
  40 {
  41   int fd;
  42 
  43 #if HAVE_DECL_ACCEPT4
  44 # undef accept4
  45   /* Try the system call first, if it exists.  (We may be running with a glibc
  46      that has the function but with an older kernel that lacks it.)  */
  47   {
  48     /* Cache the information whether the system call really exists.  */
  49     static int have_accept4_really; /* 0 = unknown, 1 = yes, -1 = no */
  50     if (have_accept4_really >= 0)
  51       {
  52         int result = accept4 (sockfd, addr, addrlen, flags);
  53         if (!(result < 0 && errno == ENOSYS))
  54           {
  55             have_accept4_really = 1;
  56             return result;
  57           }
  58         have_accept4_really = -1;
  59       }
  60   }
  61 #endif
  62 
  63   /* Check the supported flags.  */
  64   if ((flags & ~(SOCK_CLOEXEC | SOCK_NONBLOCK | O_TEXT | O_BINARY)) != 0)
  65     {
  66       errno = EINVAL;
  67       return -1;
  68     }
  69 
  70   fd = accept (sockfd, addr, addrlen);
  71   if (fd < 0)
  72     return -1;
  73 
  74 #if SOCK_CLOEXEC
  75 # if defined _WIN32 && ! defined __CYGWIN__
  76 /* Native Windows API.  */
  77   if (flags & SOCK_CLOEXEC)
  78     {
  79       HANDLE curr_process = GetCurrentProcess ();
  80       HANDLE old_handle = (HANDLE) _get_osfhandle (fd);
  81       HANDLE new_handle;
  82       int nfd;
  83 
  84       if (!DuplicateHandle (curr_process,           /* SourceProcessHandle */
  85                             old_handle,             /* SourceHandle */
  86                             curr_process,           /* TargetProcessHandle */
  87                             (PHANDLE) &new_handle,  /* TargetHandle */
  88                             (DWORD) 0,              /* DesiredAccess */
  89                             FALSE,                  /* InheritHandle */
  90                             DUPLICATE_SAME_ACCESS)) /* Options */
  91         {
  92           close (fd);
  93           errno = EBADF; /* arbitrary */
  94           return -1;
  95         }
  96 
  97       /* Closing fd before allocating the new fd ensures that the new fd will
  98          have the minimum possible value.  */
  99       close (fd);
 100       nfd = _open_osfhandle ((intptr_t) new_handle,
 101                              O_NOINHERIT | (flags & (O_TEXT | O_BINARY)));
 102       if (nfd < 0)
 103         {
 104           CloseHandle (new_handle);
 105           return -1;
 106         }
 107       return nfd;
 108     }
 109 # else
 110 /* Unix API.  */
 111   if (flags & SOCK_CLOEXEC)
 112     {
 113       int fcntl_flags;
 114 
 115       if ((fcntl_flags = fcntl (fd, F_GETFD, 0)) < 0
 116           || fcntl (fd, F_SETFD, fcntl_flags | FD_CLOEXEC) == -1)
 117         {
 118           int saved_errno = errno;
 119           close (fd);
 120           errno = saved_errno;
 121           return -1;
 122         }
 123     }
 124 # endif
 125 #endif
 126 
 127 #if SOCK_NONBLOCK
 128   if (flags & SOCK_NONBLOCK)
 129     {
 130       int fcntl_flags;
 131 
 132       if ((fcntl_flags = fcntl (fd, F_GETFL, 0)) < 0
 133           || fcntl (fd, F_SETFL, fcntl_flags | O_NONBLOCK) == -1)
 134         {
 135           int saved_errno = errno;
 136           close (fd);
 137           errno = saved_errno;
 138           return -1;
 139         }
 140     }
 141 #endif
 142 
 143 #if O_BINARY
 144   if (flags & O_BINARY)
 145     set_binary_mode (fd, O_BINARY);
 146   else if (flags & O_TEXT)
 147     set_binary_mode (fd, O_TEXT);
 148 #endif
 149 
 150   return fd;
 151 }

/* [previous][next][first][last][top][bottom][index][help] */