source: proiecte/PPPP/gdm/common/gdm-address.c @ 134

Last change on this file since 134 was 134, checked in by (none), 14 years ago

gdm sources with the modifications for webcam

File size: 14.0 KB
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
2 *
3 * Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 *
19 */
20
21
22#include "config.h"
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <fcntl.h>
27#include <unistd.h>
28#ifdef HAVE_STROPTS_H
29#include <stropts.h>
30#endif
31#include <string.h>
32#ifdef HAVE_SYS_SOCKET_H
33#include <sys/socket.h>
34#endif
35#ifdef HAVE_SYS_SOCKIO_H
36#include <sys/sockio.h>
37#endif
38#include <netdb.h>
39#include <sys/ioctl.h>
40#include <net/if.h>
41
42#ifndef G_OS_WIN32
43#include <sys/select.h>
44#include <netinet/in.h>
45#include <arpa/inet.h>
46#else
47#include <winsock2.h>
48#include <ws2tcpip.h>
49#endif
50
51#include <glib-object.h>
52
53#include "gdm-address.h"
54
55struct _GdmAddress
56{
57        struct sockaddr_storage *ss;
58};
59
60/* Register GdmAddress in the glib type system */
61GType
62gdm_address_get_type (void)
63{
64        static GType addr_type = 0;
65
66        if (addr_type == 0) {
67                addr_type = g_boxed_type_register_static ("GdmAddress",
68                                                          (GBoxedCopyFunc) gdm_address_copy,
69                                                          (GBoxedFreeFunc) gdm_address_free);
70        }
71
72        return addr_type;
73}
74
75/**
76 * gdm_address_get_family_type:
77 * @address: A pointer to a #GdmAddress
78 *
79 * Use this function to retrive the address family of @address.
80 *
81 * Return value: The address family of @address.
82 **/
83int
84gdm_address_get_family_type (GdmAddress *address)
85{
86        g_return_val_if_fail (address != NULL, -1);
87
88        return address->ss->ss_family;
89}
90
91
92/**
93 * gdm_address_new_from_sockaddr:
94 * @sa: A pointer to a sockaddr.
95 * @size: size of sockaddr in bytes.
96 *
97 * Creates a new #GdmAddress from @sa.
98 *
99 * Return value: The new #GdmAddress
100 * or %NULL if @sa was invalid or the address family isn't supported.
101 **/
102GdmAddress *
103gdm_address_new_from_sockaddr (struct sockaddr *sa,
104                               size_t           size)
105{
106        GdmAddress *addr;
107
108        g_return_val_if_fail (sa != NULL, NULL);
109        g_return_val_if_fail (size >= sizeof (struct sockaddr), NULL);
110        g_return_val_if_fail (size <= sizeof (struct sockaddr_storage), NULL);
111
112        addr = g_new0 (GdmAddress, 1);
113        addr->ss = g_new0 (struct sockaddr_storage, 1);
114        memcpy (addr->ss, sa, size);
115
116        return addr;
117}
118
119/**
120 * gdm_address_get_sockaddr_storage:
121 * @address: A #GdmAddress
122 *
123 * This function tanslates @address into a equivalent
124 * sockaddr_storage
125 *
126 * Return value: A newly allocated sockaddr_storage structure the caller must free
127 * or %NULL if @address did not point to a valid #GdmAddress.
128 **/
129struct sockaddr_storage *
130gdm_address_get_sockaddr_storage (GdmAddress *address)
131{
132        struct sockaddr_storage *ss;
133
134        g_return_val_if_fail (address != NULL, NULL);
135        g_return_val_if_fail (address->ss != NULL, NULL);
136
137        ss = g_memdup (address->ss, sizeof (struct sockaddr_storage));
138
139        return ss;
140}
141
142struct sockaddr_storage *
143gdm_address_peek_sockaddr_storage (GdmAddress *address)
144{
145        g_return_val_if_fail (address != NULL, NULL);
146
147        return address->ss;
148}
149
150static gboolean
151v4_v4_equal (const struct sockaddr_in *a,
152             const struct sockaddr_in *b)
153{
154        return a->sin_addr.s_addr == b->sin_addr.s_addr;
155}
156
157#ifdef ENABLE_IPV6
158static gboolean
159v6_v6_equal (struct sockaddr_in6 *a,
160             struct sockaddr_in6 *b)
161{
162        return IN6_ARE_ADDR_EQUAL (&a->sin6_addr, &b->sin6_addr);
163}
164#endif
165
166#define SA(__s)    ((struct sockaddr *) __s)
167#define SIN(__s)   ((struct sockaddr_in *) __s)
168#define SIN6(__s)  ((struct sockaddr_in6 *) __s)
169
170gboolean
171gdm_address_equal (GdmAddress *a,
172                   GdmAddress *b)
173{
174        guint8 fam_a;
175        guint8 fam_b;
176
177        g_return_val_if_fail (a != NULL, FALSE);
178        g_return_val_if_fail (a->ss != NULL, FALSE);
179        g_return_val_if_fail (b != NULL, FALSE);
180        g_return_val_if_fail (b->ss != NULL, FALSE);
181
182        fam_a = a->ss->ss_family;
183        fam_b = b->ss->ss_family;
184
185        if (fam_a == AF_INET && fam_b == AF_INET) {
186                return v4_v4_equal (SIN (a->ss), SIN (b->ss));
187        }
188#ifdef ENABLE_IPV6
189        else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
190                return v6_v6_equal (SIN6 (a->ss), SIN6 (b->ss));
191        }
192#endif
193        return FALSE;
194}
195
196gboolean
197gdm_address_get_hostname (GdmAddress *address,
198                          char      **hostnamep)
199{
200        char     host [NI_MAXHOST];
201        int      res;
202        gboolean ret;
203
204        g_return_val_if_fail (address != NULL, FALSE);
205        g_return_val_if_fail (address->ss != NULL, FALSE);
206
207        ret = FALSE;
208
209        host [0] = '\0';
210        res = getnameinfo ((const struct sockaddr *)address->ss,
211                           sizeof (struct sockaddr_storage),
212                           host, sizeof (host),
213                           NULL, 0,
214                           0);
215        if (res == 0) {
216                ret = TRUE;
217                goto done;
218        } else {
219                g_warning ("Unable lookup hostname: %s", gai_strerror (res));
220                gdm_address_debug (address);
221        }
222
223        /* try numeric? */
224
225 done:
226        if (hostnamep != NULL) {
227                *hostnamep = g_strdup (host);
228        }
229
230        return ret;
231}
232
233gboolean
234gdm_address_get_numeric_info (GdmAddress *address,
235                              char      **hostp,
236                              char      **servp)
237{
238        char     host [NI_MAXHOST];
239        char     serv [NI_MAXSERV];
240        int      res;
241        gboolean ret;
242
243        g_return_val_if_fail (address != NULL, FALSE);
244        g_return_val_if_fail (address->ss != NULL, FALSE);
245
246        ret = FALSE;
247
248        host [0] = '\0';
249        serv [0] = '\0';
250        res = getnameinfo ((const struct sockaddr *)address->ss,
251                           sizeof (struct sockaddr_storage),
252                           host, sizeof (host),
253                           serv, sizeof (serv),
254                           NI_NUMERICHOST | NI_NUMERICSERV);
255        if (res != 0) {
256                g_warning ("Unable lookup numeric info: %s", gai_strerror (res));
257        } else {
258                ret = TRUE;
259        }
260
261        if (servp != NULL) {
262                *servp = g_strdup (serv);
263        }
264        if (hostp != NULL) {
265                *hostp = g_strdup (host);
266        }
267
268        return ret;
269}
270
271gboolean
272gdm_address_is_loopback (GdmAddress *address)
273{
274        g_return_val_if_fail (address != NULL, FALSE);
275        g_return_val_if_fail (address->ss != NULL, FALSE);
276
277        switch (address->ss->ss_family){
278#ifdef  AF_INET6
279        case AF_INET6:
280                return IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *)address->ss)->sin6_addr);
281                break;
282#endif
283        case AF_INET:
284                return (INADDR_LOOPBACK == htonl (((struct sockaddr_in *)address->ss)->sin_addr.s_addr));
285                break;
286        default:
287                break;
288        }
289
290        return FALSE;
291}
292
293static void
294add_local_siocgifconf (GList **list)
295{
296        struct ifconf ifc;
297        struct ifreq  ifreq;
298        struct ifreq *ifr;
299        struct ifreq *the_end;
300        int           sock;
301        char          buf[BUFSIZ];
302
303        if ((sock = socket (PF_INET, SOCK_DGRAM, 0)) < 0) {
304                perror ("socket");
305                return;
306        }
307
308        ifc.ifc_len = sizeof (buf);
309        ifc.ifc_buf = buf;
310        if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0) {
311                perror ("SIOCGIFCONF");
312                close (sock);
313                return;
314        }
315
316        /* Get IP address of each active IP network interface. */
317        the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
318
319        for (ifr = ifc.ifc_req; ifr < the_end; ifr++) {
320                if (ifr->ifr_addr.sa_family == AF_INET) {
321                        /* IP net interface */
322                        ifreq = *ifr;
323
324                        if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
325                                perror("SIOCGIFFLAGS");
326                        } else if (ifreq.ifr_flags & IFF_UP) {  /* active interface */
327                                if (ioctl (sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
328                                        perror("SIOCGIFADDR");
329                                } else {
330                                        GdmAddress *address;
331                                        address = gdm_address_new_from_sockaddr ((struct sockaddr *)&ifreq.ifr_addr,
332                                                                                 sizeof (struct sockaddr));
333
334                                        gdm_address_debug (address);
335
336                                        *list = g_list_append (*list, address);
337                                }
338                        }
339                }
340
341                /* Support for variable-length addresses. */
342#ifdef HAS_SA_LEN
343                ifr = (struct ifreq *) ((caddr_t) ifr
344                                        + ifr->ifr_addr.sa_len - sizeof(struct sockaddr));
345#endif
346        }
347
348        close (sock);
349}
350
351static void
352add_local_addrinfo (GList **list)
353{
354        char             hostbuf[BUFSIZ];
355        struct addrinfo *result;
356        struct addrinfo *res;
357        struct addrinfo  hints;
358
359        hostbuf[BUFSIZ-1] = '\0';
360        if (gethostname (hostbuf, BUFSIZ-1) != 0) {
361                g_debug ("%s: Could not get server hostname, using localhost", "gdm_peek_local_address_list");
362                snprintf (hostbuf, BUFSIZ-1, "localhost");
363        }
364
365        memset (&hints, 0, sizeof (hints));
366        hints.ai_family = AF_UNSPEC;
367        hints.ai_flags = AI_CANONNAME;
368
369        g_debug ("GdmAddress: looking up hostname: %s", hostbuf);
370        result = NULL;
371        if (getaddrinfo (hostbuf, NULL, &hints, &result) != 0) {
372                g_debug ("%s: Could not get address from hostname!", "gdm_peek_local_address_list");
373
374                return;
375        }
376
377        for (res = result; res != NULL; res = res->ai_next) {
378                GdmAddress *address;
379
380                g_debug ("family=%d sock_type=%d protocol=%d flags=0x%x canonname=%s\n",
381                         res->ai_family,
382                         res->ai_socktype,
383                         res->ai_protocol,
384                         res->ai_flags,
385                         res->ai_canonname);
386                address = gdm_address_new_from_sockaddr (res->ai_addr, res->ai_addrlen);
387                *list = g_list_append (*list, address);
388        }
389
390        if (result != NULL) {
391                freeaddrinfo (result);
392                result = NULL;
393        }
394}
395
396const GList *
397gdm_address_peek_local_list (void)
398{
399        static GList  *list = NULL;
400        static time_t  last_time = 0;
401
402        /* Don't check more then every 5 seconds */
403        if (last_time + 5 > time (NULL)) {
404                return list;
405        }
406
407        g_list_foreach (list, (GFunc)gdm_address_free, NULL);
408        g_list_free (list);
409        list = NULL;
410
411        last_time = time (NULL);
412
413        add_local_siocgifconf (&list);
414        add_local_addrinfo (&list);
415
416        return list;
417}
418
419gboolean
420gdm_address_is_local (GdmAddress *address)
421{
422        const GList *list;
423
424        if (gdm_address_is_loopback (address)) {
425                return TRUE;
426        }
427
428        list = gdm_address_peek_local_list ();
429
430        while (list != NULL) {
431                GdmAddress *addr = list->data;
432
433                if (gdm_address_equal (address, addr)) {
434                        return TRUE;
435                }
436
437                list = list->next;
438        }
439
440        return FALSE;
441}
442
443/**
444 * gdm_address_copy:
445 * @address: A #GdmAddress.
446 *
447 * Duplicates @address.
448 *
449 * Return value: Duplicated @address or %NULL if @address was not valid.
450 **/
451GdmAddress *
452gdm_address_copy (GdmAddress *address)
453{
454        GdmAddress *addr;
455
456        g_return_val_if_fail (address != NULL, NULL);
457
458        addr = g_new0 (GdmAddress, 1);
459        addr->ss = g_memdup (address->ss, sizeof (struct sockaddr_storage));
460
461        return addr;
462}
463
464/**
465 * gdm_address_free:
466 * @address: A #GdmAddress.
467 *
468 * Frees the memory allocated for @address.
469 **/
470void
471gdm_address_free (GdmAddress *address)
472{
473        g_return_if_fail (address != NULL);
474
475        g_free (address->ss);
476        g_free (address);
477}
478
479/* for debugging */
480static const char *
481address_family_str (GdmAddress *address)
482{
483        const char *str;
484        switch (address->ss->ss_family) {
485        case AF_INET:
486                str = "inet";
487                break;
488        case AF_INET6:
489                str = "inet6";
490                break;
491        case AF_UNIX:
492                str = "unix";
493                break;
494        case AF_UNSPEC:
495                str = "unspecified";
496                break;
497        default:
498                str = "unknown";
499                break;
500        }
501        return str;
502}
503
504void
505gdm_address_debug (GdmAddress *address)
506{
507        char *hostname;
508        char *host;
509        char *port;
510
511        g_return_if_fail (address != NULL);
512
513        hostname = NULL;
514        host = NULL;
515        port = NULL;
516
517        gdm_address_get_hostname (address, &hostname);
518        gdm_address_get_numeric_info (address, &host, &port);
519
520        g_debug ("Address family:%d (%s) hostname:%s host:%s port:%s local:%d loopback:%d",
521                 address->ss->ss_family,
522                 address_family_str (address),
523                 hostname,
524                 host,
525                 port,
526                 gdm_address_is_local (address),
527                 gdm_address_is_loopback (address));
528
529        g_free (hostname);
530        g_free (host);
531        g_free (port);
532}
Note: See TracBrowser for help on using the repository browser.