source: trunk/third/linc/src/linc-protocols.c @ 18552

Revision 18552, 28.8 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18551, which included commits to RCS files with non-trunk default branches.
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 <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
23static 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 */
36static void
37make_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 **/
82void
83linc_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 **/
100char *
101linc_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)
124const char *
125linc_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 */
141static gboolean
142ipv4_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
172static gboolean
173linc_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
265static struct sockaddr *
266linc_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
334static struct sockaddr *
335linc_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 */
394static struct sockaddr *
395linc_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
461static struct sockaddr *
462linc_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 */
486struct sockaddr *
487linc_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 */
516static gboolean
517linc_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
567static gboolean
568linc_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
615static gboolean
616linc_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
658static gboolean
659linc_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
694static gboolean
695linc_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 */
724gboolean
725linc_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 **/
746gboolean
747linc_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
766static void
767linc_protocol_unix_destroy (int         fd,
768                            const char *dummy,
769                            const char *pathname)
770{
771        unlink (pathname);
772}
773
774static gboolean
775linc_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)
793static void
794linc_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
813static 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
886static int
887irda_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
939static int
940irda_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
1024static int
1025irda_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
1065void
1066linc_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
1082void
1083linc_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 */
1114LINCProtocolInfo * const
1115linc_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 */
1129LINCProtocolInfo * const
1130linc_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 */
1151LINCProtocolInfo * const
1152linc_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}
Note: See TracBrowser for help on using the repository browser.