/* 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"); } }