From 62730556269118f3b79dbb42bd15ad86582ba55b Mon Sep 17 00:00:00 2001 From: Thomas Ries Date: Sat, 18 Jun 2011 08:23:54 +0000 Subject: [PATCH] - moved cache for Call-IDs into separate module, to be reused for all plugins - fixed memleak (call-id was not freed upon deleting) --- src/plugin_prefix.c | 107 ++---------------------------- src/redirect_cache.c | 151 +++++++++++++++++++++++++++++++++++++++++++ src/redirect_cache.h | 34 ++++++++++ 3 files changed, 190 insertions(+), 102 deletions(-) create mode 100644 src/redirect_cache.c create mode 100644 src/redirect_cache.h diff --git a/src/plugin_prefix.c b/src/plugin_prefix.c index 1c36a44..d53161f 100644 --- a/src/plugin_prefix.c +++ b/src/plugin_prefix.c @@ -45,6 +45,7 @@ #include "siproxd.h" #include "plugins.h" +#include "redirect_cache.h" #include "log.h" static char const ident[]="$Id$"; @@ -56,7 +57,6 @@ static char desc[]="Adds a dial-prefix as defined in config file"; /* constants */ #define REDIRECTED_TAG "redirected" #define REDIRECTED_VAL "prefix" -#define CACHE_TIMEOUT 20 /* global configuration storage - required for config file location */ extern struct siproxd_config configuration; @@ -75,24 +75,13 @@ static cfgopts_t plugin_cfg_opts[] = { /* local storage needed by plugin */ -/* Call-ID cache, single linked list, dynamically alocated elements */ -typedef struct { - void *next; - osip_call_id_t *call_id; - time_t ts; -} redirected_cache_element_t; - -/* The Queue Head is static */ +/* Redirect Cache: Queue Head is static */ static redirected_cache_element_t redirected_cache; /* local prototypes */ static int plugin_prefix_redirect(sip_ticket_t *ticket); static int plugin_prefix(sip_ticket_t *ticket); -static int add_to_redirected_cache(sip_ticket_t *ticket); -static int is_in_redirected_cache(sip_ticket_t *ticket); -static int expire_redirected_cache(void); - /* * Plugin API functions code @@ -158,7 +147,7 @@ static int plugin_prefix(sip_ticket_t *ticket) { return STS_SUCCESS; /* expire old cache entries */ - expire_redirected_cache(); + expire_redirected_cache(&redirected_cache); /* REQ URI with username must exist, prefix string must exist */ if (!req_url || !req_url->username || !plugin_cfg.prefix_akey) @@ -205,7 +194,7 @@ static int plugin_prefix(sip_ticket_t *ticket) { * Only consume such ACKs that are part of such a dialog. */ else if (MSG_IS_ACK(ticket->sipmsg)) { - if (is_in_redirected_cache(ticket) == STS_TRUE) { + if (is_in_redirected_cache(&redirected_cache, ticket) == STS_TRUE) { DEBUGC(DBCLASS_PLUGIN,"processing ACK (consume it)"); sts=STS_SIP_SENT; /* eat up the ACK that was directed to myself */ } @@ -224,8 +213,6 @@ static int plugin_prefix_redirect(sip_ticket_t *ticket) { size_t username_len; osip_contact_t *contact = NULL; - add_to_redirected_cache(ticket); - /* including \0 + leading character(s) */ username_len=strlen(to_user) + strlen(plugin_cfg.prefix_akey) + 1; @@ -272,92 +259,8 @@ static int plugin_prefix_redirect(sip_ticket_t *ticket) { contact->url->username=new_to_user; /* sent redirect message back to local client */ + add_to_redirected_cache(&redirected_cache, ticket); sip_gen_response(ticket, 302 /*Moved temporarily*/); return STS_SIP_SENT; } - -/* - * cache handling - */ -static int add_to_redirected_cache(sip_ticket_t *ticket) { - redirected_cache_element_t *e; - DEBUGC(DBCLASS_PLUGIN, "entered add_to_redirected_cache()"); - - /* allocate */ - e=malloc(sizeof(redirected_cache_element_t)); - if (e == NULL) { - ERROR("out of memory"); - return STS_FAILURE; - } - - /* populate element */ - e->next = NULL; - e->ts = time(NULL); - osip_call_id_clone(ticket->sipmsg->call_id, &(e->call_id)); - - /* add to head of queue */ - e->next = redirected_cache.next; - redirected_cache.next = e; - - DEBUGC(DBCLASS_PLUGIN, "left add_to_redirected_cache()"); - return STS_SUCCESS; -} - -static int is_in_redirected_cache(sip_ticket_t *ticket) { - redirected_cache_element_t *p, *p_prev; - - DEBUGC(DBCLASS_BABBLE, "entered is_in_redirected_cache"); - /* iterate through queue */ - p_prev=NULL; - for (p=&redirected_cache; p; p=p->next) { - DEBUGC(DBCLASS_BABBLE, "l: p=%p, p->next=%p", p, p->next); - if ( (p != &redirected_cache) && (p_prev != NULL) ) { - if (compare_callid(ticket->sipmsg->call_id, p->call_id) == STS_SUCCESS) { - DEBUGC(DBCLASS_BABBLE, "remove p=%p", p); - /* remove from queue */ - p_prev->next = p->next; - free(p); - DEBUGC(DBCLASS_BABBLE, "left is_in_redirected_cache - FOUND"); - return STS_TRUE; - } /* if compare_callid */ - } - p_prev = p; - } /* for */ - DEBUGC(DBCLASS_BABBLE, "left is_in_redirected_cache - NOT FOUND"); - return STS_FALSE; -} - -/* - * Run through the whole Call-Id cache and remove - * expired elements. - */ -static int expire_redirected_cache(void) { - redirected_cache_element_t *p, *p_prev; - time_t now; - - DEBUGC(DBCLASS_BABBLE, "entered expire_redirected_cache"); - now = time(NULL); - - /* iterate through queue */ - p_prev=NULL; - for (p=&redirected_cache; p; p=p->next) { - DEBUGC(DBCLASS_BABBLE, "1: p=%p, p->next=%p", p, p->next); - if ( (p != &redirected_cache) && (p_prev != NULL) ) { - DEBUGC(DBCLASS_BABBLE,"ts:%i, now:%i", (int)p->ts, (int)now); - if ((p->ts + CACHE_TIMEOUT) < now) { - DEBUGC(DBCLASS_BABBLE, "remove p=%p", p); - /* remove from queue */ - p_prev->next = p->next; - free(p); - /* the current element is being removed and invalidated, - * set the iteration pointer to a valid element. */ - p = p_prev; - } /* if timeout */ - DEBUGC(DBCLASS_BABBLE, "2: p=%p, p->next=%p", p, p->next); - } - p_prev = p; - } /* for */ - DEBUGC(DBCLASS_BABBLE, "left expire_redirected_cache"); - return STS_FALSE; -} diff --git a/src/redirect_cache.c b/src/redirect_cache.c new file mode 100644 index 0000000..31c7d66 --- /dev/null +++ b/src/redirect_cache.c @@ -0,0 +1,151 @@ +/* + Copyright (C) 2002-2011 Thomas Ries + + This file is part of Siproxd. + + Siproxd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Siproxd 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Siproxd; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "config.h" + +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include "siproxd.h" +#include "redirect_cache.h" +#include "log.h" + +static char const ident[]="$Id: plugin_prefix.c 484 2011-06-17 16:15:41Z hb9xar $"; + +#define CACHE_TIMEOUT 20 + +/* + * Helper for siproxd plugins that operate with 302 redirection + * like the plugin_shortdial, plugin_prefix or plugin_regex . + * + * The plugin must consume the ACK from the local UA caused by the + * 302 Moved response. No other ACKs must be dropped by the plugin. + * + * The recommended way is that upon sending a "302 Moved" response + * towards the local UA, the plugin does put the Call-Id of this + * dialog into a cache. Any ACK with matching Call-Id will be dropped + * (consumed by the plugin) but nothing more. + * + * Below is a set of 3 functions to implement this functionality + * inside a plugin. The whole SIP ticket will be passed, so + * modifying the matching criteria can be easily done, transparent + * to the plugins. + * + * This is the "redirected_cache". Each plugin needs its own private + * cache. A static Queue header for the cache must be created and + * passed to the cache handling functions. + * + * static redirected_cache_element_t redirected_cache; + * [...] + * add_to_redirected_cache(&redirected_cache, ticket); + * + */ + +int add_to_redirected_cache(redirected_cache_element_t *redirected_cache, sip_ticket_t *ticket) { + redirected_cache_element_t *e; + DEBUGC(DBCLASS_PLUGIN, "entered add_to_redirected_cache()"); + + /* allocate */ + e=malloc(sizeof(redirected_cache_element_t)); + if (e == NULL) { + ERROR("out of memory"); + return STS_FAILURE; + } + + /* populate element */ + e->next = NULL; + e->ts = time(NULL); + osip_call_id_clone(ticket->sipmsg->call_id, &(e->call_id)); + + /* add to head of queue */ + e->next = redirected_cache->next; + redirected_cache->next = e; + + DEBUGC(DBCLASS_PLUGIN, "left add_to_redirected_cache()"); + return STS_SUCCESS; +} + +int is_in_redirected_cache(redirected_cache_element_t *redirected_cache, sip_ticket_t *ticket) { + redirected_cache_element_t *p, *p_prev; + + DEBUGC(DBCLASS_BABBLE, "entered is_in_redirected_cache"); + /* iterate through queue */ + p_prev=NULL; + for (p=redirected_cache; p; p=p->next) { + DEBUGC(DBCLASS_BABBLE, "l: p=%p, p->next=%p", p, p->next); + if ( (p != redirected_cache) && (p_prev != NULL) ) { + if (compare_callid(ticket->sipmsg->call_id, p->call_id) == STS_SUCCESS) { + DEBUGC(DBCLASS_BABBLE, "remove p=%p", p); + /* remove from queue */ + p_prev->next = p->next; + osip_call_id_free (p->call_id); + free(p); + DEBUGC(DBCLASS_BABBLE, "left is_in_redirected_cache - FOUND"); + return STS_TRUE; + } /* if compare_callid */ + } + p_prev = p; + } /* for */ + DEBUGC(DBCLASS_BABBLE, "left is_in_redirected_cache - NOT FOUND"); + return STS_FALSE; +} + +/* + * Run through the whole Call-Id cache and remove + * expired elements. + */ +int expire_redirected_cache(redirected_cache_element_t *redirected_cache) { + redirected_cache_element_t *p, *p_prev; + time_t now; + + DEBUGC(DBCLASS_BABBLE, "entered expire_redirected_cache"); + now = time(NULL); + + /* iterate through queue */ + p_prev=NULL; + for (p=redirected_cache; p; p=p->next) { + DEBUGC(DBCLASS_BABBLE, "1: p=%p, p->next=%p", p, p->next); + if ( (p != redirected_cache) && (p_prev != NULL) ) { + DEBUGC(DBCLASS_BABBLE,"ts:%i, now:%i", (int)p->ts, (int)now); + if ((p->ts + CACHE_TIMEOUT) < now) { + DEBUGC(DBCLASS_BABBLE, "remove p=%p", p); + /* remove from queue */ + p_prev->next = p->next; + osip_call_id_free (p->call_id); + free(p); + /* the current element is being removed and invalidated, + * set the iteration pointer to a valid element. */ + p = p_prev; + } /* if timeout */ + DEBUGC(DBCLASS_BABBLE, "2: p=%p, p->next=%p", p, p->next); + } + p_prev = p; + } /* for */ + DEBUGC(DBCLASS_BABBLE, "left expire_redirected_cache"); + return STS_FALSE; +} diff --git a/src/redirect_cache.h b/src/redirect_cache.h new file mode 100644 index 0000000..78368ef --- /dev/null +++ b/src/redirect_cache.h @@ -0,0 +1,34 @@ +/* + Copyright (C) 2011 Thomas Ries + + This file is part of Siproxd. + + Siproxd is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + Siproxd 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Siproxd; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/* $Id: siproxd.h 482 2011-06-12 18:45:17Z hb9xar $ */ + +typedef struct { + void *next; + osip_call_id_t *call_id; + time_t ts; +} redirected_cache_element_t; + +/* return STS_ codes */ +int add_to_redirected_cache(redirected_cache_element_t *redirected_cache, + sip_ticket_t *ticket); +int is_in_redirected_cache( redirected_cache_element_t *redirected_cache, + sip_ticket_t *ticket); +int expire_redirected_cache(redirected_cache_element_t *redirected_cache);