1*4b169a6bSchristos /* sockets.c --- wrappers for Windows socket functions
2*4b169a6bSchristos
3*4b169a6bSchristos Copyright (C) 2008-2022 Free Software Foundation, Inc.
4*4b169a6bSchristos
5*4b169a6bSchristos This file is free software: you can redistribute it and/or modify
6*4b169a6bSchristos it under the terms of the GNU Lesser General Public License as
7*4b169a6bSchristos published by the Free Software Foundation; either version 2.1 of the
8*4b169a6bSchristos License, or (at your option) any later version.
9*4b169a6bSchristos
10*4b169a6bSchristos This file is distributed in the hope that it will be useful,
11*4b169a6bSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
12*4b169a6bSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13*4b169a6bSchristos GNU Lesser General Public License for more details.
14*4b169a6bSchristos
15*4b169a6bSchristos You should have received a copy of the GNU Lesser General Public License
16*4b169a6bSchristos along with this program. If not, see <https://www.gnu.org/licenses/>. */
17*4b169a6bSchristos
18*4b169a6bSchristos /* Written by Simon Josefsson */
19*4b169a6bSchristos
20*4b169a6bSchristos #include <config.h>
21*4b169a6bSchristos
22*4b169a6bSchristos /* Specification. */
23*4b169a6bSchristos #include "sockets.h"
24*4b169a6bSchristos
25*4b169a6bSchristos #if WINDOWS_SOCKETS
26*4b169a6bSchristos
27*4b169a6bSchristos /* This includes winsock2.h on MinGW. */
28*4b169a6bSchristos # include <sys/socket.h>
29*4b169a6bSchristos
30*4b169a6bSchristos # include "fd-hook.h"
31*4b169a6bSchristos # if GNULIB_MSVC_NOTHROW
32*4b169a6bSchristos # include "msvc-nothrow.h"
33*4b169a6bSchristos # else
34*4b169a6bSchristos # include <io.h>
35*4b169a6bSchristos # endif
36*4b169a6bSchristos
37*4b169a6bSchristos /* Get set_winsock_errno, FD_TO_SOCKET etc. */
38*4b169a6bSchristos # include "w32sock.h"
39*4b169a6bSchristos
40*4b169a6bSchristos static int
close_fd_maybe_socket(const struct fd_hook * remaining_list,gl_close_fn primary,int fd)41*4b169a6bSchristos close_fd_maybe_socket (const struct fd_hook *remaining_list,
42*4b169a6bSchristos gl_close_fn primary,
43*4b169a6bSchristos int fd)
44*4b169a6bSchristos {
45*4b169a6bSchristos /* Note about multithread-safety: There is a race condition where, between
46*4b169a6bSchristos our calls to closesocket() and the primary close(), some other thread
47*4b169a6bSchristos could make system calls that allocate precisely the same HANDLE value
48*4b169a6bSchristos as sock; then the primary close() would call CloseHandle() on it. */
49*4b169a6bSchristos SOCKET sock;
50*4b169a6bSchristos WSANETWORKEVENTS ev;
51*4b169a6bSchristos
52*4b169a6bSchristos /* Test whether fd refers to a socket. */
53*4b169a6bSchristos sock = FD_TO_SOCKET (fd);
54*4b169a6bSchristos ev.lNetworkEvents = 0xDEADBEEF;
55*4b169a6bSchristos WSAEnumNetworkEvents (sock, NULL, &ev);
56*4b169a6bSchristos if (ev.lNetworkEvents != 0xDEADBEEF)
57*4b169a6bSchristos {
58*4b169a6bSchristos /* fd refers to a socket. */
59*4b169a6bSchristos /* FIXME: other applications, like squid, use an undocumented
60*4b169a6bSchristos _free_osfhnd free function. But this is not enough: The 'osfile'
61*4b169a6bSchristos flags for fd also needs to be cleared, but it is hard to access it.
62*4b169a6bSchristos Instead, here we just close twice the file descriptor. */
63*4b169a6bSchristos if (closesocket (sock))
64*4b169a6bSchristos {
65*4b169a6bSchristos set_winsock_errno ();
66*4b169a6bSchristos return -1;
67*4b169a6bSchristos }
68*4b169a6bSchristos else
69*4b169a6bSchristos {
70*4b169a6bSchristos /* This call frees the file descriptor and does a
71*4b169a6bSchristos CloseHandle ((HANDLE) _get_osfhandle (fd)), which fails. */
72*4b169a6bSchristos _close (fd);
73*4b169a6bSchristos return 0;
74*4b169a6bSchristos }
75*4b169a6bSchristos }
76*4b169a6bSchristos else
77*4b169a6bSchristos /* Some other type of file descriptor. */
78*4b169a6bSchristos return execute_close_hooks (remaining_list, primary, fd);
79*4b169a6bSchristos }
80*4b169a6bSchristos
81*4b169a6bSchristos static int
ioctl_fd_maybe_socket(const struct fd_hook * remaining_list,gl_ioctl_fn primary,int fd,int request,void * arg)82*4b169a6bSchristos ioctl_fd_maybe_socket (const struct fd_hook *remaining_list,
83*4b169a6bSchristos gl_ioctl_fn primary,
84*4b169a6bSchristos int fd, int request, void *arg)
85*4b169a6bSchristos {
86*4b169a6bSchristos SOCKET sock;
87*4b169a6bSchristos WSANETWORKEVENTS ev;
88*4b169a6bSchristos
89*4b169a6bSchristos /* Test whether fd refers to a socket. */
90*4b169a6bSchristos sock = FD_TO_SOCKET (fd);
91*4b169a6bSchristos ev.lNetworkEvents = 0xDEADBEEF;
92*4b169a6bSchristos WSAEnumNetworkEvents (sock, NULL, &ev);
93*4b169a6bSchristos if (ev.lNetworkEvents != 0xDEADBEEF)
94*4b169a6bSchristos {
95*4b169a6bSchristos /* fd refers to a socket. */
96*4b169a6bSchristos if (ioctlsocket (sock, request, arg) < 0)
97*4b169a6bSchristos {
98*4b169a6bSchristos set_winsock_errno ();
99*4b169a6bSchristos return -1;
100*4b169a6bSchristos }
101*4b169a6bSchristos else
102*4b169a6bSchristos return 0;
103*4b169a6bSchristos }
104*4b169a6bSchristos else
105*4b169a6bSchristos /* Some other type of file descriptor. */
106*4b169a6bSchristos return execute_ioctl_hooks (remaining_list, primary, fd, request, arg);
107*4b169a6bSchristos }
108*4b169a6bSchristos
109*4b169a6bSchristos static struct fd_hook fd_sockets_hook;
110*4b169a6bSchristos
111*4b169a6bSchristos static int initialized_sockets_version /* = 0 */;
112*4b169a6bSchristos
113*4b169a6bSchristos #endif /* WINDOWS_SOCKETS */
114*4b169a6bSchristos
115*4b169a6bSchristos int
gl_sockets_startup(_GL_UNUSED int version)116*4b169a6bSchristos gl_sockets_startup (_GL_UNUSED int version)
117*4b169a6bSchristos {
118*4b169a6bSchristos #if WINDOWS_SOCKETS
119*4b169a6bSchristos if (version > initialized_sockets_version)
120*4b169a6bSchristos {
121*4b169a6bSchristos WSADATA data;
122*4b169a6bSchristos int err;
123*4b169a6bSchristos
124*4b169a6bSchristos err = WSAStartup (version, &data);
125*4b169a6bSchristos if (err != 0)
126*4b169a6bSchristos return 1;
127*4b169a6bSchristos
128*4b169a6bSchristos if (data.wVersion != version)
129*4b169a6bSchristos {
130*4b169a6bSchristos WSACleanup ();
131*4b169a6bSchristos return 2;
132*4b169a6bSchristos }
133*4b169a6bSchristos
134*4b169a6bSchristos if (initialized_sockets_version == 0)
135*4b169a6bSchristos register_fd_hook (close_fd_maybe_socket, ioctl_fd_maybe_socket,
136*4b169a6bSchristos &fd_sockets_hook);
137*4b169a6bSchristos
138*4b169a6bSchristos initialized_sockets_version = version;
139*4b169a6bSchristos }
140*4b169a6bSchristos #endif
141*4b169a6bSchristos
142*4b169a6bSchristos return 0;
143*4b169a6bSchristos }
144*4b169a6bSchristos
145*4b169a6bSchristos int
gl_sockets_cleanup(void)146*4b169a6bSchristos gl_sockets_cleanup (void)
147*4b169a6bSchristos {
148*4b169a6bSchristos #if WINDOWS_SOCKETS
149*4b169a6bSchristos int err;
150*4b169a6bSchristos
151*4b169a6bSchristos initialized_sockets_version = 0;
152*4b169a6bSchristos
153*4b169a6bSchristos unregister_fd_hook (&fd_sockets_hook);
154*4b169a6bSchristos
155*4b169a6bSchristos err = WSACleanup ();
156*4b169a6bSchristos if (err != 0)
157*4b169a6bSchristos return 1;
158*4b169a6bSchristos #endif
159*4b169a6bSchristos
160*4b169a6bSchristos return 0;
161*4b169a6bSchristos }
162