Beginnings of GSocket API, small fixes for InetAddress
[cascardo/gnio.git] / gnio / ginet4address.c
1 /* GNIO - GLib Network Layer of GIO
2  * 
3  * Copyright (C) 2008 Christian Kellner, Samuel Cormier-Iijima
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library 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 GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General
16  * Public License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
18  * Boston, MA 02111-1307, USA.
19  *
20  * Authors: Christian Kellner <gicmo@gnome.org>
21  *          Samuel Cormier-Iijima <sciyoshi@gmail.com>
22  */
23
24 #include <config.h>
25 #include <glib.h>
26
27 #ifndef G_OS_WIN32
28 # include <netinet/in.h>
29 # include <arpa/inet.h>
30 #else
31 # include <winsock2.h>
32 # define IN_LOOPBACKNET 127
33 #endif
34
35 #include "ginet4address.h"
36
37 G_DEFINE_TYPE (GInet4Address, g_inet4_address, G_TYPE_INET_ADDRESS);
38
39 struct _GInet4AddressPrivate
40 {
41   union {
42     guint8  u4_addr8[4];
43     guint32 u4_addr32;
44   } addr;
45 };
46
47 static gchar *
48 g_inet4_address_to_string (GInetAddress *address)
49 {
50   guint8 *addr;
51
52   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), NULL);
53
54   addr = G_INET4_ADDRESS (address)->priv->addr.u4_addr8;
55
56   return g_strdup_printf ("%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
57 }
58
59 static gboolean
60 g_inet4_address_is_any (GInetAddress *address)
61 {
62   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
63
64   return (g_ntohl (G_INET4_ADDRESS (address)->priv->addr.u4_addr32) == INADDR_ANY);
65 }
66
67 static gboolean
68 g_inet4_address_is_linklocal (GInetAddress *address)
69 {
70   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
71
72   return ((g_ntohl (G_INET4_ADDRESS (address)->priv->addr.u4_addr32) & 0xffff0000) == 0xa9fe0000);
73 }
74
75 static gboolean
76 g_inet4_address_is_loopback (GInetAddress *address)
77 {
78   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
79
80   return (G_INET4_ADDRESS (address)->priv->addr.u4_addr8[0] == IN_LOOPBACKNET);
81 }
82
83 static gboolean
84 g_inet4_address_is_sitelocal (GInetAddress *address)
85 {
86   guint32 addr;
87
88   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
89
90   addr = g_ntohl (G_INET4_ADDRESS (address)->priv->addr.u4_addr32);
91
92   return ((addr & 0xff000000) == (10 << 24)) || ((addr & 0xfff00000) == 0xac100000) || ((addr & 0xffff0000) == 0xc0a80000);
93 }
94
95 static gboolean
96 g_inet4_address_is_multicast (GInetAddress *address)
97 {
98   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
99
100   return IN_MULTICAST (g_ntohl (G_INET4_ADDRESS (address)->priv->addr.u4_addr32));
101 }
102
103 static gboolean
104 g_inet4_address_is_mc_global (GInetAddress *address)
105 {
106   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
107
108   return FALSE;
109 }
110
111 static gboolean
112 g_inet4_address_is_mc_linklocal (GInetAddress *address)
113 {
114   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
115
116   return FALSE;
117 }
118
119 static gboolean
120 g_inet4_address_is_mc_nodelocal (GInetAddress *address)
121 {
122   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
123
124   return FALSE;
125 }
126
127 static gboolean
128 g_inet4_address_is_mc_orglocal (GInetAddress *address)
129 {
130   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
131
132   return FALSE;
133 }
134
135 static gboolean
136 g_inet4_address_is_mc_sitelocal (GInetAddress *address)
137 {
138   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), FALSE);
139
140   return FALSE;
141 }
142
143 static void
144 g_inet4_address_finalize (GObject *object)
145 {
146   GInet4Address *address G_GNUC_UNUSED = G_INET4_ADDRESS (object);
147
148   if (G_OBJECT_CLASS (g_inet4_address_parent_class)->finalize)
149     (*G_OBJECT_CLASS (g_inet4_address_parent_class)->finalize) (object);
150 }
151
152 static void
153 g_inet4_address_dispose (GObject *object)
154 {
155   GInet4Address *address G_GNUC_UNUSED = G_INET4_ADDRESS (object);;
156
157   if (G_OBJECT_CLASS (g_inet4_address_parent_class)->dispose)
158     (*G_OBJECT_CLASS (g_inet4_address_parent_class)->dispose) (object);
159 }
160
161 static void
162 g_inet4_address_class_init (GInet4AddressClass *klass)
163 {
164   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
165   GInetAddressClass *ginetaddress_class = G_INET_ADDRESS_CLASS (klass);
166   
167   g_type_class_add_private (klass, sizeof (GInet4AddressPrivate));
168
169   gobject_class->finalize = g_inet4_address_finalize;
170   gobject_class->dispose = g_inet4_address_dispose;
171
172   ginetaddress_class->to_string = g_inet4_address_to_string;
173   ginetaddress_class->is_any = g_inet4_address_is_any;
174   ginetaddress_class->is_linklocal = g_inet4_address_is_linklocal;
175   ginetaddress_class->is_loopback = g_inet4_address_is_loopback;
176   ginetaddress_class->is_sitelocal = g_inet4_address_is_sitelocal;
177   ginetaddress_class->is_multicast = g_inet4_address_is_multicast;
178   ginetaddress_class->is_mc_global = g_inet4_address_is_mc_global;
179   ginetaddress_class->is_mc_linklocal = g_inet4_address_is_mc_linklocal;
180   ginetaddress_class->is_mc_nodelocal = g_inet4_address_is_mc_nodelocal;
181   ginetaddress_class->is_mc_orglocal = g_inet4_address_is_mc_orglocal;
182   ginetaddress_class->is_mc_sitelocal = g_inet4_address_is_mc_sitelocal;
183 }
184
185 static void
186 g_inet4_address_init (GInet4Address *address)
187 {
188   address->priv = G_TYPE_INSTANCE_GET_PRIVATE (address,
189                                                G_TYPE_INET4_ADDRESS,
190                                                GInet4AddressPrivate);
191 }
192
193 /* ************************************************************************* */
194 /* Public Functions */
195
196 GInet4Address *
197 g_inet4_address_from_string (const gchar *string)
198 {
199   struct in_addr addr;
200
201 #ifndef G_OS_WIN32
202   if (!inet_aton (string, &addr))
203     {
204       g_warning ("Could not parse IP address %s", string);
205       return NULL;
206     }
207 #else
208   addr.s_addr = inet_addr (string);
209   if (addr.s_addr == INADDR_NONE)
210     {
211       g_warning ("Could not parse IP address %s", string);
212       return NULL;
213     }
214 #endif
215
216   return g_inet4_address_from_bytes ((guint8 *) &(addr.s_addr));
217 }
218
219 GInet4Address *
220 g_inet4_address_from_bytes (guint8 bytes[])
221 {
222   GInet4Address *address = G_INET4_ADDRESS (g_object_new (G_TYPE_INET4_ADDRESS, NULL));
223
224   guint8 *addr = address->priv->addr.u4_addr8;
225
226   addr[0] = bytes[0];
227   addr[1] = bytes[1];
228   addr[2] = bytes[2];
229   addr[3] = bytes[3];
230
231   return address;
232 }
233
234 const guint8 *
235 g_inet4_address_to_bytes (GInet4Address *address)
236 {
237   g_return_val_if_fail (G_IS_INET4_ADDRESS (address), NULL);
238
239   return address->priv->addr.u4_addr8;
240 }
241
242 GInet4Address *
243 g_inet4_address_new_loopback (void)
244 {
245   guint8 addr[4] = {127, 0, 0, 1};
246
247   return g_inet4_address_from_bytes (addr);
248 }
249
250 GInet4Address *
251 g_inet4_address_new_any (void)
252 {
253   guint8 addr[4] = {0, 0, 0, 0};
254
255   return g_inet4_address_from_bytes (addr);
256 }