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 
00030 #include "conf.h"
00031 #include "../../mem/mem.h"
00032 #include "../../mem/shm_mem.h"
00033 #include "../../sr_module.h"
00034 #include "../../proxy.h"
00035 #include <ctype.h>
00036 #include <errno.h>
00037 #include <limits.h>
00038 #include <string.h>
00039 #include <stdlib.h>
00040 #include <stdio.h>
00041 
00042 #define BUFSIZE 1000
00043 
00045 enum {
00046         sfidx_request = 0,
00047         sfidx_reply,
00048         sfilter_cnt
00049 };
00050 
00052 static int sfilter_mask[sfilter_cnt] = { 1, 2 };
00053 
00055 static char *sfilter_str[sfilter_cnt] = {
00056         "REQUEST",
00057         "REPLY"
00058 };
00059 
00060 
00061 struct fwd_setting {
00062         int active;
00063         int sfilter;
00064         char *filter_methods;
00065         struct proxy_l* proxy;
00066 };
00067 
00068 
00069 static struct fwd_setting *fwd_settings = NULL;
00070 static int fwd_max_id = 0;
00071 
00072 
00079 static void remove_spaces(char *s)
00080 {
00081         char *p, *dst;
00082         for (p = s, dst = s; *p != '\0'; ++p) {
00083                 if (!isspace(*p)) *dst++ = *p;
00084         }
00085         *dst = '\0';
00086 
00087 }
00088 
00089 
00099 static int conf_str2int(char *s)
00100 {
00101         if (s == NULL) return -1;
00102 
00103         errno = 0;
00104         char *end = NULL;
00105         long int i = strtol(s, &end, 10);
00106         if ((errno != 0) || (i == LONG_MIN) || (i == LONG_MAX) || (end == s)) {
00107                 LM_ERR("invalid string '%s'.\n", s);
00108                 return -1;
00109         }
00110 
00111         return i;
00112 }
00113 
00114 
00124 int conf_str2id(char *id_str)
00125 {
00126         int id = conf_str2int(id_str);
00127 
00128         if ((id<0) || (id > fwd_max_id)) {
00129         LM_ERR("id %d is out of range.\n", id);
00130         return -1;
00131         }
00132 
00133         return id;
00134 }
00135 
00136 
00143 static int update_switch(int id, char* param_str)
00144 {
00145         if (param_str == NULL) {
00146                 LM_ERR("param_str is NULL.\n");
00147                 return -1;
00148         }
00149 
00150         if (strcmp(param_str, "on") == 0) {
00151                 fwd_settings[id].active = 1;
00152                 return 0;
00153         } else if (strcmp(param_str, "off") == 0) {
00154                 fwd_settings[id].active = 0;
00155                 return 0;
00156         }
00157 
00158         LM_ERR("invalid switch '%s'.\n", param_str);
00159         return -1;
00160 }
00161 
00162 
00173 static int update_filter(int id, char *flist)
00174 {
00175         if (flist == NULL) {
00176                 LM_ERR("flist is NULL.\n");
00177                 return -1;
00178         }
00179 
00180         /* reset special filter mask and filter methods*/
00181         fwd_settings[id].sfilter = 0;
00182         if (fwd_settings[id].filter_methods != NULL) {
00183                 shm_free(fwd_settings[id].filter_methods);
00184                 fwd_settings[id].filter_methods = NULL;
00185         }
00186 
00187         int i;
00188         for (i=0; i<sfilter_cnt; i++) {
00189                 if (strstr(flist, sfilter_str[i]) != NULL) {
00190                         /* special filter name is found in flist -> add to special filter mask */
00191                         fwd_settings[id].sfilter |= sfilter_mask[i];
00192                 }
00193         }
00194 
00195         char buf[BUFSIZE+1], tmp[BUFSIZE+1];
00196         buf[0] = '\0';
00197         char *set_p = flist;
00198         char *token = NULL;
00199         while ((token = strsep(&set_p, ":"))) {  /* iterate through list of filters */
00200                 int found  = 0;
00201                 /* is it a special filter? */
00202                 for (i=0; i<sfilter_cnt; i++) {
00203                         if (strcmp(token, sfilter_str[i]) == 0) {
00204                                 found = 1;
00205                                 break;
00206                         }
00207                 }
00208 
00209                 if (found == 0) {
00210                 /* no special filter! */
00211                         if (buf[0]) {
00212                                 strcpy(tmp, buf);
00213                                 snprintf(buf, BUFSIZE, "%s:%s", tmp, token);
00214                                 buf[BUFSIZE]='\0';
00215                         } else {
00216                                 snprintf(buf, BUFSIZE, "%s", token);
00217                                 buf[BUFSIZE]='\0';
00218                         }
00219                 }
00220         }
00221 
00222         int len = strlen(buf);
00223         if (len > 0) {
00224                 char *flc = shm_malloc(len+1);
00225                 if (flc == NULL) {
00226                         SHM_MEM_ERROR;
00227                         return -1;
00228                 }
00229                 memcpy(flc, buf, len+1);
00230                 fwd_settings[id].filter_methods = flc;
00231         }
00232         return 0;
00233 }
00234 
00235 
00243 static int update_proxy(int id, char *host_str, char *port_str)
00244 {
00245         if (host_str == NULL) {
00246                 LM_ERR("host_str is NULL.\n");
00247                 return -1;
00248         }
00249         if (port_str == NULL) {
00250                 LM_ERR("port_str is NULL.\n");
00251                 return -1;
00252         }
00253 
00254         int port = conf_str2int(port_str);
00255         if (port < 0) {
00256                 LM_ERR("invalid port '%s'.\n", port_str);
00257                 return -1;
00258         }
00259 
00260         /* make copy of host string since mk_proxy does not */
00261         str host;
00262         host.len = strlen(host_str);
00263         host.s = shm_malloc(host.len+1);
00264         if (host.s == NULL) {
00265                 SHM_MEM_ERROR;
00266                 return -1;
00267         }
00268         strcpy(host.s, host_str);
00269 
00270         /* make proxy in shared memory */
00271         struct proxy_l* proxy;
00272         proxy = mk_shm_proxy(&host, port, PROTO_UDP);
00273         if (proxy == NULL) {
00274                 LM_ERR("cannot make proxy (host='%s', port=%d).\n", host_str, port);
00275                 shm_free(host.s);
00276                 return -1;
00277         }
00278 
00279         if (fwd_settings[id].proxy) {
00280                 /* cleaning up old proxy */
00281                 if (fwd_settings[id].proxy->name.s) {
00282                         shm_free(fwd_settings[id].proxy->name.s);
00283                 }
00284                 free_shm_proxy(fwd_settings[id].proxy);
00285                 shm_free(fwd_settings[id].proxy);
00286         }
00287         fwd_settings[id].proxy = proxy;  /* new proxy is now acitvated */
00288 
00289         return 0;
00290 }
00291 
00292 
00303 int conf_parse_switch(char *settings)
00304 {
00305         /* make a copy since we are modifying it */
00306         int len = strlen(settings);
00307         if (len==0) return 1;
00308         char *strc = (char *)pkg_malloc(len+1);
00309         if (strc == NULL) {
00310                 PKG_MEM_ERROR;
00311                 return -1;
00312         }
00313         memcpy(strc, settings, len+1);
00314         remove_spaces(strc);
00315 
00316         char *set_p = strc;
00317         char *token = NULL;
00318         while ((token = strsep(&set_p, ","))) {  /* iterate through list of settings */
00319                 char *id_str = strsep(&token, "=");
00320                 int id = conf_str2id(id_str);
00321                 if (id < 0) {
00322                         LM_ERR("cannot parse id '%s'.\n", id_str);
00323                         pkg_free(strc);
00324                         return -1;
00325                 }
00326 
00327                 /* got all data for one setting -> update configuration now */
00328                 if (update_switch(id, token) < 0) {
00329                         LM_ERR("cannot update switch.\n");
00330                         pkg_free(strc);
00331                         return -1;
00332                 }
00333         }
00334 
00335         pkg_free(strc);
00336         return 1;
00337 }
00338 
00339 
00345 int conf_show(struct mi_root* rpl_tree)
00346 {
00347         int id, sfilter;
00348         struct mi_node * node = NULL;
00349 
00350         node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "id switch %30s proxy\n", "filter");
00351         if(node == NULL)
00352                 goto error;
00353 
00354         for (id=0; id<=fwd_max_id; id++) {
00355                 char buf[BUFSIZE+1];
00356                 char tmp[BUFSIZE+1];
00357                 buf[0]='\0';
00358                 for (sfilter=0; sfilter<sfilter_cnt; sfilter++) {
00359                         if (fwd_settings[id].sfilter&sfilter_mask[sfilter]) {
00360                                 if (buf[0]) {
00361                                         strcpy(tmp, buf);
00362                                         snprintf(buf, BUFSIZE, "%s:%s", tmp, sfilter_str[sfilter]);
00363                                         buf[BUFSIZE]='\0';
00364                                 } else {
00365                                         snprintf(buf, BUFSIZE, "%s", sfilter_str[sfilter]);
00366                                         buf[BUFSIZE]='\0';
00367                                 }
00368                         }
00369                 }
00370                 if (fwd_settings[id].filter_methods) {
00371                         if (buf[0]) {
00372                                 strcpy(tmp, buf);
00373                                 snprintf(buf, BUFSIZE, "%s:%s", tmp, fwd_settings[id].filter_methods);
00374                                 buf[BUFSIZE]='\0';
00375                         } else {
00376                                 snprintf(buf, BUFSIZE, "%s", fwd_settings[id].filter_methods);
00377                                 buf[BUFSIZE]='\0';
00378                         }
00379                 }
00380                 node = addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%2d %s %33s %s:%d\n", id,
00381                         fwd_settings[id].active ? "on " : "off", buf,
00382                         fwd_settings[id].proxy ? fwd_settings[id].proxy->name.s : "",
00383                         fwd_settings[id].proxy ? fwd_settings[id].proxy->port : 0);
00384                 if(node == NULL)
00385                         goto error;
00386 
00387         }
00388         return 0;
00389 
00390 error:
00391         return -1;
00392 }
00393 
00394 
00405 int conf_parse_filter(char *settings)
00406 {
00407         /* make a copy since we are modifying it */
00408         int len = strlen(settings);
00409         if (len==0) return 1;
00410         char *strc = (char *)pkg_malloc(len+1);
00411         if (strc == NULL) {
00412                 PKG_MEM_ERROR;
00413                 return -1;
00414         }
00415         memcpy(strc, settings, len+1);
00416         remove_spaces(strc);
00417 
00418         char *set_p = strc;
00419         char *token = NULL;
00420         while ((token = strsep(&set_p, ","))) {  /* iterate through list of settings */
00421                 char *id_str = strsep(&token, "=");
00422                 int id = conf_str2id(id_str);
00423                 if (id<0) {
00424                         LM_ERR("cannot parse id '%s'.\n", id_str);
00425                         pkg_free(strc);
00426                         return -1;
00427                 }
00428                 if (update_filter(id, token) < 0) {
00429                         LM_ERR("cannot extract filters.\n");
00430                         pkg_free(strc);
00431                         return -1;
00432                 }
00433         }
00434 
00435         pkg_free(strc);
00436         return 1;
00437 }
00438 
00439 
00450 int conf_parse_proxy(char *settings)
00451 {
00452         /* make a copy since we are modifying it */
00453         int len = strlen(settings);
00454         if (len==0) return 1;
00455         char *strc = (char *)pkg_malloc(len+1);
00456         if (strc == NULL) {
00457                 PKG_MEM_ERROR;
00458                 return -1;
00459         }
00460         memcpy(strc, settings, len+1);
00461         remove_spaces(strc);
00462 
00463         char *set_p = strc;
00464         char *token = NULL;
00465         while ((token = strsep(&set_p, ","))) {  /* iterate through list of settings */
00466                 char *id_str = strsep(&token, "=");
00467                 int id = conf_str2id(id_str);
00468                 if (id<0) {
00469                         LM_ERR("cannot parse id '%s'.\n", id_str);
00470                         pkg_free(strc);
00471                         return -1;
00472                 }
00473                 char *host = strsep(&token, ":");
00474 
00475                 /* got all data for one setting -> update configuration now */
00476                 if (update_proxy(id, host, token) < 0) {
00477                         LM_ERR("cannot update proxy.\n");
00478                         pkg_free(strc);
00479                         return -1;
00480                 }
00481         }
00482 
00483         pkg_free(strc);
00484         return 1;
00485 }
00486 
00487 
00495 static int filter_methods_contains_request(int id, char *method, int method_len)
00496 {
00497         char *p = fwd_settings[id].filter_methods;
00498 
00499         while (p != NULL) {
00500                 if (strncmp(p, method, method_len) == 0) {
00501                         return 1;
00502                 }
00503                 p = strchr(p, ':');
00504                 if (p != NULL) p++;
00505         }
00506 
00507         return 0;
00508 }
00509 
00510 
00517 struct proxy_l *conf_needs_forward(struct sip_msg *msg, int id)
00518 {
00519         if ((msg == NULL) || (fwd_settings[id].active == 0)) {
00520                 return NULL;
00521         }
00522 
00523         if (msg->first_line.type == SIP_REPLY) {
00524                 if (fwd_settings[id].sfilter&sfilter_mask[sfidx_reply]) {
00525                         return fwd_settings[id].proxy;
00526                 }
00527         }
00528 
00529         if (msg->first_line.type == SIP_REQUEST) {
00530                 if (fwd_settings[id].sfilter&sfilter_mask[sfidx_request]) {
00531                         return fwd_settings[id].proxy;
00532                 }
00533 
00534                 if (filter_methods_contains_request(id, msg->first_line.u.request.method.s, msg->first_line.u.request.method.len) > 0) {
00535                         return fwd_settings[id].proxy;
00536                 }
00537         }
00538 
00539         return NULL;
00540 }
00541 
00542 
00548 int conf_init(int max_id)
00549 {
00550         /* allocate and initialize memory for configuration */
00551         fwd_settings = shm_malloc(sizeof(struct fwd_setting)*(max_id+1));
00552         if (fwd_settings == NULL) {
00553                 SHM_MEM_ERROR;
00554                 return -1;
00555         }
00556         memset(fwd_settings, 0, sizeof(struct fwd_setting)*(max_id+1));
00557         fwd_max_id = max_id;
00558         return 0;
00559 }
00560 
00561 
00565 void conf_destroy(void)
00566 {
00567         int id;
00568 
00569         if (fwd_settings) {
00570                 for (id=0; id<=fwd_max_id; id++) {
00571                         fwd_settings[id].active = 0;
00572                         if (fwd_settings[id].proxy) {
00573                                 if (fwd_settings[id].proxy->name.s) {
00574                                         shm_free(fwd_settings[id].proxy->name.s);
00575                                 }
00576                                 free_shm_proxy(fwd_settings[id].proxy);
00577                                 shm_free(fwd_settings[id].proxy);
00578                         }
00579                 }
00580                 shm_free(fwd_settings);
00581         }
00582 }