1 /* GNIO - GLib Network Layer of GIO
3 * Copyright (C) 2008 Christian Kellner, Samuel Cormier-Iijima
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.
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.
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.
20 * Authors: Christian Kellner <gicmo@gnome.org>
21 * Samuel Cormier-Iijima <sciyoshi@gmail.com>
27 #include <gnio/gnio.h>
32 G_DEFINE_TYPE (GTcpClient, g_tcp_client, G_TYPE_OBJECT);
42 struct _GTcpClientPrivate
44 GInetSocketAddress *address;
51 g_tcp_client_constructed (GObject *object)
53 GTcpClient *client = G_TCP_CLIENT (object);
55 if (client->priv->address)
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);
65 g_tcp_client_get_property (GObject *object,
70 GTcpClient *client = G_TCP_CLIENT (object);
75 g_value_set_object (value, client->priv->address);
79 g_value_set_string (value, client->priv->hostname);
83 g_value_set_uint (value, client->priv->port);
87 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
92 g_tcp_client_set_property (GObject *object,
97 GTcpClient *client = G_TCP_CLIENT (object);
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);
109 client->priv->hostname = g_value_dup_string (value);
113 client->priv->port = g_value_get_uint (value);
117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
122 g_tcp_client_finalize (GObject *object)
124 GTcpClient *client = G_TCP_CLIENT (object);
126 g_object_unref (client->priv->address);
128 if (G_OBJECT_CLASS (g_tcp_client_parent_class)->finalize)
129 (*G_OBJECT_CLASS (g_tcp_client_parent_class)->finalize) (object);
133 g_tcp_client_dispose (GObject *object)
135 GTcpClient *client = G_TCP_CLIENT (object);
137 g_free (client->priv->hostname);
139 if (G_OBJECT_CLASS (g_tcp_client_parent_class)->dispose)
140 (*G_OBJECT_CLASS (g_tcp_client_parent_class)->dispose) (object);
144 g_tcp_client_class_init (GTcpClientClass *klass)
146 GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
148 g_type_class_add_private (klass, sizeof (GTcpClientPrivate));
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;
156 g_object_class_install_property (gobject_class, PROP_ADDRESS,
157 g_param_spec_object ("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));
163 g_object_class_install_property (gobject_class, PROP_HOSTNAME,
164 g_param_spec_string ("hostname",
166 "the hostname of the remote address the socket will connect to",
168 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
170 g_object_class_install_property (gobject_class, PROP_PORT,
171 g_param_spec_uint ("port",
173 "the remote port the socket will connect to",
177 G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
181 g_tcp_client_init (GTcpClient *client)
183 client->priv = G_TYPE_INSTANCE_GET_PRIVATE (client, G_TYPE_TCP_CLIENT, GTcpClientPrivate);
185 client->priv->address = NULL;
186 client->priv->hostname = NULL;
187 client->priv->port = 0;
188 client->priv->socket = NULL;
192 g_tcp_client_new (const gchar *hostname,
195 return G_TCP_CLIENT (g_object_new (G_TYPE_TCP_CLIENT, "hostname", hostname, "port", port, NULL));
199 g_tcp_client_new_from_address (GInetSocketAddress *address)
201 return G_TCP_CLIENT (g_object_new (G_TYPE_TCP_CLIENT, "address", address, NULL));
204 GNetworkInputStream *
205 g_tcp_client_get_input_stream (GTcpClient *client)
207 if (!client->priv->socket)
210 return _g_network_input_stream_new (client->priv->socket);
213 GNetworkOutputStream *
214 g_tcp_client_get_output_stream (GTcpClient *client)
216 if (!client->priv->socket)
219 return _g_network_output_stream_new (client->priv->socket);
223 g_tcp_client_connect (GTcpClient *client,
224 GCancellable *cancellable,
227 GInetAddress *address;
229 g_return_val_if_fail (G_IS_TCP_CLIENT (client), FALSE);
231 if (!client->priv->address)
233 // we've been constructed with just hostname+port, resolve
234 GResolver *resolver = g_resolver_new ();
236 address = g_resolver_resolve (resolver, client->priv->hostname, cancellable, error);
241 client->priv->address = g_inet_socket_address_new (address, client->priv->port);
243 g_object_unref (resolver);
245 g_object_ref_sink (client->priv->address);
249 address = g_inet_socket_address_get_address (client->priv->address);
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);
258 g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "unsupported address domain");
262 if (!client->priv->socket)
265 if (g_cancellable_set_error_if_cancelled (cancellable, error))
268 if (!g_socket_connect (client->priv->socket, G_SOCKET_ADDRESS (client->priv->address), error))
275 GAsyncReadyCallback callback;
276 GCancellable *cancellable;
282 connect_callback (ConnectData *data,
283 GIOCondition condition,
287 GSimpleAsyncResult *result;
288 GError *error = NULL;
290 client = data->client;
292 if (condition & G_IO_OUT)
294 result = g_simple_async_result_new (G_OBJECT (client), data->callback, data->user_data, g_tcp_client_connect_async);
296 else if (condition & G_IO_ERR)
298 if (!g_socket_has_socket_error (client->priv->socket, &error))
299 g_warning ("got G_IO_ERR but socket does not have error");
301 result = g_simple_async_result_new_from_error (G_OBJECT (client), data->callback, data->user_data, error);
304 g_simple_async_result_complete (result);
306 g_object_unref (result);
312 g_tcp_client_connect_async (GTcpClient *client,
313 GCancellable *cancellable,
314 GAsyncReadyCallback callback,
317 GInetAddress *address;
318 GSimpleAsyncResult *result;
321 GError *error = NULL;
323 g_return_if_fail (G_IS_TCP_CLIENT (client));
325 if (!client->priv->address)
327 // we've been constructed with just hostname+port, resolve
328 // GResolver *resolver = g_resolver_new ();
332 address = g_inet_socket_address_get_address (client->priv->address);
334 if (G_IS_INET4_ADDRESS (address))
335 client->priv->socket = g_socket_new (G_SOCKET_DOMAIN_INET, G_SOCKET_TYPE_STREAM, NULL, &error);
336 else if (G_IS_INET6_ADDRESS (address))
337 client->priv->socket = g_socket_new (G_SOCKET_DOMAIN_INET6, G_SOCKET_TYPE_STREAM, NULL, &error);
340 g_simple_async_report_error_in_idle (G_OBJECT (client), callback, user_data, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "unsupported address domain");
344 if (!client->priv->socket)
346 g_simple_async_report_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
350 g_socket_set_blocking (client->priv->socket, FALSE);
352 if (!g_socket_connect (client->priv->socket, G_SOCKET_ADDRESS (client->priv->address), &error))
354 if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_PENDING))
356 // the connection is in progress
357 source = g_socket_create_source (client->priv->socket, G_IO_OUT | G_IO_ERR, cancellable);
359 data = g_new (ConnectData, 1);
361 data->client = client;
362 data->callback = callback;
363 data->cancellable = cancellable;
364 data->user_data = user_data;
366 g_source_set_callback (source, (GSourceFunc) connect_callback, data, g_free);
368 g_source_attach (source, NULL);
372 g_simple_async_report_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
377 // the connection is already completed
378 result = g_simple_async_result_new (G_OBJECT (client), callback, user_data, g_tcp_client_connect_async);
380 g_simple_async_result_complete_in_idle (result);
382 g_object_unref (result);
387 g_tcp_client_connect_finish (GTcpClient *client,
388 GAsyncResult *result,
391 GSimpleAsyncResult *simple;
393 g_return_val_if_fail (G_IS_TCP_CLIENT (client), FALSE);
395 simple = G_SIMPLE_ASYNC_RESULT (result);
397 if (g_simple_async_result_propagate_error (simple, error))
400 g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_tcp_client_connect_async);
406 g_tcp_client_close (GTcpClient *tcp_client)
408 g_return_if_fail (G_IS_TCP_CLIENT (tcp_client));