1 | /* |
---|
2 | * linc-protocols.c: This file is part of the linc library. |
---|
3 | * |
---|
4 | * Authors: |
---|
5 | * Elliot Lee (sopwith@redhat.com) |
---|
6 | * Michael Meeks (michael@ximian.com) |
---|
7 | * Mark McLouglin (mark@skynet.ie) & others |
---|
8 | * |
---|
9 | * Copyright 2001, Red Hat, Inc., Ximian, Inc., |
---|
10 | * Sun Microsystems, Inc. |
---|
11 | */ |
---|
12 | #include <config.h> |
---|
13 | #include "linc-compat.h" |
---|
14 | #include <dirent.h> |
---|
15 | #include <linc/linc-protocol.h> |
---|
16 | #include <linc/linc-connection.h> |
---|
17 | |
---|
18 | #include "linc-private.h" |
---|
19 | #include "linc-debug.h" |
---|
20 | |
---|
21 | #undef LOCAL_DEBUG |
---|
22 | |
---|
23 | static char *linc_tmpdir = NULL; |
---|
24 | |
---|
25 | /* |
---|
26 | * make_local_tmpdir: |
---|
27 | * @dirname: directory name. |
---|
28 | * |
---|
29 | * Create a directory with the name in @dirname. Also, clear the |
---|
30 | * access and modification times of @dirname. |
---|
31 | * |
---|
32 | * If the directory already exists and is not owned by the current |
---|
33 | * user, or is not solely readable by the current user, then linc |
---|
34 | * will error out. |
---|
35 | */ |
---|
36 | static void |
---|
37 | make_local_tmpdir (const char *dirname) |
---|
38 | { |
---|
39 | struct stat statbuf; |
---|
40 | |
---|
41 | if (mkdir (dirname, 0700) != 0) { |
---|
42 | int e = errno; |
---|
43 | |
---|
44 | switch (e) { |
---|
45 | case 0: |
---|
46 | case EEXIST: |
---|
47 | if (stat (dirname, &statbuf) != 0) |
---|
48 | g_error ("Can not stat %s\n", dirname); |
---|
49 | |
---|
50 | if (statbuf.st_uid != getuid ()) |
---|
51 | g_error ("Owner of %s is not the current user\n", dirname); |
---|
52 | |
---|
53 | if ((statbuf.st_mode & (S_IRWXG|S_IRWXO)) || |
---|
54 | !S_ISDIR (statbuf.st_mode)) |
---|
55 | g_error ("Wrong permissions for %s\n", dirname); |
---|
56 | |
---|
57 | break; |
---|
58 | |
---|
59 | default: |
---|
60 | g_error("Unknown error on directory creation of %s (%s)\n", |
---|
61 | dirname, g_strerror (e)); |
---|
62 | } |
---|
63 | } |
---|
64 | |
---|
65 | { /* Hide some information ( apparently ) */ |
---|
66 | struct utimbuf utb; |
---|
67 | memset (&utb, 0, sizeof (utb)); |
---|
68 | utime (dirname, &utb); |
---|
69 | } |
---|
70 | } |
---|
71 | |
---|
72 | /** |
---|
73 | * linc_set_tmpdir: |
---|
74 | * @dir: directory name. |
---|
75 | * |
---|
76 | * Set the temporary directory used by linc to @dir. |
---|
77 | * |
---|
78 | * This directory is used for the creation of UNIX sockets. |
---|
79 | * @dir must have the correct permissions, 0700, user owned |
---|
80 | * otherwise this method will g_error. |
---|
81 | **/ |
---|
82 | void |
---|
83 | linc_set_tmpdir (const char *dir) |
---|
84 | { |
---|
85 | g_free (linc_tmpdir); |
---|
86 | linc_tmpdir = g_strdup (dir); |
---|
87 | |
---|
88 | make_local_tmpdir (linc_tmpdir); |
---|
89 | } |
---|
90 | |
---|
91 | /** |
---|
92 | * linc_get_tmpdir: |
---|
93 | * @void: |
---|
94 | * |
---|
95 | * Fetches the directory name used by linc to whack |
---|
96 | * Unix Domain sockets into. |
---|
97 | * |
---|
98 | * Return value: the g_allocated socket name. |
---|
99 | **/ |
---|
100 | char * |
---|
101 | linc_get_tmpdir (void) |
---|
102 | { |
---|
103 | return g_strdup (linc_tmpdir ? linc_tmpdir : ""); |
---|
104 | } |
---|
105 | |
---|
106 | #ifdef HAVE_SOCKADDR_SA_LEN |
---|
107 | #define LINC_SET_SOCKADDR_LEN(saddr, len) \ |
---|
108 | ((struct sockaddr *)(saddr))->sa_len = (len) |
---|
109 | #else |
---|
110 | #define LINC_SET_SOCKADDR_LEN(saddr, len) |
---|
111 | #endif |
---|
112 | |
---|
113 | #if defined(AF_INET6) && defined(RES_USE_INET6) |
---|
114 | #define LINC_RESOLV_SET_IPV6 _res.options |= RES_USE_INET6 |
---|
115 | #define LINC_RESOLV_UNSET_IPV6 _res.options &= ~RES_USE_INET6 |
---|
116 | #else |
---|
117 | #define LINC_RESOLV_SET_IPV6 |
---|
118 | #define LINC_RESOLV_UNSET_IPV6 |
---|
119 | #endif |
---|
120 | |
---|
121 | |
---|
122 | |
---|
123 | #if defined(AF_INET) || defined(AF_INET6) || defined (AF_UNIX) |
---|
124 | const char * |
---|
125 | linc_get_local_hostname (void) |
---|
126 | { |
---|
127 | static char local_host[NI_MAXHOST] = { 0 }; |
---|
128 | |
---|
129 | if (local_host [0]) |
---|
130 | return local_host; |
---|
131 | |
---|
132 | if (gethostname (local_host, NI_MAXHOST) == -1) |
---|
133 | return NULL; |
---|
134 | |
---|
135 | return local_host; |
---|
136 | } |
---|
137 | |
---|
138 | /* |
---|
139 | * True if succeeded in mapping, else false. |
---|
140 | */ |
---|
141 | static gboolean |
---|
142 | ipv4_addr_from_addr (struct in_addr *dest_addr, |
---|
143 | guint8 *src_addr, |
---|
144 | int src_length) |
---|
145 | { |
---|
146 | if (src_length == 4) |
---|
147 | memcpy (dest_addr, src_addr, 4); |
---|
148 | |
---|
149 | else if (src_length == 16) { |
---|
150 | int i; |
---|
151 | |
---|
152 | #ifdef LOCAL_DEBUG |
---|
153 | g_warning ("Doing conversion ..."); |
---|
154 | #endif |
---|
155 | |
---|
156 | /* An ipv6 address, might be an IPv4 mapped though */ |
---|
157 | for (i = 0; i < 10; i++) |
---|
158 | if (src_addr [i] != 0) |
---|
159 | return FALSE; |
---|
160 | |
---|
161 | if (src_addr [10] != 0xff || |
---|
162 | src_addr [11] != 0xff) |
---|
163 | return FALSE; |
---|
164 | |
---|
165 | memcpy (dest_addr, &src_addr[12], 4); |
---|
166 | } else |
---|
167 | return FALSE; |
---|
168 | |
---|
169 | return TRUE; |
---|
170 | } |
---|
171 | |
---|
172 | static gboolean |
---|
173 | linc_protocol_is_local_ipv46 (const LINCProtocolInfo *proto, |
---|
174 | const struct sockaddr *saddr, |
---|
175 | LincSockLen saddr_len) |
---|
176 | { |
---|
177 | int i; |
---|
178 | static int warned = 0; |
---|
179 | static struct hostent *local_hostent; |
---|
180 | |
---|
181 | g_assert (saddr->sa_family == proto->family); |
---|
182 | |
---|
183 | if (!local_hostent) { |
---|
184 | LINC_RESOLV_SET_IPV6; |
---|
185 | local_hostent = gethostbyname (linc_get_local_hostname ()); |
---|
186 | } |
---|
187 | |
---|
188 | if (!local_hostent) { |
---|
189 | if (!warned++) |
---|
190 | g_warning ("can't gethostbyname on '%s'", |
---|
191 | linc_get_local_hostname ()); |
---|
192 | return FALSE; |
---|
193 | } |
---|
194 | |
---|
195 | if (!local_hostent->h_addr_list) |
---|
196 | g_error ("No address for local host"); |
---|
197 | |
---|
198 | if (proto->family != AF_INET) { |
---|
199 | #ifdef AF_INET6 |
---|
200 | if (proto->family == AF_INET6 && |
---|
201 | local_hostent->h_addrtype != AF_INET6) |
---|
202 | return FALSE; /* can connect via IPv4 */ |
---|
203 | |
---|
204 | if (proto->family != AF_INET6) |
---|
205 | return FALSE; |
---|
206 | #else |
---|
207 | return FALSE; |
---|
208 | #endif |
---|
209 | } |
---|
210 | |
---|
211 | for (i = 0; local_hostent->h_addr_list [i]; i++) { |
---|
212 | |
---|
213 | if (proto->family == AF_INET) { |
---|
214 | struct in_addr ipv4_addr; |
---|
215 | |
---|
216 | if (!ipv4_addr_from_addr (&ipv4_addr, |
---|
217 | local_hostent->h_addr_list [i], |
---|
218 | local_hostent->h_length)) |
---|
219 | continue; |
---|
220 | |
---|
221 | if (!memcmp (&ipv4_addr, |
---|
222 | &((struct sockaddr_in *)saddr)->sin_addr.s_addr, 4)) { |
---|
223 | #ifdef LOCAL_DEBUG |
---|
224 | g_warning ("local ipv4 address"); |
---|
225 | #endif |
---|
226 | return TRUE; |
---|
227 | } |
---|
228 | |
---|
229 | } |
---|
230 | #ifdef AF_INET6 |
---|
231 | else if (!memcmp (local_hostent->h_addr_list [i], |
---|
232 | &((struct sockaddr_in6 *)saddr)->sin6_addr.s6_addr, |
---|
233 | local_hostent->h_length)) { |
---|
234 | #ifdef LOCAL_DEBUG |
---|
235 | g_warning ("local ipv6 address"); |
---|
236 | #endif |
---|
237 | return TRUE; |
---|
238 | } |
---|
239 | #endif |
---|
240 | } |
---|
241 | |
---|
242 | #ifdef LOCAL_DEBUG |
---|
243 | g_warning ("No match over all"); |
---|
244 | #endif |
---|
245 | |
---|
246 | return FALSE; |
---|
247 | } |
---|
248 | |
---|
249 | #endif |
---|
250 | |
---|
251 | /* |
---|
252 | * linc_protocol_get_sockaddr_ipv4: |
---|
253 | * @proto: the #LINCProtocolInfo structure for the IPv4 protocol. |
---|
254 | * @hostname: the hostname. |
---|
255 | * @portnum: the port number. |
---|
256 | * @saddr_len: location in which to store the returned structure's length. |
---|
257 | * |
---|
258 | * Allocates and fills a #sockaddr_in with with the IPv4 address |
---|
259 | * information. |
---|
260 | * |
---|
261 | * Return Value: a pointer to a valid #sockaddr_in structure if the call |
---|
262 | * succeeds, NULL otherwise. |
---|
263 | */ |
---|
264 | #ifdef AF_INET |
---|
265 | static struct sockaddr * |
---|
266 | linc_protocol_get_sockaddr_ipv4 (const LINCProtocolInfo *proto, |
---|
267 | const char *hostname, |
---|
268 | const char *portnum, |
---|
269 | LincSockLen *saddr_len) |
---|
270 | { |
---|
271 | struct sockaddr_in *saddr; |
---|
272 | struct hostent *host; |
---|
273 | |
---|
274 | g_assert (proto->family == AF_INET); |
---|
275 | g_assert (hostname); |
---|
276 | |
---|
277 | if (!portnum) |
---|
278 | portnum = "0"; |
---|
279 | |
---|
280 | saddr = g_new0 (struct sockaddr_in, 1); |
---|
281 | |
---|
282 | *saddr_len = sizeof (struct sockaddr_in); |
---|
283 | |
---|
284 | LINC_SET_SOCKADDR_LEN (saddr, sizeof (struct sockaddr_in)); |
---|
285 | |
---|
286 | saddr->sin_family = AF_INET; |
---|
287 | saddr->sin_port = htons (atoi (portnum)); |
---|
288 | |
---|
289 | if ((saddr->sin_addr.s_addr = inet_addr (hostname)) == INADDR_NONE) { |
---|
290 | int i; |
---|
291 | |
---|
292 | LINC_RESOLV_UNSET_IPV6; |
---|
293 | if (!(_res.options & RES_INIT)) |
---|
294 | res_init(); |
---|
295 | |
---|
296 | host = gethostbyname (hostname); |
---|
297 | if (!host) { |
---|
298 | g_free (saddr); |
---|
299 | return NULL; |
---|
300 | } |
---|
301 | |
---|
302 | for(i = 0; host->h_addr_list[i]; i++) |
---|
303 | if(ipv4_addr_from_addr (&saddr->sin_addr, |
---|
304 | (guint8 *)host->h_addr_list [i], |
---|
305 | host->h_length)) |
---|
306 | break; |
---|
307 | |
---|
308 | if(!host->h_addr_list[i]) { |
---|
309 | g_free (saddr); |
---|
310 | return NULL; |
---|
311 | } |
---|
312 | } |
---|
313 | |
---|
314 | return (struct sockaddr *) saddr; |
---|
315 | } |
---|
316 | #endif /* AF_INET */ |
---|
317 | |
---|
318 | /* |
---|
319 | * linc_protocol_get_sockaddr_ipv6: |
---|
320 | * @proto: the #LINCProtocolInfo structure for the IPv6 protocol. |
---|
321 | * @hostname: the hostname. |
---|
322 | * @portnum: the port number |
---|
323 | * @saddr_len: location in which to store the returned structure's length. |
---|
324 | * |
---|
325 | * Allocates and fills a #sockaddr_in6 with with the IPv6 address |
---|
326 | * information. |
---|
327 | * |
---|
328 | * NOTE: This function is untested. |
---|
329 | * |
---|
330 | * Return Value: a pointer to a valid #sockaddr_in6 structure if the call |
---|
331 | * succeeds, NULL otherwise. |
---|
332 | */ |
---|
333 | #ifdef AF_INET6 |
---|
334 | static struct sockaddr * |
---|
335 | linc_protocol_get_sockaddr_ipv6 (const LINCProtocolInfo *proto, |
---|
336 | const char *hostname, |
---|
337 | const char *portnum, |
---|
338 | LincSockLen *saddr_len) |
---|
339 | { |
---|
340 | struct sockaddr_in6 *saddr; |
---|
341 | struct hostent *host; |
---|
342 | |
---|
343 | g_assert (proto->family == AF_INET6); |
---|
344 | g_assert (hostname); |
---|
345 | |
---|
346 | if (!portnum) |
---|
347 | portnum = "0"; |
---|
348 | |
---|
349 | saddr = g_new0 (struct sockaddr_in6, 1); |
---|
350 | |
---|
351 | *saddr_len = sizeof (struct sockaddr_in6); |
---|
352 | |
---|
353 | LINC_SET_SOCKADDR_LEN (saddr, sizeof (struct sockaddr_in6)); |
---|
354 | |
---|
355 | saddr->sin6_family = AF_INET6; |
---|
356 | saddr->sin6_port = htons (atoi (portnum)); |
---|
357 | #ifdef HAVE_INET_PTON |
---|
358 | if (inet_pton (AF_INET6, hostname, &saddr->sin6_addr) > 0) |
---|
359 | return (struct sockaddr *)saddr; |
---|
360 | #endif |
---|
361 | |
---|
362 | if (!(_res.options & RES_INIT)) |
---|
363 | res_init(); |
---|
364 | |
---|
365 | LINC_RESOLV_SET_IPV6; |
---|
366 | host = gethostbyname (hostname); |
---|
367 | if (!host || host->h_addrtype != AF_INET6) { |
---|
368 | g_free (saddr); |
---|
369 | return NULL; |
---|
370 | } |
---|
371 | |
---|
372 | memcpy (&saddr->sin6_addr, host->h_addr_list[0], sizeof (struct in6_addr)); |
---|
373 | |
---|
374 | return (struct sockaddr *)saddr; |
---|
375 | } |
---|
376 | #endif /* AF_INET6 */ |
---|
377 | |
---|
378 | #ifdef AF_UNIX |
---|
379 | /* |
---|
380 | * linc_protocol_get_sockaddr_unix: |
---|
381 | * @proto: the #LINCProtocolInfo structure for the UNIX sockets protocol. |
---|
382 | * @dummy: not used. |
---|
383 | * @path: the path name of the UNIX socket. |
---|
384 | * @saddr_len: location in which to store the returned structure's length. |
---|
385 | * |
---|
386 | * Allocates and fills a #sockaddr_un with with the UNIX socket address |
---|
387 | * information. |
---|
388 | * |
---|
389 | * If @path is NULL, a new, unique path name will be generated. |
---|
390 | * |
---|
391 | * Return Value: a pointer to a valid #sockaddr_un structure if the call |
---|
392 | * succeeds, NULL otherwise. |
---|
393 | */ |
---|
394 | static struct sockaddr * |
---|
395 | linc_protocol_get_sockaddr_unix (const LINCProtocolInfo *proto, |
---|
396 | const char *dummy, |
---|
397 | const char *path, |
---|
398 | LincSockLen *saddr_len) |
---|
399 | { |
---|
400 | struct sockaddr_un *saddr; |
---|
401 | int pathlen; |
---|
402 | char buf[64], *actual_path; |
---|
403 | |
---|
404 | g_assert (proto->family == AF_UNIX); |
---|
405 | |
---|
406 | if (!path) { |
---|
407 | struct timeval t; |
---|
408 | static guint pid = 0, idx = 0; |
---|
409 | |
---|
410 | if (!pid) |
---|
411 | pid = getpid (); |
---|
412 | |
---|
413 | gettimeofday (&t, NULL); |
---|
414 | g_snprintf (buf, sizeof (buf), |
---|
415 | "%s/linc-%x-%x-%x%x", |
---|
416 | linc_tmpdir ? linc_tmpdir : "", |
---|
417 | pid, idx, |
---|
418 | (guint) (rand() ^ t.tv_sec), |
---|
419 | (guint) (idx ^ t.tv_usec)); |
---|
420 | idx++; |
---|
421 | #ifdef CONNECTION_DEBUG |
---|
422 | if (g_file_test (buf, G_FILE_TEST_EXISTS)) |
---|
423 | g_warning ("'%s' already exists !", buf); |
---|
424 | #endif |
---|
425 | actual_path = buf; |
---|
426 | } else |
---|
427 | actual_path = (char *)path; |
---|
428 | |
---|
429 | pathlen = strlen (actual_path); |
---|
430 | |
---|
431 | if (pathlen >= sizeof (saddr->sun_path)) |
---|
432 | return NULL; |
---|
433 | |
---|
434 | saddr = g_new0 (struct sockaddr_un, 1); |
---|
435 | |
---|
436 | *saddr_len = sizeof (struct sockaddr_un) - sizeof (saddr->sun_path) + pathlen; |
---|
437 | |
---|
438 | LINC_SET_SOCKADDR_LEN (saddr, *saddr_len); |
---|
439 | |
---|
440 | saddr->sun_family = AF_UNIX; |
---|
441 | strncpy (saddr->sun_path, actual_path, sizeof (saddr->sun_path) - 1); |
---|
442 | saddr->sun_path[sizeof (saddr->sun_path) - 1] = '\0'; |
---|
443 | |
---|
444 | return (struct sockaddr *)saddr; |
---|
445 | } |
---|
446 | #endif /* AF_UNIX */ |
---|
447 | |
---|
448 | /* |
---|
449 | * linc_protocol_get_sockaddr_irda: |
---|
450 | * @proto: |
---|
451 | * @hostname: |
---|
452 | * @service: |
---|
453 | * @saddr_len: |
---|
454 | * |
---|
455 | * NOTE: This function is not implemented. We need to hack something |
---|
456 | * together from irda_getaddrinfo. |
---|
457 | * |
---|
458 | * Return Value: |
---|
459 | */ |
---|
460 | #ifdef AF_IRDA |
---|
461 | static struct sockaddr * |
---|
462 | linc_protocol_get_sockaddr_irda (const LINCProtocolInfo *proto, |
---|
463 | const char *hostname, |
---|
464 | const char *service, |
---|
465 | LincSockLen *saddr_len) |
---|
466 | { |
---|
467 | g_assert (proto->family == AF_IRDA); |
---|
468 | |
---|
469 | return NULL; |
---|
470 | } |
---|
471 | #endif /* AF_IRDA */ |
---|
472 | |
---|
473 | /* |
---|
474 | * linc_protocol_get_sockaddr: |
---|
475 | * @proto: a #LINCProtocolInfo structure. |
---|
476 | * @hostname: protocol dependant host information. |
---|
477 | * @service: protocol dependant service information. |
---|
478 | * @saddr_len: location in which to store the returned structure's length. |
---|
479 | * |
---|
480 | * Allocates, fills in and returns the #sockaddr structure appropriate |
---|
481 | * for the supplied protocol, @proto. |
---|
482 | * |
---|
483 | * Return Value: a pointer to a valid #sockaddr structure if the call |
---|
484 | * succeeds, NULL otherwise. |
---|
485 | */ |
---|
486 | struct sockaddr * |
---|
487 | linc_protocol_get_sockaddr (const LINCProtocolInfo *proto, |
---|
488 | const char *hostname, |
---|
489 | const char *service, |
---|
490 | LincSockLen *saddr_len) |
---|
491 | { |
---|
492 | if (proto && proto->get_sockaddr) |
---|
493 | return proto->get_sockaddr (proto, hostname, service, saddr_len); |
---|
494 | |
---|
495 | return NULL; |
---|
496 | } |
---|
497 | |
---|
498 | /* |
---|
499 | * linc_protocol_get_sockinfo_ipv46: |
---|
500 | * @host: a #hostent structure describing the host. |
---|
501 | * @port: the portnumber. |
---|
502 | * @hostname: pointer by which the hostname string is returned. |
---|
503 | * @portnum: pointer by which the port number string is returned. |
---|
504 | * |
---|
505 | * Generates two strings, returned through @hostname and @portnum, corresponding |
---|
506 | * to @host and @port. On return @hostname should contain the canonical hostname |
---|
507 | * of the host and @portnum should contain the port number string. |
---|
508 | * |
---|
509 | * If @host is NULL, the local host name is used. |
---|
510 | * |
---|
511 | * Note: both @hostname and @service are allocated on the heap and should be |
---|
512 | * freed using g_free(). |
---|
513 | * |
---|
514 | * Return Value: #TRUE if the function succeeds, #FALSE otherwise. |
---|
515 | */ |
---|
516 | static gboolean |
---|
517 | linc_protocol_get_sockinfo_ipv46 (struct hostent *host, |
---|
518 | guint port, |
---|
519 | gchar **hostname, |
---|
520 | char **portnum) |
---|
521 | { |
---|
522 | if (!host) { |
---|
523 | const char *local_host; |
---|
524 | |
---|
525 | if (!(local_host = linc_get_local_hostname ())) |
---|
526 | return FALSE; |
---|
527 | |
---|
528 | LINC_RESOLV_SET_IPV6; |
---|
529 | host = gethostbyname (local_host); |
---|
530 | } |
---|
531 | |
---|
532 | if (!host) |
---|
533 | return FALSE; |
---|
534 | |
---|
535 | if (hostname) |
---|
536 | *hostname = g_strdup (host->h_name); |
---|
537 | |
---|
538 | if (portnum) { |
---|
539 | gchar tmpport[NI_MAXSERV]; |
---|
540 | |
---|
541 | g_snprintf (tmpport, sizeof (tmpport), "%d", ntohs (port)); |
---|
542 | |
---|
543 | *portnum = g_strdup (tmpport); |
---|
544 | } |
---|
545 | |
---|
546 | return TRUE; |
---|
547 | } |
---|
548 | |
---|
549 | /* |
---|
550 | * linc_protocol_get_sockinfo_ipv4: |
---|
551 | * @proto: the #LINCProtocolInfo structure for the IPv4 protocol. |
---|
552 | * @sockaddr: a #sockaddr_in structure desribing the socket. |
---|
553 | * @hostname: pointer by which the hostname string is returned. |
---|
554 | * @portnum: pointer by which the port number string is returned. |
---|
555 | * |
---|
556 | * Generates two strings, returned through @hostname and @portnum, describing |
---|
557 | * the socket address, @sockaddr. On return @hostname should contain the |
---|
558 | * canonical hostname of the host described in @sockaddr and @portnum should |
---|
559 | * contain the port number of the socket described in @sockaddr. |
---|
560 | * |
---|
561 | * Note: both @hostname and @service are allocated on the heap and should be |
---|
562 | * freed using g_free(). |
---|
563 | * |
---|
564 | * Return Value: #TRUE if the function succeeds, #FALSE otherwise. |
---|
565 | */ |
---|
566 | #ifdef AF_INET |
---|
567 | static gboolean |
---|
568 | linc_protocol_get_sockinfo_ipv4 (const LINCProtocolInfo *proto, |
---|
569 | const struct sockaddr *saddr, |
---|
570 | gchar **hostname, |
---|
571 | gchar **portnum) |
---|
572 | { |
---|
573 | struct sockaddr_in *sa_in = (struct sockaddr_in *)saddr; |
---|
574 | struct hostent *host = NULL; |
---|
575 | |
---|
576 | g_assert (proto && saddr && saddr->sa_family == AF_INET); |
---|
577 | |
---|
578 | if (sa_in->sin_addr.s_addr != INADDR_ANY) { |
---|
579 | host = gethostbyaddr ((char *)&sa_in->sin_addr, |
---|
580 | sizeof (struct in_addr), AF_INET); |
---|
581 | if (!host) |
---|
582 | return FALSE; |
---|
583 | } |
---|
584 | |
---|
585 | return linc_protocol_get_sockinfo_ipv46 (host, sa_in->sin_port, |
---|
586 | hostname, portnum); |
---|
587 | } |
---|
588 | #endif /* AF_INET */ |
---|
589 | |
---|
590 | /* |
---|
591 | * linc_protocol_get_sockinfo_ipv6: |
---|
592 | * @proto: the #LINCProtocolInfo structure for the IPv6 protocol. |
---|
593 | * @sockaddr: a #sockaddr_in structure desribing the socket. |
---|
594 | * @hostname: pointer by which the hostname string is returned. |
---|
595 | * @portnum: pointer by which the port number string is returned. |
---|
596 | * |
---|
597 | * Generates two strings, returned through @hostname and @portnum, describing |
---|
598 | * the socket address, @sockaddr. On return @hostname should contain the |
---|
599 | * canonical hostname of the host described in @sockaddr and @portnum should |
---|
600 | * contain the port number of the socket described in @sockaddr. |
---|
601 | * |
---|
602 | * Note: both @hostname and @service are allocated on the heap and should be |
---|
603 | * freed using g_free(). |
---|
604 | * |
---|
605 | * Return Value: #TRUE if the function succeeds, #FALSE otherwise. |
---|
606 | */ |
---|
607 | #ifdef AF_INET6 |
---|
608 | |
---|
609 | /* FIXME: is IN6ADDR_ANY_INIT exported on Mac OS X ? */ |
---|
610 | /* on Mac OS X 10.1 inaddr6_any isn't exported by libc */ |
---|
611 | #ifndef in6addr_any |
---|
612 | static const struct in6_addr in6addr_any = { { { 0 } } }; |
---|
613 | #endif |
---|
614 | |
---|
615 | static gboolean |
---|
616 | linc_protocol_get_sockinfo_ipv6 (const LINCProtocolInfo *proto, |
---|
617 | const struct sockaddr *saddr, |
---|
618 | gchar **hostname, |
---|
619 | gchar **portnum) |
---|
620 | { |
---|
621 | struct sockaddr_in6 *sa_in6 = (struct sockaddr_in6 *)saddr; |
---|
622 | struct hostent *host = NULL; |
---|
623 | |
---|
624 | g_assert (proto && saddr && saddr->sa_family == AF_INET6); |
---|
625 | |
---|
626 | if (!memcmp (&sa_in6->sin6_addr, &in6addr_any, sizeof (struct in6_addr))) { |
---|
627 | |
---|
628 | host = gethostbyaddr ((char *)&sa_in6->sin6_addr, |
---|
629 | sizeof (struct in6_addr), AF_INET6); |
---|
630 | if (!host) |
---|
631 | return FALSE; |
---|
632 | } |
---|
633 | |
---|
634 | return linc_protocol_get_sockinfo_ipv46 (host, sa_in6->sin6_port, |
---|
635 | hostname, portnum); |
---|
636 | } |
---|
637 | |
---|
638 | #endif /* AF_INET6 */ |
---|
639 | |
---|
640 | /* |
---|
641 | * linc_protocol_get_sockinfo_unix: |
---|
642 | * @proto: a #LINCProtocolInfo structure. |
---|
643 | * @sockaddr: a #sockaddr_un structure desribing the socket. |
---|
644 | * @hostname: pointer by which the hostname string is returned. |
---|
645 | * @service: pointer by which the sockets pathname string is returned. |
---|
646 | * |
---|
647 | * Generates two strings, returned through @hostname and @sock_path, describing |
---|
648 | * the socket address, @sockaddr. On return @hostname should contain the |
---|
649 | * canonical hostname of the local host and @sock_path should contain the |
---|
650 | * path name of the unix socket described in @sockaddr. |
---|
651 | * |
---|
652 | * Note: both @hostname and @sock_path are allocated on the heap and should |
---|
653 | * be freed using g_free(). |
---|
654 | * |
---|
655 | * Return Value: #TRUE if the function succeeds, #FALSE otherwise. |
---|
656 | */ |
---|
657 | #ifdef AF_UNIX |
---|
658 | static gboolean |
---|
659 | linc_protocol_get_sockinfo_unix (const LINCProtocolInfo *proto, |
---|
660 | const struct sockaddr *saddr, |
---|
661 | gchar **hostname, |
---|
662 | gchar **sock_path) |
---|
663 | { |
---|
664 | struct sockaddr_un *sa_un = (struct sockaddr_un *)saddr; |
---|
665 | |
---|
666 | g_assert (proto && saddr && saddr->sa_family == AF_UNIX); |
---|
667 | |
---|
668 | if (hostname) { |
---|
669 | const char *local_host; |
---|
670 | |
---|
671 | if (!(local_host = linc_get_local_hostname ())) |
---|
672 | return FALSE; |
---|
673 | |
---|
674 | *hostname = g_strdup (local_host); |
---|
675 | } |
---|
676 | |
---|
677 | if (sock_path) |
---|
678 | *sock_path = g_strdup (sa_un->sun_path); |
---|
679 | |
---|
680 | return TRUE; |
---|
681 | } |
---|
682 | #endif /* AF_UNIX */ |
---|
683 | |
---|
684 | /* |
---|
685 | * linc_protocol_get_sockinfo_irda: |
---|
686 | * @proto: a #LINCProtocolInfo structure. |
---|
687 | * @sockaddr: a #sockaddr_irda structure desribing the socket. |
---|
688 | * @hostname: |
---|
689 | * @service: |
---|
690 | * |
---|
691 | * Return Value: #TRUE if the function succeeds, #FALSE otherwise. |
---|
692 | */ |
---|
693 | #ifdef AF_IRDA |
---|
694 | static gboolean |
---|
695 | linc_protocol_get_sockinfo_irda (const LINCProtocolInfo *proto, |
---|
696 | const struct sockaddr *saddr, |
---|
697 | gchar **hostname, |
---|
698 | gchar **portnum) |
---|
699 | { |
---|
700 | g_assert (proto && saddr && saddr->sa_family == AF_IRDA); |
---|
701 | |
---|
702 | return FALSE; |
---|
703 | } |
---|
704 | #endif /* AF_IRDA */ |
---|
705 | |
---|
706 | /* |
---|
707 | * linc_protocol_get_sockinfo: |
---|
708 | * @proto: a #LINCProtocolInfo structure. |
---|
709 | * @sockaddr: a #sockadrr structure desribing the socket. |
---|
710 | * @hostname: pointer by which the hostname string is returned. |
---|
711 | * @service: pointer by which the service string is returned. |
---|
712 | * |
---|
713 | * Generates two strings, returned through @hostname and @service, describing |
---|
714 | * the socket address, @sockaddr. On return @hostname should contain the |
---|
715 | * canonical hostname of the host described in @sockaddr and @service should |
---|
716 | * contain the service descriptor(e.g. port number) of the socket described in |
---|
717 | * @sockaddr |
---|
718 | * |
---|
719 | * Note: both @hostname and @service are allocated on the heap and should be |
---|
720 | * freed using g_free(). |
---|
721 | * |
---|
722 | * Return Value: #TRUE if the function succeeds, #FALSE otherwise. |
---|
723 | */ |
---|
724 | gboolean |
---|
725 | linc_protocol_get_sockinfo (const LINCProtocolInfo *proto, |
---|
726 | const struct sockaddr *saddr, |
---|
727 | gchar **hostname, |
---|
728 | gchar **service) |
---|
729 | { |
---|
730 | if (proto && proto->get_sockinfo) |
---|
731 | return proto->get_sockinfo (proto, saddr, hostname, service); |
---|
732 | |
---|
733 | return FALSE; |
---|
734 | } |
---|
735 | |
---|
736 | /** |
---|
737 | * linc_protocol_is_local: |
---|
738 | * @proto: the protocol |
---|
739 | * @saddr: the socket address of a connecting client. |
---|
740 | * |
---|
741 | * This method determines if the client is from the same |
---|
742 | * machine or not - per protocol. |
---|
743 | * |
---|
744 | * Return value: TRUE if the connection is local, else FALSE |
---|
745 | **/ |
---|
746 | gboolean |
---|
747 | linc_protocol_is_local (const LINCProtocolInfo *proto, |
---|
748 | const struct sockaddr *saddr, |
---|
749 | LincSockLen saddr_len) |
---|
750 | { |
---|
751 | if (proto && proto->is_local) |
---|
752 | return proto->is_local (proto, saddr, saddr_len); |
---|
753 | |
---|
754 | return FALSE; |
---|
755 | } |
---|
756 | |
---|
757 | /* |
---|
758 | * af_unix_destroy: |
---|
759 | * @fd: file descriptor of the socket. |
---|
760 | * @dummy: not used. |
---|
761 | * @pathname: path name of the UNIX socket |
---|
762 | * |
---|
763 | * Removes the UNIX socket file. |
---|
764 | */ |
---|
765 | #ifdef AF_UNIX |
---|
766 | static void |
---|
767 | linc_protocol_unix_destroy (int fd, |
---|
768 | const char *dummy, |
---|
769 | const char *pathname) |
---|
770 | { |
---|
771 | unlink (pathname); |
---|
772 | } |
---|
773 | |
---|
774 | static gboolean |
---|
775 | linc_protocol_unix_is_local (const LINCProtocolInfo *proto, |
---|
776 | const struct sockaddr *saddr, |
---|
777 | LincSockLen saddr_len) |
---|
778 | { |
---|
779 | return TRUE; |
---|
780 | } |
---|
781 | #endif /* AF_UNIX */ |
---|
782 | |
---|
783 | /* |
---|
784 | * linc_protocol_tcp_setup: |
---|
785 | * @fd: file descriptor of the socket. |
---|
786 | * @cnx_flags: a #LINCConnectionOptions value. |
---|
787 | * |
---|
788 | * Sets the TCP_NODELAY option on the TCP socket. |
---|
789 | * |
---|
790 | * Note: this is not applied to SSL TCP sockets. |
---|
791 | */ |
---|
792 | #if defined(AF_INET) || defined(AF_INET6) |
---|
793 | static void |
---|
794 | linc_protocol_tcp_setup (int fd, |
---|
795 | LINCConnectionOptions cnx_flags) |
---|
796 | { |
---|
797 | #ifdef TCP_NODELAY |
---|
798 | if (!(cnx_flags & LINC_CONNECTION_SSL)) { |
---|
799 | struct protoent *proto; |
---|
800 | int on = 1; |
---|
801 | |
---|
802 | proto = getprotobyname ("tcp"); |
---|
803 | if (!proto) |
---|
804 | return; |
---|
805 | |
---|
806 | setsockopt (fd, proto->p_proto, TCP_NODELAY, |
---|
807 | &on, sizeof (on)); |
---|
808 | } |
---|
809 | #endif |
---|
810 | } |
---|
811 | #endif /* defined(AF_INET) || defined(AF_INET6) */ |
---|
812 | |
---|
813 | static LINCProtocolInfo static_linc_protocols[] = { |
---|
814 | #if defined(AF_INET) |
---|
815 | { |
---|
816 | "IPv4", /* name */ |
---|
817 | AF_INET, /* family */ |
---|
818 | sizeof (struct sockaddr_in), /* addr_len */ |
---|
819 | IPPROTO_TCP, /* stream_proto_num */ |
---|
820 | 0, /* flags */ |
---|
821 | linc_protocol_tcp_setup, /* setup */ |
---|
822 | NULL, /* destroy */ |
---|
823 | linc_protocol_get_sockaddr_ipv4,/* get_sockaddr */ |
---|
824 | linc_protocol_get_sockinfo_ipv4,/* get_sockinfo */ |
---|
825 | linc_protocol_is_local_ipv46 /* is_local */ |
---|
826 | }, |
---|
827 | #endif |
---|
828 | #if defined(AF_INET6) |
---|
829 | { |
---|
830 | "IPv6", /* name */ |
---|
831 | AF_INET6, /* family */ |
---|
832 | sizeof (struct sockaddr_in6), /* addr_len */ |
---|
833 | IPPROTO_TCP, /* stream_proto_num */ |
---|
834 | 0, /* flags */ |
---|
835 | linc_protocol_tcp_setup, /* setup */ |
---|
836 | NULL, /* destroy */ |
---|
837 | linc_protocol_get_sockaddr_ipv6,/* get_sockaddr */ |
---|
838 | linc_protocol_get_sockinfo_ipv6,/* get_sockinfo */ |
---|
839 | linc_protocol_is_local_ipv46 /* is_local */ |
---|
840 | }, |
---|
841 | #endif |
---|
842 | #ifdef AF_UNIX |
---|
843 | { |
---|
844 | "UNIX", /* name */ |
---|
845 | AF_UNIX, /* family */ |
---|
846 | sizeof (struct sockaddr_un), /* addr_len */ |
---|
847 | 0, /* stream_proto_num */ |
---|
848 | LINC_PROTOCOL_SECURE|LINC_PROTOCOL_NEEDS_BIND, /* flags */ |
---|
849 | NULL, /* setup */ |
---|
850 | linc_protocol_unix_destroy, /* destroy */ |
---|
851 | linc_protocol_get_sockaddr_unix, /* get_sockaddr */ |
---|
852 | linc_protocol_get_sockinfo_unix, /* get_sockinfo */ |
---|
853 | linc_protocol_unix_is_local /* is_local */ |
---|
854 | }, |
---|
855 | #endif |
---|
856 | #ifdef AF_IRDA |
---|
857 | { |
---|
858 | "IrDA", /* name */ |
---|
859 | AF_IRDA, /* family */ |
---|
860 | sizeof (struct sockaddr_irda), /* addr_len */ |
---|
861 | 0, /* stream_proto_num */ |
---|
862 | LINC_PROTOCOL_NEEDS_BIND, /* flags */ |
---|
863 | NULL, /* setup */ |
---|
864 | NULL, /* destroy */ |
---|
865 | linc_protocol_get_sockaddr_irda, /* get_sockaddr */ |
---|
866 | linc_protocol_get_sockinfo_irda, /* get_sockinfo */ |
---|
867 | NULL /* is_local */ |
---|
868 | }, |
---|
869 | #endif |
---|
870 | { NULL /* name */ } |
---|
871 | }; |
---|
872 | |
---|
873 | /* |
---|
874 | * Routines for AF_IRDA |
---|
875 | * FIXME: These are left here only as a reference for implementing |
---|
876 | * linc_protocol_get_sockinfo_irda and |
---|
877 | * linc_protocol_get_sockaddr_irda |
---|
878 | * |
---|
879 | */ |
---|
880 | #if 0 |
---|
881 | #ifdef AF_IRDA |
---|
882 | |
---|
883 | #define MAX_IRDA_DEVICES 10 |
---|
884 | #define IRDA_NICKNAME_MAX (sizeof (((struct irda_device_info *)NULL)->info) + 1) |
---|
885 | |
---|
886 | static int |
---|
887 | irda_find_device (guint32 *addr, |
---|
888 | char *name, |
---|
889 | gboolean name_to_addr) |
---|
890 | { |
---|
891 | struct irda_device_list *list; |
---|
892 | unsigned char *buf; |
---|
893 | int len, i, retval, fd; |
---|
894 | |
---|
895 | retval = -1; |
---|
896 | |
---|
897 | fd = socket (AF_IRDA, SOCK_STREAM, 0); |
---|
898 | if (fd < 0) |
---|
899 | return -1; |
---|
900 | |
---|
901 | len = sizeof (struct irda_device_list) + |
---|
902 | sizeof (struct irda_device_info) * MAX_IRDA_DEVICES; |
---|
903 | |
---|
904 | buf = g_alloca (len); |
---|
905 | list = (struct irda_device_list *)buf; |
---|
906 | |
---|
907 | if (getsockopt (fd, SOL_IRLMP, IRLMP_ENUMDEVICES, buf, &len)) |
---|
908 | goto out; |
---|
909 | |
---|
910 | if (len < 1) |
---|
911 | goto out; |
---|
912 | |
---|
913 | for (i = 0; i < list->len && retval; i++) { |
---|
914 | if(name_to_addr) { |
---|
915 | if (!strcmp (list->dev[i].info, name)) { |
---|
916 | *addr = list->dev[i].daddr; |
---|
917 | retval = 0; |
---|
918 | } |
---|
919 | } |
---|
920 | else { |
---|
921 | if (list->dev[i].daddr == *addr) { |
---|
922 | strncpy (name, list->dev[i].info, |
---|
923 | sizeof(list->dev[i].info)); |
---|
924 | name[sizeof (list->dev[i].info)] = '\0'; |
---|
925 | retval = 0; |
---|
926 | } |
---|
927 | } |
---|
928 | } |
---|
929 | |
---|
930 | out: |
---|
931 | LINC_CLOSE (fd); |
---|
932 | |
---|
933 | return retval; |
---|
934 | } |
---|
935 | |
---|
936 | #define IRDA_PREFIX "IrDA-" |
---|
937 | #define IRDA_PREFIX_LEN 5 |
---|
938 | |
---|
939 | static int |
---|
940 | irda_getaddrinfo (const char *nodename, |
---|
941 | const char *servname, |
---|
942 | const struct addrinfo *hints, |
---|
943 | struct addrinfo **res) |
---|
944 | { |
---|
945 | struct sockaddr_irda sai; |
---|
946 | struct addrinfo *retval; |
---|
947 | char hnbuf[IRDA_NICKNAME_MAX + IRDA_PREFIX_LEN]; |
---|
948 | int n; |
---|
949 | char *tptr; |
---|
950 | |
---|
951 | /* |
---|
952 | * For now, it *has* to start with IRDA_PREFIX to be in the IRDA |
---|
953 | * hostname/address format we use |
---|
954 | */ |
---|
955 | if (nodename && strcmp (nodename, IRDA_PREFIX)) |
---|
956 | return EAI_NONAME; |
---|
957 | |
---|
958 | sai.sir_family = AF_IRDA; |
---|
959 | sai.sir_lsap_sel = LSAP_ANY; |
---|
960 | |
---|
961 | if (servname) |
---|
962 | g_snprintf (sai.sir_name, sizeof (sai.sir_name), "%s", servname); |
---|
963 | else { |
---|
964 | struct timeval t; |
---|
965 | |
---|
966 | gettimeofday (&t, NULL); |
---|
967 | g_snprintf (sai.sir_name, sizeof (sai.sir_name), "IIOP%x%x", |
---|
968 | rand(), (guint)(t.tv_sec^t.tv_usec)); |
---|
969 | } |
---|
970 | |
---|
971 | if (nodename) { |
---|
972 | if (!strncmp (nodename + IRDA_PREFIX_LEN, "0x", 2)) { |
---|
973 | if (sscanf (nodename + strlen(IRDA_PREFIX "0x"), |
---|
974 | "%u", &sai.sir_addr) != 1) |
---|
975 | return EAI_NONAME; |
---|
976 | |
---|
977 | /* It's a numeric address - we need to find the hostname */ |
---|
978 | g_strncpy (hnbuf, IRDA_PREFIX, IRDA_NICKNAME_MAX + IRDA_PREFIX_LEN); |
---|
979 | if (irda_find_device (&sai.sir_addr, |
---|
980 | hnbuf + IRDA_PREFIX_LEN, |
---|
981 | FALSE)) |
---|
982 | return EAI_NONAME; |
---|
983 | |
---|
984 | nodename = hnbuf; |
---|
985 | } |
---|
986 | else if (!(hints->ai_flags & AI_NUMERICHOST)) { |
---|
987 | /* It's a name - we need to find the address */ |
---|
988 | if (irda_find_device (&sai.sir_addr, |
---|
989 | (char *)nodename + IRDA_PREFIX_LEN, |
---|
990 | TRUE)) |
---|
991 | return EAI_NONAME; |
---|
992 | } |
---|
993 | else |
---|
994 | return EAI_NONAME; |
---|
995 | } |
---|
996 | else |
---|
997 | /* AI_PASSIVE flag gets ignored, sort of */ |
---|
998 | hnbuf[0] = 0; |
---|
999 | |
---|
1000 | n = sizeof (struct addrinfo) + sizeof (struct sockaddr_irda); |
---|
1001 | |
---|
1002 | if (hints->ai_flags & AI_CANONNAME) |
---|
1003 | n += strlen(hnbuf) + 1; |
---|
1004 | |
---|
1005 | retval = g_malloc0(n); |
---|
1006 | |
---|
1007 | tptr = (char *)retval; |
---|
1008 | tptr += sizeof (struct addrinfo); |
---|
1009 | retval->ai_addr = (struct sockaddr *)tptr; |
---|
1010 | memcpy (retval->ai_addr, &sai, sizeof (struct sockaddr_irda)); |
---|
1011 | tptr += sizeof (struct sockaddr_irda); |
---|
1012 | g_strncpy (tptr, hnbuf, IRDA_NICKNAME_MAX + IRDA_PREFIX_LEN); |
---|
1013 | retval->ai_family = AF_IRDA; |
---|
1014 | retval->ai_socktype = SOCK_STREAM; |
---|
1015 | retval->ai_protocol = 0; |
---|
1016 | retval->ai_next = NULL; |
---|
1017 | retval->ai_addrlen = sizeof(struct sockaddr_irda); |
---|
1018 | |
---|
1019 | *res = retval; |
---|
1020 | |
---|
1021 | return 0; |
---|
1022 | } |
---|
1023 | |
---|
1024 | static int |
---|
1025 | irda_getnameinfo (const struct sockaddr *sa, |
---|
1026 | LincSockLen sa_len, |
---|
1027 | char *host, |
---|
1028 | size_t hostlen, |
---|
1029 | char *serv, |
---|
1030 | size_t servlen, |
---|
1031 | int flags) |
---|
1032 | { |
---|
1033 | struct sockaddr_irda *sai = (struct sockaddr_irda *) sa; |
---|
1034 | gboolean got_host = FALSE; |
---|
1035 | /* Here, we talk to the host specified, and ask it for its name */ |
---|
1036 | |
---|
1037 | if (sa_len != sizeof (struct sockaddr_irda)) |
---|
1038 | return -1; |
---|
1039 | |
---|
1040 | /* It doesn't seem like the sir_lsap_sel is supposed to be taken into consideration when connecting... */ |
---|
1041 | if (!(flags & NI_NUMERICHOST)) { |
---|
1042 | guint32 daddr; |
---|
1043 | char hostbuf [IRDA_NICKNAME_MAX]; |
---|
1044 | |
---|
1045 | daddr = sai->sir_addr; |
---|
1046 | if (!irda_find_device (&daddr, hostbuf, FALSE)) { |
---|
1047 | g_snprintf (host, hostlen, "%s", hostbuf); |
---|
1048 | got_host = TRUE; |
---|
1049 | } |
---|
1050 | } |
---|
1051 | if (!got_host) { |
---|
1052 | if (flags & NI_NAMEREQD) |
---|
1053 | return -1; |
---|
1054 | |
---|
1055 | g_snprintf (host, hostlen, IRDA_PREFIX "%#08x", sai->sir_addr); |
---|
1056 | } |
---|
1057 | |
---|
1058 | g_snprintf(serv, servlen, "%s", sai->sir_name); |
---|
1059 | |
---|
1060 | return 0; |
---|
1061 | } |
---|
1062 | #endif /* AF_IRDA */ |
---|
1063 | #endif /* 0 */ |
---|
1064 | |
---|
1065 | void |
---|
1066 | linc_protocol_destroy_cnx (const LINCProtocolInfo *proto, |
---|
1067 | int fd, |
---|
1068 | const char *host, |
---|
1069 | const char *service) |
---|
1070 | { |
---|
1071 | g_return_if_fail (proto != NULL); |
---|
1072 | |
---|
1073 | if (fd >= 0) { |
---|
1074 | if (proto->destroy) |
---|
1075 | proto->destroy (fd, host, service); |
---|
1076 | |
---|
1077 | LINC_CLOSE (fd); |
---|
1078 | } |
---|
1079 | } |
---|
1080 | |
---|
1081 | |
---|
1082 | void |
---|
1083 | linc_protocol_destroy_addr (const LINCProtocolInfo *proto, |
---|
1084 | int fd, |
---|
1085 | struct sockaddr *saddr) |
---|
1086 | { |
---|
1087 | g_return_if_fail (proto != NULL); |
---|
1088 | |
---|
1089 | if (fd >= 0) { |
---|
1090 | #ifdef AF_UNIX |
---|
1091 | if (proto->family == AF_UNIX && proto->destroy) { |
---|
1092 | /* We are AF_UNIX - we need the path to unlink */ |
---|
1093 | struct sockaddr_un *addr_un = |
---|
1094 | (struct sockaddr_un *) saddr; |
---|
1095 | proto->destroy (fd, NULL, addr_un->sun_path); |
---|
1096 | } |
---|
1097 | #endif |
---|
1098 | LINC_CLOSE (fd); |
---|
1099 | g_free (saddr); |
---|
1100 | } |
---|
1101 | |
---|
1102 | } |
---|
1103 | |
---|
1104 | /* |
---|
1105 | * linc_protocol_all: |
---|
1106 | * |
---|
1107 | * Returns a list of protocols supported by linc. |
---|
1108 | * |
---|
1109 | * Note: the list is terminated by a #LINCProtocolInfo with a |
---|
1110 | * NULL name pointer. |
---|
1111 | * |
---|
1112 | * Return Value: an array of #LINCProtocolInfo structures. |
---|
1113 | */ |
---|
1114 | LINCProtocolInfo * const |
---|
1115 | linc_protocol_all (void) |
---|
1116 | { |
---|
1117 | return static_linc_protocols; |
---|
1118 | } |
---|
1119 | |
---|
1120 | /* |
---|
1121 | * linc_protocol_find: |
---|
1122 | * @name: name of the protocol. |
---|
1123 | * |
---|
1124 | * Find a protocol identified by @name. |
---|
1125 | * |
---|
1126 | * Return Value: a pointer to a valid #LINCProtocolInfo structure if |
---|
1127 | * the protocol is supported by linc, NULL otherwise. |
---|
1128 | */ |
---|
1129 | LINCProtocolInfo * const |
---|
1130 | linc_protocol_find (const char *name) |
---|
1131 | { |
---|
1132 | int i; |
---|
1133 | |
---|
1134 | for (i = 0; static_linc_protocols [i].name; i++) { |
---|
1135 | if (!strcmp (name, static_linc_protocols [i].name)) |
---|
1136 | return &static_linc_protocols [i]; |
---|
1137 | } |
---|
1138 | |
---|
1139 | return NULL; |
---|
1140 | } |
---|
1141 | |
---|
1142 | /* |
---|
1143 | * linc_protocol_find_num: |
---|
1144 | * @family: the family identifier of the protocol - i.e. AF_* |
---|
1145 | * |
---|
1146 | * Find a protocol identified by @family. |
---|
1147 | * |
---|
1148 | * Return Value: a pointer to a valid #LINCProtocolInfo structure if |
---|
1149 | * the protocol is supported by linc, NULL otherwise. |
---|
1150 | */ |
---|
1151 | LINCProtocolInfo * const |
---|
1152 | linc_protocol_find_num (const int family) |
---|
1153 | { |
---|
1154 | int i; |
---|
1155 | |
---|
1156 | for (i = 0; static_linc_protocols [i].name; i++) { |
---|
1157 | if (family == static_linc_protocols [i].family) |
---|
1158 | return &static_linc_protocols [i]; |
---|
1159 | } |
---|
1160 | |
---|
1161 | return NULL; |
---|
1162 | } |
---|