/* BTP library - Banana Tree Protocol
* Copyright (C) 1999-2001 The Regents of the University of Michigan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "b_conn_handler.h"
#include "btp_debug.h"
#include "util.h"
typedef struct _BConnHandler
{
BConn* conn;
gint type;
gint subtype;
BConnHandlerReceiveFunc receive;
BConnHandlerTimeoutFunc timeout;
guint timer;
gpointer user_data;
} BConnHandler;
static BConnHandler* b_conn_handler_get (BConn* conn, gint type, gint subtype, gpointer user_data);
static gboolean handler_timeout (gpointer data);
/* ************************************************************ */
void
b_conn_handler_add (BConn* conn, gint type, gint subtype,
BConnHandlerReceiveFunc receive, gpointer user_data)
{
BTPP (9, "HANDLER ADD %p, %d, %d, %p\n", conn, type, subtype, receive);
b_conn_handler_add_full (conn, type, subtype, receive, NULL, 0, user_data);
}
void
b_conn_handler_add_full (BConn* conn, gint type, gint subtype,
BConnHandlerReceiveFunc receive,
BConnHandlerTimeoutFunc timeout, guint time,
gpointer user_data)
{
BConnHandler* handler;
g_return_if_fail (conn);
g_return_if_fail (receive);
BTPP (9, "HANDLER ADD FULL %p, %d, %d, %p\n", conn, type, subtype, receive);
handler = b_conn_handler_get (conn, type, subtype, user_data);
if (handler)
{
/* Make sure handler is identical */
g_return_if_fail (handler->receive == receive);
g_return_if_fail (handler->timeout == timeout);
/* But don't allow an identical handler */
return;
}
handler = g_new0 (BConnHandler, 1);
handler->conn = conn;
handler->type = type;
handler->subtype = subtype;
handler->receive = receive;
handler->timeout = timeout;
handler->user_data = user_data;
if (timeout)
handler->timer = g_timeout_add (time, handler_timeout, handler);
conn->handlers = g_slist_prepend (conn->handlers, handler);
}
void
b_conn_handler_remove (BConn* conn, gint type, gint subtype, gpointer user_data)
{
BConnHandler* handler;
BTPP (9, "HANDLER REMOVE %p, %d, %d\n", conn, type, subtype);
handler = b_conn_handler_get (conn, type, subtype, user_data);
if (handler)
{
conn->handlers = g_slist_remove (conn->handlers, handler);
if (handler->timer)
g_source_remove (handler->timer);
g_free (handler);
}
else
BTPP (9, "HANDLER REMOVE: NOT HERE\n");
}
void
b_conn_handler_dispatch (BConn* conn, BPacket* packet)
{
GSList* i;
GSList* handlers;
gboolean found_handler = FALSE;
g_return_if_fail (conn);
g_return_if_fail (!conn->should_destroy);
g_return_if_fail (packet);
BTPP (9, "HANDLER DISPATCH %p, %s, %d\n", conn,
b_packet_type_to_string(packet->type), packet->subtype);
handlers = g_slist_copy (conn->handlers);
for (i = handlers; i != NULL; i = i->next)
{
BConnHandler* handler = (BConnHandler*) i->data;
g_return_if_fail (handler);
/* Skip if the handler is no longer in the handler list */
if (!g_slist_find (conn->handlers, handler))
continue;
/* Dispatch if this is the appropriate handler. */
if ((handler->type == -1 || handler->type == packet->type) &&
(handler->subtype == -1 || handler->subtype == packet->subtype))
{
found_handler = TRUE;
/* Cancel the timeout */
if (handler->timer)
{
g_source_remove (handler->timer);
handler->timer = 0;
}
/* Call the function. */
BTPP (9, "HANDLER DISPATCH to %p\n", handler->receive);
handler->receive (conn, packet, handler->user_data);
/* If the conn has been destoryed, return */
if (conn->should_destroy)
return;
}
}
g_slist_free (handlers);
if (!found_handler)
{
g_warning ("Couldn't find handler for packet of type %s, %d\n",
b_packet_type_to_string(packet->type), packet->subtype);
}
}
void
b_conn_handler_remove_all (BConn* conn)
{
GSList* i;
for (i = conn->handlers; i != NULL; i = i->next)
{
BConnHandler* handler = (BConnHandler*) i->data;
if (handler->timer)
g_source_remove (handler->timer);
g_free (handler);
}
g_slist_free (conn->handlers);
conn->handlers = NULL;
}
static BConnHandler*
b_conn_handler_get (BConn* conn, gint type, gint subtype, gpointer user_data)
{
GSList* i;
for (i = conn->handlers; i != NULL; i = i->next)
{
BConnHandler* handler = (BConnHandler*) i->data;
if (handler->type == type &&
handler->subtype == subtype &&
handler->user_data == user_data)
return handler;
}
return NULL;
}
static gboolean
handler_timeout (gpointer data)
{
BConnHandler* handler = (BConnHandler*) data;
/* fprintf (stderr, "handler timeout for packet of type %s, %d\n", */
/* b_packet_type_to_string(handler->type), handler->subtype); */
/* b_conn_print (stderr, handler->conn); */
/* fprintf (stderr, "\n"); */
/* Clear timer */
handler->timer = 0;
/* Remove from handlers */
handler->conn->handlers = g_slist_remove (handler->conn->handlers, handler);
/* Call timeout function */
handler->timeout (handler->conn, handler->type, handler->subtype,
handler->user_data);
g_free (handler);
return FALSE;
}
void
b_conn_handler_print (FILE* file, BConn* conn)
{
GSList* i;
for (i = conn->handlers; i != NULL; i = i->next)
{
BConnHandler* handler = (BConnHandler*) i->data;
fprintf (file, "(%s, %d, %s) ",
b_packet_type_to_string(handler->type),
handler->subtype,
handler->timer?"timer":"no timer");
}
}
syntax highlighted by Code2HTML, v. 0.9.1