1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3
* Copyright (C) 2007 William Jon McCann <mccann@jhu.edu>
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.
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.
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.
32
#ifdef HAVE_SYS_SOCKET_H
33
#include <sys/socket.h>
35
#ifdef HAVE_SYS_SOCKIO_H
36
#include <sys/sockio.h>
39
#include <sys/ioctl.h>
43
#include <sys/select.h>
44
#include <netinet/in.h>
45
#include <arpa/inet.h>
51
#include <glib-object.h>
53
#include "gdm-address.h"
57
struct sockaddr_storage *ss;
60
/* Register GdmAddress in the glib type system */
62
gdm_address_get_type (void)
64
static GType addr_type = 0;
67
addr_type = g_boxed_type_register_static ("GdmAddress",
68
(GBoxedCopyFunc) gdm_address_copy,
69
(GBoxedFreeFunc) gdm_address_free);
76
* gdm_address_get_family_type:
77
* @address: A pointer to a #GdmAddress
79
* Use this function to retrive the address family of @address.
81
* Return value: The address family of @address.
84
gdm_address_get_family_type (GdmAddress *address)
86
g_return_val_if_fail (address != NULL, -1);
88
return address->ss->ss_family;
93
* gdm_address_new_from_sockaddr:
94
* @sa: A pointer to a sockaddr.
95
* @size: size of sockaddr in bytes.
97
* Creates a new #GdmAddress from @sa.
99
* Return value: The new #GdmAddress
100
* or %NULL if @sa was invalid or the address family isn't supported.
103
gdm_address_new_from_sockaddr (struct sockaddr *sa,
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);
112
addr = g_new0 (GdmAddress, 1);
113
addr->ss = g_new0 (struct sockaddr_storage, 1);
114
memcpy (addr->ss, sa, size);
120
* gdm_address_get_sockaddr_storage:
121
* @address: A #GdmAddress
123
* This function tanslates @address into a equivalent
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.
129
struct sockaddr_storage *
130
gdm_address_get_sockaddr_storage (GdmAddress *address)
132
struct sockaddr_storage *ss;
134
g_return_val_if_fail (address != NULL, NULL);
135
g_return_val_if_fail (address->ss != NULL, NULL);
137
ss = g_memdup (address->ss, sizeof (struct sockaddr_storage));
142
struct sockaddr_storage *
143
gdm_address_peek_sockaddr_storage (GdmAddress *address)
145
g_return_val_if_fail (address != NULL, NULL);
151
v4_v4_equal (const struct sockaddr_in *a,
152
const struct sockaddr_in *b)
154
return a->sin_addr.s_addr == b->sin_addr.s_addr;
159
v6_v6_equal (struct sockaddr_in6 *a,
160
struct sockaddr_in6 *b)
162
return IN6_ARE_ADDR_EQUAL (&a->sin6_addr, &b->sin6_addr);
166
#define SA(__s) ((struct sockaddr *) __s)
167
#define SIN(__s) ((struct sockaddr_in *) __s)
168
#define SIN6(__s) ((struct sockaddr_in6 *) __s)
171
gdm_address_equal (GdmAddress *a,
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);
182
fam_a = a->ss->ss_family;
183
fam_b = b->ss->ss_family;
185
if (fam_a == AF_INET && fam_b == AF_INET) {
186
return v4_v4_equal (SIN (a->ss), SIN (b->ss));
189
else if (fam_a == AF_INET6 && fam_b == AF_INET6) {
190
return v6_v6_equal (SIN6 (a->ss), SIN6 (b->ss));
198
address_family_str (GdmAddress *address)
201
switch (address->ss->ss_family) {
222
_gdm_address_debug (GdmAddress *address, char *hostname, char *host, char *port)
224
g_return_if_fail (address != NULL);
231
g_debug ("Address family:%d (%s) hostname:%s host:%s port:%s local:%d loopback:%d",
232
address->ss->ss_family,
233
address_family_str (address) ? address_family_str (address) : "(null)",
234
hostname ? hostname : "(null)",
235
host ? host : "(null)",
236
port ? port : "(null)",
237
gdm_address_is_local (address),
238
gdm_address_is_loopback (address));
246
gdm_address_debug (GdmAddress *address)
252
gdm_address_get_hostname (address, &hostname);
253
gdm_address_get_numeric_info (address, &host, &port);
255
_gdm_address_debug (address, hostname, host, port);
259
gdm_address_get_hostname (GdmAddress *address,
262
char host [NI_MAXHOST];
266
g_return_val_if_fail (address != NULL, FALSE);
267
g_return_val_if_fail (address->ss != NULL, FALSE);
272
res = getnameinfo ((const struct sockaddr *)address->ss,
273
(int) gdm_sockaddr_len (address->ss),
283
err_msg = gai_strerror (res);
284
g_warning ("Unable to lookup hostname: %s",
285
err_msg ? err_msg : "(null)");
286
_gdm_address_debug (address, NULL, NULL, NULL);
292
if (hostnamep != NULL) {
293
*hostnamep = g_strdup (host);
300
gdm_address_get_numeric_info (GdmAddress *address,
304
char host [NI_MAXHOST];
305
char serv [NI_MAXSERV];
309
g_return_val_if_fail (address != NULL, FALSE);
310
g_return_val_if_fail (address->ss != NULL, FALSE);
316
res = getnameinfo ((const struct sockaddr *)address->ss,
317
(int) gdm_sockaddr_len (address->ss),
320
NI_NUMERICHOST | NI_NUMERICSERV);
324
err_msg = gai_strerror (res);
325
g_warning ("Unable to lookup numeric info: %s",
326
err_msg ? err_msg : "(null)");
327
_gdm_address_debug (address, NULL, NULL, NULL);
333
*servp = g_strdup (serv);
336
*hostp = g_strdup (host);
343
gdm_address_is_loopback (GdmAddress *address)
345
g_return_val_if_fail (address != NULL, FALSE);
346
g_return_val_if_fail (address->ss != NULL, FALSE);
348
switch (address->ss->ss_family){
351
return IN6_IS_ADDR_LOOPBACK (&((struct sockaddr_in6 *)address->ss)->sin6_addr);
355
return (INADDR_LOOPBACK == htonl (((struct sockaddr_in *)address->ss)->sin_addr.s_addr));
365
add_local_siocgifconf (GList **list)
370
struct ifreq *the_end;
374
if ((sock = socket (PF_INET, SOCK_DGRAM, 0)) < 0) {
379
ifc.ifc_len = sizeof (buf);
381
if (ioctl (sock, SIOCGIFCONF, (char *) &ifc) < 0) {
382
perror ("SIOCGIFCONF");
387
/* Get IP address of each active IP network interface. */
388
the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len);
390
for (ifr = ifc.ifc_req; ifr < the_end; ifr++) {
391
if (ifr->ifr_addr.sa_family == AF_INET) {
392
/* IP net interface */
395
if (ioctl (sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) {
396
perror("SIOCGIFFLAGS");
397
} else if (ifreq.ifr_flags & IFF_UP) { /* active interface */
398
if (ioctl (sock, SIOCGIFADDR, (char *) &ifreq) < 0) {
399
perror("SIOCGIFADDR");
402
address = gdm_address_new_from_sockaddr ((struct sockaddr *)&ifreq.ifr_addr,
403
sizeof (struct sockaddr));
405
gdm_address_debug (address);
407
*list = g_list_append (*list, address);
412
/* Support for variable-length addresses. */
414
ifr = (struct ifreq *) ((caddr_t) ifr
415
+ ifr->ifr_addr.sa_len - sizeof(struct sockaddr));
423
add_local_addrinfo (GList **list)
425
char hostbuf[BUFSIZ];
426
struct addrinfo *result;
427
struct addrinfo *res;
428
struct addrinfo hints;
430
hostbuf[BUFSIZ-1] = '\0';
431
if (gethostname (hostbuf, BUFSIZ-1) != 0) {
432
g_debug ("%s: Could not get server hostname, using localhost", "gdm_peek_local_address_list");
433
snprintf (hostbuf, BUFSIZ-1, "localhost");
436
memset (&hints, 0, sizeof (hints));
437
hints.ai_family = AF_UNSPEC;
438
hints.ai_flags = AI_CANONNAME;
440
g_debug ("GdmAddress: looking up hostname: %s", hostbuf);
442
if (getaddrinfo (hostbuf, NULL, &hints, &result) != 0) {
443
g_debug ("%s: Could not get address from hostname!", "gdm_peek_local_address_list");
448
for (res = result; res != NULL; res = res->ai_next) {
451
g_debug ("family=%d sock_type=%d protocol=%d flags=0x%x canonname=%s\n",
456
res->ai_canonname ? res->ai_canonname : "(null)");
457
address = gdm_address_new_from_sockaddr (res->ai_addr, res->ai_addrlen);
458
*list = g_list_append (*list, address);
461
if (result != NULL) {
462
freeaddrinfo (result);
468
gdm_address_peek_local_list (void)
470
static GList *list = NULL;
471
static time_t last_time = 0;
473
/* Don't check more then every 5 seconds */
474
if (last_time + 5 > time (NULL)) {
478
g_list_foreach (list, (GFunc)gdm_address_free, NULL);
482
last_time = time (NULL);
484
add_local_siocgifconf (&list);
485
add_local_addrinfo (&list);
491
gdm_address_is_local (GdmAddress *address)
495
if (gdm_address_is_loopback (address)) {
499
list = gdm_address_peek_local_list ();
501
while (list != NULL) {
502
GdmAddress *addr = list->data;
504
if (gdm_address_equal (address, addr)) {
516
* @address: A #GdmAddress.
518
* Duplicates @address.
520
* Return value: Duplicated @address or %NULL if @address was not valid.
523
gdm_address_copy (GdmAddress *address)
527
g_return_val_if_fail (address != NULL, NULL);
529
addr = g_new0 (GdmAddress, 1);
530
addr->ss = g_memdup (address->ss, sizeof (struct sockaddr_storage));
537
* @address: A #GdmAddress.
539
* Frees the memory allocated for @address.
542
gdm_address_free (GdmAddress *address)
544
g_return_if_fail (address != NULL);
546
g_free (address->ss);