X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=hcconn.c;h=c15256fbd696440724b301a2c7b9e835dafd6f46;hb=cf309ca41249b88d93bf6ae0b927e6c9ac6527bb;hp=2297c946ca29a66c1ca90a98ffe3d0552a438e92;hpb=7dd51d1e79948d7ac45d4d15171d0b253d3cf371;p=cascardo%2Frnetproxy.git diff --git a/hcconn.c b/hcconn.c index 2297c94..c15256f 100644 --- a/hcconn.c +++ b/hcconn.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Thadeu Lima de Souza Cascardo + * Copyright (C) 2009 Thadeu Lima de Souza Cascardo * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -20,8 +20,11 @@ #include "hcconn.h" #include #include +#include #include "hcconn_internal.h" +/* The server connection watch */ + struct hc_server_cb { GIOChannel *channel; @@ -58,57 +61,119 @@ hc_server_add_watch (int fd, cb->channel = g_io_channel_unix_new (fd); cb->func = func; cb->data = data; + /* TODO: we should have some way to remove this watch */ g_io_add_watch_full (cb->channel, G_PRIORITY_DEFAULT, G_IO_IN, hc_server_watch, cb, hc_server_cb_destroy); } + +/* The IOChannel (simple socket) layer */ + +struct channel_layer +{ + GIOChannel *channel; + guint watch; +}; + ssize_t hc_conn_channel_read (gpointer data, char *buffer, size_t len) { - int fd = g_io_channel_unix_get_fd ((GIOChannel *) data); + struct channel_layer *layer = data; + int fd = g_io_channel_unix_get_fd (layer->channel); return read (fd, buffer, len); } ssize_t hc_conn_channel_write (gpointer data, char *buffer, size_t len) { - int fd = g_io_channel_unix_get_fd ((GIOChannel *) data); + struct channel_layer *layer = data; + int fd = g_io_channel_unix_get_fd (layer->channel); return write (fd, buffer, len); } void hc_conn_channel_close (gpointer data) { - int fd = g_io_channel_unix_get_fd ((GIOChannel *) data); - shutdown (fd, SHUT_RDWR); + struct channel_layer *layer = data; + int fd = g_io_channel_unix_get_fd (layer->channel); + g_source_remove (layer->watch); + close (fd); + g_io_channel_unref (layer->channel); + g_slice_free (struct channel_layer, layer); } gboolean hc_conn_watch (GIOChannel *channel, GIOCondition cond, gpointer data) { HCConn *conn = data; - HCEvent event = HC_EVENT_READ; + /* TODO: What about other events, like closing? */ + HCEvent event; + int fd = g_io_channel_unix_get_fd (channel); + char buffer; + int r; + if (cond & G_IO_IN) + { + event = HC_EVENT_READ; + r = recv (fd, &buffer, 1, MSG_PEEK); + if (r == 0) + { + event = HC_EVENT_CLOSE; + } + else if (r == -1) + { + /* FIXME: create HC_EVENT_ERROR */ + event = HC_EVENT_CLOSE; + } + } + else if (cond & G_IO_HUP) + { + event = HC_EVENT_CLOSE; + } + else if (cond & G_IO_ERR) + { + /* FIXME: create HC_EVENT_ERROR */ + event = HC_EVENT_CLOSE; + } + else + { + /* TODO: handle other conditions and create error event */ + g_warning ("Received an unexpected IO condition."); + } if (conn->func) conn->func (conn, event, conn->data); return TRUE; } -HCConn * -hc_conn_new (int fd, HCClientFunc func, gpointer data) +int +hc_conn_set_driver_channel (HCConn *conn, int fd) { - HCConn *conn; - conn = g_slice_new (HCConn); - conn->channel = g_io_channel_unix_new (fd); - conn->func = func; - conn->data = data; - conn->layer = conn->channel; + struct channel_layer *layer = g_slice_new (struct channel_layer); + layer->channel = g_io_channel_unix_new (fd); + conn->layer = layer; conn->read = hc_conn_channel_read; conn->write = hc_conn_channel_write; conn->close = hc_conn_channel_close; - conn->watch = g_io_add_watch (conn->channel, G_IO_IN, hc_conn_watch, conn); + /* TODO: We must watch other events */ + layer->watch = g_io_add_watch (layer->channel, + G_IO_IN | G_IO_HUP | G_IO_ERR, + hc_conn_watch, conn); + /* TODO: connection should be asynchronous so this could make sense */ if (conn->func) conn->func (conn, HC_EVENT_CONNECT, conn->data); fcntl (fd, F_SETFL, fcntl (fd, F_GETFL, 0) | O_NONBLOCK); + return 0; +} + + +/* The core connection system */ + +HCConn * +hc_conn_new (HCClientFunc func, gpointer data) +{ + HCConn *conn; + conn = g_slice_new (HCConn); + conn->func = func; + conn->data = data; return conn; } @@ -122,21 +187,29 @@ hc_conn_set_callback (HCConn *conn, HCClientFunc func, gpointer data) ssize_t hc_conn_read (HCConn *conn, char *buffer, size_t len) { - return conn->read (conn->layer, buffer, len); + if (conn->read) + return conn->read (conn->layer, buffer, len); + return 0; } void hc_conn_write (HCConn *conn, char *buffer, size_t len) { /* TODO: Do buffering or something like that */ - conn->write (conn->layer, buffer, len); + /* Do we really need to? */ + /* In case of error, we should do something */ + if (conn->write) + conn->write (conn->layer, buffer, len); } void hc_conn_close (HCConn *conn) { - g_source_remove (conn->watch); - conn->close (conn->layer); - g_io_channel_unref (conn->channel); + if (conn->close) + conn->close (conn->layer); + conn->read = NULL; + conn->write = NULL; + conn->close = NULL; + conn->func = NULL; g_slice_free (HCConn, conn); }