use _GL_ATTRIBUTE_CONST and _GL_ATTRIBUTE_PURE
[gnulib.git] / lib / sockets.c
1 /* sockets.c --- wrappers for Windows socket functions
2
3    Copyright (C) 2008-2011 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 /* The attribute __const__ was added in gcc 2.95.  */
26 #undef _GL_ATTRIBUTE_CONST
27 #if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 95)
28 # define _GL_ATTRIBUTE_CONST __attribute__ ((__const__))
29 #else
30 # define _GL_ATTRIBUTE_CONST /* empty */
31 #endif
32
33 #if WINDOWS_SOCKETS
34
35 /* This includes winsock2.h on MinGW. */
36 # include <sys/socket.h>
37
38 # include "fd-hook.h"
39
40 /* Get set_winsock_errno, FD_TO_SOCKET etc. */
41 # include "w32sock.h"
42
43 static int
44 close_fd_maybe_socket (const struct fd_hook *remaining_list,
45                        gl_close_fn primary,
46                        int fd)
47 {
48   SOCKET sock;
49   WSANETWORKEVENTS ev;
50
51   /* Test whether fd refers to a socket.  */
52   sock = FD_TO_SOCKET (fd);
53   ev.lNetworkEvents = 0xDEADBEEF;
54   WSAEnumNetworkEvents (sock, NULL, &ev);
55   if (ev.lNetworkEvents != 0xDEADBEEF)
56     {
57       /* fd refers to a socket.  */
58       /* FIXME: other applications, like squid, use an undocumented
59          _free_osfhnd free function.  But this is not enough: The 'osfile'
60          flags for fd also needs to be cleared, but it is hard to access it.
61          Instead, here we just close twice the file descriptor.  */
62       if (closesocket (sock))
63         {
64           set_winsock_errno ();
65           return -1;
66         }
67       else
68         {
69           /* This call frees the file descriptor and does a
70              CloseHandle ((HANDLE) _get_osfhandle (fd)), which fails.  */
71           _close (fd);
72           return 0;
73         }
74     }
75   else
76     /* Some other type of file descriptor.  */
77     return execute_close_hooks (remaining_list, primary, fd);
78 }
79
80 static int
81 ioctl_fd_maybe_socket (const struct fd_hook *remaining_list,
82                        gl_ioctl_fn primary,
83                        int fd, int request, void *arg)
84 {
85   SOCKET sock;
86   WSANETWORKEVENTS ev;
87
88   /* Test whether fd refers to a socket.  */
89   sock = FD_TO_SOCKET (fd);
90   ev.lNetworkEvents = 0xDEADBEEF;
91   WSAEnumNetworkEvents (sock, NULL, &ev);
92   if (ev.lNetworkEvents != 0xDEADBEEF)
93     {
94       /* fd refers to a socket.  */
95       if (ioctlsocket (sock, request, arg) < 0)
96         {
97           set_winsock_errno ();
98           return -1;
99         }
100       else
101         return 0;
102     }
103   else
104     /* Some other type of file descriptor.  */
105     return execute_ioctl_hooks (remaining_list, primary, fd, request, arg);
106 }
107
108 static struct fd_hook fd_sockets_hook;
109
110 static int initialized_sockets_version /* = 0 */;
111
112 #endif /* WINDOWS_SOCKETS */
113
114 int _GL_ATTRIBUTE_CONST
115 gl_sockets_startup (int version _GL_UNUSED)
116 {
117 #if WINDOWS_SOCKETS
118   if (version > initialized_sockets_version)
119     {
120       WSADATA data;
121       int err;
122
123       err = WSAStartup (version, &data);
124       if (err != 0)
125         return 1;
126
127       if (data.wVersion < version)
128         return 2;
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   return 0;
139 }
140
141 int
142 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   return 0;
157 }