Moved network related functions to GLib signal handlers

connect, recv and close events are now handled by GLib signals
(connect, net-recv and net-hup, respectively)
This commit is contained in:
Gergely Polonkai 2013-01-05 22:56:42 +01:00
parent b99f9e1ea2
commit 54b5fe00aa
3 changed files with 205 additions and 110 deletions

View File

@ -73,6 +73,12 @@ remove_client(WmudClient *client, gboolean send_quitmessage)
wmud_client_close(client, send_quitmessage);
}
static void
hup_client(WmudClient *client)
{
remove_client(client, FALSE);
}
/**
* wmud_client_callback:
* @client: the socket of the client on which the data arrived
@ -80,116 +86,107 @@ remove_client(WmudClient *client, gboolean send_quitmessage)
* @client: the WmudClient structure of the client
*
* Processes incoming client data, and client hangup
*
* Return value: %FALSE if the connection is closed after this call, %TRUE
* otherwise
*/
static gboolean
wmud_client_callback(GSocket *client_socket, GIOCondition condition, WmudClient *client)
static void
recv_client(WmudClient *client)
{
GError *err = NULL;
GSocket *client_socket;
gssize len;
gchar *buf2;
gchar *buf = g_malloc0(sizeof(gchar) * (MAX_RECV_LEN + 1));
if (condition & G_IO_HUP) {
client_socket = wmud_client_get_socket(client);
if ((len = g_socket_receive(client_socket, buf, MAX_RECV_LEN, NULL, &err)) == 0) {
g_free(buf);
remove_client(client, FALSE);
return FALSE;
} else if ((condition & G_IO_IN) || (condition & G_IO_PRI)) {
gssize len;
gchar *buf2;
gchar *buf = g_malloc0(sizeof(gchar) * (MAX_RECV_LEN + 1));
if ((len = g_socket_receive(client_socket, buf, MAX_RECV_LEN, NULL, &err)) == 0) {
g_free(buf);
remove_client(client, FALSE);
return FALSE;
}
buf2 = buf;
while (TRUE) {
char *r = strchr((char *)buf2, '\r'),
*n = strchr((char *)buf2, '\n');
if (r || n) {
gint i,
sloc = -1;
if ((r < n) && r) {
if (wmud_client_get_buffer_length(client) > 0)
g_string_append_len(wmud_client_get_buffer(client), buf2, (r - buf2));
else
g_string_overwrite_len(wmud_client_get_buffer(client), 0, buf2, (r - buf2));
buf2 = r;
} else if (n) {
if (wmud_client_get_buffer_length(client) > 0)
g_string_append_len(wmud_client_get_buffer(client), buf2, (n - buf2));
else
g_string_overwrite_len(wmud_client_get_buffer(client), 0, buf2, (n - buf2));
buf2 = n;
}
/* Remove telnet codes from the string */
for (i = 0; i < wmud_client_get_buffer_length(client); i++) {
guchar c = (wmud_client_get_buffer(client)->str)[i];
if ((c >= 240) || (c == 1)) {
if (sloc == -1)
sloc = i;
} else {
if (sloc != -1) {
g_string_erase(wmud_client_get_buffer(client), sloc, i - sloc);
sloc = -1;
}
}
}
if (sloc != -1)
g_string_erase(wmud_client_get_buffer(client), sloc, -1);
switch (wmud_client_get_state(client))
{
case WMUD_CLIENT_STATE_FRESH:
state_fresh(client);
break;
case WMUD_CLIENT_STATE_PASSWAIT:
state_passwait(client);
break;
case WMUD_CLIENT_STATE_MENU:
state_menu(client);
break;
case WMUD_CLIENT_STATE_INGAME:
wmud_interpret_game_command(client);
break;
case WMUD_CLIENT_STATE_YESNO:
state_yesno(client);
break;
case WMUD_CLIENT_STATE_REGISTERING:
state_registering(client);
break;
case WMUD_CLIENT_STATE_REGEMAIL_CONFIRM:
state_regemail_confirm(client);
break;
}
g_string_erase(wmud_client_get_buffer(client), 0, -1);
for (; ((*buf2 == '\r') || (*buf2 == '\n')) && *buf2; buf2++);
if (!*buf2)
break;
} else {
if (wmud_client_get_buffer_length(client) > 0)
g_string_append(wmud_client_get_buffer(client), buf2);
else
g_string_overwrite(wmud_client_get_buffer(client), 0, buf2);
break;
}
}
g_free(buf);
return;
}
return TRUE;
buf2 = buf;
while (TRUE) {
char *r = strchr((char *)buf2, '\r'),
*n = strchr((char *)buf2, '\n');
if (r || n) {
gint i,
sloc = -1;
if ((r < n) && r) {
if (wmud_client_get_buffer_length(client) > 0)
g_string_append_len(wmud_client_get_buffer(client), buf2, (r - buf2));
else
g_string_overwrite_len(wmud_client_get_buffer(client), 0, buf2, (r - buf2));
buf2 = r;
} else if (n) {
if (wmud_client_get_buffer_length(client) > 0)
g_string_append_len(wmud_client_get_buffer(client), buf2, (n - buf2));
else
g_string_overwrite_len(wmud_client_get_buffer(client), 0, buf2, (n - buf2));
buf2 = n;
}
/* Remove telnet codes from the string */
for (i = 0; i < wmud_client_get_buffer_length(client); i++) {
guchar c = (wmud_client_get_buffer(client)->str)[i];
if ((c >= 240) || (c == 1)) {
if (sloc == -1)
sloc = i;
} else {
if (sloc != -1) {
g_string_erase(wmud_client_get_buffer(client), sloc, i - sloc);
sloc = -1;
}
}
}
if (sloc != -1)
g_string_erase(wmud_client_get_buffer(client), sloc, -1);
switch (wmud_client_get_state(client))
{
case WMUD_CLIENT_STATE_FRESH:
state_fresh(client);
break;
case WMUD_CLIENT_STATE_PASSWAIT:
state_passwait(client);
break;
case WMUD_CLIENT_STATE_MENU:
state_menu(client);
break;
case WMUD_CLIENT_STATE_INGAME:
wmud_interpret_game_command(client);
break;
case WMUD_CLIENT_STATE_YESNO:
state_yesno(client);
break;
case WMUD_CLIENT_STATE_REGISTERING:
state_registering(client);
break;
case WMUD_CLIENT_STATE_REGEMAIL_CONFIRM:
state_regemail_confirm(client);
break;
}
g_string_erase(wmud_client_get_buffer(client), 0, -1);
for (; ((*buf2 == '\r') || (*buf2 == '\n')) && *buf2; buf2++);
if (!*buf2)
break;
} else {
if (wmud_client_get_buffer_length(client) > 0)
g_string_append(wmud_client_get_buffer(client), buf2);
else
g_string_overwrite(wmud_client_get_buffer(client), 0, buf2);
break;
}
}
g_free(buf);
}
/**
@ -207,7 +204,6 @@ gboolean
game_source_callback(GSocket *socket, GIOCondition condition, struct AcceptData *accept_data)
{
GSocket *client_socket;
GSource *client_source;
GError *err = NULL;
GSocketAddress *remote_addr;
WmudClient *client;
@ -218,13 +214,12 @@ game_source_callback(GSocket *socket, GIOCondition condition, struct AcceptData
client = wmud_client_new();
wmud_client_set_socket(WMUD_CLIENT(client), client_socket);
client_source = wmud_client_get_socket_source(client);
wmud_client_set_context(client, accept_data->context);
g_signal_connect(client, "net-hup", G_CALLBACK(hup_client), NULL);
g_signal_connect(client, "net-recv", G_CALLBACK(recv_client), NULL);
clients = g_slist_prepend(clients, client);
g_source_set_callback(client_source, (GSourceFunc)wmud_client_callback, client, NULL);
g_source_attach(client_source, accept_data->context);
g_clear_error(&err);
if ((remote_addr = g_socket_get_remote_address(client_socket, &err)) != NULL) {

View File

@ -16,10 +16,29 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "wmudclient.h"
#include "wmudclient.h"
#include "players.h"
/**
* SECTION:wmudclient
* @short_description: wMUD Client
* @inclide: wmudclient.h
*
* #WmudClient is for storing an active client connection
**/
G_DEFINE_TYPE(WmudClient, wmud_client, G_TYPE_OBJECT);
enum {
SIG_CONNECTED,
SIG_NET_HUP,
SIG_NET_RECV,
SIG_LAST
};
static guint signals[SIG_LAST] = { 0 };
#define WMUD_CLIENT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), WMUD_TYPE_CLIENT, WmudClientPrivate))
struct _WmudClientPrivate
@ -33,10 +52,9 @@ struct _WmudClientPrivate
gboolean bademail;
gint login_try_count;
WmudClientYesnoCallback yesno_callback;
time_t last_recv;
};
G_DEFINE_TYPE(WmudClient, wmud_client, G_TYPE_OBJECT);
static void
wmud_client_dispose(GObject *gobject)
{
@ -62,6 +80,12 @@ wmud_client_finalize(GObject *gobject)
G_OBJECT_CLASS(wmud_client_parent_class)->finalize(gobject);
}
static void net_recv(WmudClient *self)
{
self->priv->last_recv = time(NULL);
g_message("net-recv");
}
static void
wmud_client_class_init(WmudClientClass *klass)
{
@ -70,6 +94,47 @@ wmud_client_class_init(WmudClientClass *klass)
gobject_class->dispose = wmud_client_dispose;
gobject_class->finalize = wmud_client_finalize;
/**
* WmudClient::connected:
* @client: The client emitting the signal
*
* Emitted when a new client connection is accepted
**/
signals[SIG_CONNECTED] = g_signal_newv("connected",
WMUD_TYPE_CLIENT,
G_SIGNAL_RUN_LAST,
NULL,
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 0, NULL);
/**
* WmudClient::net-hup:
* @client: The client emitting the signal
*
* Emitted when the remote side closes the connection
**/
signals[SIG_NET_HUP] = g_signal_newv("net-hup",
WMUD_TYPE_CLIENT,
G_SIGNAL_RUN_LAST,
NULL,
NULL, NULL,
g_cclosure_marshal_VOID__OBJECT,
G_TYPE_NONE, 0, NULL);
/**
* WmudClient::net-recv:
* @client: The client emitting the signal
*
* Emitted when data is received through the client socket
**/
signals[SIG_NET_RECV] = g_signal_newv("net-recv",
WMUD_TYPE_CLIENT,
G_SIGNAL_RUN_LAST,
g_cclosure_new(G_CALLBACK(net_recv), NULL, NULL),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0, NULL);
g_type_class_add_private(klass, sizeof(WmudClientPrivate));
}
@ -80,6 +145,20 @@ wmud_client_init(WmudClient *self)
self->priv->socket_source = NULL;
self->priv->state = WMUD_CLIENT_STATE_FRESH;
self->priv->buffer = g_string_new("");
self->priv->last_recv = time(NULL);
g_signal_emit_by_name(self, "connected", G_TYPE_NONE);
}
static gboolean
net_emitter(GSocket *client_socket, GIOCondition condition, WmudClient *self)
{
if (condition & G_IO_HUP)
g_signal_emit_by_name(self, "net-close", G_TYPE_NONE);
else if ((condition & G_IO_IN) || (condition & G_IO_PRI))
g_signal_emit_by_name(self, "net-recv", G_TYPE_NONE);
return TRUE;
}
WmudClient *
@ -94,6 +173,8 @@ wmud_client_set_socket(WmudClient *self, GSocket *socket)
/* TODO: Check if a socket is already set! */
self->priv->socket = socket;
self->priv->socket_source = g_socket_create_source(socket, G_IO_IN | G_IO_OUT | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL, NULL);
g_source_set_callback(self->priv->socket_source, (GSourceFunc)net_emitter, self, NULL);
}
GSocket *
@ -233,3 +314,15 @@ wmud_client_get_bademail(WmudClient *self)
return self->priv->bademail;
}
void
wmud_client_set_context(WmudClient *self, GMainContext *context)
{
g_source_attach(self->priv->socket_source, context);
}
guint32
wmud_client_get_last_recv_age(WmudClient *self)
{
return (time(NULL) - self->priv->last_recv);
}

View File

@ -31,6 +31,11 @@
#define WMUD_IS_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WMUD_TYPE_CLIENT))
#define WMUD_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WMUT_TYPE_CLIENT, WmudClientClass))
/**
* WmudClient:
*
* A connected game client
*/
typedef struct _WmudClient WmudClient;
typedef struct _WmudClientClass WmudClientClass;
typedef struct _WmudClientPrivate WmudClientPrivate;
@ -102,6 +107,8 @@ void wmud_client_increase_login_fail_count(WmudClient *client);
gint wmud_client_get_login_fail_count(WmudClient *client);
void wmud_client_set_bademail(WmudClient *client, gboolean bademail);
gboolean wmud_client_get_bademail(WmudClient *client);
guint32 wmud_client_get_last_recv_age(WmudClient *client);
void wmud_client_set_context(WmudClient *client, GMainContext *context);
#endif /* __WMUD_WMUDCLIENT_H__ */