PageRenderTime 61ms CodeModel.GetById 2ms app.highlight 54ms RepoModel.GetById 1ms app.codeStats 1ms

/libgebr/comm/gebr-comm-socket.c

https://bitbucket.org/gebrproject/gebr
C | 456 lines | 319 code | 93 blank | 44 comment | 43 complexity | 65afd4fca846d996b114a365ce692985 MD5 | raw file
  1/*   libgebr - GeBR Library
  2 *   Copyright (C) 2007-2009 GeBR core team (http://www.gebrproject.com/)
  3 *
  4 *   This program is free software: you can redistribute it and/or modify
  5 *   it under the terms of the GNU General Public License as published by
  6 *   the Free Software Foundation, either version 3 of the License, or
  7 *   (at your option) any later version.
  8 *
  9 *   This program is distributed in the hope that it will be useful,
 10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12 *   GNU General Public License for more details.
 13 *
 14 *   You should have received a copy of the GNU General Public License
 15 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 16 *
 17 *   Inspired on Qt 4.3 version of QAbstractSocket, by Trolltech
 18 */
 19
 20#include <stdio.h>
 21#include <string.h>
 22#include <sys/types.h>
 23#include <sys/socket.h>
 24#include <sys/ioctl.h>
 25#include <netdb.h>
 26#include <netinet/in.h>
 27#include <netinet/ip.h>
 28#include <arpa/inet.h>
 29#include <errno.h>
 30
 31#include "gebr-comm-socket.h"
 32#include "gebr-comm-socketprivate.h"
 33#include "gebr-comm-socketaddressprivate.h"
 34
 35/*
 36 * gobject stuff
 37 */
 38
 39enum {
 40	READY_READ,
 41	READY_WRITE,
 42	ERROR,
 43	LAST_SIGNAL
 44};
 45static guint object_signals[LAST_SIGNAL];
 46
 47static void gebr_comm_socket_class_init(GebrCommSocketClass * class)
 48{
 49	/* virtual */
 50	class->connected = NULL;
 51	class->disconnected = NULL;
 52	class->new_connection = NULL;
 53
 54	/* signals */
 55	object_signals[READY_READ] = g_signal_new("ready-read", GEBR_COMM_SOCKET_TYPE, (GSignalFlags) (G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), G_STRUCT_OFFSET(GebrCommSocketClass, ready_read), NULL, NULL,	/* acumulators */
 56						  g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 57	object_signals[READY_WRITE] = g_signal_new("ready-write", GEBR_COMM_SOCKET_TYPE, (GSignalFlags) (G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), G_STRUCT_OFFSET(GebrCommSocketClass, ready_write), NULL, NULL,	/* acumulators */
 58						   g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0);
 59	object_signals[ERROR] = g_signal_new("error", GEBR_COMM_SOCKET_TYPE, (GSignalFlags) (G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION), G_STRUCT_OFFSET(GebrCommSocketClass, error), NULL, NULL,	/* acumulators */
 60					     g_cclosure_marshal_VOID__INT, G_TYPE_NONE, 1, G_TYPE_INT);
 61}
 62
 63static void gebr_comm_socket_init(GebrCommSocket * socket)
 64{
 65	socket->io_channel = NULL;
 66}
 67
 68G_DEFINE_TYPE(GebrCommSocket, gebr_comm_socket, G_TYPE_OBJECT)
 69
 70/*
 71 * internal functions
 72 */
 73static gboolean __gebr_comm_socket_read(GIOChannel * source, GIOCondition condition, GebrCommSocket * socket)
 74{
 75	if (condition & G_IO_NVAL) {
 76		/* probably a fd change */
 77		return FALSE;
 78	}
 79	if (condition & G_IO_ERR) {
 80		_gebr_comm_socket_emit_error(socket, GEBR_COMM_SOCKET_ERROR_CONNECTION_REFUSED);
 81		return FALSE;
 82	}
 83	if (condition & G_IO_HUP) {
 84		GebrCommSocketClass *klass;
 85
 86		klass = GEBR_COMM_SOCKET_GET_CLASS(socket);
 87		switch (socket->state) {
 88		case GEBR_COMM_SOCKET_STATE_CONNECTED:
 89			socket->state = GEBR_COMM_SOCKET_STATE_UNCONNECTED;
 90			if (klass->disconnected != NULL)
 91				klass->disconnected(socket);
 92			break;
 93		default:
 94			break;
 95		}
 96
 97		return FALSE;
 98	}
 99	if (!gebr_comm_socket_bytes_available(socket)) {
100		GebrCommSocketClass *klass;
101		gboolean ret;
102
103		klass = GEBR_COMM_SOCKET_GET_CLASS(socket);
104		switch (socket->state) {
105		case GEBR_COMM_SOCKET_STATE_LISTENING:
106			if (klass->new_connection != NULL)
107				klass->new_connection(socket);
108
109			ret = TRUE;
110			break;
111		case GEBR_COMM_SOCKET_STATE_CONNECTED:
112			socket->state = GEBR_COMM_SOCKET_STATE_UNCONNECTED;
113			if (klass->disconnected != NULL)
114				klass->disconnected(socket);
115
116			ret = FALSE;
117			break;
118		default:
119			ret = TRUE;
120			break;
121		}
122
123		return ret;
124	}
125
126	g_signal_emit(socket, object_signals[READY_READ], 0);
127
128	return TRUE;
129}
130
131void __gebr_comm_socket_write_queue(GebrCommSocket * socket)
132{
133	g_return_if_fail(socket->state == GEBR_COMM_SOCKET_STATE_CONNECTED);
134	/* write queud bytes */
135	if (socket->queue_write_bytes->len) {
136		ssize_t written_bytes;
137
138		_gebr_comm_socket_enable_write_watch(socket);
139
140		written_bytes = send(_gebr_comm_socket_get_fd(socket), socket->queue_write_bytes->data,
141				     socket->queue_write_bytes->len > 4096 ? 4096 : socket->queue_write_bytes->len, 0);
142
143		if (written_bytes != -1)
144			g_byte_array_remove_range(socket->queue_write_bytes, 0, written_bytes);
145	}
146}
147
148static gboolean __gebr_comm_socket_write(GIOChannel * source, GIOCondition condition, GebrCommSocket * socket)
149{
150	if (condition & G_IO_NVAL) {
151		/* probably a fd change */
152		goto out;
153	}
154	if (condition & G_IO_ERR) {
155		switch (errno) {
156		case ECONNREFUSED:
157			_gebr_comm_socket_emit_error(socket, GEBR_COMM_SOCKET_ERROR_CONNECTION_REFUSED);
158			break;
159		case EINPROGRESS:
160			return TRUE;
161		case 0:
162			return FALSE;
163		default:
164			_gebr_comm_socket_emit_error(socket, GEBR_COMM_SOCKET_ERROR_UNKNOWN);
165			break;
166		}
167		if (socket->state == GEBR_COMM_SOCKET_STATE_CONNECTED) {
168			GebrCommSocketClass *klass;
169
170			klass = GEBR_COMM_SOCKET_GET_CLASS(socket);
171			socket->state = GEBR_COMM_SOCKET_STATE_UNCONNECTED;
172			if (klass->disconnected != NULL)
173				klass->disconnected(socket);
174		}
175		goto out;
176	}
177	if (condition & G_IO_HUP) {
178		/* TODO: */
179		goto out;
180	}
181	if (socket->state != GEBR_COMM_SOCKET_STATE_CONNECTED) {
182		GebrCommSocketClass *klass;
183
184		klass = GEBR_COMM_SOCKET_GET_CLASS(socket);
185		switch (socket->state) {
186		case GEBR_COMM_SOCKET_STATE_CONNECTING:
187			socket->state = GEBR_COMM_SOCKET_STATE_CONNECTED;
188			if (klass->connected != NULL)
189				klass->connected(socket);
190			break;
191		default:
192			break;
193		}
194
195		goto out;
196	}
197
198	__gebr_comm_socket_write_queue(socket);
199
200 out:	return FALSE;
201}
202
203/*
204 * private functions
205 */
206
207void _gebr_comm_socket_init(GebrCommSocket * socket, int fd, enum GebrCommSocketAddressType address_type)
208{
209	GError *error;
210
211	/* free previous stuff */
212	_gebr_comm_socket_close(socket);
213
214	error = NULL;
215	socket->write_watch_id = 0;
216	socket->read_watch_id = 0;
217	socket->address_type = address_type;
218	socket->state = GEBR_COMM_SOCKET_STATE_NONE;
219	socket->last_error = GEBR_COMM_SOCKET_ERROR_NONE;
220	/* IO channel */
221	socket->io_channel = g_io_channel_unix_new(fd);
222	g_io_channel_set_encoding(socket->io_channel, NULL, &error);
223	g_io_channel_set_close_on_unref(socket->io_channel, TRUE);
224	/* byte array */
225	socket->queue_write_bytes = g_byte_array_new();
226}
227
228void _gebr_comm_socket_close(GebrCommSocket * socket)
229{
230	if (socket->io_channel != NULL) {
231		if (socket->write_watch_id)
232			g_source_remove(socket->write_watch_id);
233
234		if (socket->read_watch_id)
235			g_source_remove(socket->read_watch_id);
236
237		g_io_channel_unref(socket->io_channel);
238		socket->io_channel = NULL;
239		g_byte_array_free(socket->queue_write_bytes, TRUE);
240	}
241}
242
243int _gebr_comm_socket_get_fd(GebrCommSocket * socket)
244{
245	return g_io_channel_unix_get_fd(socket->io_channel);
246}
247
248void _gebr_comm_socket_enable_read_watch(GebrCommSocket * socket)
249{
250	socket->read_watch_id = g_io_add_watch(socket->io_channel, G_IO_IN | G_IO_PRI | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
251					       (GIOFunc) __gebr_comm_socket_read, socket);
252}
253
254void _gebr_comm_socket_enable_write_watch(GebrCommSocket * socket)
255{
256	socket->write_watch_id = g_io_add_watch(socket->io_channel, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
257						(GIOFunc) __gebr_comm_socket_write, socket);
258}
259
260void _gebr_comm_socket_emit_error(GebrCommSocket * socket, enum GebrCommSocketError error)
261{
262	socket->last_error = error;
263	g_signal_emit(socket, object_signals[ERROR], 0, error);
264}
265
266/*
267 * user functions
268 */
269
270void gebr_comm_socket_close(GebrCommSocket * socket)
271{
272	g_return_if_fail(GEBR_COMM_IS_SOCKET(socket));
273
274	_gebr_comm_socket_close(socket);
275
276	g_object_unref(G_OBJECT(socket));
277}
278
279void gebr_comm_socket_flush(GebrCommSocket * socket)
280{
281	g_return_if_fail(GEBR_COMM_IS_SOCKET(socket));
282
283	GError *error;
284	gint flags;
285
286	flags = g_io_channel_get_flags(socket->io_channel);
287
288	error = NULL;
289	g_io_channel_set_flags(socket->io_channel, 0, &error);
290	error = NULL;
291	g_io_channel_flush(socket->io_channel, &error);
292
293	error = NULL;
294	g_io_channel_set_flags(socket->io_channel, flags, &error);
295}
296
297void gebr_comm_socket_set_blocking(GebrCommSocket * socket, gboolean blocking_operations)
298{
299	g_return_if_fail(GEBR_COMM_IS_SOCKET(socket));
300
301	GError *error;
302
303	error = NULL;
304	if (!blocking_operations)
305		g_io_channel_set_flags(socket->io_channel, g_io_channel_get_flags(socket->io_channel) | G_IO_FLAG_NONBLOCK, &error);
306	else
307		g_io_channel_set_flags(socket->io_channel, g_io_channel_get_flags(socket->io_channel) & ~G_IO_FLAG_NONBLOCK, &error);
308
309}
310
311enum GebrCommSocketState gebr_comm_socket_get_state(GebrCommSocket * socket)
312{
313	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), GEBR_COMM_SOCKET_STATE_NONE); 
314
315	return socket->state;
316}
317
318enum GebrCommSocketError gebr_comm_socket_get_last_error(GebrCommSocket * socket)
319{
320	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), GEBR_COMM_SOCKET_ERROR_NONE);
321
322	return socket->last_error;
323}
324
325GebrCommSocketAddress gebr_comm_socket_get_address(GebrCommSocket * socket)
326{
327	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), _gebr_comm_socket_address_unknown());
328
329	GebrCommSocketAddress address;
330
331	_gebr_comm_socket_address_getsockname(&address, socket->address_type, _gebr_comm_socket_get_fd(socket));
332
333	return address;
334}
335
336gulong gebr_comm_socket_bytes_available(GebrCommSocket * socket)
337{
338	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), 0);
339
340	/* Adapted from QNativeSocketEnginePrivate::nativeBytesAvailable()
341	 * (qnativesocketengine_unix.cpp:528 of Qt 4.3.0)
342	 */
343	size_t nbytes = 0;
344	gulong available = 0;
345
346	if (ioctl(_gebr_comm_socket_get_fd(socket), FIONREAD, (char *)&nbytes) >= 0)
347		available = (gulong) nbytes;
348
349	return available;
350}
351
352gulong gebr_comm_socket_bytes_to_write(GebrCommSocket * socket)
353{
354	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), 0);
355
356	return socket->queue_write_bytes->len;
357}
358
359GByteArray *gebr_comm_socket_read(GebrCommSocket * socket, gsize max_size)
360{
361	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), NULL);
362
363	if (socket->state != GEBR_COMM_SOCKET_STATE_CONNECTED)
364		return NULL;
365
366	guint8 buffer[max_size];
367	size_t read_bytes;
368	GByteArray *byte_array;
369
370	read_bytes = recv(_gebr_comm_socket_get_fd(socket), buffer, max_size, 0);
371	if (read_bytes == -1)
372		return NULL;
373
374	byte_array = g_byte_array_new();
375	g_byte_array_append(byte_array, buffer, read_bytes);
376
377	return byte_array;
378}
379
380GString *gebr_comm_socket_read_string(GebrCommSocket * socket, gsize max_size)
381{
382	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), NULL);
383
384	if (socket->state != GEBR_COMM_SOCKET_STATE_CONNECTED)
385		return NULL;
386
387	gchar buffer[max_size + 1];
388	size_t read_bytes;
389	GString *string;
390
391	read_bytes = recv(_gebr_comm_socket_get_fd(socket), buffer, max_size, 0);
392	if (read_bytes == -1)
393		return NULL;
394
395	buffer[read_bytes] = '\0';
396	string = g_string_new(NULL);
397	g_string_assign(string, buffer);
398
399	return string;
400}
401
402GByteArray *gebr_comm_socket_read_all(GebrCommSocket * socket)
403{
404	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), NULL);
405
406	/* trick for lazyness */
407	return gebr_comm_socket_read(socket, gebr_comm_socket_bytes_available(socket));
408}
409
410GString *gebr_comm_socket_read_string_all(GebrCommSocket * socket)
411{
412	g_return_val_if_fail(GEBR_COMM_IS_SOCKET(socket), NULL);
413
414	/* trick for lazyness */
415	return gebr_comm_socket_read_string(socket, gebr_comm_socket_bytes_available(socket));
416}
417
418void gebr_comm_socket_write(GebrCommSocket * socket, GByteArray * byte_array)
419{
420	g_return_if_fail(GEBR_COMM_IS_SOCKET(socket));
421
422	g_byte_array_append(socket->queue_write_bytes, byte_array->data, byte_array->len);
423	_gebr_comm_socket_enable_write_watch(socket);
424}
425
426void gebr_comm_socket_write_immediately(GebrCommSocket * socket, GByteArray * byte_array)
427{
428	g_return_if_fail(GEBR_COMM_IS_SOCKET(socket));
429
430	g_byte_array_append(socket->queue_write_bytes, byte_array->data, byte_array->len);
431	__gebr_comm_socket_write_queue(socket);
432}
433
434void gebr_comm_socket_write_string(GebrCommSocket * socket, GString * string)
435{
436	g_return_if_fail(GEBR_COMM_IS_SOCKET(socket));
437
438	GByteArray byte_array;
439
440	byte_array.data = (guint8 *)string->str;
441	byte_array.len = string->len;
442
443	gebr_comm_socket_write(socket, &byte_array);
444}
445
446void gebr_comm_socket_write_string_immediately(GebrCommSocket * socket, GString * string)
447{
448	g_return_if_fail(GEBR_COMM_IS_SOCKET(socket));
449
450	GByteArray byte_array;
451
452	byte_array.data = (guint8 *)string->str;
453	byte_array.len = string->len;
454
455	gebr_comm_socket_write_immediately(socket, &byte_array);
456}