1 /* GNet - Networking library
2 * Copyright (C) 2000 David Helder
3 * Copyright (C) 2000-2003 Andrew Lanoix
4 * Copyright (C) 2007 Tim-Philipp Müller <tim centricular net>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
21
22 #include "gnet-private.h"
23 #include "gnet.h"
24
25
26 /*
27
28 Super-function.
29
30 When creating a listening socket, we need to create the appropriate
31 socket and set-up an address for binding. These operations depend
32 on the particular interface, or on IPv6 policy if there is no interface.
33
34 */
35
36 static SOCKET
_gnet_create_ipv4_listen_socket(int type,int port,struct sockaddr_storage * sa)37 _gnet_create_ipv4_listen_socket (int type, int port, struct sockaddr_storage* sa)
38 {
39 struct sockaddr_in* sa_in;
40
41 sa_in = (struct sockaddr_in*) sa;
42 sa_in->sin_family = AF_INET;
43 GNET_SOCKADDR_SET_SS_LEN(*sa);
44 sa_in->sin_addr.s_addr = g_htonl(INADDR_ANY);
45 sa_in->sin_port = g_htons(port);
46
47 return socket (AF_INET, type, 0);
48 }
49
50 static SOCKET
_gnet_create_ipv6_listen_socket(int type,int port,struct sockaddr_storage * sa)51 _gnet_create_ipv6_listen_socket (int type, int port, struct sockaddr_storage* sa)
52 {
53 #ifdef HAVE_IPV6
54 struct sockaddr_in6* sa_in6;
55 #ifdef GNET_WIN32
56 struct addrinfo Hints, *AddrInfo;
57 char port_buff[12];
58 #endif
59
60 sa_in6 = (struct sockaddr_in6*) sa;
61
62 #ifndef GNET_WIN32 /* Unix */
63 sa_in6->sin6_family = AF_INET6;
64 GNET_SOCKADDR_SET_SS_LEN(*sa);
65 memset(&sa_in6->sin6_addr, 0, sizeof(sa_in6->sin6_addr));
66 sa_in6->sin6_port = g_htons(port);
67 #else /* Windows */
68 /* A simple memset does not work for some reason on Windows */
69 sprintf(port_buff, "%d", port);
70 memset(&Hints, 0, sizeof(Hints));
71 Hints.ai_family = AF_INET6;
72 Hints.ai_socktype = type;
73 Hints.ai_flags = AI_NUMERICHOST | AI_PASSIVE;
74 pfn_getaddrinfo(NULL, port_buff, &Hints, &AddrInfo);
75 memcpy(sa_in6, AddrInfo->ai_addr, AddrInfo->ai_addrlen);
76 pfn_freeaddrinfo(AddrInfo);
77 #endif
78 return socket (AF_INET6, type, 0);
79
80 #else
81 return GNET_INVALID_SOCKET;
82 #endif
83 }
84
85 SOCKET
_gnet_create_listen_socket(int type,const GInetAddr * iface,int port,struct sockaddr_storage * sa)86 _gnet_create_listen_socket (int type, const GInetAddr* iface, int port, struct sockaddr_storage* sa)
87 {
88 SOCKET sockfd = GNET_INVALID_SOCKET;
89
90 if (iface)
91 {
92 int family = GNET_INETADDR_FAMILY(iface);
93 *sa = iface->sa;
94 GNET_SOCKADDR_PORT_SET(*sa, g_htons(port));
95
96 sockfd = socket (family, type, 0);
97 }
98 else
99 {
100 GIPv6Policy ipv6_policy;
101
102 ipv6_policy = gnet_ipv6_get_policy();
103 switch (ipv6_policy) {
104 case GIPV6_POLICY_IPV4_THEN_IPV6:
105 sockfd = _gnet_create_ipv4_listen_socket (type, port, sa);
106 if (!GNET_IS_SOCKET_VALID(sockfd))
107 sockfd = _gnet_create_ipv6_listen_socket (type, port, sa);
108 break;
109 case GIPV6_POLICY_IPV6_THEN_IPV4:
110 sockfd = _gnet_create_ipv6_listen_socket (type, port, sa);
111 if (!GNET_IS_SOCKET_VALID(sockfd))
112 sockfd = _gnet_create_ipv4_listen_socket (type, port, sa);
113 break;
114 case GIPV6_POLICY_IPV4_ONLY:
115 sockfd = _gnet_create_ipv4_listen_socket (type, port, sa);
116 break;
117 case GIPV6_POLICY_IPV6_ONLY:
118 sockfd = _gnet_create_ipv6_listen_socket (type, port, sa);
119 break;
120 default:
121 g_assert_not_reached ();
122 break;
123 }
124 }
125
126 return sockfd;
127 }
128
129
130
131
132
133 /* _gnet_io_channel_new:
134 * @sockfd: socket descriptor
135 *
136 * Create a new IOChannel from a descriptor. In GLib 2.0, turn off
137 * encoding and buffering.
138 *
139 * Returns: An iochannel.
140 */
141 GIOChannel*
_gnet_io_channel_new(SOCKET sockfd)142 _gnet_io_channel_new (SOCKET sockfd)
143 {
144 GIOChannel* iochannel;
145
146 iochannel = GNET_SOCKET_IO_CHANNEL_NEW(sockfd);
147 if (iochannel == NULL)
148 return NULL;
149
150 g_io_channel_set_encoding (iochannel, NULL, NULL);
151 g_io_channel_set_buffered (iochannel, FALSE);
152
153 return iochannel;
154 }
155
156 #ifdef GNET_WIN32
157
158 BOOL WINAPI
159 DllMain(HINSTANCE hinstDLL,
160 DWORD fdwReason,
161 LPVOID lpvReserved);
162
163 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)164 DllMain(HINSTANCE hinstDLL, /* handle to DLL module */
165 DWORD fdwReason, /* reason for calling functionm */
166 LPVOID lpvReserved /* reserved */)
167 {
168
169 switch(fdwReason)
170 {
171 case DLL_PROCESS_ATTACH:
172 /* The DLL is being mapped into process's address space */
173 /* Do any required initialization on a per application basis, return FALSE if failed */
174 {
175 if( !gnet_initialize_windows_sockets() )
176 {
177 return FALSE;
178 }
179
180 /* The WinSock DLL is acceptable. Proceed. */
181 break;
182 }
183 case DLL_THREAD_ATTACH:
184 /* A thread is created. Do any required initialization on a per thread basis*/
185 {
186 /*Nothing needs to be done. */
187 break;
188 }
189 case DLL_THREAD_DETACH:
190 /* Thread exits with cleanup */
191 {
192 /*Nothing needs to be done. */
193 break;
194 }
195 case DLL_PROCESS_DETACH:
196 /* The DLL unmapped from process's address space. Do necessary cleanup */
197 {
198 /*CleanUp WinSock 2 */
199 WSACleanup();
200
201 break;
202 }
203 }
204
205 return TRUE;
206 }
207
gnet_initialize_windows_sockets(void)208 int gnet_initialize_windows_sockets(void)
209 {
210 WORD wVersionRequested;
211 WSADATA wsaData;
212 int err;
213
214 wVersionRequested = MAKEWORD( 2, 0 );
215
216 err = WSAStartup(wVersionRequested, &wsaData);
217 if (err != 0)
218 {
219 return FALSE;
220 }
221
222 /* Confirm that the WinSock DLL supports 2.0.*/
223 /* Note that if the DLL supports versions greater */
224 /* than 2.0 in addition to 2.0, it will still return */
225 /* 2.0 in wVersion since that is the version we */
226 /* requested. */
227
228 if (LOBYTE(wsaData.wVersion) != 2 ||
229 HIBYTE(wsaData.wVersion) != 0) {
230 /* Tell the user that we could not find a usable */
231 /* WinSock DLL. */
232 WSACleanup();
233 return FALSE;
234 }
235
236 return TRUE;
237 }
238
gnet_uninitialize_windows_sockets(void)239 void gnet_uninitialize_windows_sockets(void)
240 {
241 WSACleanup();
242 }
243
244
245 #endif
246
247 /* private utility functions */
248
249 guint
_gnet_idle_add_full(GMainContext * context,gint priority,GSourceFunc function,gpointer data,GDestroyNotify notify)250 _gnet_idle_add_full (GMainContext * context, gint priority,
251 GSourceFunc function, gpointer data, GDestroyNotify notify)
252 {
253 GSource *source;
254 guint id;
255
256 g_return_val_if_fail (function != NULL, 0);
257
258 if (context == NULL)
259 context = g_main_context_default ();
260
261 source = g_idle_source_new ();
262
263 if (priority != G_PRIORITY_DEFAULT_IDLE)
264 g_source_set_priority (source, priority);
265
266 g_source_set_callback (source, function, data, notify);
267 id = g_source_attach (source, context);
268 g_source_unref (source);
269
270 return id;
271 }
272
273 guint
_gnet_timeout_add_full(GMainContext * context,gint priority,guint interval,GSourceFunc function,gpointer data,GDestroyNotify notify)274 _gnet_timeout_add_full (GMainContext * context, gint priority, guint interval,
275 GSourceFunc function, gpointer data, GDestroyNotify notify)
276 {
277 GSource *source;
278 guint id;
279
280 g_return_val_if_fail (function != NULL, 0);
281
282 if (context == NULL)
283 context = g_main_context_default ();
284
285 source = g_timeout_source_new (interval);
286
287 if (priority != G_PRIORITY_DEFAULT)
288 g_source_set_priority (source, priority);
289
290 g_source_set_callback (source, function, data, notify);
291 id = g_source_attach (source, context);
292 g_source_unref (source);
293
294 return id;
295 }
296
297 guint
_gnet_io_watch_add_full(GMainContext * context,gint priority,GIOChannel * channel,GIOCondition condition,GIOFunc function,gpointer data,GDestroyNotify notify)298 _gnet_io_watch_add_full (GMainContext * context, gint priority,
299 GIOChannel * channel, GIOCondition condition, GIOFunc function,
300 gpointer data, GDestroyNotify notify)
301 {
302 GSource *source;
303 guint id;
304
305 g_return_val_if_fail (channel != NULL, 0);
306 g_return_val_if_fail (condition != 0, 0);
307
308 if (context == NULL)
309 context = g_main_context_default ();
310
311 source = g_io_create_watch (channel, condition);
312
313 if (priority != G_PRIORITY_DEFAULT)
314 g_source_set_priority (source, priority);
315
316 g_source_set_callback (source, (GSourceFunc) function, data, notify);
317
318 id = g_source_attach (source, context);
319 g_source_unref (source);
320
321 return id;
322 }
323
324 void
_gnet_source_remove(GMainContext * context,guint source_id)325 _gnet_source_remove (GMainContext * context, guint source_id)
326 {
327 if (source_id != 0) {
328 GSource *source;
329
330 if (context == NULL)
331 context = g_main_context_default ();
332
333 source = g_main_context_find_source_by_id (context, source_id);
334
335 if (source)
336 g_source_destroy (source);
337 /* else g_warning ("Trying to remove source %u from main context %p, "
338 "but it doesn't exist!", source_id, context); */
339 }
340 }
341
342