1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ |
|
2 /* |
|
3 * Copyright (C) 2006 Imendio AB |
|
4 * |
|
5 * This program is free software; you can redistribute it and/or |
|
6 * modify it under the terms of the GNU Lesser General Public License as |
|
7 * published by the Free Software Foundation; either version 2 of the |
|
8 * License, or (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 GNU |
|
13 * Lesser General Public License for more details. |
|
14 * |
|
15 * You should have received a copy of the GNU Lesser General Public |
|
16 * License along with this program; if not, write to the |
|
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
|
18 * Boston, MA 02111-1307, USA. |
|
19 */ |
|
20 |
|
21 #include <config.h> |
|
22 //#include <glib.h> |
|
23 //#include <glib/gi18n.h> |
|
24 |
|
25 #ifndef G_OS_WIN32 |
|
26 //#include <libc/netinet/net_types.h> |
|
27 |
|
28 #include <errno.h> |
|
29 #include <string.h> |
|
30 #include <unistd.h> |
|
31 #include <sys/socket.h> |
|
32 #include <fcntl.h> |
|
33 #include <netinet/in.h> |
|
34 //#include <libc/netinet/ip.h> |
|
35 //#include <libc/netinet/tcp.h> |
|
36 #include <arpa/inet.h> |
|
37 #include <netdb.h> |
|
38 // hack - to compile without the error of n_long not defined |
|
39 #define LM_SHUTDOWN SHUT_RDWR |
|
40 |
|
41 #else /* G_OS_WIN32 */ |
|
42 |
|
43 #include <winsock2.h> |
|
44 #define LM_SHUTDOWN SD_BOTH |
|
45 |
|
46 #endif /* G_OS_WIN32 */ |
|
47 |
|
48 #include "lm-internals.h" |
|
49 #include "lm-connection.h" |
|
50 #include "lm-sock.h" |
|
51 #include "lm-debug.h" |
|
52 |
|
53 #define IPV6_MAX_ADDRESS_LEN 46 /* 45 + '\0' */ |
|
54 |
|
55 #ifdef EMULATOR |
|
56 #include "libloudmouth_wsd_solution.h" |
|
57 |
|
58 GET_GLOBAL_VAR_FROM_TLS(initialised,lm_sock,gboolean) |
|
59 #define initialised (*GET_WSD_VAR_NAME(initialised,lm_sock,g)()) |
|
60 |
|
61 #else |
|
62 static gboolean initialised = FALSE; |
|
63 #endif |
|
64 gboolean |
|
65 _lm_sock_library_init (void) |
|
66 { |
|
67 #ifdef G_OS_WIN32 |
|
68 WORD version; |
|
69 WSADATA data; |
|
70 int error; |
|
71 #endif /* G_OS_WIN32 */ |
|
72 |
|
73 if (initialised) { |
|
74 return TRUE; |
|
75 } |
|
76 |
|
77 lm_verbose ("Socket library initialising...\n"); |
|
78 |
|
79 #ifdef G_OS_WIN32 |
|
80 lm_verbose ("Checking for winsock 2.0 or above...\n"); |
|
81 |
|
82 version = MAKEWORD (2, 0); |
|
83 |
|
84 error = WSAStartup (version, &data); |
|
85 if (error != 0) { |
|
86 g_printerr ("WSAStartup() failed, error:%d\n", error); |
|
87 return FALSE; |
|
88 } |
|
89 |
|
90 /* Confirm that the WinSock DLL supports 2.0. |
|
91 * Note that if the DLL supports versions greater |
|
92 * than 2.0 in addition to 2.0, it will still return |
|
93 * 2.0 in wVersion since that is the version we |
|
94 * requested. |
|
95 */ |
|
96 if (LOBYTE (data.wVersion) != 2 || |
|
97 HIBYTE (data.wVersion) != 0) { |
|
98 /* Tell the user that we could not find a usable |
|
99 * WinSock DLL. |
|
100 */ |
|
101 g_printerr ("Socket library version is not sufficient!\n"); |
|
102 WSACleanup (); |
|
103 return FALSE; |
|
104 } |
|
105 #endif /* G_OS_WIN32 */ |
|
106 |
|
107 initialised = TRUE; |
|
108 |
|
109 return TRUE; |
|
110 } |
|
111 |
|
112 void |
|
113 _lm_sock_library_shutdown (void) |
|
114 { |
|
115 if (!initialised) { |
|
116 return; |
|
117 } |
|
118 |
|
119 lm_verbose ("Socket library shutting down...\n"); |
|
120 |
|
121 #ifdef G_OS_WIN32 |
|
122 WSACleanup (); |
|
123 #endif /* G_OS_WIN32 */ |
|
124 |
|
125 initialised = FALSE; |
|
126 } |
|
127 |
|
128 void |
|
129 _lm_sock_set_blocking (LmSocketT sock, |
|
130 gboolean block) |
|
131 { |
|
132 int res; |
|
133 |
|
134 #ifndef G_OS_WIN32 |
|
135 res = fcntl (sock, F_SETFL, block ? 0 : O_NONBLOCK); |
|
136 #else /* G_OS_WIN32 */ |
|
137 u_long mode = (block ? 0 : 1); |
|
138 res = ioctlsocket (sock, FIONBIO, &mode); |
|
139 #endif /* G_OS_WIN32 */ |
|
140 |
|
141 if (res != 0) { |
|
142 // g_log (LM_LOG_DOMAIN, LM_LOG_LEVEL_NET, |
|
143 // "Could not set connection to be %s\n", |
|
144 // block ? "blocking" : "non-blocking"); |
|
145 lm_verbose ("[_lm_sock_set_blocking]: Could not set connection to be %s\n", |
|
146 block ? "blocking" : "non-blocking"); |
|
147 } |
|
148 } |
|
149 |
|
150 void |
|
151 _lm_sock_shutdown (LmSocketT sock) |
|
152 { |
|
153 shutdown (sock, LM_SHUTDOWN); |
|
154 } |
|
155 |
|
156 void |
|
157 _lm_sock_close (LmSocketT sock) |
|
158 { |
|
159 #ifndef G_OS_WIN32 |
|
160 close (sock); |
|
161 #else /* G_OS_WIN32 */ |
|
162 closesocket (sock); |
|
163 #endif /* G_OS_WIN32 */ |
|
164 } |
|
165 |
|
166 LmSocketT |
|
167 _lm_sock_makesocket (int af, |
|
168 int type, |
|
169 int protocol) |
|
170 { |
|
171 int optval = 1; |
|
172 int sock_fd = -1; |
|
173 unsigned int optlen = sizeof(optval); |
|
174 sock_fd = socket (af, type, protocol); |
|
175 setsockopt(sock_fd,SOL_SOCKET,SO_REUSEADDR|SO_REUSEPORT,&optval,optlen); |
|
176 |
|
177 return (LmSocketT)sock_fd; |
|
178 } |
|
179 |
|
180 int |
|
181 _lm_sock_connect (LmSocketT sock, |
|
182 const struct sockaddr *name, |
|
183 int namelen) |
|
184 { |
|
185 return connect (sock, name, namelen); |
|
186 } |
|
187 |
|
188 gboolean |
|
189 _lm_sock_is_blocking_error (int err) |
|
190 { |
|
191 #ifndef G_OS_WIN32 |
|
192 return (err == _LM_SOCK_EINPROGRESS); |
|
193 #else /* G_OS_WIN32 */ |
|
194 return (err == _LM_SOCK_EINPROGRESS || |
|
195 err == _LM_SOCK_EWOULDBLOCK || |
|
196 err == _LM_SOCK_EINVAL); |
|
197 #endif /* G_OS_WIN32 */ |
|
198 } |
|
199 |
|
200 gboolean |
|
201 _lm_sock_is_blocking_success (int err) |
|
202 { |
|
203 //Bug fixed by MRT from week 50 devlong onwards |
|
204 return (err == _LM_SOCK_EEXISTS); |
|
205 //Error EEXIST = 17 is not expected here. But It should be mrt error 107 |
|
206 //fix take later |
|
207 //Before week 50 SDK |
|
208 //return (err == _LM_SOCK_EALREADY || err == _LM_SOCK_EISCONN); |
|
209 } |
|
210 |
|
211 int |
|
212 _lm_sock_get_last_error (void) |
|
213 { |
|
214 #ifndef G_OS_WIN32 |
|
215 return errno; |
|
216 #else /* G_OS_WIN32 */ |
|
217 return WSAGetLastError (); |
|
218 #endif /* G_OS_WIN32 */ |
|
219 } |
|
220 |
|
221 void |
|
222 _lm_sock_get_error (LmSocketT sock, |
|
223 void *error, |
|
224 socklen_t *len) |
|
225 { |
|
226 getsockopt (sock, SOL_SOCKET, SO_ERROR, (void*) error, len); |
|
227 } |
|
228 |
|
229 const gchar * |
|
230 _lm_sock_get_error_str (int err) |
|
231 { |
|
232 #ifndef G_OS_WIN32 |
|
233 return strerror (err); |
|
234 #else /* G_OS_WIN32 */ |
|
235 switch (err) { |
|
236 case WSAEINTR: return _("Connect interrupted and canceled"); |
|
237 case WSAEACCES: return _("Permission denied"); |
|
238 case WSAEFAULT: return _("Bad address"); |
|
239 case WSAEINVAL: return _("Invalid argument"); |
|
240 case WSAEMFILE: return _("Too many open sockets"); |
|
241 case WSAEWOULDBLOCK: return _("Resource temporarily unavailable"); |
|
242 case WSAEINPROGRESS: return _("Operation now in progress"); |
|
243 case WSAEALREADY: return _("Operation already in progress"); |
|
244 case WSAENOTSOCK: return _("Socket operation on nonsocket"); |
|
245 case WSAEDESTADDRREQ: return _("Destination address required"); |
|
246 case WSAEMSGSIZE: return _("Message too long"); |
|
247 case WSAEPROTOTYPE: return _("Protocol wrong type for socket"); |
|
248 case WSAENOPROTOOPT: return _("Bad protocol option"); |
|
249 case WSAEPROTONOSUPPORT: return _("Protocol not supported"); |
|
250 case WSAESOCKTNOSUPPORT: return _("Socket type not supported"); |
|
251 case WSAEOPNOTSUPP: return _("Operation not supported"); |
|
252 case WSAEPFNOSUPPORT: return _("Protocol family not supported"); |
|
253 case WSAEAFNOSUPPORT: return _("Address family not supported by protocol family"); |
|
254 case WSAEADDRINUSE: return _("Address already in use"); |
|
255 case WSAEADDRNOTAVAIL: return _("Can not assign requested address"); |
|
256 case WSAENETDOWN: return _("Network is down"); |
|
257 case WSAENETUNREACH: return _("Network is unreachable"); |
|
258 case WSAENETRESET: return _("Network dropped connection on reset"); |
|
259 case WSAECONNABORTED: return _("Software caused connection abort"); |
|
260 case WSAECONNRESET: return _("Connection reset by peer"); |
|
261 case WSAENOBUFS: return _("No buffer space available"); |
|
262 case WSAEISCONN: return _("Socket is already connected"); |
|
263 case WSAENOTCONN: return _("Socket is not connected"); |
|
264 case WSAESHUTDOWN: return _("Can not send after socket shutdown"); |
|
265 case WSAETIMEDOUT: return _("Connection timed out"); |
|
266 case WSAECONNREFUSED: return _("Connection refused"); |
|
267 case WSAEHOSTDOWN: return _("Host is down"); |
|
268 case WSAEHOSTUNREACH: return _("No route to host"); |
|
269 case WSAEPROCLIM: return _("Too many processes"); |
|
270 case WSASYSNOTREADY: return _("Network subsystem is unavailable"); |
|
271 case WSAVERNOTSUPPORTED: return _("Winsock library version is out of range "); |
|
272 case WSANOTINITIALISED: return _("Successful WSAStartup not yet performed"); |
|
273 case WSAEDISCON: return _("Graceful shutdown in progress"); |
|
274 case WSATYPE_NOT_FOUND: return _("Class type not found"); |
|
275 case WSAHOST_NOT_FOUND: return _("Host not found"); |
|
276 case WSATRY_AGAIN: return _("Nonauthoritative host not found"); |
|
277 case WSANO_RECOVERY: return _("This is a nonrecoverable error"); |
|
278 case WSANO_DATA: return _("Valid name, no data record of requested type"); |
|
279 case WSA_INVALID_HANDLE: return _("Specified event object handle is invalid"); |
|
280 case WSA_INVALID_PARAMETER: return _("One or more parameters are invalid"); |
|
281 case WSA_IO_INCOMPLETE: return _("Overlapped I/O event object no in signaled state"); |
|
282 case WSA_IO_PENDING: return _("Overlapped operations will complete later"); |
|
283 case WSA_NOT_ENOUGH_MEMORY: return _("Insufficient memory available"); |
|
284 case WSA_OPERATION_ABORTED: return _("Overlapped operation aborted"); |
|
285 /* os dependent */ |
|
286 case WSASYSCALLFAILURE: return _("System call failure"); |
|
287 } |
|
288 |
|
289 return _("Unknown"); |
|
290 #endif /* G_OS_WIN32 */ |
|
291 } |
|
292 |
|
293 const gchar * |
|
294 _lm_sock_addrinfo_get_error_str (int err) |
|
295 { |
|
296 switch (err) { |
|
297 case EAI_AGAIN: |
|
298 return ("The nameserver failed to return an " |
|
299 "address, try again later"); |
|
300 case EAI_BADFLAGS: |
|
301 return ("Internal error trying to obtain remote address"); |
|
302 case EAI_FAIL: |
|
303 return ("The nameserver encountered errors " |
|
304 "looking up this address"); |
|
305 /* EAI_NODATA is apparently missing on FreeBSD. On recent GNU libc, |
|
306 * it requires _GNU_SOURCE to be defined; in the unlikely case that |
|
307 * that GNU libc returns this value we'll return the default message */ |
|
308 #ifdef EAI_NODATA |
|
309 case EAI_NODATA: |
|
310 return _("The remote host exists but no address " |
|
311 "is available"); |
|
312 #endif |
|
313 case EAI_NONAME: |
|
314 return ("The remote address is unknown"); |
|
315 case EAI_FAMILY: |
|
316 case EAI_SERVICE: |
|
317 case EAI_SOCKTYPE: |
|
318 return ("The remote address is not obtainable " |
|
319 "for that socket type."); |
|
320 default: |
|
321 break; |
|
322 } |
|
323 |
|
324 return ("The remote address could not be obtained "); |
|
325 } |
|
326 |
|
327 #ifdef USE_TCP_KEEPALIVES |
|
328 gboolean |
|
329 _lm_sock_set_keepalive (LmSocketT sock, int delay) |
|
330 { |
|
331 int opt; |
|
332 |
|
333 lm_verbose ("[_lm_sock_set_keepalive]: USE_TCP_KEEPALIVES Enabled\n"); |
|
334 |
|
335 opt = 1; |
|
336 if (setsockopt (sock, SOL_SOCKET, SO_KEEPALIVE, &opt, sizeof (opt)) < 0) { |
|
337 return FALSE; |
|
338 } |
|
339 |
|
340 //opt = 3; /* 3 keepalives before considering connection dead */ |
|
341 /*if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPCNT, &opt, sizeof (opt)) < 0) { |
|
342 return FALSE; |
|
343 } |
|
344 |
|
345 opt = delay; |
|
346 if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPIDLE, &opt, sizeof (opt)) < 0) { |
|
347 return FALSE; |
|
348 } |
|
349 |
|
350 opt = delay; |
|
351 if (setsockopt (sock, IPPROTO_TCP, TCP_KEEPINTVL, &opt, sizeof (opt)) < 0) { |
|
352 return FALSE; |
|
353 }*/ |
|
354 UNUSED_FORMAL_PARAM(delay); |
|
355 return TRUE; |
|
356 } |
|
357 #endif /* USE_TCP_KEEPALIVES */ |
|
358 |
|
359 gchar * |
|
360 _lm_sock_get_local_host (LmSocketT sock) |
|
361 { |
|
362 struct sockaddr addr_info; |
|
363 void *sock_addr; |
|
364 socklen_t namelen; |
|
365 char addrbuf[IPV6_MAX_ADDRESS_LEN]; |
|
366 const char *host; |
|
367 |
|
368 namelen = sizeof (struct sockaddr); |
|
369 if (getsockname (sock, &addr_info, &namelen)) { |
|
370 return NULL; |
|
371 } |
|
372 |
|
373 switch (addr_info.sa_family) { |
|
374 case AF_INET: |
|
375 |
|
376 sock_addr = & (((struct sockaddr_in *) &addr_info)->sin_addr); |
|
377 break; |
|
378 case AF_INET6: |
|
379 sock_addr = & (((struct sockaddr_in6 *) &addr_info)->sin6_addr); |
|
380 break; |
|
381 default: |
|
382 return NULL; |
|
383 } |
|
384 /* inet_ntoa has been obsoleted in favour of inet_ntop */ |
|
385 host = inet_ntop (addr_info.sa_family, |
|
386 sock_addr, |
|
387 addrbuf, |
|
388 IPV6_MAX_ADDRESS_LEN); |
|
389 |
|
390 return g_strdup (host); |
|
391 } |
|
392 |
|