1 #include <sys/types.h>
2 #include <sys/socket.h>
3 #include <netinet/in.h>			/* ipv4 support */
4 #include <sys/un.h>			/* local (aka unix) support */
5 #include <string.h>
6 
7 #include "config.h"
8 #include "gsksocketaddress.h"
9 #include "gskipv4.h"
10 #include "gskerror.h"
11 #include "gskghelpers.h"
12 #include "gskmacros.h"
13 
14 G_DEFINE_ABSTRACT_TYPE(GskSocketAddress, gsk_socket_address, G_TYPE_OBJECT);
15 G_DEFINE_TYPE(GskSocketAddressIpv4, gsk_socket_address_ipv4, GSK_TYPE_SOCKET_ADDRESS);
16 G_DEFINE_TYPE(GskSocketAddressIpv6, gsk_socket_address_ipv6, GSK_TYPE_SOCKET_ADDRESS);
17 G_DEFINE_TYPE(GskSocketAddressEthernet, gsk_socket_address_ethernet, GSK_TYPE_SOCKET_ADDRESS);
18 G_DEFINE_TYPE(GskSocketAddressLocal, gsk_socket_address_local, GSK_TYPE_SOCKET_ADDRESS);
19 
20 /* Macro to initialize the sa_len-like member of
21    sockaddr, if it exists. */
22 #if HAS_SOCKADDR_SA_LEN
23 #define MAYBE_SET_LENGTH_MEMBER(addr_member, type)		\
24 	G_STMT_START{ addr_member = sizeof(type); }G_STMT_END
25 #else
26 #define MAYBE_SET_LENGTH_MEMBER(addr_member, type)
27 #endif
28 
29 /* Define GSK_[AP]F_LOCAL as portible wrappers for [AP]F_LOCAL. */
30 #if HAS_PF_LOCAL
31 #define GSK_PF_LOCAL PF_LOCAL
32 #define GSK_AF_LOCAL AF_LOCAL
33 #elif HAS_PF_UNIX
34 #define GSK_PF_LOCAL PF_UNIX
35 #define GSK_AF_LOCAL AF_UNIX
36 #else
37 #warn "no PF_UNIX or PF_LOCAL macros (?)"
38 #endif
39 
40 /* --- GskSocketAddress implementation --- */
41 static void
gsk_socket_address_init(GskSocketAddress * socket_address)42 gsk_socket_address_init (GskSocketAddress *socket_address)
43 {
44 }
45 
46 static void
gsk_socket_address_class_init(GskSocketAddressClass * class)47 gsk_socket_address_class_init (GskSocketAddressClass *class)
48 {
49 }
50 
51 /* --- GskSocketAddressIpv4 implementation --- */
52 
53 static gboolean
gsk_socket_address_ipv4_to_native(GskSocketAddress * address,gpointer output)54 gsk_socket_address_ipv4_to_native   (GskSocketAddress *address,
55 			             gpointer          output)
56 {
57   GskSocketAddressIpv4 *ipv4 = GSK_SOCKET_ADDRESS_IPV4 (address);
58   struct sockaddr_in *addr = output;
59   memset (addr, 0, sizeof (struct sockaddr_in));
60   addr->sin_family = PF_INET;
61   MAYBE_SET_LENGTH_MEMBER (addr->sin_len, struct sockaddr_in);
62   addr->sin_port = GUINT16_TO_BE (ipv4->ip_port);
63   memcpy (&addr->sin_addr, ipv4->ip_address, 4);
64   return TRUE;
65 }
66 
67 static gboolean
gsk_socket_address_ipv4_from_native(GskSocketAddress * address,gconstpointer sockaddr_data,gsize sockaddr_length)68 gsk_socket_address_ipv4_from_native (GskSocketAddress *address,
69 			             gconstpointer     sockaddr_data,
70 			             gsize             sockaddr_length)
71 {
72   GskSocketAddressIpv4 *ipv4 = GSK_SOCKET_ADDRESS_IPV4 (address);
73   const struct sockaddr_in *addr = sockaddr_data;
74   ipv4->ip_port = GUINT16_FROM_BE (addr->sin_port);
75   memcpy (ipv4->ip_address, &addr->sin_addr, 4);
76   return TRUE;
77 }
78 
79 static char *
gsk_socket_address_ipv4_to_string(GskSocketAddress * address)80 gsk_socket_address_ipv4_to_string  (GskSocketAddress *address)
81 {
82   GskSocketAddressIpv4 *ipv4 = GSK_SOCKET_ADDRESS_IPV4 (address);
83   if (ipv4->ip_port != 0)
84     return g_strdup_printf ("%d.%d.%d.%d:%d",
85                             ipv4->ip_address[0],
86                             ipv4->ip_address[1],
87                             ipv4->ip_address[2],
88                             ipv4->ip_address[3],
89                             ipv4->ip_port);
90   else
91     return g_strdup_printf ("%d.%d.%d.%d",
92                             ipv4->ip_address[0],
93                             ipv4->ip_address[1],
94                             ipv4->ip_address[2],
95                             ipv4->ip_address[3]);
96 }
97 
98 static gboolean
gsk_socket_address_ipv4_equals(GskSocketAddress * a,GskSocketAddress * b)99 gsk_socket_address_ipv4_equals (GskSocketAddress *a,
100 				GskSocketAddress *b)
101 {
102   GskSocketAddressIpv4 *ipv4_a = GSK_SOCKET_ADDRESS_IPV4 (a);
103   GskSocketAddressIpv4 *ipv4_b = GSK_SOCKET_ADDRESS_IPV4 (b);
104   return ipv4_a->ip_address[0] == ipv4_b->ip_address[0]
105       && ipv4_a->ip_address[1] == ipv4_b->ip_address[1]
106       && ipv4_a->ip_address[2] == ipv4_b->ip_address[2]
107       && ipv4_a->ip_address[3] == ipv4_b->ip_address[3]
108       && ipv4_a->ip_port == ipv4_b->ip_port;
109 }
110 
111 static guint
gsk_socket_address_ipv4_hash(GskSocketAddress * a)112 gsk_socket_address_ipv4_hash (GskSocketAddress *a)
113 {
114   GskSocketAddressIpv4 *ipv4 = GSK_SOCKET_ADDRESS_IPV4 (a);
115   guint hash = ipv4->ip_address[0];
116   hash *= 33;
117   hash += ipv4->ip_address[1];
118   hash *= 33;
119   hash += ipv4->ip_address[2];
120   hash *= 33;
121   hash += ipv4->ip_address[3];
122   hash *= 33;
123   hash += ipv4->ip_port;
124   return hash;
125 }
126 
127 static void
gsk_socket_address_ipv4_init(GskSocketAddressIpv4 * socket_address_ipv4)128 gsk_socket_address_ipv4_init (GskSocketAddressIpv4 *socket_address_ipv4)
129 {
130 }
131 
132 static void
gsk_socket_address_ipv4_class_init(GskSocketAddressIpv4Class * ipv4_class)133 gsk_socket_address_ipv4_class_init (GskSocketAddressIpv4Class *ipv4_class)
134 {
135   GskSocketAddressClass *class = GSK_SOCKET_ADDRESS_CLASS (ipv4_class);
136   class->address_family = AF_INET;
137   class->protocol_family = PF_INET;
138   class->sizeof_native_address = sizeof (struct sockaddr_in);
139   class->from_native = gsk_socket_address_ipv4_from_native;
140   class->to_native = gsk_socket_address_ipv4_to_native;
141   class->to_string = gsk_socket_address_ipv4_to_string;
142   class->hash = gsk_socket_address_ipv4_hash;
143   class->equals = gsk_socket_address_ipv4_equals;
144   gsk_socket_address_register_subclass (class);
145 }
146 
147 /* --- ipv6 implementation --- */
148 #if SUPPORTS_IPV6
149 static gboolean
gsk_socket_address_ipv6_to_native(GskSocketAddress * address,gpointer output)150 gsk_socket_address_ipv6_to_native   (GskSocketAddress *address,
151 			             gpointer          output)
152 {
153   GskSocketAddressIpv6 *ipv6 = GSK_SOCKET_ADDRESS_IPV6 (address);
154   struct sockaddr_in6 *addr = output;
155   MAYBE_SET_LENGTH_MEMBER (addr->sin6_len, struct sockaddr_in6);
156   addr->sin6_family = AF_INET6;
157   addr->sin6_port = GUINT16_TO_BE (ipv6->port);
158   addr->sin6_flowinfo = GUINT32_TO_BE (ipv6->flow_info);
159   addr->sin6_scope_id = GUINT32_TO_BE (ipv6->scope_id);
160   g_assert (sizeof (addr->sin6_addr) == 16);
161   memcpy (&addr->sin6_addr, ipv6->address, 16);
162   return TRUE;
163 }
164 
165 static gboolean
gsk_socket_address_ipv6_from_native(GskSocketAddress * address,gconstpointer sockaddr_data,gsize sockaddr_length)166 gsk_socket_address_ipv6_from_native (GskSocketAddress *address,
167 			             gconstpointer     sockaddr_data,
168 			             gsize             sockaddr_length)
169 {
170   GskSocketAddressIpv6 *ipv6 = GSK_SOCKET_ADDRESS_IPV6 (address);
171   const struct sockaddr_in6 *addr = sockaddr_data;
172   ipv6->port = GUINT16_FROM_BE (addr->sin6_port);
173   ipv6->flow_info = GUINT32_FROM_BE (addr->sin6_flowinfo);
174   ipv6->scope_id = GUINT32_FROM_BE (addr->sin6_scope_id);
175   memcpy (ipv6->address, &addr->sin6_addr, 16);
176   return TRUE;
177 }
178 #endif
179 
180 static char *
gsk_socket_address_ipv6_to_string(GskSocketAddress * address)181 gsk_socket_address_ipv6_to_string  (GskSocketAddress *address)
182 {
183   GString *str = g_string_new ("");
184   GskSocketAddressIpv6 *ipv6 = GSK_SOCKET_ADDRESS_IPV6 (address);
185   guint8 *a = ipv6->address;
186   guint i;
187   g_string_printf (str, "%d@%x", ipv6->port, a[0]);
188   for (i = 1; i < 16; i++)
189     g_string_append_printf (str, ":%x", a[1]);
190   return g_string_free (str, FALSE);
191 }
192 
193 static gboolean
gsk_socket_address_ipv6_equals(GskSocketAddress * a,GskSocketAddress * b)194 gsk_socket_address_ipv6_equals (GskSocketAddress *a,
195 				GskSocketAddress *b)
196 {
197   GskSocketAddressIpv6 *ipv6_a = GSK_SOCKET_ADDRESS_IPV6 (a);
198   GskSocketAddressIpv6 *ipv6_b = GSK_SOCKET_ADDRESS_IPV6 (b);
199   return ipv6_a->port == ipv6_b->port
200      &&  memcmp (ipv6_a->address, ipv6_b->address, 16) == 0;
201 }
202 
203 static guint
gsk_socket_address_ipv6_hash(GskSocketAddress * a)204 gsk_socket_address_ipv6_hash (GskSocketAddress *a)
205 {
206   GskSocketAddressIpv6 *ipv6 = GSK_SOCKET_ADDRESS_IPV6 (a);
207   guint hash = ipv6->port;
208   guint i;
209   for (i = 0; i < 16; i++)
210     {
211       hash *= 33;
212       hash += ipv6->address[i];
213     }
214   return hash;
215 }
216 
217 static void
gsk_socket_address_ipv6_init(GskSocketAddressIpv6 * socket_address_ipv6)218 gsk_socket_address_ipv6_init (GskSocketAddressIpv6 *socket_address_ipv6)
219 {
220 }
221 
222 static void
gsk_socket_address_ipv6_class_init(GskSocketAddressIpv6Class * ipv6_class)223 gsk_socket_address_ipv6_class_init (GskSocketAddressIpv6Class *ipv6_class)
224 {
225   GskSocketAddressClass *class = GSK_SOCKET_ADDRESS_CLASS (ipv6_class);
226 #if SUPPORTS_IPV6
227   class->address_family = AF_INET6;
228   class->protocol_family = PF_INET6;
229   class->sizeof_native_address = sizeof (struct sockaddr_in6);
230   class->from_native = gsk_socket_address_ipv6_from_native;
231   class->to_native = gsk_socket_address_ipv6_to_native;
232 #endif
233   class->to_string = gsk_socket_address_ipv6_to_string;
234   class->hash = gsk_socket_address_ipv6_hash;
235   class->equals = gsk_socket_address_ipv6_equals;
236   gsk_socket_address_register_subclass (class);
237 }
238 
239 /* --- local (aka unix) socket address implementation --- */
240 static gboolean
gsk_socket_address_local_to_native(GskSocketAddress * address,gpointer output)241 gsk_socket_address_local_to_native   (GskSocketAddress *address,
242 			             gpointer          output)
243 {
244   GskSocketAddressLocal *local = GSK_SOCKET_ADDRESS_LOCAL (address);
245   struct sockaddr_un *addr = output;
246   MAYBE_SET_LENGTH_MEMBER (addr->sun_len, struct sockaddr_un);
247   addr->sun_family = GSK_PF_LOCAL;
248   /* XXX: zero out other (a priori, unknown) arguments */
249   strncpy (addr->sun_path, local->path, sizeof (addr->sun_path));
250   return TRUE;
251 }
252 
253 
254 static gboolean
gsk_socket_address_local_from_native(GskSocketAddress * address,gconstpointer sockaddr_data,gsize sockaddr_length)255 gsk_socket_address_local_from_native (GskSocketAddress *address,
256 			              gconstpointer     sockaddr_data,
257 			              gsize             sockaddr_length)
258 {
259   GskSocketAddressLocal *local = GSK_SOCKET_ADDRESS_LOCAL (address);
260   const struct sockaddr_un *native = sockaddr_data;
261   gint max_len;
262   guint len;
263   if (GSK_STRUCT_IS_LAST_MEMBER (struct sockaddr_un, sun_path))
264     max_len = sockaddr_length - G_STRUCT_OFFSET(struct sockaddr_un, sun_path);
265   else
266     max_len = sizeof (native->sun_path);
267   if (max_len <= 0)
268     return FALSE;
269 
270   g_free (local->path);
271   len = gsk_strnlen (native->sun_path, max_len);
272   local->path = g_new (char, len + 1);
273   memcpy (local->path, native->sun_path, len);
274   local->path[len] = '\0';
275   return TRUE;
276 }
277 
278 static char *
gsk_socket_address_local_to_string(GskSocketAddress * address)279 gsk_socket_address_local_to_string  (GskSocketAddress *address)
280 {
281   GskSocketAddressLocal *local = GSK_SOCKET_ADDRESS_LOCAL (address);
282   return g_strdup (local->path);
283 }
284 
285 static gboolean
gsk_socket_address_local_equals(GskSocketAddress * a,GskSocketAddress * b)286 gsk_socket_address_local_equals (GskSocketAddress *a,
287 				GskSocketAddress *b)
288 {
289   GskSocketAddressLocal *local_a = GSK_SOCKET_ADDRESS_LOCAL (a);
290   GskSocketAddressLocal *local_b = GSK_SOCKET_ADDRESS_LOCAL (b);
291   return strcmp (local_a->path, local_b->path) == 0;
292 }
293 
294 static guint
gsk_socket_address_local_hash(GskSocketAddress * a)295 gsk_socket_address_local_hash (GskSocketAddress *a)
296 {
297   GskSocketAddressLocal *local = GSK_SOCKET_ADDRESS_LOCAL (a);
298   return g_str_hash (local->path);
299 }
300 
301 static void
gsk_socket_address_local_init(GskSocketAddressLocal * socket_address_local)302 gsk_socket_address_local_init (GskSocketAddressLocal *socket_address_local)
303 {
304 }
305 
306 static void
gsk_socket_address_local_finalize(GObject * object)307 gsk_socket_address_local_finalize (GObject *object)
308 {
309   GskSocketAddressLocal *local = GSK_SOCKET_ADDRESS_LOCAL (object);
310   g_free (local->path);
311   G_OBJECT_CLASS (gsk_socket_address_local_parent_class)->finalize (object);
312 }
313 
314 static void
gsk_socket_address_local_class_init(GskSocketAddressLocalClass * class)315 gsk_socket_address_local_class_init (GskSocketAddressLocalClass *class)
316 {
317   GskSocketAddressClass *address_class = GSK_SOCKET_ADDRESS_CLASS (class);
318   GObjectClass *object_class = G_OBJECT_CLASS (class);
319   class->max_path_length = GSK_STRUCT_MEMBER_SIZE (struct sockaddr_un, sun_path);
320   address_class->sizeof_native_address = sizeof (struct sockaddr_un);
321   address_class->address_family = GSK_AF_LOCAL;
322   address_class->protocol_family = GSK_PF_LOCAL;
323   address_class->to_native = gsk_socket_address_local_to_native;
324   address_class->from_native = gsk_socket_address_local_from_native;
325   address_class->to_string = gsk_socket_address_local_to_string;
326   address_class->equals = gsk_socket_address_local_equals;
327   address_class->hash = gsk_socket_address_local_hash;
328   gsk_socket_address_register_subclass (address_class);
329   object_class->finalize = gsk_socket_address_local_finalize;
330 }
331 
332 /**
333  * gsk_socket_address_local_new:
334  * @path: path in filesystem to hook this socket up.
335  *
336  * Create a socket-address which is associated with a path
337  * in the local filesystem.  Such socket-addresses
338  * are useful for fast communication between processes on the same
339  * host.
340  *
341  * Sometimes, these types of addresses are called unix-domain addresses,
342  * but it is better to avoid the term unix for a generic concept.
343  *
344  * returns: the newly allocated socket address.
345  */
346 GskSocketAddress *
gsk_socket_address_local_new(const char * path)347 gsk_socket_address_local_new (const char *path)
348 {
349   GskSocketAddressLocalClass *class = g_type_class_ref (GSK_TYPE_SOCKET_ADDRESS_LOCAL);
350   guint path_len = strlen (path);
351   GskSocketAddressLocal *rv;
352   if (path_len > class->max_path_length)
353     return NULL;
354   rv = g_object_new (G_OBJECT_CLASS_TYPE (class), NULL);
355   rv->path = g_strdup (path);
356   g_type_class_unref (class);
357   return GSK_SOCKET_ADDRESS (rv);
358 }
359 
360 /* --- Ethernet (MAC) addresses --- */
361 #if 0	/* TODO: conversions to/from native */
362 static gboolean
363 gsk_socket_address_ethernet_to_native (GskSocketAddress *address,
364                                        gpointer          output)
365 {
366   GskSocketAddressEthernet *ethernet = GSK_SOCKET_ADDRESS_ETHERNET (address);
367   ...
368 }
369 
370 static gboolean
371 gsk_socket_address_ethernet_from_native (GskSocketAddress *address,
372                                          gconstpointer     sockaddr_data,
373                                          gsize             sockaddr_length)
374 {
375   GskSocketAddressEthernet *ethernet = GSK_SOCKET_ADDRESS_ETHERNET (address);
376   ...
377 }
378 #endif
379 
380 static guint
gsk_socket_address_ethernet_hash(GskSocketAddress * addr)381 gsk_socket_address_ethernet_hash (GskSocketAddress *addr)
382 {
383   GskSocketAddressEthernet *ethernet = GSK_SOCKET_ADDRESS_ETHERNET (addr);
384   guint i;
385   guint rv = 0;
386   for (i = 0; i < 6; i++)
387     {
388       rv *= 167;
389       rv += ethernet->mac_address[i];
390     }
391   return rv;
392 }
393 
394 static char    *
gsk_socket_address_ethernet_to_string(GskSocketAddress * address)395 gsk_socket_address_ethernet_to_string (GskSocketAddress *address)
396 {
397   GskSocketAddressEthernet *ethernet = GSK_SOCKET_ADDRESS_ETHERNET (address);
398   return g_strdup_printf ("%02X:%02X:%02X:%02X:%02X:%02X",
399 			  ethernet->mac_address[0],
400 			  ethernet->mac_address[1],
401 			  ethernet->mac_address[2],
402 			  ethernet->mac_address[3],
403 			  ethernet->mac_address[4],
404 			  ethernet->mac_address[5]);
405 }
406 
407 static gboolean
gsk_socket_address_ethernet_equals(GskSocketAddress * addr1,GskSocketAddress * addr2)408 gsk_socket_address_ethernet_equals (GskSocketAddress *addr1,
409                                     GskSocketAddress *addr2)
410 {
411   GskSocketAddressEthernet *ethernet1 = GSK_SOCKET_ADDRESS_ETHERNET (addr1);
412   GskSocketAddressEthernet *ethernet2 = GSK_SOCKET_ADDRESS_ETHERNET (addr2);
413   return memcmp (ethernet1->mac_address, ethernet2->mac_address, 6) == 0;
414 }
415 
416 /* --- functions --- */
417 static void
gsk_socket_address_ethernet_init(GskSocketAddressEthernet * socket_address_ethernet)418 gsk_socket_address_ethernet_init (GskSocketAddressEthernet *socket_address_ethernet)
419 {
420 }
421 
422 static void
gsk_socket_address_ethernet_class_init(GskSocketAddressEthernetClass * eth_class)423 gsk_socket_address_ethernet_class_init (GskSocketAddressEthernetClass *eth_class)
424 {
425   GskSocketAddressClass *class = GSK_SOCKET_ADDRESS_CLASS (eth_class);
426   class->hash = gsk_socket_address_ethernet_hash;
427   class->to_string = gsk_socket_address_ethernet_to_string;
428   class->equals = gsk_socket_address_ethernet_equals;
429   /* TODO: convert to/from native */
430 #if 0
431   class->to_native = gsk_socket_address_ethernet_to_native;
432   class->from_native = gsk_socket_address_ethernet_from_native;
433   class->address_family = AF_???;
434   class->protocol_family = PF_???;
435   class->sizeof_native_address = sizeof (struct sockaddr_??? );
436   gsk_socket_address_register_subclass (class);
437 #endif
438 }
439 
440 /**
441  * gsk_socket_address_ethernet_new:
442  * @mac_addr: the 6-byte unique address of this ethernet device.
443  *
444  * Allocate a new socket address corresponding to an
445  * ethernet device.
446  *
447  * returns: the newly allocated socket-address.
448  */
449 GskSocketAddress *
gsk_socket_address_ethernet_new(const guint8 * mac_addr)450 gsk_socket_address_ethernet_new (const guint8 *mac_addr)
451 {
452   GskSocketAddressEthernet *eth = g_object_new (GSK_TYPE_SOCKET_ADDRESS_ETHERNET, NULL);
453   memcpy (eth->mac_address, mac_addr, 6);
454   return GSK_SOCKET_ADDRESS (eth);
455 }
456 
457 /* --- public methods --- */
458 static GHashTable *native_to_gtype = NULL;
459 static GStaticRWLock native_to_gtype_lock = G_STATIC_RW_LOCK_INIT;
460 
461 #define N2G_WRITE_LOCK()   g_static_rw_lock_writer_lock(&native_to_gtype_lock)
462 #define N2G_WRITE_UNLOCK() g_static_rw_lock_writer_unlock(&native_to_gtype_lock)
463 #define N2G_READ_LOCK()    g_static_rw_lock_reader_lock(&native_to_gtype_lock)
464 #define N2G_READ_UNLOCK()  g_static_rw_lock_reader_unlock(&native_to_gtype_lock)
465 
466 /**
467  * gsk_socket_address_from_native:
468  * @native_data: a struct sockaddr_t*.
469  * @native_size: length of native_data.
470  *
471  * Allocate a new GskSocketAddress based on
472  * native_data, if we know how.
473  *
474  * returns: a new GskSocketAddress or NULL if we could not interpret the sockaddr.
475  */
476 GskSocketAddress *
gsk_socket_address_from_native(gconstpointer native_data,gsize native_size)477 gsk_socket_address_from_native   (gconstpointer native_data,
478 				  gsize         native_size)
479 {
480   const struct sockaddr *addr = native_data;
481   GType type;
482   GskSocketAddressClass *class;
483   GObject *rv_object;
484   GskSocketAddress *rv;
485   guint family;
486   N2G_READ_LOCK ();
487   if (native_to_gtype == NULL)
488     {
489       N2G_READ_UNLOCK ();
490       return NULL;
491     }
492   family = (guint) addr->sa_family;
493   type = (GType) g_hash_table_lookup (native_to_gtype, GUINT_TO_POINTER (family));
494   N2G_READ_UNLOCK ();
495   if (type == 0)
496     {
497       return NULL;
498     }
499   rv_object = g_object_new (type, NULL);
500   rv = GSK_SOCKET_ADDRESS (rv_object);
501   class = GSK_SOCKET_ADDRESS_GET_CLASS (rv);
502   if (!((*class->from_native) (rv, native_data, native_size)))
503     {
504       g_object_unref (rv);
505       return NULL;
506     }
507   return GSK_SOCKET_ADDRESS (rv);
508 }
509 
510 /**
511  * gsk_socket_address_sizeof_native:
512  * @address: a socket address.
513  *
514  * Determine how many bytes of storage the sockaddr_t
515  * based on this object will require.
516  *
517  * returns: the size in bytes of the native sockaddr type.
518  */
519 guint
gsk_socket_address_sizeof_native(GskSocketAddress * address)520 gsk_socket_address_sizeof_native (GskSocketAddress *address)
521 {
522   return GSK_SOCKET_ADDRESS_GET_CLASS (address)->sizeof_native_address;
523 }
524 
525 /**
526  * gsk_socket_address_protocol_family:
527  * @address: a socket address.
528  *
529  * Get the PF_* macro value corresponding to this address.
530  *
531  * returns: the protocol family.
532  */
533 gint
gsk_socket_address_protocol_family(GskSocketAddress * address)534 gsk_socket_address_protocol_family (GskSocketAddress *address)
535 {
536   return GSK_SOCKET_ADDRESS_GET_CLASS (address)->protocol_family;
537 }
538 
539 /**
540  * gsk_socket_address_address_family:
541  * @address: a socket address.
542  *
543  * Get the AF_* macro value corresponding to this address.
544  *
545  * returns: the address family.
546  */
547 gint
gsk_socket_address_address_family(GskSocketAddress * address)548 gsk_socket_address_address_family (GskSocketAddress *address)
549 {
550   return GSK_SOCKET_ADDRESS_GET_CLASS (address)->address_family;
551 }
552 
553 /**
554  * gsk_socket_address_to_native:
555  * @address: a socket address.
556  * @output: a struct sockaddr_t (at least conceptually)
557  * @error: optional error return value.
558  *
559  * Convert a socket-address to its native form.
560  *
561  * returns: whether it was able to convert the address.
562  */
563 gboolean
gsk_socket_address_to_native(GskSocketAddress * address,gpointer output,GError ** error)564 gsk_socket_address_to_native     (GskSocketAddress *address,
565 				  gpointer          output,
566 				  GError          **error)
567 {
568   GskSocketAddressClass *class = GSK_SOCKET_ADDRESS_GET_CLASS (address);
569   if (G_UNLIKELY (!class->to_native (address, output)))
570     {
571       g_set_error (error, GSK_G_ERROR_DOMAIN, GSK_ERROR_FOREIGN_ADDRESS,
572 		   "error making a native socket-address for %s",
573 		   g_type_name (G_OBJECT_CLASS_TYPE (class)));
574       return FALSE;
575     }
576   return TRUE;
577 }
578 
579 /**
580  * gsk_socket_address_to_string:
581  * @address: a socket address.
582  *
583  * Convert a socket-address to a newly allocated string,
584  * which the caller must free.
585  *
586  * returns: a string for the user to free.
587  */
588 char *
gsk_socket_address_to_string(GskSocketAddress * address)589 gsk_socket_address_to_string     (GskSocketAddress *address)
590 {
591   GskSocketAddressClass *class = GSK_SOCKET_ADDRESS_GET_CLASS (address);
592   return class->to_string (address);
593 }
594 
595 /**
596  * gsk_socket_address_ipv4_new:
597  * @ip_address: the 4-byte IP address
598  * @port: the port number.
599  *
600  * Allocate a new IPv4 address given a numeric IP and port number.
601  *
602  * returns: a new GskSocketAddress
603  */
604 GskSocketAddress *
gsk_socket_address_ipv4_new(const guint8 * ip_address,guint16 port)605 gsk_socket_address_ipv4_new (const guint8 *ip_address,
606 			     guint16       port)
607 {
608   GskSocketAddressIpv4 *ipv4;
609   ipv4 = g_object_new (GSK_TYPE_SOCKET_ADDRESS_IPV4, NULL);
610   ipv4->ip_port = port;
611   memcpy (ipv4->ip_address, ip_address, 4);
612   return GSK_SOCKET_ADDRESS (ipv4);
613 }
614 
615 /**
616  * gsk_socket_address_equals:
617  * @address_a_ptr: a pointer to a #GskSocketAddress.
618  * @address_b_ptr: a pointer to a #GskSocketAddress.
619  *
620  * This function is a GEqualFunc which can determine
621  * if two socket address are the same.
622  * This is principally used with #gsk_socket_address_hash
623  * to make a hash-table mapping from socket-addresses.
624  *
625  * (This just uses the virtual method of GskSocketAddressClass)
626  *
627  * returns: whether the addresses are equal.
628  */
629 gboolean
gsk_socket_address_equals(gconstpointer address_a_ptr,gconstpointer address_b_ptr)630 gsk_socket_address_equals        (gconstpointer     address_a_ptr,
631 				  gconstpointer     address_b_ptr)
632 {
633   GskSocketAddress *address_a = (GskSocketAddress *) address_a_ptr;
634   GskSocketAddress *address_b = (GskSocketAddress *) address_b_ptr;
635   GskSocketAddressClass *class;
636   GType type_a, type_b;
637   g_return_val_if_fail (GSK_IS_SOCKET_ADDRESS (address_a)
638 		     && GSK_IS_SOCKET_ADDRESS (address_b), FALSE);
639   type_a = G_OBJECT_TYPE (address_a);
640   type_b = G_OBJECT_TYPE (address_b);
641   if (type_a != type_b)
642     return FALSE;
643   class = GSK_SOCKET_ADDRESS_GET_CLASS (address_a);
644   return (*class->equals) (address_a, address_b);
645 }
646 
647 /**
648  * gsk_socket_address_hash:
649  * @address_ptr: a pointer to a #GskSocketAddress.
650  *
651  * This function is a GHashFunc which can determine
652  * a hash value for a socket-address.
653  *
654  * This is principally used with #gsk_socket_address_equals
655  * to make a hash-table mapping from socket-addresses.
656  *
657  * (This just uses the virtual method of GskSocketAddressClass)
658  *
659  * returns: the hash value for the socket-address.
660  */
661 guint
gsk_socket_address_hash(gconstpointer address_ptr)662 gsk_socket_address_hash (gconstpointer  address_ptr)
663 {
664   GskSocketAddress *address = (GskSocketAddress *) address_ptr;
665   GskSocketAddressClass *class;
666   g_return_val_if_fail (GSK_IS_SOCKET_ADDRESS (address), 0);
667   class = GSK_SOCKET_ADDRESS_GET_CLASS (address);
668   return (*class->hash) (address);
669 }
670 
671 /* --- protected methods --- */
672 /**
673  * gsk_socket_address_register_subclass:
674  * @klass: a concrete derived class.
675  *
676  * Add the class to a per address-family hash table
677  * for use converting from native.
678  */
679 void
gsk_socket_address_register_subclass(GskSocketAddressClass * klass)680 gsk_socket_address_register_subclass (GskSocketAddressClass *klass)
681 {
682   GType type = G_OBJECT_CLASS_TYPE (klass);
683   N2G_WRITE_LOCK ();
684   if (native_to_gtype == NULL)
685     native_to_gtype = g_hash_table_new (NULL, NULL);
686   g_hash_table_insert (native_to_gtype,
687 		       GUINT_TO_POINTER (klass->address_family),
688 		       (gpointer) type);
689   N2G_WRITE_UNLOCK ();
690 }
691 
692 /* --- public: a few useful quarks, for use with g_object_set_qdata --- */
693 GQuark
gsk_socket_address_get_remote_quark()694 gsk_socket_address_get_remote_quark()
695 {
696   static GQuark rv = 0;
697   if (rv == 0)
698     rv = g_quark_from_static_string ("gsk-socket-address-remote-quark");
699   return rv;
700 }
701 
702 GQuark
gsk_socket_address_get_local_quark()703 gsk_socket_address_get_local_quark()
704 {
705   static GQuark rv = 0;
706   if (rv == 0)
707     rv = g_quark_from_static_string ("gsk-socket-address-local-quark");
708   return rv;
709 }
710 
711 /* Deprecated.  included for binary compatibility */
712 #undef gsk_socket_address_new_local
gsk_socket_address_new_local(const char * path)713 GskSocketAddress *gsk_socket_address_new_local (const char       *path)
714 {
715   return gsk_socket_address_local_new (path);
716 }
717 #undef gsk_socket_address_new_ethernet
gsk_socket_address_new_ethernet(const guint8 * mac_addr)718 GskSocketAddress *gsk_socket_address_new_ethernet  (const guint8     *mac_addr)
719 {
720   return gsk_socket_address_ethernet_new (mac_addr);
721 }
722 
723