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