Some more socket stuff
[cascardo/gnio.git] / gnio / gsocket.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 <gio/gasynchelper.h>
28
29 #include <string.h>
30 #ifndef G_OS_WIN32
31 # include <netinet/in.h>
32 # include <arpa/inet.h>
33 # include <netdb.h>
34 # include <fcntl.h>
35 # include <unistd.h>
36 # include <sys/types.h>
37 #else
38
39 #endif
40 #include <errno.h>
41
42 #include "ginetaddress.h"
43 #include "ginet4address.h"
44 #include "ginet6address.h"
45 #include "gsocket.h"
46 #include "gnioerror.h"
47 #include "ginetsocketaddress.h"
48
49 G_DEFINE_TYPE (GSocket, g_socket, G_TYPE_OBJECT);
50
51 enum
52 {
53   PROP_0,
54   PROP_FD,
55   PROP_BLOCKING
56 };
57
58 struct _GSocketPrivate
59 {
60   gint fd;
61   gboolean blocking;
62 };
63
64 static void
65 g_socket_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
66 {
67   GSocket *socket = G_SOCKET (object);
68
69   switch (prop_id)
70     {
71       case PROP_FD:
72         g_value_set_int (value, socket->priv->fd);
73         break;
74
75       case PROP_BLOCKING:
76         g_value_set_boolean (value, socket->priv->blocking);
77         break;
78
79       default:
80         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
81     }
82 }
83
84 static void
85 g_socket_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
86 {
87   GSocket *socket = G_SOCKET (object);
88
89   switch (prop_id)
90     {
91       case PROP_FD:
92         socket->priv->fd = g_value_get_int (value);
93         break;
94
95       case PROP_BLOCKING:
96         g_socket_set_blocking (socket, g_value_get_boolean (value));
97         break;
98
99       default:
100         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
101     }
102 }
103
104 static void
105 g_socket_finalize (GObject *object)
106 {
107   GSocket *socket G_GNUC_UNUSED = G_SOCKET (object);
108
109   if (G_OBJECT_CLASS (g_socket_parent_class)->finalize)
110     (*G_OBJECT_CLASS (g_socket_parent_class)->finalize) (object);
111 }
112
113 static void
114 g_socket_dispose (GObject *object)
115 {
116   GSocket *socket G_GNUC_UNUSED = G_SOCKET (object);;
117
118   if (G_OBJECT_CLASS (g_socket_parent_class)->dispose)
119     (*G_OBJECT_CLASS (g_socket_parent_class)->dispose) (object);
120 }
121
122 static void
123 g_socket_class_init (GSocketClass *klass)
124 {
125   GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
126
127   g_type_class_add_private (klass, sizeof (GSocketPrivate));
128
129   gobject_class->finalize = g_socket_finalize;
130   gobject_class->dispose = g_socket_dispose;
131   gobject_class->set_property = g_socket_set_property;
132   gobject_class->get_property = g_socket_get_property;
133
134   g_object_class_install_property (gobject_class, PROP_FD,
135                                    g_param_spec_int ("fd",
136                                                      "file descriptor",
137                                                      "the socket's file descriptor",
138                                                      G_MININT,
139                                                      G_MAXINT,
140                                                      -1,
141                                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
142
143   g_object_class_install_property (gobject_class, PROP_BLOCKING,
144                                    g_param_spec_boolean ("blocking",
145                                                          "blocking",
146                                                          "whether or not this socket is blocking",
147                                                          TRUE,
148                                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
149 }
150
151 static void
152 g_socket_init (GSocket *socket)
153 {
154   socket->priv = G_TYPE_INSTANCE_GET_PRIVATE (socket, G_TYPE_SOCKET, GSocketPrivate);
155
156   socket->priv->fd = -1;
157   socket->priv->blocking = TRUE;
158 }
159
160 GSocket *
161 g_socket_new (gint domain, gint type, gint protocol)
162 {
163   gint sock;
164
165   sock = socket(domain, type, protocol);
166
167   if (sock < 0)
168     return NULL;
169
170   return G_SOCKET (g_object_new (G_TYPE_SOCKET, "fd", sock, NULL));
171 }
172
173 GSocket *
174 g_socket_new_from_fd (gint fd)
175 {
176   glong arg;
177   gboolean blocking;
178
179   if ((arg = fcntl (fd, F_GETFL, NULL)) < 0)
180     g_warning ("Error getting socket status flags: %s", g_strerror (errno));
181
182   blocking = ((arg & O_NONBLOCK) != 0);
183
184   return G_SOCKET (g_object_new (G_TYPE_SOCKET, "blocking", blocking, "fd", fd, NULL));
185 }
186
187 void
188 g_socket_set_blocking (GSocket  *socket,
189                        gboolean  blocking)
190 {
191   glong arg;
192
193   g_return_if_fail (G_IS_SOCKET (socket));
194
195   if ((arg = fcntl (socket->priv->fd, F_GETFL, NULL)) < 0)
196     g_warning ("Error getting socket status flags: %s", g_strerror (errno));
197
198   arg = blocking ? arg & ~O_NONBLOCK : arg | O_NONBLOCK;
199
200   if (fcntl (socket->priv->fd, F_SETFL, arg) < 0)
201     g_warning ("Error setting socket status flags: %s", g_strerror (errno));
202
203   socket->priv->blocking = blocking;
204 }
205
206 gboolean
207 g_socket_get_blocking (GSocket *socket)
208 {
209   g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
210
211   return socket->priv->blocking;
212 }
213
214 GSocketAddress *
215 g_socket_get_peer_address (GSocket  *socket,
216                            GError  **error)
217 {
218   gchar buffer[256];
219   gsize len;
220
221   g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
222
223   if (getpeername (socket->priv->fd, (struct sockaddr *) buffer, &len) < 0)
224     {
225       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "could not get peer address");
226       return NULL;
227     }
228
229   return g_socket_address_from_native (buffer, len);
230 }
231
232 void
233 g_socket_listen (GSocket *socket,
234                  gint     backlog)
235 {
236   g_return_if_fail (G_IS_SOCKET (socket));
237
238   listen (socket->priv->fd, backlog);
239 }
240
241 gboolean
242 g_socket_bind (GSocket         *socket,
243                GSocketAddress  *address,
244                GError         **error)
245 {
246   g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE);
247
248   {
249     gchar addr[256];
250
251     if (!g_socket_address_to_native (address, addr))
252       return FALSE;
253
254     if (bind (socket->priv->fd, (struct sockaddr *) addr, g_socket_address_native_size (address)) < 0)
255       {
256         // TODO: set error
257         return FALSE;
258       }
259
260     g_object_unref (address);
261
262     return TRUE;
263   }
264 }
265
266 GSocket *
267 g_socket_accept (GSocket       *socket,
268                  GCancellable  *cancellable,
269                  GError       **error)
270 {
271   gint ret;
272
273   if (g_cancellable_set_error_if_cancelled (cancellable, error))
274     return NULL;
275
276   if ((ret = accept (socket->priv->fd, NULL, 0)) < 0)
277     {
278       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error accepting connection");
279       return NULL;
280     }
281
282   if (g_cancellable_set_error_if_cancelled (cancellable, error))
283     {
284       close (ret);
285       return NULL;
286     }
287
288   return g_socket_new_from_fd (ret);
289 }
290
291 typedef struct {
292   GAsyncReadyCallback callback;
293   GCancellable *cancellable;
294   gpointer user_data;
295   GSocket *socket;
296 } AcceptData;
297
298 static gboolean
299 accept_callback (AcceptData *data,
300                  GIOCondition condition,
301                  gint fd)
302 {
303   GSocket *socket;
304   GSimpleAsyncResult *result;
305   gint ret;
306
307   socket = data->socket;
308
309   if (condition & G_IO_IN)
310     {
311       if ((ret = accept (socket->priv->fd, NULL, 0)) < 0)
312         {
313           if (errno == EAGAIN)
314             return TRUE;
315
316           result = g_simple_async_result_new_error (G_OBJECT (socket), data->callback, data->user_data, G_IO_ERROR, g_io_error_from_errno (errno), "error accepting connection");
317         }
318       else
319         {
320           result = g_simple_async_result_new (G_OBJECT (socket), data->callback, data->user_data, g_socket_accept_async);
321
322           g_simple_async_result_set_op_res_gpointer (result, g_socket_new_from_fd (ret), g_object_unref);
323         }
324       g_simple_async_result_complete (result);
325
326       g_object_unref (result);
327     }
328
329   return FALSE;
330 }
331
332 void
333 g_socket_accept_async (GSocket             *socket,
334                        GCancellable        *cancellable,
335                        GAsyncReadyCallback  callback,
336                        gpointer             user_data)
337 {
338   GSource *source;
339   GSimpleAsyncResult *result;
340   AcceptData *data;
341   gint ret;
342
343   g_return_if_fail (G_IS_SOCKET (socket));
344
345   if (g_socket_get_blocking (socket))
346     g_socket_set_blocking (socket, FALSE);
347
348   if ((ret = accept (socket->priv->fd, NULL, 0)) < 0)
349     {
350       if (errno == EAGAIN)
351         {
352           source = _g_fd_source_new (socket->priv->fd, G_IO_IN | G_IO_HUP | G_IO_ERR, cancellable);
353
354           data = g_new (AcceptData, 1);
355
356           data->socket = socket;
357           data->callback = callback;
358           data->cancellable = cancellable;
359           data->user_data = user_data;
360
361           g_source_set_callback (source, (GSourceFunc) accept_callback, data, g_free);
362
363           g_source_attach (source, NULL);
364         }
365       else
366         {
367           g_simple_async_report_error_in_idle (G_OBJECT (socket), callback, user_data, G_IO_ERROR, g_io_error_from_errno (errno), "error accepting connection");
368         }
369     }
370   else
371     {
372       result = g_simple_async_result_new (G_OBJECT (socket), callback, user_data, g_socket_accept_async);
373
374       g_simple_async_result_set_op_res_gpointer (result, g_socket_new_from_fd (ret), g_object_unref);
375
376       g_simple_async_result_complete_in_idle (result);
377
378       g_object_unref (result);
379     }
380 }
381
382 GSocket *
383 g_socket_accept_finish (GSocket       *socket,
384                         GAsyncResult  *result,
385                         GError       **error)
386 {
387   GSocket *new_socket;
388   GSimpleAsyncResult *simple;
389
390   g_return_val_if_fail (G_IS_SOCKET (socket), NULL);
391
392   simple = G_SIMPLE_ASYNC_RESULT (result);
393
394   if (g_simple_async_result_propagate_error (simple, error))
395     return NULL;
396
397   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_accept_async);
398
399   new_socket = g_object_ref (g_simple_async_result_get_op_res_gpointer (simple));
400
401   return new_socket;
402 }
403
404 gboolean
405 g_socket_connect (GSocket         *socket,
406                   GSocketAddress  *address,
407                   GCancellable    *cancellable,
408                   GError         **error)
409 {
410   gchar buffer[256];
411
412   g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE);
413
414   g_socket_address_to_native (address, buffer);
415
416   if (connect (socket->priv->fd, (struct sockaddr *) buffer, g_socket_address_native_size (address)) < 0)
417     {
418       if (errno == EINPROGRESS)
419         g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING, "connection in progress");
420       else
421         g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error connecting: %s", g_strerror (errno));
422       return FALSE;
423     }
424
425   return TRUE;
426 }
427
428 typedef struct {
429   GAsyncReadyCallback callback;
430   GCancellable *cancellable;
431   gpointer user_data;
432   GSocket *socket;
433   gchar address_buffer[256];
434   gsize address_length;
435 } ConnectData;
436
437 static gboolean
438 connect_callback (ConnectData *data,
439                   GIOCondition condition,
440                   gint fd)
441 {
442   GSocket *socket;
443   GSimpleAsyncResult *result = NULL;
444   guint sockerr;
445   gsize sockerr_size = 1;
446
447   socket = data->socket;
448
449   if (condition & G_IO_OUT)
450     {
451       result = g_simple_async_result_new (G_OBJECT (socket), data->callback, data->user_data, g_socket_connect_async);
452     }
453   else if (condition & G_IO_ERR)
454     {
455       if (getsockopt (socket->priv->fd, SOL_SOCKET, SO_ERROR, (gpointer) &sockerr, &sockerr_size) < 0)
456         g_warning ("getsockopt: %s", g_strerror (errno));
457
458       if (sockerr != 0)
459         result = g_simple_async_result_new_error (G_OBJECT (socket), data->callback, data->user_data, G_IO_ERROR, g_io_error_from_errno (sockerr), "error connecting: %s", g_strerror (sockerr));
460       else
461         g_warning ("getsockopt SO_ERROR returned no error, with sockerr = %d", sockerr);
462     }
463
464   g_simple_async_result_complete (result);
465
466   g_object_unref (result);
467
468   return FALSE;
469 }
470
471 void
472 g_socket_connect_async (GSocket             *socket,
473                         GSocketAddress      *address,
474                         GCancellable        *cancellable,
475                         GAsyncReadyCallback  callback,
476                         gpointer             user_data)
477 {
478   GSource *source;
479   GSimpleAsyncResult *result;
480   ConnectData *data;
481   gint ret;
482   gchar buffer[256];
483   gsize len;
484
485   g_return_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address));
486
487   if (g_socket_get_blocking (socket))
488     g_socket_set_blocking (socket, FALSE);
489
490   g_socket_address_to_native (address, buffer);
491
492   len = g_socket_address_native_size (address);
493
494   if ((ret = connect (socket->priv->fd, (struct sockaddr *) buffer, len)) < 0)
495     {
496       if (errno == EINPROGRESS)
497         {
498           source = _g_fd_source_new (socket->priv->fd, G_IO_OUT | G_IO_ERR, cancellable);
499
500           data = g_new (ConnectData, 1);
501
502           data->socket = socket;
503           data->callback = callback;
504           data->cancellable = cancellable;
505           data->user_data = user_data;
506           data->address_length = len;
507           memcpy (data->address_buffer, buffer, len);
508
509           g_source_set_callback (source, (GSourceFunc) connect_callback, data, g_free);
510
511           g_source_attach (source, NULL);
512         }
513       else
514         {
515           g_simple_async_report_error_in_idle (G_OBJECT (socket), callback, user_data, G_IO_ERROR, g_io_error_from_errno (errno), "error connecting: %s", g_strerror (errno));
516         }
517     }
518   else
519     {
520       result = g_simple_async_result_new (G_OBJECT (socket), callback, user_data, g_socket_connect_async);
521
522       g_simple_async_result_complete_in_idle (result);
523
524       g_object_unref (result);
525     }
526 }
527
528 gboolean
529 g_socket_connect_finish (GSocket       *socket,
530                          GAsyncResult  *result,
531                          GError       **error)
532 {
533   GSimpleAsyncResult *simple;
534
535   g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
536
537   simple = G_SIMPLE_ASYNC_RESULT (result);
538
539   if (g_simple_async_result_propagate_error (simple, error))
540     return FALSE;
541
542   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_connect_async);
543
544   return TRUE;
545 }