📄 lcr_mod.c
字号:
/* * $Id: lcr_mod.c,v 1.28 2006/05/26 12:16:23 juhe Exp $ * * Least Cost Routing module (also implements sequential forking) * * Copyright (C) 2005 Juha Heinanen * * This file is part of openser, a free SIP server. * * openser 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 * * openser 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: * ------- * 2005-02-14: Introduced lcr module (jh) * 2005-02-20: Added sequential forking functions (jh) * 2005-02-25: Added support for int AVP names, combined addr and port * AVPs (jh) * 2005-07-28: Added support for gw URI scheme and transport, * backport from ser (kd) * 2005-08-20: Added support for gw prefixes (jh) * 2005-09-03: Request-URI user part can be modified between load_gws() * and first next_gw() calls. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <arpa/inet.h>#include <regex.h>#include "../../sr_module.h"#include "../../dprint.h"#include "../../ut.h"#include "../../error.h"#include "../../mem/mem.h"#include "../../mem/shm_mem.h"#include "../../db/db.h"#include "../../usr_avp.h"#include "../../parser/parse_uri.h"#include "../../parser/parse_from.h"#include "../../parser/msg_parser.h"#include "../mysql/dbase.h"#include "../../action.h"#include "../../qvalue.h"#include "../../dset.h"#include "../../ip_addr.h"#include "fifo.h"MODULE_VERSION/* * Version of gw and lcr tables required by the module, * increment this value if you change the table in * an backwards incompatible way */#define GW_TABLE_VERSION 3#define LCR_TABLE_VERSION 2/* usr_avp flag for sequential forking */#define Q_FLAG (1<<2)static void destroy(void); /* Module destroy function */static int child_init(int rank); /* Per-child initialization function */static int mod_init(void); /* Module initialization function */static int fixstring2int(void **param, int param_count); /* string to int fixup */int reload_gws ( void );#define GW_TABLE "gw"#define GW_NAME_COL "gw_name"#define IP_ADDR_COL "ip_addr"#define PORT_COL "port"#define URI_SCHEME_COL "uri_scheme"#define TRANSPORT_COL "transport"#define GRP_ID_COL "grp_id"#define LCR_TABLE "lcr"#define STRIP_COL "strip"#define PREFIX_COL "prefix"#define FROM_URI_COL "from_uri"#define PRIORITY_COL "priority"#define MAX_QUERY_SIZE 512#define MAX_NO_OF_GWS 32#define MAX_NO_OF_LCRS 256#define MAX_PREFIX_LEN 16#define MAX_FROM_URI_LEN 128/* Default avp names */#define DEF_GW_URI_AVP "1400"#define DEF_CONTACT_AVP "1401"#define DEF_RURI_USER_AVP "1402"#define DEF_FR_INV_TIMER_AVP "fr_inv_timer_avp"#define DEF_FR_INV_TIMER 90#define DEF_FR_INV_TIMER_NEXT 30#define DEF_RPID_AVP "rpid"#define DEF_DB_MODE 1/* * Type definitions */typedef enum sip_protos uri_transport;struct gw_info { unsigned int ip_addr; unsigned int port; unsigned int grp_id; uri_type scheme; uri_transport transport; unsigned int strip; char prefix[MAX_PREFIX_LEN]; unsigned short prefix_len;};struct lcr_info { char prefix[MAX_PREFIX_LEN]; unsigned short prefix_len; char from_uri[MAX_FROM_URI_LEN + 1]; unsigned short from_uri_len; unsigned int grp_id; unsigned short priority; unsigned short end_record;};struct from_uri_regex { regex_t re; short int valid;};struct mi { unsigned int gw_index; unsigned int route_index; int randomizer;};/* * Database variables */static db_con_t* db_handle = 0; /* Database connection handle */static db_func_t lcr_dbf;/* * Module parameter variables */static str db_url = str_init(DEFAULT_RODB_URL);str gw_table = str_init(GW_TABLE);str gw_name_col = str_init(GW_NAME_COL);str ip_addr_col = str_init(IP_ADDR_COL);str port_col = str_init(PORT_COL);str uri_scheme_col = str_init(URI_SCHEME_COL);str transport_col = str_init(TRANSPORT_COL);str grp_id_col = str_init(GRP_ID_COL);str lcr_table = str_init(LCR_TABLE);str strip_col = str_init(STRIP_COL);str prefix_col = str_init(PREFIX_COL);str from_uri_col = str_init(FROM_URI_COL);str priority_col = str_init(PRIORITY_COL);str gw_uri_avp = str_init(DEF_GW_URI_AVP);str ruri_user_avp = str_init(DEF_RURI_USER_AVP);str contact_avp = str_init(DEF_CONTACT_AVP);str inv_timer_avp = str_init(DEF_FR_INV_TIMER_AVP);int inv_timer = DEF_FR_INV_TIMER;int inv_timer_next = DEF_FR_INV_TIMER_NEXT;str rpid_avp = str_init(DEF_RPID_AVP);int db_mode = DEF_DB_MODE;/* * Other module types and variables */struct contact { str uri; qvalue_t q; unsigned short q_flag; struct contact *next;};int_str gw_uri_name, ruri_user_name, contact_name, rpid_name, inv_timer_name;unsigned short gw_uri_avp_name_str;unsigned short ruri_user_avp_name_str;unsigned short contact_avp_name_str;unsigned short rpid_avp_name_str;struct gw_info **gws; /* Pointer to current gw table pointer */struct gw_info *gws_1; /* Pointer to gw table 1 */struct gw_info *gws_2; /* Pointer to gw table 2 */struct lcr_info **lcrs; /* Pointer to current lcr table pointer */struct lcr_info *lcrs_1; /* Pointer to lcr table 1 */struct lcr_info *lcrs_2; /* Pointer to lcr table 2 */unsigned int *lcrs_ws_reload_counter;unsigned int reload_counter;struct from_uri_regex from_uri_reg[MAX_NO_OF_LCRS];/* * Module functions that are defined later */int load_gws(struct sip_msg* _m, char* _s1, char* _s2);int load_gws_grp(struct sip_msg* _m, char* _s1, char* _s2);int next_gw(struct sip_msg* _m, char* _s1, char* _s2);int from_gw(struct sip_msg* _m, char* _s1, char* _s2);int from_gw_grp(struct sip_msg* _m, char* _s1, char* _s2);int to_gw(struct sip_msg* _m, char* _s1, char* _s2);int to_gw_grp(struct sip_msg* _m, char* _s1, char* _s2);int load_contacts (struct sip_msg*, char*, char*);int next_contacts (struct sip_msg*, char*, char*);/* * Exported functions */static cmd_export_t cmds[] = { {"load_gws", load_gws, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE}, {"load_gws", load_gws_grp, 1, fixstring2int, REQUEST_ROUTE | FAILURE_ROUTE}, {"next_gw", next_gw, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE}, {"from_gw", from_gw, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE}, {"from_gw", from_gw_grp, 1, fixstring2int, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE}, {"to_gw", to_gw, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE}, {"to_gw", to_gw_grp, 1, fixstring2int, REQUEST_ROUTE | FAILURE_ROUTE}, {"load_contacts", load_contacts, 0, 0, REQUEST_ROUTE}, {"next_contacts", next_contacts, 0, 0, REQUEST_ROUTE | FAILURE_ROUTE}, {0, 0, 0, 0, 0}};/* * Exported parameters */static param_export_t params[] = { {"db_url", STR_PARAM, &db_url.s }, {"gw_table", STR_PARAM, &gw_table.s }, {"gw_name_column", STR_PARAM, &gw_name_col.s }, {"ip_addr_column", STR_PARAM, &ip_addr_col.s }, {"port_column", STR_PARAM, &port_col.s }, {"uri_scheme_column", STR_PARAM, &uri_scheme_col.s }, {"transport_column", STR_PARAM, &transport_col.s }, {"grp_id_column", STR_PARAM, &grp_id_col.s }, {"lcr_table", STR_PARAM, &lcr_table.s }, {"strip_column", STR_PARAM, &strip_col.s }, {"prefix_column", STR_PARAM, &prefix_col.s }, {"from_uri_column", STR_PARAM, &from_uri_col.s }, {"priority_column", STR_PARAM, &priority_col.s }, {"gw_uri_avp", STR_PARAM, &gw_uri_avp.s }, {"ruri_user_avp", STR_PARAM, &ruri_user_avp.s }, {"contact_avp", STR_PARAM, &contact_avp.s }, {"fr_inv_timer_avp", STR_PARAM, &inv_timer_avp.s }, {"fr_inv_timer", INT_PARAM, &inv_timer }, {"fr_inv_timer_next", INT_PARAM, &inv_timer_next }, {"rpid_avp", STR_PARAM, &rpid_avp.s }, {"db_mode", INT_PARAM, &db_mode }, {0, 0, 0}};/* * Module interface */struct module_exports exports = { "lcr", cmds, /* Exported functions */ params, /* Exported parameters */ 0, /* exported statistics */ mod_init, /* module initialization function */ 0, /* response function */ destroy, /* destroy function */ child_init /* child initialization function */};int lcr_db_init(char* db_url){ if (lcr_dbf.init==0){ LOG(L_CRIT, "BUG: lcr_db_bind: null dbf\n"); goto error; } db_handle=lcr_dbf.init(db_url); if (db_handle==0){ LOG(L_ERR, "ERROR: lcr_db_bind: unable to connect to the database\n"); goto error; } return 0;error: return -1;}int lcr_db_bind(char* db_url){ if (bind_dbmod(db_url, &lcr_dbf)<0){ LOG(L_ERR, "ERROR: lcr_db_bind: unable to bind to the database" " module\n"); return -1; } if (!DB_CAPABILITY(lcr_dbf, DB_CAP_QUERY)) { LOG(L_ERR, "ERROR: lcr_db_bind: Database module does not " "implement 'query' function\n"); return -1; } if (!DB_CAPABILITY(lcr_dbf, DB_CAP_RAW_QUERY)) { LOG(L_ERR, "ERROR: lcr_db_bind: Database module does not " "implement raw 'query' function\n"); return -1; } return 0;}void lcr_db_close(){ if (db_handle && lcr_dbf.close){ lcr_dbf.close(db_handle); db_handle=0; }}int lcr_db_ver(char* db_url, str* name){ db_con_t* dbh; int ver; if (lcr_dbf.init==0){ LOG(L_CRIT, "BUG: lcr_db_ver: unbound database\n"); return -1; } dbh=lcr_dbf.init(db_url); if (dbh==0){ LOG(L_ERR, "ERROR: lcr_db_ver: unable to open database connection\n"); return -1; } ver=table_version(&lcr_dbf, dbh, name); lcr_dbf.close(dbh); return ver;}/* * Module initialization function callee in each child separately */static int child_init(int rank){ if (lcr_db_init(db_url.s) < 0) { LOG(L_ERR, "ERROR: lcr:child_init():" " Unable to connect to the database\n"); return -1; } return 0;}/* * Module initialization function that is called before the main process forks */static int mod_init(void){ int ver, i; unsigned int par; DBG("lcr - initializing\n"); /* Bind database */ if (lcr_db_bind(db_url.s)) { LOG(L_ERR, "ERROR: lcr:mod_init(): No database module found\n"); return -1; } /* Update length of module variables */ db_url.len = strlen(db_url.s); gw_table.len = strlen(gw_table.s); gw_name_col.len = strlen(gw_name_col.s); ip_addr_col.len = strlen(ip_addr_col.s); port_col.len = strlen(port_col.s); uri_scheme_col.len = strlen(uri_scheme_col.s); transport_col.len = strlen(transport_col.s); grp_id_col.len = strlen(grp_id_col.s); lcr_table.len = strlen(lcr_table.s); strip_col.len = strlen(strip_col.s); prefix_col.len = strlen(prefix_col.s); from_uri_col.len = strlen(from_uri_col.s); priority_col.len = strlen(priority_col.s); gw_uri_avp.len = strlen(gw_uri_avp.s); ruri_user_avp.len = strlen(ruri_user_avp.s); contact_avp.len = strlen(contact_avp.s); inv_timer_avp.len = strlen(inv_timer_avp.s); rpid_avp.len = strlen(rpid_avp.s); /* Check table version */ ver = lcr_db_ver(db_url.s, &gw_table); if (ver < 0) { LOG(L_ERR, "ERROR: lcr:mod_init():" " Error while querying table version\n"); goto err; } else if (ver < GW_TABLE_VERSION) { LOG(L_ERR, "ERROR: lcr:mod_init(): Invalid table version" " of gw table\n"); goto err; } /* Check table version */ ver = lcr_db_ver(db_url.s, &lcr_table); if (ver < 0) { LOG(L_ERR, "ERROR: lcr:mod_init():" " Error while querying table version\n"); goto err; } else if (ver < LCR_TABLE_VERSION) { LOG(L_ERR, "ERROR: lcr:mod_init(): Invalid table version of" " lcr table (use openser_mysql.sh reinstall)\n"); goto err; } /* Initialize fifo interface */ (void)init_lcr_fifo(); /* Initializing gw tables and gw table pointer variable */ gws_1 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) * (MAX_NO_OF_GWS + 1)); if (gws_1 == 0) { LOG(L_ERR, "ERROR: lcr: mod_init(): " "No memory for gw table\n"); goto err; } gws_2 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) * (MAX_NO_OF_GWS + 1)); if (gws_2 == 0) { LOG(L_ERR, "ERROR: lcr: mod_init(): " "No memory for gw table\n"); goto err; } for (i = 0; i < MAX_NO_OF_GWS + 1; i++) { gws_1[i].ip_addr = gws_2[i].ip_addr = 0; } gws = (struct gw_info **)shm_malloc(sizeof(struct gw_info *)); if (gws == 0) { LOG(L_ERR, "ERROR: lcr: mod_init(): " "No memory for gw table pointer\n"); } *gws = gws_1; /* Initializing lcr tables and lcr table pointer variable */ lcrs_1 = (struct lcr_info *)shm_malloc(sizeof(struct lcr_info) * (MAX_NO_OF_LCRS + 1)); if (lcrs_1 == 0) { LOG(L_ERR, "ERROR: lcr: mod_init(): " "No memory for lcr table\n"); goto err; } lcrs_2 = (struct lcr_info *)shm_malloc(sizeof(struct lcr_info) * (MAX_NO_OF_LCRS + 1)); if (lcrs_2 == 0) { LOG(L_ERR, "ERROR: lcr: mod_init(): " "No memory for lcr table\n"); goto err; } for (i = 0; i < MAX_NO_OF_LCRS + 1; i++) { lcrs_1[i].end_record = lcrs_2[i].end_record = 0; } lcrs = (struct lcr_info **)shm_malloc(sizeof(struct lcr_info *)); if (lcrs == 0) { LOG(L_ERR, "ERROR: lcr: mod_init(): " "No memory for lcr table pointer\n"); goto err; } *lcrs = lcrs_1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -