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