Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

host_addr.h

Go to the documentation of this file.
00001 /*
00002  * $Id: host_addr.h,v 1.9 2005/11/29 14:57:00 cbiere Exp $
00003  *
00004  * Copyright (c) 2001-2003, Raphael Manfredi
00005  * Copyright (c) 2005, Christian Biere
00006  *
00007  *----------------------------------------------------------------------
00008  * This file is part of gtk-gnutella.
00009  *
00010  *  gtk-gnutella is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  gtk-gnutella is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU General Public License
00021  *  along with gtk-gnutella; if not, write to the Free Software
00022  *  Foundation, Inc.:
00023  *      59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *----------------------------------------------------------------------
00025  */
00026 
00037 #ifndef _host_addr_h_
00038 #define _host_addr_h_
00039 
00040 #include "common.h"
00041 #include "misc.h"
00042 
00043 enum net_type {
00044     NET_TYPE_NONE   = 0,
00045     NET_TYPE_IPV4   = 4,
00046     NET_TYPE_IPV6   = 6,
00047 };
00048 
00049 #ifdef USE_IPV6
00050 typedef struct host_addr {
00051     guint32 net;    
00052     union {
00053         guint8  ipv6[16];   
00054         guint32 ipv4;       
00056         guint8  u8[16];
00057         guint16 u16[8];
00058         guint32 u32[4];
00059     } addr;
00060 } host_addr_t;
00061 
00062 #else /* !USE_IPV6 */
00063 
00064 /* For an IPv4-only configuration */
00065 typedef guint32 host_addr_t; 
00067 #endif /* USE_IPV6*/
00068 
00069 #if defined(USE_IPV6)
00070 static const host_addr_t ipv6_unspecified = {   /* :: */
00071     NET_TYPE_IPV6,
00072     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00073 };
00074 
00075 static const host_addr_t ipv6_loopback = {  /* ::1 */
00076     NET_TYPE_IPV6,
00077     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 } },
00078 };
00079 
00080 static const host_addr_t ipv6_ipv4_mapped = {   /* ::ffff:0:0 */
00081     NET_TYPE_IPV6,
00082     { { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0 } },
00083 };
00084 
00085 static const host_addr_t ipv6_multicast = {     /* ff00:: */
00086     NET_TYPE_IPV6,
00087     { { 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00088 };
00089 
00090 static const host_addr_t ipv6_link_local = {    /* fe80:: */
00091     NET_TYPE_IPV6,
00092     { { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00093 };
00094 
00095 static const host_addr_t ipv6_site_local = {    /* fec0:: */
00096     NET_TYPE_IPV6,
00097     { { 0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00098 };
00099 
00100 static const host_addr_t ipv6_6to4 = {          /* 2002:: */
00101     NET_TYPE_IPV6,
00102     { { 0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } },
00103 };
00104 
00105 
00106 static const host_addr_t zero_host_addr;
00107 
00108 gboolean host_addr_convert(const host_addr_t from, host_addr_t *to,
00109     enum net_type to_net);
00110 gboolean host_addr_can_convert(const host_addr_t from, enum net_type to_net);
00111 gboolean host_addr_6to4_to_ipv4(const host_addr_t from, host_addr_t *to);
00112 
00113 static inline gboolean
00114 host_addr_initialized(const host_addr_t ha)
00115 {
00116     switch (ha.net) {
00117     case NET_TYPE_IPV4:
00118     case NET_TYPE_IPV6:
00119         return TRUE;
00120     case NET_TYPE_NONE:
00121         return FALSE;
00122     }
00123     g_assert_not_reached();
00124     return FALSE;
00125 }
00126 
00127 static inline enum net_type 
00128 host_addr_net(const host_addr_t ha)
00129 {
00130     return ha.net;
00131 }
00132 
00133 static inline guint32
00134 host_addr_ipv4(const host_addr_t ha)
00135 {
00136     return NET_TYPE_IPV4 == ha.net ? ha.addr.ipv4 : 0;
00137 }
00138 
00139 static inline const guint8 *
00140 host_addr_ipv6(const host_addr_t *ha)
00141 {
00142     return NET_TYPE_IPV6 == ha->net ? ha->addr.ipv6 : NULL;
00143 }
00144 
00145 static inline host_addr_t
00146 host_addr_set_ipv4(guint32 ip)
00147 {
00148     host_addr_t ha;
00149 
00150     ha.net = NET_TYPE_IPV4;
00151     ha.addr.ipv4 = ip;
00152     return ha;
00153 }
00154 
00155 static inline void
00156 host_addr_set_ipv6(host_addr_t *ha, const guint8 *ipv6)
00157 {
00158     ha->net = NET_TYPE_IPV6;
00159     memcpy(ha->addr.ipv6, ipv6, 16);
00160 }
00161 
00162 static inline gboolean
00163 host_addr_equal(const host_addr_t a, const host_addr_t b)
00164 {
00165     if (a.net == b.net) {
00166         switch (a.net) {
00167         case NET_TYPE_IPV4:
00168             return a.addr.ipv4 == b.addr.ipv4;
00169         case NET_TYPE_IPV6:
00170             if (0 != memcmp(a.addr.ipv6, b.addr.ipv6, sizeof a.addr.ipv6)) {
00171                 host_addr_t a_ipv4, b_ipv4;
00172 
00173                 return host_addr_convert(a, &a_ipv4, NET_TYPE_IPV4) &&
00174                     host_addr_convert(b, &b_ipv4, NET_TYPE_IPV4) &&
00175                     a_ipv4.addr.ipv4 == b_ipv4.addr.ipv4;
00176             }
00177             return TRUE;
00178 
00179         case NET_TYPE_NONE:
00180             return TRUE;
00181         }
00182         g_assert_not_reached();
00183     } else {
00184         host_addr_t to;
00185 
00186         return host_addr_convert(a, &to, b.net) && host_addr_equal(to, b);
00187     }
00188     return FALSE;
00189 }
00190 
00191 static inline gint
00192 host_addr_cmp(host_addr_t a, host_addr_t b)
00193 {
00194     gint r;
00195 
00196     r = CMP(a.net, b.net);
00197     if (0 != r) {
00198         host_addr_t to;
00199 
00200         if (!host_addr_convert(b, &to, a.net))
00201             return r;
00202         b = to;
00203     }
00204 
00205     switch (a.net) {
00206     case NET_TYPE_IPV4:
00207         return CMP(a.addr.ipv4, b.addr.ipv4);
00208     case NET_TYPE_IPV6:
00209         {
00210             guint i;
00211 
00212             for (i = 0; i < G_N_ELEMENTS(a.addr.ipv6); i++) {
00213                 r = CMP(a.addr.ipv6[i], b.addr.ipv6[i]);
00214                 if (0 != r)
00215                     break;
00216             }
00217         }
00218         return r;
00219     case NET_TYPE_NONE:
00220         return 0;
00221     }
00222     g_assert_not_reached();
00223     return 0;
00224 }
00225 
00226 static inline gboolean
00227 host_addr_matches(const host_addr_t a, const host_addr_t b, guint8 bits)
00228 {
00229     host_addr_t to;
00230     guint8 shift;
00231 
00232     if (!host_addr_convert(b, &to, a.net))
00233         return FALSE;
00234 
00235     switch (a.net) {
00236     case NET_TYPE_IPV4:
00237         shift = bits < 32 ? 32 - bits : 0;
00238         return (a.addr.ipv4 >> shift) == (to.addr.ipv4 >> shift);
00239 
00240     case NET_TYPE_IPV6:
00241         {
00242             gint i;
00243 
00244             bits = MIN(128, bits);
00245             for (i = 0; bits >= 8; i++, bits -= 8) {
00246                 if (a.addr.ipv6[i] != to.addr.ipv6[i])
00247                     return FALSE;
00248             }
00249 
00250             if (bits > 0) {
00251                 guint8 shift = 8 - bits;
00252                 return (a.addr.ipv6[i] >> shift) == (to.addr.ipv6[i] >> shift);
00253             }
00254 
00255         }
00256         return TRUE;
00257 
00258     case NET_TYPE_NONE:
00259         return TRUE;
00260     }
00261 
00262     g_assert_not_reached();
00263     return FALSE;
00264 }
00265 
00266 
00267 static inline gboolean
00268 is_host_addr(const host_addr_t ha)
00269 {
00270     switch (host_addr_net(ha)) {
00271     case NET_TYPE_IPV4:
00272         return 0 != ha.addr.ipv4;
00273     case NET_TYPE_IPV6:
00274         return 0 != memcmp(ha.addr.ipv6, zero_host_addr.addr.ipv6,
00275                         sizeof ha.addr.ipv6);
00276     case NET_TYPE_NONE:
00277         return FALSE;
00278     }
00279     g_assert_not_reached();
00280     return FALSE;
00281 }
00282 
00283 static inline int
00284 host_addr_family(const host_addr_t ha)
00285 {
00286     switch (ha.net) {
00287     case NET_TYPE_IPV4:
00288         return AF_INET;
00289     case NET_TYPE_IPV6:
00290         return AF_INET6;
00291     case NET_TYPE_NONE:
00292         break;
00293     }
00294     g_message("%u:%u", (guint8) ha.net, ha.addr.ipv4);
00295     g_assert_not_reached();
00296     return -1;
00297 }
00298 
00299 static inline guint32
00300 host_addr_hash(host_addr_t ha)
00301 {
00302     switch (ha.net) {
00303     case NET_TYPE_IPV6:
00304         {
00305             host_addr_t ha_ipv4;
00306 
00307             if (!host_addr_convert(ha, &ha_ipv4, NET_TYPE_IPV4)) {
00308                 guint32 h = ha.net ^ ha.addr.ipv6[15];
00309                 guint i;
00310 
00311                 for (i = 0; i < sizeof ha.addr.ipv6; i++)
00312                     h ^= (guint32) ha.addr.ipv6[i] << (i * 2);
00313 
00314                 return h;
00315             }
00316             ha = ha_ipv4;
00317         }
00318         /* FALL THROUGH */
00319     case NET_TYPE_IPV4:
00320         return ha.net ^ ha.addr.ipv4;
00321     case NET_TYPE_NONE:
00322         return 0;
00323     }
00324     g_assert_not_reached();
00325     return -1;
00326 }
00327 
00328 #else
00329 
00330 /* IPv4 only */
00331 
00332 #define host_addr_initialized(x)    TRUE
00333 #define host_addr_net(x) (((void) (x)), NET_TYPE_IPV4)
00334 #define host_addr_family(x) (((void) (x)), AF_INET)
00335 #define host_addr_ipv4(x) (x)
00336 #define host_addr_set_ipv4(x) (x)
00337 #define host_addr_set_net(x, y) G_STMT_START { (void) ((x), (y)) } G_STMT_END
00338 #define is_host_addr(x) (0 != (x))
00339 #define host_addr_equal(a, b) ((a) == (b))
00340 #define host_addr_cmp(a, b) (CMP((a), (b)))
00341 #define host_addr_hash(x) (x)
00342 #define zero_host_addr 0
00343 
00344 static inline gboolean
00345 host_addr_convert(const host_addr_t from, host_addr_t *to,
00346     enum net_type to_net)
00347 {
00348     if (NET_TYPE_IPV4 == to_net) {
00349         *to = from;
00350         return TRUE;
00351     }
00352     *to = zero_host_addr;
00353     return FALSE;
00354 }
00355 
00356 static inline gboolean
00357 host_addr_6to4_to_ipv4(const host_addr_t unused_from, host_addr_t *to)
00358 {
00359     (void) unused_from;
00360 
00361     if (to)
00362         *to = zero_host_addr;
00363     return FALSE;
00364 }
00365 
00366 static inline G_GNUC_CONST WARN_UNUSED_RESULT gboolean
00367 host_addr_matches(guint32 a, guint32 b, guint8 bits)
00368 {
00369     guint8 shift;
00370 
00371     shift = bits < 32 ? 32 - bits : 0;
00372     return (a >> shift) == (b >> shift);
00373 }
00374 
00375 #endif /* USE_IPV6 */
00376 
00377 guint host_addr_hash_func(gconstpointer key);
00378 gboolean host_addr_eq_func(gconstpointer p, gconstpointer q);
00379 void wfree_host_addr(gpointer key, gpointer unused_data);
00380 
00381 gboolean is_private_addr(const host_addr_t addr);
00382 gboolean host_addr_is_routable(const host_addr_t addr);
00383 gboolean host_addr_is_loopback(const host_addr_t addr);
00384 const gchar *host_addr_to_string(const host_addr_t addr);
00385 size_t host_addr_to_string_buf(const host_addr_t addr, gchar *, size_t);
00386 host_addr_t string_to_host_addr(const gchar *s, const gchar **endptr);
00387 const gchar *host_addr_port_to_string(const host_addr_t addr, guint16 port);
00388 size_t host_addr_port_to_string_buf(const host_addr_t addr,
00389                 guint16 port, gchar *, size_t);
00390 gboolean string_to_host_addr_port(const gchar *str, const gchar **endptr,
00391     host_addr_t *addr_ptr, guint16 *port_ptr);
00392 host_addr_t name_to_host_addr(const gchar *host);
00393 const gchar *host_addr_to_name(const host_addr_t addr);
00394 gboolean string_to_host_or_addr(const char *s, const gchar **endptr,
00395         host_addr_t *ha);
00396 
00397 #endif /* _host_addr_h_ */
00398 /* vi: set ts=4 sw=4 cindent: */

Generated on Sun Feb 12 10:49:56 2006 for Gtk-Gnutella by doxygen 1.3.6