Some more stuff for GSockets
[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
28 #include <string.h>
29 #ifndef G_OS_WIN32
30 # include <netinet/in.h>
31 # include <arpa/inet.h>
32 # include <netdb.h>
33 # include <fcntl.h>
34 # include <unistd.h>
35 #else
36
37 #endif
38 #include <errno.h>
39
40 #include "ginetaddress.h"
41 #include "ginet4address.h"
42 #include "ginet6address.h"
43 #include "gsocket.h"
44 #include "gnioerror.h"
45 #include "ginetsocketaddress.h"
46
47 G_DEFINE_TYPE (GSocket, g_socket, G_TYPE_OBJECT);
48
49 enum
50 {
51   PROP_0,
52   PROP_FD,
53   PROP_BLOCKING
54 };
55
56 struct _GSocketPrivate
57 {
58   gint fd;
59   gboolean blocking;
60 };
61
62 static void
63 g_socket_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
64 {
65   GSocket *socket = G_SOCKET (object);
66
67   switch (prop_id)
68     {
69       case PROP_FD:
70         g_value_set_int (value, socket->priv->fd);
71         break;
72
73       case PROP_BLOCKING:
74         g_value_set_boolean (value, socket->priv->blocking);
75         break;
76
77       default:
78         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
79     }
80 }
81
82 static void
83 g_socket_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
84 {
85   GSocket *socket = G_SOCKET (object);
86
87   switch (prop_id)
88     {
89       case PROP_FD:
90         socket->priv->fd = g_value_get_int (value);
91         break;
92
93       case PROP_BLOCKING:
94         g_socket_set_blocking (socket, g_value_get_boolean (value));
95         break;
96
97       default:
98         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
99     }
100 }
101
102 static void
103 g_socket_finalize (GObject *object)
104 {
105   GSocket *socket G_GNUC_UNUSED = G_SOCKET (object);
106
107   if (G_OBJECT_CLASS (g_socket_parent_class)->finalize)
108     (*G_OBJECT_CLASS (g_socket_parent_class)->finalize) (object);
109 }
110
111 static void
112 g_socket_dispose (GObject *object)
113 {
114   GSocket *socket G_GNUC_UNUSED = G_SOCKET (object);;
115
116   if (G_OBJECT_CLASS (g_socket_parent_class)->dispose)
117     (*G_OBJECT_CLASS (g_socket_parent_class)->dispose) (object);
118 }
119
120 static void
121 g_socket_class_init (GSocketClass *klass)
122 {
123   GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
124
125   g_type_class_add_private (klass, sizeof (GSocketPrivate));
126
127   gobject_class->finalize = g_socket_finalize;
128   gobject_class->dispose = g_socket_dispose;
129   gobject_class->set_property = g_socket_set_property;
130   gobject_class->get_property = g_socket_get_property;
131
132   g_object_class_install_property (gobject_class, PROP_FD,
133                                    g_param_spec_int ("fd",
134                                                      "file descriptor",
135                                                      "the socket's file descriptor",
136                                                      G_MININT,
137                                                      G_MAXINT,
138                                                      -1,
139                                                      G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
140
141   g_object_class_install_property (gobject_class, PROP_BLOCKING,
142                                    g_param_spec_boolean ("blocking",
143                                                          "blocking",
144                                                          "whether or not this socket is blocking",
145                                                          FALSE,
146                                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK));
147 }
148
149 static void
150 g_socket_init (GSocket *socket)
151 {
152   socket->priv = G_TYPE_INSTANCE_GET_PRIVATE (socket, G_TYPE_SOCKET, GSocketPrivate);
153
154   socket->priv->fd = -1;
155   socket->priv->blocking = TRUE;
156 }
157
158 GSocket *
159 g_socket_new (gint domain, gint type, gint protocol)
160 {
161   gint sock;
162
163   sock = socket(domain, type, protocol);
164
165   if (sock < 0)
166     return NULL;
167
168   return G_SOCKET (g_object_new (G_TYPE_SOCKET, "fd", sock, NULL));
169 }
170
171 GSocket *
172 g_socket_new_from_fd (gint fd)
173 {
174   glong arg;
175   gboolean blocking;
176
177   if ((arg = fcntl (fd, F_GETFL, NULL)) < 0)
178     g_warning ("Error getting socket status flags: %s", g_strerror (errno));
179
180   blocking = ((arg & O_NONBLOCK) != 0);
181
182   return G_SOCKET (g_object_new (G_TYPE_SOCKET, "blocking", blocking, "fd", fd, NULL));
183 }
184
185 void
186 g_socket_set_blocking (GSocket  *socket,
187                        gboolean  blocking)
188 {
189   glong arg;
190
191   g_return_if_fail (G_IS_SOCKET (socket));
192
193   if ((arg = fcntl (socket->priv->fd, F_GETFL, NULL)) < 0)
194     g_warning ("Error getting socket status flags: %s", g_strerror (errno));
195
196   arg = blocking ? arg | O_NONBLOCK : arg & ~O_NONBLOCK;
197
198   if (fcntl (socket->priv->fd, F_SETFL, arg) < 0)
199     g_warning ("Error setting socket status flags: %s", g_strerror (errno));
200 }
201
202 GSocketAddress *
203 g_socket_get_peer_address (GSocket  *socket,
204                            GError  **error)
205 {
206   gchar buffer[128];
207   gsize len;
208
209   if (getpeername (socket->priv->fd, (struct sockaddr *) buffer, &len) < 0)
210     {
211       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "could not get peer address");
212       return NULL;
213     }
214
215   return g_socket_address_from_native (buffer, len);
216 }
217
218 void
219 g_socket_listen (GSocket *socket,
220                  gint     backlog)
221 {
222   g_return_if_fail (G_IS_SOCKET (socket));
223
224   listen (socket->priv->fd, backlog);
225 }
226
227 gboolean
228 g_socket_bind (GSocket         *socket,
229                GSocketAddress  *address,
230                GError         **error)
231 {
232   g_return_val_if_fail (G_IS_SOCKET (socket) && G_IS_SOCKET_ADDRESS (address), FALSE);
233
234   {
235     gchar addr[g_socket_address_native_size (address)];
236
237     if (!g_socket_address_to_native (address, addr))
238       return FALSE;
239
240     if (bind (socket->priv->fd, (struct sockaddr *) addr, g_socket_address_native_size (address)) < 0)
241       {
242         // TODO: set error
243         return FALSE;
244       }
245
246     g_object_unref (address);
247
248     return TRUE;
249   }
250 }
251
252 GSocket *
253 g_socket_accept (GSocket       *socket,
254                  GCancellable  *cancellable,
255                  GError       **error)
256 {
257   gint ret;
258
259   if (g_cancellable_set_error_if_cancelled (cancellable, error))
260     return NULL;
261
262   if ((ret = accept (socket->priv->fd, NULL, 0)) < 0)
263     {
264       g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error accepting connection");
265       return NULL;
266     }
267
268   if (g_cancellable_set_error_if_cancelled (cancellable, error))
269     {
270       close (ret);
271       return NULL;
272     }
273
274   return g_socket_new_from_fd (ret);
275 }
276
277 void
278 g_socket_accept_async (GSocket             *socket,
279                        GCancellable        *cancellable,
280                        GAsyncReadyCallback *callback,
281                        gpointer             user_data)
282 {
283   
284 }
285
286 GSocket *
287 g_socket_accept_finish (GSocket       *socket,
288                         GAsyncResult  *result,
289                         GError       **error)
290 {
291   return NULL;
292 }
293
294 gboolean
295 g_socket_connect (GSocket         *socket,
296                   GSocketAddress  *address,
297                   GCancellable    *cancellable,
298                   GError         **error)
299 {
300   g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
301 /*
302   if (connect () < 0)
303     {
304       if (errno == EINPROGRESS)
305         g_set_error (error, G_IO_ERROR, G_IO_ERROR_PENDING, "connection in progress");
306       else
307         g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errno), "error connecting: %s", g_strerror (errno));
308       return FALSE;
309     }
310 */
311   return TRUE;
312 }
313
314 void
315 g_socket_connect_async (GSocket             *socket,
316                         GSocketAddress      *address,
317                         GCancellable        *cancellable,
318                         GAsyncReadyCallback *callback,
319                         gpointer             user_data)
320 {
321
322 }
323
324 gboolean
325 g_socket_connect_finish (GSocket       *socket,
326                          GAsyncResult  *result,
327                          GError       **error)
328 {
329   return FALSE;
330 }