accept4.c 4.1 KB

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