source: trunk/ORBit2-2.14.0/linc2/src/linc-protocols.c

Last change on this file was 92, checked in by cinc, 19 years ago

Orbit2 modified for use with NOM

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