xref: /netbsd-src/external/gpl3/gdb/dist/gnulib/import/sockets.c (revision 4b169a6ba595ae283ca507b26b15fdff40495b1c)
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