📄 cpl.c
字号:
/* * $Id: cpl.c,v 1.51.2.3 2005/06/21 17:52:13 andrei Exp $ * * Copyright (C) 2001-2003 FhG Fokus * * This file is part of ser, a free SIP server. * * ser 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 * * For a license to use the ser software under conditions * other than those described here, or to purchase support for this * software, please contact iptel.org by e-mail at the following addresses: * info@iptel.org * * ser 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * History: * ------- * 2003-03-11: New module interface (janakj) * 2003-03-16: flags export parameter added (janakj) * 2003-11-11: build_lump_rpl() removed, add_lump_rpl() has flags (bogdan) * 2004-06-06 updated to the new DB api (andrei) * 2004-06-14: all global variables merged into cpl_env and cpl_fct; * case_sensitive and realm_prefix added for building AORs - see * build_userhost (bogdan) * 2004-10-09: added process_register_norpl to allow register processing * without sending the reply(bogdan) - based on a patch sent by * Christopher Crawford */#include <stdio.h>#include <string.h>#include <sys/types.h>#include <sys/stat.h>#include <unistd.h>#include <fcntl.h>#include <signal.h>#include "../../mem/shm_mem.h"#include "../../mem/mem.h"#include "../../sr_module.h"#include "../../str.h"#include "../../ut.h"#include "../../dprint.h"#include "../../data_lump_rpl.h"#include "../../fifo_server.h"#include "../../usr_avp.h"#include "../../parser/parse_uri.h"#include "../../parser/parse_from.h"#include "../../parser/parse_content.h"#include "../../parser/parse_disposition.h"#include "../../db/db.h"#include "cpl_run.h"#include "cpl_env.h"#include "cpl_db.h"#include "cpl_loader.h"#include "cpl_parser.h"#include "cpl_nonsig.h"#include "loc_set.h"#define MAX_PROXY_RECURSE 10#define MAX_USERHOST_LEN 256/* modules param variables */static char *DB_URL = 0; /* database url */static char *DB_TABLE = 0; /* */static char *dtd_file = 0; /* name of the DTD file for CPL parser */static char *lookup_domain = 0;static pid_t aux_process = 0; /* pid of the private aux. process */static char *timer_avp = 0; /* name of variable timer AVP */struct cpl_enviroment cpl_env = { 0, /* no cpl logging */ 0, /* recurse proxy level is 0 */ 0, /* no script route to be run before proxy */ 6, /* nat flag */ 0, /* user part is not case sensitive */ {0,0}, /* no domain prefix to be ignored */ {-1,-1}, /* communication pipe to aux_process */ {0,0}, /* original TZ \0 terminated "TZ=value" format */ 0, /* udomain */ 0, /* no branches on lookup */ 0, /* timer avp type */ /*(int_str)*/{ 0 } /* timer avp name/ID */};struct cpl_functions cpl_fct;MODULE_VERSIONstatic int cpl_invoke_script (struct sip_msg* msg, char* str, char* str2);static int w_process_register(struct sip_msg* msg, char* str, char* str2);static int w_process_register_norpl(struct sip_msg* msg, char* str,char* str2);static int cpl_process_register(struct sip_msg* msg, int no_rpl);static int fixup_cpl_run_script(void** param, int param_no);static int cpl_init(void);static int cpl_child_init(int rank);static int cpl_exit(void);/* * Exported functions */static cmd_export_t cmds[] = { {"cpl_run_script",cpl_invoke_script,2,fixup_cpl_run_script,REQUEST_ROUTE}, {"cpl_process_register",w_process_register,0,0,REQUEST_ROUTE}, {"cpl_process_register_norpl",w_process_register_norpl,0,0,REQUEST_ROUTE}, {0, 0, 0, 0, 0}};/* * Exported parameters */static param_export_t params[] = { {"cpl_db", STR_PARAM, &DB_URL }, {"cpl_table", STR_PARAM, &DB_TABLE }, {"cpl_dtd_file", STR_PARAM, &dtd_file }, {"proxy_recurse", INT_PARAM, &cpl_env.proxy_recurse }, {"proxy_route", INT_PARAM, &cpl_env.proxy_route }, {"nat_flag", INT_PARAM, &cpl_env.nat_flag }, {"log_dir", STR_PARAM, &cpl_env.log_dir }, {"case_sensitive", INT_PARAM, &cpl_env.case_sensitive }, {"realm_prefix", STR_PARAM, &cpl_env.realm_prefix.s }, {"lookup_domain", STR_PARAM, &lookup_domain }, {"lookup_append_branches", INT_PARAM, &cpl_env.lu_append_branches}, {"timer_avp", STR_PARAM, &timer_avp }, {0, 0, 0}};struct module_exports exports = { "cpl-c", cmds, /* Exported functions */ params, /* Exported parameters */ cpl_init, /* Module initialization function */ (response_function) 0, (destroy_function) cpl_exit, 0, (child_init_function) cpl_child_init /* per-child init function */};static int fixup_cpl_run_script(void** param, int param_no){ long flag; if (param_no==1) { if (!strcasecmp( "incoming", *param)) flag = CPL_RUN_INCOMING; else if (!strcasecmp( "outgoing", *param)) flag = CPL_RUN_OUTGOING; else { LOG(L_ERR,"ERROR:fixup_cpl_run_script: script directive \"%s\"" " unknown!\n",(char*)*param); return E_UNSPEC; } pkg_free(*param); *param=(void*)flag; return 0; } else if (param_no==2) { if ( !strcasecmp("is_stateless", *param) ) { flag = 0; } else if ( !strcasecmp("is_stateful", *param) ) { flag = CPL_IS_STATEFUL; } else if ( !strcasecmp("force_stateful", *param) ) { flag = CPL_FORCE_STATEFUL; } else { LOG(L_ERR,"ERROR:fixup_cpl_run_script: flag \"%s\" (second param)" " unknown!\n",(char*)*param); return E_UNSPEC; } pkg_free(*param); *param=(void*)flag; } return 0;}static int cpl_init(void){ bind_usrloc_t bind_usrloc; load_tm_f load_tm; struct stat stat_t; char *ptr; int val; str foo; LOG(L_INFO,"CPL - initializing\n"); /* check the module params */ if (DB_URL==0) { LOG(L_CRIT,"ERROR:cpl_init: mandatory parameter \"cpl_db\" " "found empty\n"); goto error; } if (DB_TABLE==0) { LOG(L_CRIT,"ERROR:cpl_init: mandatory parameter \"cpl_table\" " "found empty\n"); goto error; } if (cpl_env.proxy_recurse>MAX_PROXY_RECURSE) { LOG(L_CRIT,"ERROR:cpl_init: value of proxy_recurse param (%d) exceeds " "the maximum safety value (%d)\n", cpl_env.proxy_recurse,MAX_PROXY_RECURSE); goto error; } /* fix the timer_avp name */ if (timer_avp) { foo.s = timer_avp; foo.len = strlen(foo.s); if (parse_avp_spec(&foo,&cpl_env.timer_avp_type,&cpl_env.timer_avp)<0){ LOG(L_CRIT,"ERROR:cpl_init: invalid timer AVP specs \"%s\"\n", timer_avp); goto error; } if (cpl_env.timer_avp_type&AVP_NAME_STR && cpl_env.timer_avp.s==&foo) { if ( (cpl_env.timer_avp.s=(str*)pkg_malloc(sizeof(str)))==0 ) { LOG(L_ERR, "ERROR:cpl_init: no more pkg mem\n"); goto error; } *(cpl_env.timer_avp.s) = foo; } } if (dtd_file==0) { LOG(L_CRIT,"ERROR:cpl_init: mandatory parameter \"cpl_dtd_file\" " "found empty\n"); goto error; } else { /* check if the dtd file exists */ if (stat( dtd_file, &stat_t)==-1) { LOG(L_ERR,"ERROR:cpl_init: checking file \"%s\" status failed;" " stat returned %s\n",dtd_file,strerror(errno)); goto error; } if ( !S_ISREG( stat_t.st_mode ) ) { LOG(L_ERR,"ERROR:cpl_init: dir \"%s\" is not a regular file!\n", dtd_file); goto error; } if (access( dtd_file, R_OK )==-1) { LOG(L_ERR,"ERROR:cpl_init: checking file \"%s\" for permissions " "failed; access returned %s\n",dtd_file,strerror(errno)); goto error; } } if (cpl_env.log_dir==0) { LOG(L_INFO,"INFO:cpl_init: log_dir param found void -> logging " " disabled!\n"); } else { if ( strlen(cpl_env.log_dir)>MAX_LOG_DIR_SIZE ) { LOG(L_ERR,"ERROR:cpl_init: dir \"%s\" has a too long name :-(!\n", cpl_env.log_dir); goto error; } /* check if the dir exists */ if (stat( cpl_env.log_dir, &stat_t)==-1) { LOG(L_ERR,"ERROR:cpl_init: checking dir \"%s\" status failed;" " stat returned %s\n",cpl_env.log_dir,strerror(errno)); goto error; } if ( !S_ISDIR( stat_t.st_mode ) ) { LOG(L_ERR,"ERROR:cpl_init: dir \"%s\" is not a directory!\n", cpl_env.log_dir); goto error; } if (access( cpl_env.log_dir, R_OK|W_OK )==-1) { LOG(L_ERR,"ERROR:cpl_init: checking dir \"%s\" for permissions " "failed; access returned %s\n", cpl_env.log_dir, strerror(errno)); goto error; } } /* bind to the mysql module */ if (cpl_db_bind(DB_URL)<0) goto error; /* import the TM auto-loading function */ if ( !(load_tm=(load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) { LOG(L_ERR, "ERROR:cpl_c:cpl_init: cannot import load_tm\n"); goto error; } /* let the auto-loading function load all TM stuff */ if (load_tm( &(cpl_fct.tmb) )==-1) goto error; /* load the send_reply function from sl module */ if ((cpl_fct.sl_reply=find_export("sl_send_reply", 2, 0))==0) { LOG(L_ERR, "ERROR:cpl_c:cpl_init: cannot import sl_send_reply; maybe " "you forgot to load the sl module\n"); goto error; } /* bind to usrloc module if requested */ if (lookup_domain) { /* import all usrloc functions */ bind_usrloc = (bind_usrloc_t)find_export("ul_bind_usrloc", 1, 0); if (!bind_usrloc) { LOG(L_ERR, "ERROR:cpl_c:cpl_init: Can't bind usrloc\n"); goto error; } if (bind_usrloc( &(cpl_fct.ulb) ) < 0) { LOG(L_ERR, "ERROR:cpl_c:cpl_init: importing usrloc failed\n"); goto error; } /* convert lookup_domain from char* to udomain_t* pointer */ if (cpl_fct.ulb.register_udomain( lookup_domain, &cpl_env.lu_domain) < 0) { LOG(L_ERR, "ERROR:cpl_c:cpl_init: Error while registering domain " "<%s>\n",lookup_domain); goto error; } } else { LOG(L_NOTICE,"NOTICE:cpl_init: no lookup_domain given -> disable " " lookup node\n"); } /* register the fifo commands */ if (register_fifo_cmd( cpl_load, "LOAD_CPL", 0)!=1) { LOG(L_CRIT,"ERROR:cpl_init: cannot register LOAD_CPL fifo cmd!\n"); goto error; } if (register_fifo_cmd( cpl_remove, "REMOVE_CPL", 0)!=1) { LOG(L_CRIT,"ERROR:cpl_init: cannot register REMOVE_CPL fifo cmd!\n"); goto error; } if (register_fifo_cmd( cpl_get, "GET_CPL", 0)!=1) { LOG(L_CRIT,"ERROR:cpl_init: cannot register GET_CPL fifo cmd!\n"); goto error; } /* build a pipe for sending commands to aux process */ if ( pipe( cpl_env.cmd_pipe )==-1 ) { LOG(L_CRIT,"ERROR:cpl_init: cannot create command pipe: %s!\n", strerror(errno) ); goto error; } /* set the writing non blocking */ if ( (val=fcntl(cpl_env.cmd_pipe[1], F_GETFL, 0))<0 ) { LOG(L_ERR,"ERROR:cpl_init: getting flags from pipe[1] failed: fcntl " "said %s!\n",strerror(errno)); goto error; } if ( fcntl(cpl_env.cmd_pipe[1], F_SETFL, val|O_NONBLOCK) ) { LOG(L_ERR,"ERROR:cpl_init: setting flags to pipe[1] failed: fcntl " "said %s!\n",strerror(errno)); goto error; } /* init the CPL parser */ if (init_CPL_parser( dtd_file )!=1 ) { LOG(L_ERR,"ERROR:cpl_init: init_CPL_parser failed!\n"); goto error; } /* make a copy of the original TZ env. variable */ ptr = getenv("TZ"); cpl_env.orig_tz.len = 3/*"TZ="*/ + (ptr?(strlen(ptr)+1):0); if ( (cpl_env.orig_tz.s=shm_malloc( cpl_env.orig_tz.len ))==0 ) { LOG(L_ERR,"ERROR:cpl_init: no more shm mem. for saving TZ!\n"); goto error; } memcpy(cpl_env.orig_tz.s,"TZ=",3); if (ptr) strcpy(cpl_env.orig_tz.s+3,ptr); /* convert realm_prefix from string null terminated to str */ if (cpl_env.realm_prefix.s) { cpl_env.realm_prefix.len = strlen(cpl_env.realm_prefix.s); /* convert the realm_prefix to lower cases */ strlower( &cpl_env.realm_prefix ); } return 0;error: return -1;}static int cpl_child_init(int rank){ pid_t pid; /* don't do anything for main process and TCP manager process */ if (rank==PROC_MAIN || rank==PROC_TCP_MAIN) return 0; /* only child 1 will fork the aux process */ if (rank==1) { pid = fork(); if (pid==-1) { LOG(L_CRIT,"ERROR:cpl_child_init(%d): cannot fork: %s!\n", rank, strerror(errno)); goto error; } else if (pid==0) { /* I'm the child */ cpl_aux_process( cpl_env.cmd_pipe[0], cpl_env.log_dir); } else { LOG(L_INFO,"INFO:cpl_child_init(%d): I just gave birth to a child!" " I'm a PARENT!!\n",rank); /* I'm the parent -> remember the pid */ aux_process = pid; } } return cpl_db_init(DB_URL, DB_TABLE);error: return -1;}static int cpl_exit(void){ /* free the TZ orig */ if (cpl_env.orig_tz.s) shm_free(cpl_env.orig_tz.s); /* if still running, stop the aux process */ if (!aux_process) { LOG(L_INFO,"INFO:cpl_c:cpl_exit: aux process hasn't been created -> " "nothing to kill :-(\n"); } else { /* kill the auxiliary process */ if (kill( aux_process, SIGKILL)!=0) { if (errno==ESRCH) { LOG(L_INFO,"INFO:cpl_c:cpl_exit: seems that my child is " "already dead! :-((\n"); } else { LOG(L_ERR,"ERROR:cpl_c:cpl_exit: killing the aux. process " "failed! kill said: %s\n",strerror(errno)); return -1; } } else { LOG(L_INFO,"INFO:cl_c:cpl_exit: I have blood on my hands!! I just" " killed my own child!"); } } return 0;}#define BUILD_UH_SHM (1<<0)#define BUILD_UH_ADDSIP (1<<1)static inline int build_userhost(struct sip_uri *uri, str *uh, int flg){ static char buf[MAX_USERHOST_LEN]; unsigned char do_strip; char *p; int i; /* do we need to strip realm prefix? */ do_strip = 0; if (cpl_env.realm_prefix.len && cpl_env.realm_prefix.len<uri->host.len) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -