Starting the NetworkStreams. HTTP to www.google.com works
[cascardo/gnio.git] / gnio / gtcpclient.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 #include <gio/gio.h>
27 #include <gnio/gnio.h>
28
29 #include <string.h>
30 #include <errno.h>
31
32 G_DEFINE_TYPE (GTcpClient, g_tcp_client, G_TYPE_OBJECT);
33
34 enum
35 {
36   PROP_0,
37   PROP_ADDRESS,
38   PROP_HOSTNAME,
39   PROP_PORT
40 };
41
42 struct _GTcpClientPrivate
43 {
44   GInetSocketAddress *address;
45   gchar              *hostname;
46   gushort             port;
47   GSocket            *socket;
48 };
49
50 static void
51 g_tcp_client_constructed (GObject *object)
52 {
53   GTcpClient *client = G_TCP_CLIENT (object);
54
55   if (client->priv->address)
56     {
57       // we've been constructed with an address, extract hostname+port
58       client->priv->hostname = g_inet_address_to_string (g_inet_socket_address_get_address (client->priv->address));
59       client->priv->port = g_inet_socket_address_get_port (client->priv->address);
60       return;
61     }
62 }
63
64 static void
65 g_tcp_client_get_property (GObject    *object,
66                            guint       prop_id,
67                            GValue     *value,
68                            GParamSpec *pspec)
69 {
70   GTcpClient *client = G_TCP_CLIENT (object);
71
72   switch (prop_id)
73     {
74       case PROP_ADDRESS:
75         g_value_set_object (value, client->priv->address);
76         break;
77
78       case PROP_HOSTNAME:
79         g_value_set_string (value, client->priv->hostname);
80         break;
81
82       case PROP_PORT:
83         g_value_set_uint (value, client->priv->port);
84         break;
85
86       default:
87         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
88     }
89 }
90
91 static void
92 g_tcp_client_set_property (GObject      *object,
93                            guint         prop_id,
94                            const GValue *value,
95                            GParamSpec   *pspec)
96 {
97   GTcpClient *client = G_TCP_CLIENT (object);
98
99   switch (prop_id)
100     {
101       case PROP_ADDRESS:
102         // sink the address' floating reference
103         client->priv->address = G_INET_SOCKET_ADDRESS (g_value_get_object (value));
104         if (client->priv->address)
105           g_object_ref_sink (client->priv->address);
106         break;
107
108       case PROP_HOSTNAME:
109         client->priv->hostname = g_value_dup_string (value);
110         break;
111
112       case PROP_PORT:
113         client->priv->port = g_value_get_uint (value);
114         break;
115
116       default:
117         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
118     }
119 }
120
121 static void
122 g_tcp_client_finalize (GObject *object)
123 {
124   GTcpClient *client = G_TCP_CLIENT (object);
125
126   g_object_unref (client->priv->address);
127
128   if (G_OBJECT_CLASS (g_tcp_client_parent_class)->finalize)
129     (*G_OBJECT_CLASS (g_tcp_client_parent_class)->finalize) (object);
130 }
131
132 static void
133 g_tcp_client_dispose (GObject *object)
134 {
135   GTcpClient *client = G_TCP_CLIENT (object);
136
137   g_free (client->priv->hostname);
138
139   if (G_OBJECT_CLASS (g_tcp_client_parent_class)->dispose)
140     (*G_OBJECT_CLASS (g_tcp_client_parent_class)->dispose) (object);
141 }
142
143 static void
144 g_tcp_client_class_init (GTcpClientClass *klass)
145 {
146   GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
147
148   g_type_class_add_private (klass, sizeof (GTcpClientPrivate));
149
150   gobject_class->finalize = g_tcp_client_finalize;
151   gobject_class->dispose = g_tcp_client_dispose;
152   gobject_class->constructed = g_tcp_client_constructed;
153   gobject_class->set_property = g_tcp_client_set_property;
154   gobject_class->get_property = g_tcp_client_get_property;
155
156   g_object_class_install_property (gobject_class, PROP_ADDRESS,
157                                    g_param_spec_object ("address",
158                                                         "address",
159                                                         "the remote address the socket will connect to",
160                                                         G_TYPE_INET_SOCKET_ADDRESS,
161                                                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
162
163   g_object_class_install_property (gobject_class, PROP_HOSTNAME,
164                                    g_param_spec_string ("hostname",
165                                                         "hostname",
166                                                         "the hostname of the remote address the socket will connect to",
167                                                         NULL,
168                                                         G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
169
170   g_object_class_install_property (gobject_class, PROP_PORT,
171                                    g_param_spec_uint ("port",
172                                                       "port",
173                                                       "the remote port the socket will connect to",
174                                                       0,
175                                                       G_MAXUSHORT,
176                                                       0,
177                                                       G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
178 }
179
180 static void
181 g_tcp_client_init (GTcpClient *client)
182 {
183   client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, G_TYPE_TCP_CLIENT, GTcpClientPrivate);
184
185   client->priv->address = NULL;
186   client->priv->hostname = NULL;
187   client->priv->port = 0;
188   client->priv->socket = NULL;
189 }
190
191 GTcpClient *
192 g_tcp_client_new (const gchar *hostname,
193                   gushort      port)
194 {
195   return G_TCP_CLIENT (g_object_new (G_TYPE_TCP_CLIENT, "hostname", hostname, "port", port, NULL));
196 }
197
198 GTcpClient *
199 g_tcp_client_new_from_address (GInetSocketAddress *address)
200 {
201   return G_TCP_CLIENT (g_object_new (G_TYPE_TCP_CLIENT, "address", address, NULL));
202 }
203
204 GNetworkInputStream *
205 g_tcp_client_get_input_stream (GTcpClient *client)
206 {
207   if (!client->priv->socket)
208     return NULL;
209
210   return _g_network_input_stream_new (client->priv->socket);
211 }
212
213 GNetworkOutputStream *
214 g_tcp_client_get_output_stream (GTcpClient *client)
215 {
216   if (!client->priv->socket)
217     return NULL;
218
219   return _g_network_output_stream_new (client->priv->socket);
220 }
221
222 gboolean
223 g_tcp_client_connect (GTcpClient    *client,
224                       GCancellable  *cancellable,
225                       GError       **error)
226 {
227   GInetAddress *address;
228
229   g_return_val_if_fail (G_IS_TCP_CLIENT (client), FALSE);
230
231   if (!client->priv->address)
232     {
233       // we've been constructed with just hostname+port, resolve
234       GResolver *resolver = g_resolver_new ();
235
236       address = g_resolver_resolve (resolver, client->priv->hostname, cancellable, error);
237
238       if (!address)
239         return FALSE;
240
241       client->priv->address = g_inet_socket_address_new (address, client->priv->port);
242
243       g_object_unref (resolver);
244
245       g_object_ref_sink (client->priv->address);
246     }
247   else
248     {
249      address = g_inet_socket_address_get_address (client->priv->address);
250     }
251
252   if (G_IS_INET4_ADDRESS (address))
253     client->priv->socket = g_socket_new (G_SOCKET_DOMAIN_INET, G_SOCKET_TYPE_STREAM, NULL, error);
254   else if (G_IS_INET6_ADDRESS (address))
255     client->priv->socket = g_socket_new (G_SOCKET_DOMAIN_INET6, G_SOCKET_TYPE_STREAM, NULL, error);
256   else
257     {
258       g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "unsupported address domain");
259       return FALSE;
260     }
261
262   if (!client->priv->socket)
263     return FALSE;
264
265   if (g_cancellable_set_error_if_cancelled (cancellable, error))
266     return FALSE;
267
268   if (!g_socket_connect (client->priv->socket, G_SOCKET_ADDRESS (client->priv->address), error))
269     return FALSE;
270
271   return TRUE;
272 }
273
274 typedef struct {
275   GAsyncReadyCallback  callback;
276   GCancellable        *cancellable;
277   gpointer             user_data;
278   GTcpClient          *client;
279   gchar                address_buffer[256];
280   gsize                address_length;
281 } ConnectData;
282
283 /*
284 static gboolean
285 connect_callback (ConnectData *data,
286                   GIOCondition condition,
287                   gint fd)
288 {
289   return FALSE;
290 }
291 */
292
293 void
294 g_tcp_client_connect_async (GTcpClient          *client,
295                             GCancellable        *cancellable,
296                             GAsyncReadyCallback  callback,
297                             gpointer             user_data)
298 {
299
300 }
301
302 gboolean
303 g_tcp_client_connect_finish (GTcpClient    *client,
304                              GAsyncResult  *result,
305                              GError       **error)
306 {
307   GSimpleAsyncResult *simple;
308
309   g_return_val_if_fail (G_IS_TCP_CLIENT (client), FALSE);
310
311   simple = G_SIMPLE_ASYNC_RESULT (result);
312
313   if (g_simple_async_result_propagate_error (simple, error))
314     return FALSE;
315
316   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_tcp_client_connect_async);
317
318   return TRUE;
319 }
320
321 void
322 g_tcp_client_close (GTcpClient *tcp_client)
323 {
324   g_return_if_fail (G_IS_TCP_CLIENT (tcp_client));
325 }