conf.c

Go to the documentation of this file.
00001 /*
00002  * $Id$
00003  *
00004  * Copyright (C) 2009 1&1 Internet AG
00005  *
00006  * This file is part of Kamailio, a free SIP server.
00007  *
00008  * Kamailio is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version
00012  *
00013  * Kamailio is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License 
00019  * along with this program; if not, write to the Free Software 
00020  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00021  */
00022 
00023 
00024 #include "conf.h"
00025 #include "../../mem/mem.h"
00026 #include "../../mem/shm_mem.h"
00027 #include "../../sr_module.h"
00028 #include "../../proxy.h"
00029 #include <ctype.h>
00030 #include <errno.h>
00031 #include <limits.h>
00032 #include <string.h>
00033 #include <stdlib.h>
00034 #include <stdio.h>
00035 
00036 
00037 #define BUFSIZE 1000
00038 
00039 
00040 /* special filter indices */
00041 enum {
00042    sfidx_request = 0,
00043    sfidx_reply,
00044    sfilter_cnt
00045 };
00046 
00047 /*! special filter masks */
00048 static int sfilter_mask[sfilter_cnt] = { 1, 2 };
00049 
00050 /*! special filter names */
00051 static char *sfilter_str[sfilter_cnt] = {
00052    "REQUEST",
00053    "REPLY"
00054 };
00055 
00056 
00057 struct fwd_setting {
00058    int active;
00059    int sfilter;
00060    char *filter_methods;
00061    struct proxy_l* proxy;
00062 };
00063 
00064 
00065 static struct fwd_setting *fwd_settings = NULL;
00066 static int fwd_max_id = 0;
00067 
00068 
00069 /*!
00070  * \brief Removes white spaces and new lines from s
00071  * \todo check if we can use the functions from ut.h
00072  * Removes white spaces and new lines from s, the contents of s are modified.
00073  * \param s the string.
00074  */
00075 static void remove_spaces(char *s)
00076 {
00077    char *p, *dst;
00078 
00079    for (p = s, dst = s; *p != '\0'; ++p, ++dst) {
00080       while (isspace(*p)) ++p;
00081       *dst = *p;
00082    }
00083    *dst = '\0';
00084 }
00085 
00086 
00087 /*!
00088  * \brief Converts a string to integer.
00089  * \todo check if we can use the functions from ut.h
00090  *  params:
00091  *    s: The string to be converted to int.
00092  *  returns:
00093  *    >=0 on success
00094  *     -1 otherwise
00095  */
00096 static int conf_str2int(char *s)
00097 {
00098    if (s == NULL) return -1;
00099 
00100    errno = 0;
00101    char *end = NULL;
00102    long int i = strtol(s, &end, 10);
00103    if ((errno != 0) || (i == LONG_MIN) || (i == LONG_MAX) || (end == s)) {
00104       LM_ERR("invalid string '%s'.\n", s);
00105       return -1;
00106    }
00107 
00108    return i;
00109 }
00110 
00111 
00112 /*!
00113  * \brief Converts string to integer and checks for validity.
00114  * \todo check if we can use the functions from ut.h
00115  *  params:
00116  *    id_str: ID as string to be converted to int.
00117  *  returns:
00118  *    >=0 on success
00119  *     -1 otherwise
00120  */
00121 int conf_str2id(char *id_str)
00122 {
00123    int id = conf_str2int(id_str);
00124 
00125    if ((id<0) || (id > fwd_max_id)) {
00126    LM_ERR("id %d is out of range.\n", id);
00127    return -1;
00128    }
00129 
00130    return id;
00131 }
00132 
00133 
00134 /*!
00135  * \brief Updates switch configuration
00136  * \param id Update the configuration with this ID.
00137  * \param param_str can be either "off" or "on".
00138  * \return 0 on success, -1 otherwise
00139  */
00140 static int update_switch(int id, char* param_str)
00141 {
00142    if (param_str == NULL) {
00143       LM_ERR("param_str is NULL.\n");
00144       return -1;
00145    }
00146 
00147    if (strcmp(param_str, "on") == 0) {
00148       fwd_settings[id].active = 1;
00149       return 0;
00150    } else if (strcmp(param_str, "off") == 0) {
00151       fwd_settings[id].active = 0;
00152       return 0;
00153    }
00154 
00155    LM_ERR("invalid switch '%s'.\n", param_str);
00156    return -1;
00157 }
00158 
00159 
00160 /*!
00161  * \brief Updates filter configuration.
00162  * Updates filter configuration.
00163  * If filter_methods is not NULL, memory is freed.
00164  * If filter methods are found, memory for the string is allocated,
00165  * otherwise filter_methods is set to NULL.
00166  * \param id update the configuration with this ID.
00167  * \param flist a list of filter names.
00168  * \return 0 on success, -1 otherwise
00169  */
00170 static int update_filter(int id, char *flist)
00171 {
00172    if (flist == NULL) {
00173       LM_ERR("flist is NULL.\n");
00174       return -1;
00175    }
00176 
00177    /* reset special filter mask and filter methods*/
00178    fwd_settings[id].sfilter = 0;
00179    if (fwd_settings[id].filter_methods != NULL) {
00180       shm_free(fwd_settings[id].filter_methods);
00181       fwd_settings[id].filter_methods = NULL;
00182    }
00183 
00184    int i;
00185    for (i=0; i<sfilter_cnt; i++) {
00186       if (strstr(flist, sfilter_str[i]) != NULL) {
00187          /* special filter name is found in flist -> add to special filter mask */
00188          fwd_settings[id].sfilter |= sfilter_mask[i];
00189       }
00190    }
00191 
00192    char buf[BUFSIZE+1], tmp[BUFSIZE+1];
00193    buf[0] = '\0';
00194    char *set_p = flist;
00195    char *token = NULL;
00196    while ((token = strsep(&set_p, ":"))) {  /* iterate through list of filters */
00197       int found  = 0;
00198       /* is it a special filter? */
00199       for (i=0; i<sfilter_cnt; i++) {
00200          if (strcmp(token, sfilter_str[i]) == 0) {
00201             found = 1;
00202             break;
00203          }
00204       }
00205 
00206       if (found == 0) {
00207       /* no special filter! */
00208          if (buf[0]) {
00209             strcpy(tmp, buf);
00210             snprintf(buf, BUFSIZE, "%s:%s", tmp, token);
00211             buf[BUFSIZE]='\0';
00212          } else {
00213             snprintf(buf, BUFSIZE, "%s", token);
00214             buf[BUFSIZE]='\0';
00215          }
00216       }
00217    }
00218 
00219    int len = strlen(buf);
00220    if (len > 0) {
00221       char *flc = shm_malloc(len+1);
00222       if (flc == NULL) {
00223          SHM_MEM_ERROR;
00224          return -1;
00225       }
00226       memcpy(flc, buf, len+1);
00227       fwd_settings[id].filter_methods = flc;
00228    }
00229    return 0;
00230 }
00231 
00232 
00233 /*!
00234  * Updates proxy configuration
00235  * \param id update the configuration with this ID.
00236  * \param host_str the destination host.
00237  * \param port_str the port number as string.
00238  * \return 0 on success, -1 otherwise
00239  */
00240 static int update_proxy(int id, char *host_str, char *port_str)
00241 {
00242    if (host_str == NULL) {
00243       LM_ERR("host_str is NULL.\n");
00244       return -1;
00245    }
00246    if (port_str == NULL) {
00247       LM_ERR("port_str is NULL.\n");
00248       return -1;
00249    }
00250 
00251    int port = conf_str2int(port_str);
00252    if (port < 0) {
00253       LM_ERR("invalid port '%s'.\n", port_str);
00254       return -1;
00255    }
00256 
00257    /* make copy of host string since mk_proxy does not */
00258    str host;
00259    host.len = strlen(host_str);
00260    host.s = shm_malloc(host.len+1);
00261    if (host.s == NULL) {
00262       SHM_MEM_ERROR;
00263       return -1;
00264    }
00265    strcpy(host.s, host_str);
00266 
00267    /* make proxy in shared memory */
00268    struct proxy_l* proxy;
00269    proxy = mk_shm_proxy(&host, port, PROTO_UDP, 0);
00270    if (proxy == NULL) {
00271       LM_ERR("cannot make proxy (host='%s', port=%d).\n", host_str, port);
00272       shm_free(host.s);
00273       return -1;
00274    }
00275 
00276    if (fwd_settings[id].proxy) {
00277       /* cleaning up old proxy */
00278       if (fwd_settings[id].proxy->name.s) {
00279          shm_free(fwd_settings[id].proxy->name.s);
00280       }
00281       free_shm_proxy(fwd_settings[id].proxy);
00282       shm_free(fwd_settings[id].proxy);
00283    }
00284    fwd_settings[id].proxy = proxy;  /* new proxy is now acitvated */
00285 
00286    return 0;
00287 }
00288 
00289 
00290 /*!
00291  * \brief Parses configuration string for the switch
00292  * Parses a configuration string for switch settings and updates
00293  * the configuration structure.
00294  * \param settings the configuration string in the following form:
00295  *              <id>=<switch>[,<id>=<switch>]...
00296  * \return 1 on success, -1 otherwise
00297  */
00298 int conf_parse_switch(char *settings)
00299 {
00300    /* make a copy since we are modifying it */
00301    int len = strlen(settings);
00302    if (len==0) return 1;
00303    char *strc = (char *)pkg_malloc(len+1);
00304    if (strc == NULL) {
00305       PKG_MEM_ERROR;
00306       return -1;
00307    }
00308    memcpy(strc, settings, len+1);
00309    remove_spaces(strc);
00310 
00311    char *set_p = strc;
00312    char *token = NULL;
00313    while ((token = strsep(&set_p, ","))) {  /* iterate through list of settings */
00314       char *id_str = strsep(&token, "=");
00315       int id = conf_str2id(id_str);
00316       if (id < 0) {
00317          LM_ERR("cannot parse id '%s'.\n", id_str);
00318          pkg_free(strc);
00319          return -1;
00320       }
00321 
00322       /* got all data for one setting -> update configuration now */
00323       if (update_switch(id, token) < 0) {
00324          LM_ERR("cannot update switch.\n");
00325          pkg_free(strc);
00326          return -1;
00327       }
00328    }
00329 
00330    pkg_free(strc);
00331    return 1;
00332 }
00333 
00334 
00335 /*!
00336  * \brief Output configuration in FIFO format
00337  * \param rpl_tree FIFO root
00338  * \return 0 on success, -1 on failure
00339  */
00340 int conf_show(struct mi_root* rpl_tree)
00341 {
00342    int id, sfilter;
00343    struct mi_node * node = NULL;
00344 
00345    node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "id switch %30s proxy\n", "filter");
00346    if(node == NULL)
00347       goto error;
00348 
00349    for (id=0; id<=fwd_max_id; id++) {
00350       char buf[BUFSIZE+1];
00351       char tmp[BUFSIZE+1];
00352       buf[0]='\0';
00353       for (sfilter=0; sfilter<sfilter_cnt; sfilter++) {
00354          if (fwd_settings[id].sfilter&sfilter_mask[sfilter]) {
00355             if (buf[0]) {
00356                strcpy(tmp, buf);
00357                snprintf(buf, BUFSIZE, "%s:%s", tmp, sfilter_str[sfilter]);
00358                buf[BUFSIZE]='\0';
00359             } else {
00360                snprintf(buf, BUFSIZE, "%s", sfilter_str[sfilter]);
00361                buf[BUFSIZE]='\0';
00362             }
00363          }
00364       }
00365       if (fwd_settings[id].filter_methods) {
00366          if (buf[0]) {
00367             strcpy(tmp, buf);
00368             snprintf(buf, BUFSIZE, "%s:%s", tmp, fwd_settings[id].filter_methods);
00369             buf[BUFSIZE]='\0';
00370          } else {
00371             snprintf(buf, BUFSIZE, "%s", fwd_settings[id].filter_methods);
00372             buf[BUFSIZE]='\0';
00373          }
00374       }
00375       node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%2d %s %33s %s:%d\n", id,
00376          fwd_settings[id].active ? "on " : "off", buf,
00377          fwd_settings[id].proxy ? fwd_settings[id].proxy->name.s : "",
00378          fwd_settings[id].proxy ? fwd_settings[id].proxy->port : 0);
00379       if(node == NULL)
00380          goto error;
00381 
00382    }
00383    return 0;
00384 
00385 error:
00386    return -1;
00387 }
00388 
00389 
00390 /*!
00391  * \brief Parses a configuration string for the filter
00392  * Parses a configuration string for switch settings and
00393  * updates the configuration structure.
00394  * \param settings The configuration string in the following form:
00395  *              <id>=<filter>[:<filter>]...[,<id>=<filter>[:<filter>]...]...
00396  * \return 1 on success, -1 otherwise
00397  */
00398 int conf_parse_filter(char *settings)
00399 {
00400    /* make a copy since we are modifying it */
00401    int len = strlen(settings);
00402    if (len==0) return 1;
00403    char *strc = (char *)pkg_malloc(len+1);
00404    if (strc == NULL) {
00405       PKG_MEM_ERROR;
00406       return -1;
00407    }
00408    memcpy(strc, settings, len+1);
00409    remove_spaces(strc);
00410 
00411    char *set_p = strc;
00412    char *token = NULL;
00413    while ((token = strsep(&set_p, ","))) {  /* iterate through list of settings */
00414       char *id_str = strsep(&token, "=");
00415       int id = conf_str2id(id_str);
00416       if (id<0) {
00417          LM_ERR("cannot parse id '%s'.\n", id_str);
00418          pkg_free(strc);
00419          return -1;
00420       }
00421       if (update_filter(id, token) < 0) {
00422          LM_ERR("cannot extract filters.\n");
00423          pkg_free(strc);
00424          return -1;
00425       }
00426    }
00427 
00428    pkg_free(strc);
00429    return 1;
00430 }
00431 
00432 
00433 /*!
00434  * \brief Parses a configuration string for proxy settings
00435  * Parses a configuration string for proxy settings and
00436  * updates the configuration structure.
00437  * \param settings: The configuration string in the following form:
00438  *              <id>=<host>:<port>[,<id>=<host>:<port>]...
00439  * \return: 1 on success, -1 otherwise
00440  */
00441 int conf_parse_proxy(char *settings)
00442 {
00443    /* make a copy since we are modifying it */
00444    int len = strlen(settings);
00445    if (len==0) return 1;
00446    char *strc = (char *)pkg_malloc(len+1);
00447    if (strc == NULL) {
00448       PKG_MEM_ERROR;
00449       return -1;
00450    }
00451    memcpy(strc, settings, len+1);
00452    remove_spaces(strc);
00453 
00454    char *set_p = strc;
00455    char *token = NULL;
00456    while ((token = strsep(&set_p, ","))) {  /* iterate through list of settings */
00457       char *id_str = strsep(&token, "=");
00458       int id = conf_str2id(id_str);
00459       if (id<0) {
00460          LM_ERR("cannot parse id '%s'.\n", id_str);
00461          pkg_free(strc);
00462          return -1;
00463       }
00464       char *host = strsep(&token, ":");
00465 
00466       /* got all data for one setting -> update configuration now */
00467       if (update_proxy(id, host, token) < 0) {
00468          LM_ERR("cannot update proxy.\n");
00469          pkg_free(strc);
00470          return -1;
00471       }
00472    }
00473 
00474    pkg_free(strc);
00475    return 1;
00476 }
00477 
00478 
00479 /*!
00480  * \brief Checks if method string is in filter_methods
00481  * \param id use configuration with this ID when checking
00482  * \param method method string to be searched for
00483  * \param method_len length of method string
00484  * \return 1 if method is found in filter_methods, 0 otherwise
00485  */
00486 static int filter_methods_contains_request(int id, char *method, int method_len)
00487 {
00488    char *p = fwd_settings[id].filter_methods;
00489 
00490    while (p != NULL) {
00491       if (strncmp(p, method, method_len) == 0) {
00492          return 1;
00493       }
00494       p = strchr(p, ':');
00495       if (p != NULL) p++;
00496    }
00497 
00498    return 0;
00499 }
00500 
00501 
00502 /*!
00503  * \brief Checks forwarding is needed
00504  * \param msg the SIP message to be forwarded
00505  * \param id use configuration with this ID when checking
00506  * \return pointer to proxy structure of destination if forwarding is needed, NULL otherwise
00507  */
00508 struct proxy_l *conf_needs_forward(struct sip_msg *msg, int id)
00509 {
00510    if ((msg == NULL) || (fwd_settings[id].active == 0)) {
00511       return NULL;
00512    }
00513 
00514    if (msg->first_line.type == SIP_REPLY) {
00515       if (fwd_settings[id].sfilter&sfilter_mask[sfidx_reply]) {
00516          return fwd_settings[id].proxy;
00517       }
00518    }
00519 
00520    if (msg->first_line.type == SIP_REQUEST) {
00521       if (fwd_settings[id].sfilter&sfilter_mask[sfidx_request]) {
00522          return fwd_settings[id].proxy;
00523       }
00524 
00525       if (filter_methods_contains_request(id, msg->first_line.u.request.method.s, msg->first_line.u.request.method.len) > 0) {
00526          return fwd_settings[id].proxy;
00527       }
00528    }
00529 
00530    return NULL;
00531 }
00532 
00533 
00534 /*!
00535  * \brief Initialize configuration
00536  * \param max_id number of configuration statements
00537  * \return 0 on success, -1 on failure
00538  */
00539 int conf_init(int max_id)
00540 {
00541    /* allocate and initialize memory for configuration */
00542    fwd_settings = shm_malloc(sizeof(struct fwd_setting)*(max_id+1));
00543    if (fwd_settings == NULL) {
00544       SHM_MEM_ERROR;
00545       return -1;
00546    }
00547    memset(fwd_settings, 0, sizeof(struct fwd_setting)*(max_id+1));
00548    fwd_max_id = max_id;
00549    return 0;
00550 }
00551 
00552 
00553 /*!
00554  * \brief Destroy configuration
00555  */
00556 void conf_destroy(void)
00557 {
00558    int id;
00559 
00560    if (fwd_settings) {
00561       for (id=0; id<=fwd_max_id; id++) {
00562          fwd_settings[id].active = 0;
00563          if (fwd_settings[id].proxy) {
00564             if (fwd_settings[id].proxy->name.s) {
00565                shm_free(fwd_settings[id].proxy->name.s);
00566             }
00567             free_shm_proxy(fwd_settings[id].proxy);
00568             shm_free(fwd_settings[id].proxy);
00569          }
00570       }
00571       shm_free(fwd_settings);
00572    }
00573 }

Generated on Mon May 21 18:00:25 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6