123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582 |
- /*
- * $Id$
- *
- * Copyright (C) 2009 1&1 Internet AG
- *
- * This file is part of Kamailio, a free SIP server.
- *
- * Kamailio 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
- *
- * Kamailio 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 this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- /*!
- * \file
- * \brief SIP-router utils ::
- * \ingroup utils
- * Module: \ref utils
- */
- #include "conf.h"
- #include "../../mem/mem.h"
- #include "../../mem/shm_mem.h"
- #include "../../sr_module.h"
- #include "../../proxy.h"
- #include <ctype.h>
- #include <errno.h>
- #include <limits.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #define BUFSIZE 1000
- /*! \brief special filter indices */
- enum {
- sfidx_request = 0,
- sfidx_reply,
- sfilter_cnt
- };
- /*! special filter masks */
- static int sfilter_mask[sfilter_cnt] = { 1, 2 };
- /*! special filter names */
- static char *sfilter_str[sfilter_cnt] = {
- "REQUEST",
- "REPLY"
- };
- struct fwd_setting {
- int active;
- int sfilter;
- char *filter_methods;
- struct proxy_l* proxy;
- };
- static struct fwd_setting *fwd_settings = NULL;
- static int fwd_max_id = 0;
- /*!
- * \brief Removes white spaces and new lines from s
- * \todo check if we can use the functions from ut.h
- * Removes white spaces and new lines from s, the contents of s are modified.
- * \param s the string.
- */
- static void remove_spaces(char *s)
- {
- char *p, *dst;
- for (p = s, dst = s; *p != '\0'; ++p) {
- if (!isspace(*p)) *dst++ = *p;
- }
- *dst = '\0';
- }
- /*!
- * \brief Converts a string to integer.
- * \todo check if we can use the functions from ut.h
- * params:
- * s: The string to be converted to int.
- * returns:
- * >=0 on success
- * -1 otherwise
- */
- static int conf_str2int(char *s)
- {
- if (s == NULL) return -1;
- errno = 0;
- char *end = NULL;
- long int i = strtol(s, &end, 10);
- if ((errno != 0) || (i == LONG_MIN) || (i == LONG_MAX) || (end == s)) {
- LM_ERR("invalid string '%s'.\n", s);
- return -1;
- }
- return i;
- }
- /*!
- * \brief Converts string to integer and checks for validity.
- * \todo check if we can use the functions from ut.h
- * params:
- * id_str: ID as string to be converted to int.
- * returns:
- * >=0 on success
- * -1 otherwise
- */
- int conf_str2id(char *id_str)
- {
- int id = conf_str2int(id_str);
- if ((id<0) || (id > fwd_max_id)) {
- LM_ERR("id %d is out of range.\n", id);
- return -1;
- }
- return id;
- }
- /*!
- * \brief Updates switch configuration
- * \param id Update the configuration with this ID.
- * \param param_str can be either "off" or "on".
- * \return 0 on success, -1 otherwise
- */
- static int update_switch(int id, char* param_str)
- {
- if (param_str == NULL) {
- LM_ERR("param_str is NULL.\n");
- return -1;
- }
- if (strcmp(param_str, "on") == 0) {
- fwd_settings[id].active = 1;
- return 0;
- } else if (strcmp(param_str, "off") == 0) {
- fwd_settings[id].active = 0;
- return 0;
- }
- LM_ERR("invalid switch '%s'.\n", param_str);
- return -1;
- }
- /*!
- * \brief Updates filter configuration.
- * Updates filter configuration.
- * If filter_methods is not NULL, memory is freed.
- * If filter methods are found, memory for the string is allocated,
- * otherwise filter_methods is set to NULL.
- * \param id update the configuration with this ID.
- * \param flist a list of filter names.
- * \return 0 on success, -1 otherwise
- */
- static int update_filter(int id, char *flist)
- {
- if (flist == NULL) {
- LM_ERR("flist is NULL.\n");
- return -1;
- }
- /* reset special filter mask and filter methods*/
- fwd_settings[id].sfilter = 0;
- if (fwd_settings[id].filter_methods != NULL) {
- shm_free(fwd_settings[id].filter_methods);
- fwd_settings[id].filter_methods = NULL;
- }
- int i;
- for (i=0; i<sfilter_cnt; i++) {
- if (strstr(flist, sfilter_str[i]) != NULL) {
- /* special filter name is found in flist -> add to special filter mask */
- fwd_settings[id].sfilter |= sfilter_mask[i];
- }
- }
- char buf[BUFSIZE+1], tmp[BUFSIZE+1];
- buf[0] = '\0';
- char *set_p = flist;
- char *token = NULL;
- while ((token = strsep(&set_p, ":"))) { /* iterate through list of filters */
- int found = 0;
- /* is it a special filter? */
- for (i=0; i<sfilter_cnt; i++) {
- if (strcmp(token, sfilter_str[i]) == 0) {
- found = 1;
- break;
- }
- }
- if (found == 0) {
- /* no special filter! */
- if (buf[0]) {
- strcpy(tmp, buf);
- snprintf(buf, BUFSIZE, "%s:%s", tmp, token);
- buf[BUFSIZE]='\0';
- } else {
- snprintf(buf, BUFSIZE, "%s", token);
- buf[BUFSIZE]='\0';
- }
- }
- }
- int len = strlen(buf);
- if (len > 0) {
- char *flc = shm_malloc(len+1);
- if (flc == NULL) {
- SHM_MEM_ERROR;
- return -1;
- }
- memcpy(flc, buf, len+1);
- fwd_settings[id].filter_methods = flc;
- }
- return 0;
- }
- /*!
- * Updates proxy configuration
- * \param id update the configuration with this ID.
- * \param host_str the destination host.
- * \param port_str the port number as string.
- * \return 0 on success, -1 otherwise
- */
- static int update_proxy(int id, char *host_str, char *port_str)
- {
- if (host_str == NULL) {
- LM_ERR("host_str is NULL.\n");
- return -1;
- }
- if (port_str == NULL) {
- LM_ERR("port_str is NULL.\n");
- return -1;
- }
- int port = conf_str2int(port_str);
- if (port < 0) {
- LM_ERR("invalid port '%s'.\n", port_str);
- return -1;
- }
- /* make copy of host string since mk_proxy does not */
- str host;
- host.len = strlen(host_str);
- host.s = shm_malloc(host.len+1);
- if (host.s == NULL) {
- SHM_MEM_ERROR;
- return -1;
- }
- strcpy(host.s, host_str);
- /* make proxy in shared memory */
- struct proxy_l* proxy;
- proxy = mk_shm_proxy(&host, port, PROTO_UDP);
- if (proxy == NULL) {
- LM_ERR("cannot make proxy (host='%s', port=%d).\n", host_str, port);
- shm_free(host.s);
- return -1;
- }
- if (fwd_settings[id].proxy) {
- /* cleaning up old proxy */
- if (fwd_settings[id].proxy->name.s) {
- shm_free(fwd_settings[id].proxy->name.s);
- }
- free_shm_proxy(fwd_settings[id].proxy);
- shm_free(fwd_settings[id].proxy);
- }
- fwd_settings[id].proxy = proxy; /* new proxy is now acitvated */
- return 0;
- }
- /*!
- * \brief Parses configuration string for the switch
- * Parses a configuration string for switch settings and updates
- * the configuration structure.
- * \param settings the configuration string in the following form:
- \verbatim
- * <id>=<switch>[,<id>=<switch>]...
- \endverbatim
- * \return 1 on success, -1 otherwise
- */
- int conf_parse_switch(char *settings)
- {
- /* make a copy since we are modifying it */
- int len = strlen(settings);
- if (len==0) return 1;
- char *strc = (char *)pkg_malloc(len+1);
- if (strc == NULL) {
- PKG_MEM_ERROR;
- return -1;
- }
- memcpy(strc, settings, len+1);
- remove_spaces(strc);
- char *set_p = strc;
- char *token = NULL;
- while ((token = strsep(&set_p, ","))) { /* iterate through list of settings */
- char *id_str = strsep(&token, "=");
- int id = conf_str2id(id_str);
- if (id < 0) {
- LM_ERR("cannot parse id '%s'.\n", id_str);
- pkg_free(strc);
- return -1;
- }
- /* got all data for one setting -> update configuration now */
- if (update_switch(id, token) < 0) {
- LM_ERR("cannot update switch.\n");
- pkg_free(strc);
- return -1;
- }
- }
- pkg_free(strc);
- return 1;
- }
- /*!
- * \brief Output configuration in FIFO format
- * \param rpl_tree FIFO root
- * \return 0 on success, -1 on failure
- */
- int conf_show(struct mi_root* rpl_tree)
- {
- int id, sfilter;
- struct mi_node * node = NULL;
- node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "id switch %30s proxy\n", "filter");
- if(node == NULL)
- goto error;
- for (id=0; id<=fwd_max_id; id++) {
- char buf[BUFSIZE+1];
- char tmp[BUFSIZE+1];
- buf[0]='\0';
- for (sfilter=0; sfilter<sfilter_cnt; sfilter++) {
- if (fwd_settings[id].sfilter&sfilter_mask[sfilter]) {
- if (buf[0]) {
- strcpy(tmp, buf);
- snprintf(buf, BUFSIZE, "%s:%s", tmp, sfilter_str[sfilter]);
- buf[BUFSIZE]='\0';
- } else {
- snprintf(buf, BUFSIZE, "%s", sfilter_str[sfilter]);
- buf[BUFSIZE]='\0';
- }
- }
- }
- if (fwd_settings[id].filter_methods) {
- if (buf[0]) {
- strcpy(tmp, buf);
- snprintf(buf, BUFSIZE, "%s:%s", tmp, fwd_settings[id].filter_methods);
- buf[BUFSIZE]='\0';
- } else {
- snprintf(buf, BUFSIZE, "%s", fwd_settings[id].filter_methods);
- buf[BUFSIZE]='\0';
- }
- }
- node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%2d %s %33s %s:%d\n", id,
- fwd_settings[id].active ? "on " : "off", buf,
- fwd_settings[id].proxy ? fwd_settings[id].proxy->name.s : "",
- fwd_settings[id].proxy ? fwd_settings[id].proxy->port : 0);
- if(node == NULL)
- goto error;
- }
- return 0;
- error:
- return -1;
- }
- /*!
- * \brief Parses a configuration string for the filter
- * Parses a configuration string for switch settings and
- * updates the configuration structure.
- * \param settings The configuration string in the following form:
- \verbatim
- * <id>=<filter>[:<filter>]...[,<id>=<filter>[:<filter>]...]...
- \endverbatim
- * \return 1 on success, -1 otherwise
- */
- int conf_parse_filter(char *settings)
- {
- /* make a copy since we are modifying it */
- int len = strlen(settings);
- if (len==0) return 1;
- char *strc = (char *)pkg_malloc(len+1);
- if (strc == NULL) {
- PKG_MEM_ERROR;
- return -1;
- }
- memcpy(strc, settings, len+1);
- remove_spaces(strc);
- char *set_p = strc;
- char *token = NULL;
- while ((token = strsep(&set_p, ","))) { /* iterate through list of settings */
- char *id_str = strsep(&token, "=");
- int id = conf_str2id(id_str);
- if (id<0) {
- LM_ERR("cannot parse id '%s'.\n", id_str);
- pkg_free(strc);
- return -1;
- }
- if (update_filter(id, token) < 0) {
- LM_ERR("cannot extract filters.\n");
- pkg_free(strc);
- return -1;
- }
- }
- pkg_free(strc);
- return 1;
- }
- /*!
- * \brief Parses a configuration string for proxy settings
- * Parses a configuration string for proxy settings and
- * updates the configuration structure.
- * \param settings: The configuration string in the following form:
- \verbatim
- * <id>=<host>:<port>[,<id>=<host>:<port>]...
- \endverbatim
- * \return: 1 on success, -1 otherwise
- */
- int conf_parse_proxy(char *settings)
- {
- /* make a copy since we are modifying it */
- int len = strlen(settings);
- if (len==0) return 1;
- char *strc = (char *)pkg_malloc(len+1);
- if (strc == NULL) {
- PKG_MEM_ERROR;
- return -1;
- }
- memcpy(strc, settings, len+1);
- remove_spaces(strc);
- char *set_p = strc;
- char *token = NULL;
- while ((token = strsep(&set_p, ","))) { /* iterate through list of settings */
- char *id_str = strsep(&token, "=");
- int id = conf_str2id(id_str);
- if (id<0) {
- LM_ERR("cannot parse id '%s'.\n", id_str);
- pkg_free(strc);
- return -1;
- }
- char *host = strsep(&token, ":");
- /* got all data for one setting -> update configuration now */
- if (update_proxy(id, host, token) < 0) {
- LM_ERR("cannot update proxy.\n");
- pkg_free(strc);
- return -1;
- }
- }
- pkg_free(strc);
- return 1;
- }
- /*!
- * \brief Checks if method string is in filter_methods
- * \param id use configuration with this ID when checking
- * \param method method string to be searched for
- * \param method_len length of method string
- * \return 1 if method is found in filter_methods, 0 otherwise
- */
- static int filter_methods_contains_request(int id, char *method, int method_len)
- {
- char *p = fwd_settings[id].filter_methods;
- while (p != NULL) {
- if (strncmp(p, method, method_len) == 0) {
- return 1;
- }
- p = strchr(p, ':');
- if (p != NULL) p++;
- }
- return 0;
- }
- /*!
- * \brief Checks forwarding is needed
- * \param msg the SIP message to be forwarded
- * \param id use configuration with this ID when checking
- * \return pointer to proxy structure of destination if forwarding is needed, NULL otherwise
- */
- struct proxy_l *conf_needs_forward(struct sip_msg *msg, int id)
- {
- if ((msg == NULL) || (fwd_settings[id].active == 0)) {
- return NULL;
- }
- if (msg->first_line.type == SIP_REPLY) {
- if (fwd_settings[id].sfilter&sfilter_mask[sfidx_reply]) {
- return fwd_settings[id].proxy;
- }
- }
- if (msg->first_line.type == SIP_REQUEST) {
- if (fwd_settings[id].sfilter&sfilter_mask[sfidx_request]) {
- return fwd_settings[id].proxy;
- }
- if (filter_methods_contains_request(id, msg->first_line.u.request.method.s, msg->first_line.u.request.method.len) > 0) {
- return fwd_settings[id].proxy;
- }
- }
- return NULL;
- }
- /*!
- * \brief Initialize configuration
- * \param max_id number of configuration statements
- * \return 0 on success, -1 on failure
- */
- int conf_init(int max_id)
- {
- /* allocate and initialize memory for configuration */
- fwd_settings = shm_malloc(sizeof(struct fwd_setting)*(max_id+1));
- if (fwd_settings == NULL) {
- SHM_MEM_ERROR;
- return -1;
- }
- memset(fwd_settings, 0, sizeof(struct fwd_setting)*(max_id+1));
- fwd_max_id = max_id;
- return 0;
- }
- /*!
- * \brief Destroy configuration
- */
- void conf_destroy(void)
- {
- int id;
- if (fwd_settings) {
- for (id=0; id<=fwd_max_id; id++) {
- fwd_settings[id].active = 0;
- if (fwd_settings[id].proxy) {
- if (fwd_settings[id].proxy->name.s) {
- shm_free(fwd_settings[id].proxy->name.s);
- }
- free_shm_proxy(fwd_settings[id].proxy);
- shm_free(fwd_settings[id].proxy);
- }
- }
- shm_free(fwd_settings);
- }
- }
|