Wed, 10 Feb 2010 21:14:04 +0100
Import unmodified vendor sources for correction and improvement.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/opensips/modules/lcr/lcr_mod.c Wed Feb 10 21:14:04 2010 +0100 1.3 @@ -0,0 +1,2187 @@ 1.4 +/* 1.5 + * $Id: lcr_mod.c 6015 2009-08-22 21:45:06Z bogdan_iancu $ 1.6 + * 1.7 + * Least Cost Routing module (also implements sequential forking) 1.8 + * 1.9 + * Copyright (C) 2005 Juha Heinanen 1.10 + * Copyright (C) 2006 Voice Sistem SRL 1.11 + * 1.12 + * This file is part of opensips, a free SIP server. 1.13 + * 1.14 + * opensips is free software; you can redistribute it and/or modify 1.15 + * it under the terms of the GNU General Public License as published by 1.16 + * the Free Software Foundation; either version 2 of the License, or 1.17 + * (at your option) any later version 1.18 + * 1.19 + * opensips is distributed in the hope that it will be useful, 1.20 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 1.21 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.22 + * GNU General Public License for more details. 1.23 + * 1.24 + * You should have received a copy of the GNU General Public License 1.25 + * along with this program; if not, write to the Free Software 1.26 + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 1.27 + * 1.28 + * History: 1.29 + * ------- 1.30 + * 2005-02-14: Introduced lcr module (jh) 1.31 + * 2005-02-20: Added sequential forking functions (jh) 1.32 + * 2005-02-25: Added support for int AVP names, combined addr and port 1.33 + * AVPs (jh) 1.34 + * 2005-07-28: Added support for gw URI scheme and transport, 1.35 + * backport from ser (kd) 1.36 + * 2005-08-20: Added support for gw prefixes (jh) 1.37 + * 2005-09-03: Request-URI user part can be modified between load_gws() 1.38 + * and first next_gw() calls. 1.39 + */ 1.40 + 1.41 +#include <stdio.h> 1.42 +#include <stdlib.h> 1.43 +#include <string.h> 1.44 +#include <sys/types.h> 1.45 +#include <sys/socket.h> 1.46 +#include <netinet/in.h> 1.47 +#include <arpa/inet.h> 1.48 +#include <regex.h> 1.49 +#include "../../sr_module.h" 1.50 +#include "../../dprint.h" 1.51 +#include "../../ut.h" 1.52 +#include "../../error.h" 1.53 +#include "../../mem/mem.h" 1.54 +#include "../../mem/shm_mem.h" 1.55 +#include "../../db/db.h" 1.56 +#include "../../usr_avp.h" 1.57 +#include "../../parser/parse_uri.h" 1.58 +#include "../../parser/parse_from.h" 1.59 +#include "../../parser/msg_parser.h" 1.60 +#include "../../action.h" 1.61 +#include "../../qvalue.h" 1.62 +#include "../../dset.h" 1.63 +#include "../../ip_addr.h" 1.64 +#include "../../resolve.h" 1.65 +#include "../../mi/mi.h" 1.66 +#include "../../mod_fix.h" 1.67 +#include "../../socket_info.h" 1.68 +#include "../../pvar.h" 1.69 +#include "../../mod_fix.h" 1.70 +#include "mi.h" 1.71 + 1.72 + 1.73 + 1.74 +/* 1.75 + * Version of gw and lcr tables required by the module, 1.76 + * increment this value if you change the table in 1.77 + * an backwards incompatible way 1.78 + */ 1.79 +#define GW_TABLE_VERSION 8 1.80 +#define LCR_TABLE_VERSION 3 1.81 + 1.82 +/* usr_avp flag for sequential forking */ 1.83 +#define Q_FLAG (1<<2) 1.84 + 1.85 +static void destroy(void); /* Module destroy function */ 1.86 +static int mi_child_init(void); 1.87 +static int mod_init(void); /* Module initialization function */ 1.88 +static int fixstringloadgws(void **param, int param_count); 1.89 + 1.90 +int reload_gws ( void ); 1.91 + 1.92 +#define GW_TABLE "gw" 1.93 + 1.94 +#define GW_NAME_COL "gw_name" 1.95 + 1.96 +#define GRP_ID_COL "grp_id" 1.97 + 1.98 +#define IP_ADDR_COL "ip_addr" 1.99 + 1.100 +#define PORT_COL "port" 1.101 + 1.102 +#define URI_SCHEME_COL "uri_scheme" 1.103 + 1.104 +#define TRANSPORT_COL "transport" 1.105 + 1.106 +#define STRIP_COL "strip" 1.107 + 1.108 +#define TAG_COL "tag" 1.109 + 1.110 +#define FLAGS_COL "flags" 1.111 + 1.112 +#define LCR_TABLE "lcr" 1.113 + 1.114 +#define PREFIX_COL "prefix" 1.115 + 1.116 +#define FROM_URI_COL "from_uri" 1.117 + 1.118 +#define PRIORITY_COL "priority" 1.119 + 1.120 +#define MAX_NO_OF_GWS 32 1.121 +#define MAX_NO_OF_LCRS 256 1.122 +#define MAX_PREFIX_LEN 256 1.123 +#define MAX_TAG_LEN 16 1.124 +#define MAX_FROM_URI_LEN 256 1.125 + 1.126 +/* Default module parameter values */ 1.127 +#define DEF_FR_INV_TIMER 90 1.128 +#define DEF_FR_INV_TIMER_NEXT 30 1.129 +#define DEF_PREFIX_MODE 0 1.130 + 1.131 +/* 1.132 + * Type definitions 1.133 + */ 1.134 + 1.135 +typedef enum sip_protos uri_transport; 1.136 + 1.137 +struct gw_info { 1.138 + unsigned int ip_addr; 1.139 + unsigned int port; 1.140 + unsigned int grp_id; 1.141 + uri_type scheme; 1.142 + uri_transport transport; 1.143 + unsigned int strip; 1.144 + char tag[MAX_TAG_LEN + 1]; 1.145 + unsigned short tag_len; 1.146 + unsigned int flags; 1.147 +}; 1.148 + 1.149 +struct lcr_info { 1.150 + char prefix[MAX_PREFIX_LEN + 1]; 1.151 + unsigned short prefix_len; 1.152 + char from_uri[MAX_FROM_URI_LEN + 1]; 1.153 + unsigned short from_uri_len; 1.154 + unsigned int grp_id; 1.155 + unsigned short priority; 1.156 + unsigned short end_record; 1.157 +}; 1.158 + 1.159 +struct prefix_regex { 1.160 + regex_t re; 1.161 + short int valid; 1.162 +}; 1.163 + 1.164 +struct from_uri_regex { 1.165 + regex_t re; 1.166 + short int valid; 1.167 +}; 1.168 + 1.169 +struct mi { 1.170 + int gw_index; 1.171 + int route_index; 1.172 + int randomizer; 1.173 +}; 1.174 + 1.175 + 1.176 +/* 1.177 + * Database variables 1.178 + */ 1.179 +static db_con_t* db_handle = 0; /* Database connection handle */ 1.180 +static db_func_t lcr_dbf; 1.181 + 1.182 +/* 1.183 + * Module parameter variables 1.184 + */ 1.185 + 1.186 +/* database */ 1.187 +static str db_url = str_init(DEFAULT_RODB_URL); 1.188 +static str gw_table = str_init(GW_TABLE); 1.189 +static str gw_name_col = str_init(GW_NAME_COL); 1.190 +static str grp_id_col = str_init(GRP_ID_COL); 1.191 +static str ip_addr_col = str_init(IP_ADDR_COL); 1.192 +static str port_col = str_init(PORT_COL); 1.193 +static str uri_scheme_col = str_init(URI_SCHEME_COL); 1.194 +static str transport_col = str_init(TRANSPORT_COL); 1.195 +static str strip_col = str_init(STRIP_COL); 1.196 +static str tag_col = str_init(TAG_COL); 1.197 +static str flags_col = str_init(FLAGS_COL); 1.198 +static str lcr_table = str_init(LCR_TABLE); 1.199 +static str prefix_col = str_init(PREFIX_COL); 1.200 +static str from_uri_col = str_init(FROM_URI_COL); 1.201 +static str priority_col = str_init(PRIORITY_COL); 1.202 + 1.203 +/* timer */ 1.204 +int fr_inv_timer = DEF_FR_INV_TIMER; 1.205 +int fr_inv_timer_next = DEF_FR_INV_TIMER_NEXT; 1.206 + 1.207 +/* avps */ 1.208 +static char *fr_inv_timer_avp_param = NULL; 1.209 +static char *gw_uri_avp_param = NULL; 1.210 +static char *ruri_user_avp_param = NULL; 1.211 +static char *contact_avp_param = NULL; 1.212 +static char *rpid_avp_param = NULL; 1.213 +static char *flags_avp_param = NULL; 1.214 + 1.215 +/* prefix mode */ 1.216 +int prefix_mode_param = DEF_PREFIX_MODE; 1.217 + 1.218 +/* 1.219 + * Other module types and variables 1.220 + */ 1.221 + 1.222 +struct contact { 1.223 + str uri; 1.224 + qvalue_t q; 1.225 + str dst_uri; 1.226 + str path; 1.227 + unsigned int flags; 1.228 + struct socket_info* sock; 1.229 + unsigned short q_flag; 1.230 + struct contact *next; 1.231 +}; 1.232 + 1.233 +static int fr_inv_timer_avp_type; 1.234 +static int_str fr_inv_timer_avp; 1.235 +static int gw_uri_avp_type; 1.236 +static int_str gw_uri_avp; 1.237 +static int ruri_user_avp_type; 1.238 +static int_str ruri_user_avp; 1.239 +static int contact_avp_type; 1.240 +static int_str contact_avp; 1.241 +static int rpid_avp_type; 1.242 +static int_str rpid_avp; 1.243 +static int flags_avp_type; 1.244 +static int_str flags_avp; 1.245 + 1.246 +struct gw_info **gws; /* Pointer to current gw table pointer */ 1.247 +struct gw_info *gws_1; /* Pointer to gw table 1 */ 1.248 +struct gw_info *gws_2; /* Pointer to gw table 2 */ 1.249 + 1.250 +struct lcr_info **lcrs; /* Pointer to current lcr table pointer */ 1.251 +struct lcr_info *lcrs_1; /* Pointer to lcr table 1 */ 1.252 +struct lcr_info *lcrs_2; /* Pointer to lcr table 2 */ 1.253 + 1.254 +unsigned int *lcrs_ws_reload_counter; 1.255 +unsigned int reload_counter; 1.256 + 1.257 +struct prefix_regex prefix_reg[MAX_NO_OF_LCRS]; 1.258 +struct from_uri_regex from_uri_reg[MAX_NO_OF_LCRS]; 1.259 + 1.260 +/* 1.261 + * Module functions that are defined later 1.262 + */ 1.263 +static int load_gws_0(struct sip_msg* _m, char* _s1, char* _s2); 1.264 +static int load_gws_1(struct sip_msg* _m, char* _s1, char* _s2); 1.265 +static int load_gws_from_grp(struct sip_msg* _m, char* _s1, char* _s2); 1.266 +static int next_gw(struct sip_msg* _m, char* _s1, char* _s2); 1.267 +static int from_gw_0(struct sip_msg* _m, char* _s1, char* _s2); 1.268 +static int from_gw_1(struct sip_msg* _m, char* _s1, char* _s2); 1.269 +static int from_gw_grp(struct sip_msg* _m, char* _s1, char* _s2); 1.270 +static int to_gw(struct sip_msg* _m, char* _s1, char* _s2); 1.271 +static int to_gw_grp(struct sip_msg* _m, char* _s1, char* _s2); 1.272 +static int load_contacts (struct sip_msg*, char*, char*); 1.273 +static int next_contacts (struct sip_msg*, char*, char*); 1.274 + 1.275 + 1.276 +/* 1.277 + * Exported functions 1.278 + */ 1.279 +static cmd_export_t cmds[] = { 1.280 + {"load_gws", (cmd_function)load_gws_0, 0, 0, 0, REQUEST_ROUTE}, 1.281 + {"load_gws", (cmd_function)load_gws_1, 1, fixup_pvar_null, 1.282 + fixup_free_pvar_null, REQUEST_ROUTE}, 1.283 + {"load_gws_from_grp", (cmd_function)load_gws_from_grp, 1, 1.284 + fixstringloadgws, 0, REQUEST_ROUTE}, 1.285 + {"next_gw", (cmd_function)next_gw, 0, 0, 0, 1.286 + REQUEST_ROUTE | FAILURE_ROUTE}, 1.287 + {"from_gw", (cmd_function)from_gw_0, 0, 0, 0, 1.288 + REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE}, 1.289 + {"from_gw", (cmd_function)from_gw_1, 1, fixup_pvar_null, 1.290 + fixup_free_pvar_null, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE}, 1.291 + {"from_gw_grp", (cmd_function)from_gw_grp, 1, fixup_uint_null, 0, 1.292 + REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE}, 1.293 + {"to_gw", (cmd_function)to_gw, 0, 0, 0, 1.294 + REQUEST_ROUTE | FAILURE_ROUTE}, 1.295 + {"to_gw", (cmd_function)to_gw_grp, 1, fixup_uint_null, 0, 1.296 + REQUEST_ROUTE | FAILURE_ROUTE}, 1.297 + {"load_contacts", (cmd_function)load_contacts, 0, 0, 0, 1.298 + REQUEST_ROUTE}, 1.299 + {"next_contacts", (cmd_function)next_contacts, 0, 0, 0, 1.300 + REQUEST_ROUTE | FAILURE_ROUTE}, 1.301 + {0, 0, 0, 0, 0, 0} 1.302 +}; 1.303 + 1.304 + 1.305 +/* 1.306 + * Exported parameters 1.307 + */ 1.308 +static param_export_t params[] = { 1.309 + {"db_url", STR_PARAM, &db_url.s }, 1.310 + {"gw_table", STR_PARAM, &gw_table.s }, 1.311 + {"gw_name_column", STR_PARAM, &gw_name_col.s }, 1.312 + {"grp_id_column", STR_PARAM, &grp_id_col.s }, 1.313 + {"ip_addr_column", STR_PARAM, &ip_addr_col.s }, 1.314 + {"port_column", STR_PARAM, &port_col.s }, 1.315 + {"uri_scheme_column", STR_PARAM, &uri_scheme_col.s }, 1.316 + {"transport_column", STR_PARAM, &transport_col.s }, 1.317 + {"strip_column", STR_PARAM, &strip_col.s }, 1.318 + {"tag_column", STR_PARAM, &tag_col.s }, 1.319 + {"flags_column", STR_PARAM, &flags_col.s }, 1.320 + {"lcr_table", STR_PARAM, &lcr_table.s }, 1.321 + {"prefix_column", STR_PARAM, &prefix_col.s }, 1.322 + {"from_uri_column", STR_PARAM, &from_uri_col.s }, 1.323 + {"priority_column", STR_PARAM, &priority_col.s }, 1.324 + {"fr_inv_timer_avp", STR_PARAM, &fr_inv_timer_avp_param }, 1.325 + {"gw_uri_avp", STR_PARAM, &gw_uri_avp_param }, 1.326 + {"ruri_user_avp", STR_PARAM, &ruri_user_avp_param }, 1.327 + {"contact_avp", STR_PARAM, &contact_avp_param }, 1.328 + {"rpid_avp", STR_PARAM, &rpid_avp_param }, 1.329 + {"flags_avp", STR_PARAM, &flags_avp_param }, 1.330 + {"fr_inv_timer", INT_PARAM, &fr_inv_timer }, 1.331 + {"fr_inv_timer_next", INT_PARAM, &fr_inv_timer_next }, 1.332 + {"prefix_mode", INT_PARAM, &prefix_mode_param }, 1.333 + {0, 0, 0} 1.334 +}; 1.335 + 1.336 + 1.337 +/* 1.338 + * Exported MI functions 1.339 + */ 1.340 +static mi_export_t mi_cmds[] = { 1.341 + { MI_LCR_RELOAD, mi_lcr_reload, MI_NO_INPUT_FLAG, 0, mi_child_init }, 1.342 + { MI_LCR_DUMP, mi_lcr_dump, MI_NO_INPUT_FLAG, 0, 0 }, 1.343 + { 0, 0, 0, 0 ,0} 1.344 +}; 1.345 + 1.346 + 1.347 +/* 1.348 + * Module interface 1.349 + */ 1.350 +struct module_exports exports = { 1.351 + "lcr", 1.352 + MODULE_VERSION, 1.353 + DEFAULT_DLFLAGS, /* dlopen flags */ 1.354 + cmds, /* Exported functions */ 1.355 + params, /* Exported parameters */ 1.356 + 0, /* exported statistics */ 1.357 + mi_cmds, /* exported MI functions */ 1.358 + 0, /* exported pseudo-variables */ 1.359 + 0, /* extra processes */ 1.360 + mod_init, /* module initialization function */ 1.361 + 0, /* response function */ 1.362 + destroy, /* destroy function */ 1.363 + 0 /* child initialization function */ 1.364 +}; 1.365 + 1.366 + 1.367 +static int lcr_db_init(const str* db_url) 1.368 +{ 1.369 + if (lcr_dbf.init==0){ 1.370 + LM_CRIT("Null lcr_dbf\n"); 1.371 + goto error; 1.372 + } 1.373 + db_handle=lcr_dbf.init(db_url); 1.374 + if (db_handle==0){ 1.375 + LM_ERR("Unable to connect to the database\n"); 1.376 + goto error; 1.377 + } 1.378 + return 0; 1.379 +error: 1.380 + return -1; 1.381 +} 1.382 + 1.383 + 1.384 + 1.385 +static int lcr_db_bind(const str* db_url) 1.386 +{ 1.387 + if (db_bind_mod(db_url, &lcr_dbf)<0){ 1.388 + LM_ERR("Unable to bind to the database module\n"); 1.389 + return -1; 1.390 + } 1.391 + 1.392 + if (!DB_CAPABILITY(lcr_dbf, DB_CAP_QUERY)) { 1.393 + LM_ERR("Database module does not implement 'query' function\n"); 1.394 + return -1; 1.395 + } 1.396 + 1.397 + return 0; 1.398 +} 1.399 + 1.400 + 1.401 +static void lcr_db_close(void) 1.402 +{ 1.403 + if (db_handle && lcr_dbf.close){ 1.404 + lcr_dbf.close(db_handle); 1.405 + db_handle=0; 1.406 + } 1.407 +} 1.408 + 1.409 + 1.410 +static int mi_child_init(void) 1.411 +{ 1.412 + return lcr_db_init(&db_url); 1.413 +} 1.414 + 1.415 + 1.416 +/* 1.417 + * Module initialization function that is called before the main process forks 1.418 + */ 1.419 +static int mod_init(void) 1.420 +{ 1.421 + int i; 1.422 + pv_spec_t avp_spec; 1.423 + str s; 1.424 + unsigned short avp_flags; 1.425 + 1.426 + LM_DBG("Initializing\n"); 1.427 + 1.428 + /* Update length of module variables */ 1.429 + db_url.len = strlen(db_url.s); 1.430 + gw_table.len = strlen(gw_table.s); 1.431 + gw_name_col.len = strlen(gw_name_col.s); 1.432 + grp_id_col.len = strlen(grp_id_col.s); 1.433 + ip_addr_col.len = strlen(ip_addr_col.s); 1.434 + port_col.len = strlen(port_col.s); 1.435 + uri_scheme_col.len = strlen(uri_scheme_col.s); 1.436 + transport_col.len = strlen(transport_col.s); 1.437 + strip_col.len = strlen(strip_col.s); 1.438 + tag_col.len = strlen(tag_col.s); 1.439 + flags_col.len = strlen(flags_col.s); 1.440 + lcr_table.len = strlen(lcr_table.s); 1.441 + prefix_col.len = strlen(prefix_col.s); 1.442 + from_uri_col.len = strlen(from_uri_col.s); 1.443 + priority_col.len = strlen(priority_col.s); 1.444 + 1.445 + /* Bind database */ 1.446 + if (lcr_db_bind(&db_url)) { 1.447 + LM_ERR("No database module found\n"); 1.448 + return -1; 1.449 + } 1.450 + 1.451 + /* Check value of prefix_mode */ 1.452 + if ((prefix_mode_param != 0) && (prefix_mode_param != 1)) { 1.453 + LM_ERR("Invalid prefix_mode value <%d>\n", prefix_mode_param); 1.454 + return -1; 1.455 + } 1.456 + 1.457 + /* Process AVP params */ 1.458 + if (fr_inv_timer_avp_param && *fr_inv_timer_avp_param) { 1.459 + s.s = fr_inv_timer_avp_param; s.len = strlen(s.s); 1.460 + if (pv_parse_spec(&s, &avp_spec)==0 1.461 + || avp_spec.type!=PVT_AVP) { 1.462 + LM_ERR("Malformed or non AVP definition <%s>\n", 1.463 + fr_inv_timer_avp_param); 1.464 + return -1; 1.465 + } 1.466 + 1.467 + if(pv_get_avp_name(0, &(avp_spec.pvp), &fr_inv_timer_avp, &avp_flags)!=0) { 1.468 + LM_ERR("Invalid AVP definition <%s>\n", fr_inv_timer_avp_param); 1.469 + return -1; 1.470 + } 1.471 + fr_inv_timer_avp_type = avp_flags; 1.472 + } else { 1.473 + LM_ERR("AVP fr_inv_timer_avp has not been defined\n"); 1.474 + return -1; 1.475 + } 1.476 + 1.477 + if (gw_uri_avp_param && *gw_uri_avp_param) { 1.478 + s.s = gw_uri_avp_param; s.len = strlen(s.s); 1.479 + if (pv_parse_spec(&s, &avp_spec)==0 1.480 + || avp_spec.type!=PVT_AVP) { 1.481 + LM_ERR("Malformed or non AVP definition <%s>\n", gw_uri_avp_param); 1.482 + return -1; 1.483 + } 1.484 + 1.485 + if(pv_get_avp_name(0, &(avp_spec.pvp), &gw_uri_avp, &avp_flags)!=0) { 1.486 + LM_ERR("Invalid AVP definition <%s>\n", gw_uri_avp_param); 1.487 + return -1; 1.488 + } 1.489 + gw_uri_avp_type = avp_flags; 1.490 + } else { 1.491 + LM_ERR("AVP gw_uri_avp has not been defined\n"); 1.492 + return -1; 1.493 + } 1.494 + 1.495 + if (ruri_user_avp_param && *ruri_user_avp_param) { 1.496 + s.s = ruri_user_avp_param; s.len = strlen(s.s); 1.497 + if (pv_parse_spec(&s, &avp_spec)==0 1.498 + || avp_spec.type!=PVT_AVP) { 1.499 + LM_ERR("Malformed or non AVP definition <%s>\n", 1.500 + ruri_user_avp_param); 1.501 + return -1; 1.502 + } 1.503 + 1.504 + if(pv_get_avp_name(0, &(avp_spec.pvp), &ruri_user_avp, &avp_flags)!=0) { 1.505 + LM_ERR("Invalid AVP definition <%s>\n", ruri_user_avp_param); 1.506 + return -1; 1.507 + } 1.508 + ruri_user_avp_type = avp_flags; 1.509 + } else { 1.510 + LM_ERR("AVP ruri_user_avp has not been defined\n"); 1.511 + return -1; 1.512 + } 1.513 + 1.514 + if (contact_avp_param && *contact_avp_param) { 1.515 + s.s = contact_avp_param; s.len = strlen(s.s); 1.516 + if (pv_parse_spec(&s, &avp_spec)==0 1.517 + || avp_spec.type!=PVT_AVP) { 1.518 + LM_ERR("Malformed or non AVP definition <%s>\n", 1.519 + contact_avp_param); 1.520 + return -1; 1.521 + } 1.522 + 1.523 + if(pv_get_avp_name(0, &(avp_spec.pvp), &contact_avp, &avp_flags)!=0) { 1.524 + LM_ERR("Invalid AVP definition <%s>\n", contact_avp_param); 1.525 + return -1; 1.526 + } 1.527 + contact_avp_type = avp_flags; 1.528 + } else { 1.529 + LM_ERR("AVP contact_avp has not been defined\n"); 1.530 + return -1; 1.531 + } 1.532 + 1.533 + if (rpid_avp_param && *rpid_avp_param) { 1.534 + s.s = rpid_avp_param; s.len = strlen(s.s); 1.535 + if (pv_parse_spec(&s, &avp_spec)==0 1.536 + || avp_spec.type!=PVT_AVP) { 1.537 + LM_ERR("Malformed or non AVP definition <%s>\n", rpid_avp_param); 1.538 + return -1; 1.539 + } 1.540 + 1.541 + if(pv_get_avp_name(0, &(avp_spec.pvp), &rpid_avp, &avp_flags)!=0) { 1.542 + LM_ERR("Invalid AVP definition <%s>\n", rpid_avp_param); 1.543 + return -1; 1.544 + } 1.545 + rpid_avp_type = avp_flags; 1.546 + } else { 1.547 + LM_ERR("AVP rpid_avp has not been defined\n"); 1.548 + return -1; 1.549 + } 1.550 + 1.551 + if (flags_avp_param && *flags_avp_param) { 1.552 + s.s = flags_avp_param; s.len = strlen(s.s); 1.553 + if (pv_parse_spec(&s, &avp_spec)==0 1.554 + || avp_spec.type!=PVT_AVP) { 1.555 + LM_ERR("Malformed or non AVP definition <%s>\n", flags_avp_param); 1.556 + return -1; 1.557 + } 1.558 + 1.559 + if(pv_get_avp_name(0, &(avp_spec.pvp), &flags_avp, &avp_flags)!=0) { 1.560 + LM_ERR("Invalid AVP definition <%s>\n", flags_avp_param); 1.561 + return -1; 1.562 + } 1.563 + flags_avp_type = avp_flags; 1.564 + } else { 1.565 + LM_ERR("AVP flags_avp has not been defined\n"); 1.566 + return -1; 1.567 + } 1.568 + 1.569 + /* Check table version */ 1.570 + db_con_t* dbh; 1.571 + if (lcr_dbf.init==0){ 1.572 + LM_CRIT("Unbound database\n"); 1.573 + return -1; 1.574 + } 1.575 + dbh=lcr_dbf.init(&db_url); 1.576 + if (dbh==0){ 1.577 + LM_ERR("Unable to open database connection\n"); 1.578 + return -1; 1.579 + } 1.580 + if((db_check_table_version(&lcr_dbf, dbh, &gw_table, GW_TABLE_VERSION) < 0) || 1.581 + (db_check_table_version(&lcr_dbf, dbh, &lcr_table, LCR_TABLE_VERSION) < 0)) { 1.582 + LM_ERR("error during table version check.\n"); 1.583 + lcr_dbf.close(dbh); 1.584 + goto err; 1.585 + } 1.586 + lcr_dbf.close(dbh); 1.587 + 1.588 + /* Initializing gw tables and gw table pointer variable */ 1.589 + gws_1 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) * 1.590 + (MAX_NO_OF_GWS + 1)); 1.591 + if (gws_1 == 0) { 1.592 + LM_ERR("No memory for gw table\n"); 1.593 + goto err; 1.594 + } 1.595 + gws_2 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) * 1.596 + (MAX_NO_OF_GWS + 1)); 1.597 + if (gws_2 == 0) { 1.598 + LM_ERR("No memory for gw table\n"); 1.599 + goto err; 1.600 + } 1.601 + for (i = 0; i < MAX_NO_OF_GWS + 1; i++) { 1.602 + gws_1[i].ip_addr = gws_2[i].ip_addr = 0; 1.603 + } 1.604 + gws = (struct gw_info **)shm_malloc(sizeof(struct gw_info *)); 1.605 + if (gws == 0) { 1.606 + LM_ERR("No memory for gw table pointer\n"); 1.607 + } 1.608 + *gws = gws_1; 1.609 + 1.610 + /* Initializing lcr tables and lcr table pointer variable */ 1.611 + lcrs_1 = (struct lcr_info *)shm_malloc(sizeof(struct lcr_info) * 1.612 + (MAX_NO_OF_LCRS + 1)); 1.613 + if (lcrs_1 == 0) { 1.614 + LM_ERR("No memory for lcr table\n"); 1.615 + goto err; 1.616 + } 1.617 + lcrs_2 = (struct lcr_info *)shm_malloc(sizeof(struct lcr_info) * 1.618 + (MAX_NO_OF_LCRS + 1)); 1.619 + if (lcrs_2 == 0) { 1.620 + LM_ERR("No memory for lcr table\n"); 1.621 + goto err; 1.622 + } 1.623 + for (i = 0; i < MAX_NO_OF_LCRS + 1; i++) { 1.624 + lcrs_1[i].end_record = lcrs_2[i].end_record = 0; 1.625 + } 1.626 + lcrs = (struct lcr_info **)shm_malloc(sizeof(struct lcr_info *)); 1.627 + if (lcrs == 0) { 1.628 + LM_ERR("No memory for lcr table pointer\n"); 1.629 + goto err; 1.630 + } 1.631 + *lcrs = lcrs_1; 1.632 + 1.633 + lcrs_ws_reload_counter = (unsigned int *)shm_malloc(sizeof(unsigned int)); 1.634 + if (lcrs_ws_reload_counter == 0) { 1.635 + LM_ERR("No memory for reload counter\n"); 1.636 + goto err; 1.637 + } 1.638 + *lcrs_ws_reload_counter = reload_counter = 0; 1.639 + 1.640 + memset(prefix_reg, 0, sizeof(struct prefix_regex) * MAX_NO_OF_LCRS); 1.641 + memset(from_uri_reg, 0, sizeof(struct from_uri_regex) * MAX_NO_OF_LCRS); 1.642 + 1.643 + /* First reload */ 1.644 + if (reload_gws() == -1) { 1.645 + LM_CRIT("Failed to reload gateways and routes\n"); 1.646 + goto err; 1.647 + } 1.648 + 1.649 + return 0; 1.650 + 1.651 +err: 1.652 + return -1; 1.653 +} 1.654 + 1.655 + 1.656 +static void destroy(void) 1.657 +{ 1.658 + lcr_db_close(); 1.659 +} 1.660 + 1.661 +/* 1.662 + * Sort lcr records by prefix_len and priority. 1.663 + */ 1.664 +static int comp_lcrs(const void *m1, const void *m2) 1.665 +{ 1.666 + int result = -1; 1.667 + 1.668 + struct mi *mi1 = (struct mi *) m1; 1.669 + struct mi *mi2 = (struct mi *) m2; 1.670 + 1.671 + struct lcr_info lcr_record1 = (*lcrs)[mi1->route_index]; 1.672 + struct lcr_info lcr_record2 = (*lcrs)[mi2->route_index]; 1.673 + 1.674 + if (prefix_mode_param == 0) { 1.675 + /* Sort by prefix. */ 1.676 + if (lcr_record1.prefix_len > lcr_record2.prefix_len) { 1.677 + result = 1; 1.678 + } else if (lcr_record1.prefix_len == lcr_record2.prefix_len) { 1.679 + /* Sort by priority. */ 1.680 + if (lcr_record1.priority < lcr_record2.priority) { 1.681 + result = 1; 1.682 + } else if (lcr_record1.priority == lcr_record2.priority) { 1.683 + /* Nothing to do. */ 1.684 + result = 0; 1.685 + } 1.686 + } 1.687 + } else { 1.688 + if (lcr_record1.priority < lcr_record2.priority) { 1.689 + result = 1; 1.690 + } else if (lcr_record1.priority == lcr_record2.priority) { 1.691 + /* Nothing to do. */ 1.692 + result = 0; 1.693 + } 1.694 + } 1.695 + 1.696 + return result; 1.697 +} 1.698 + 1.699 +/* 1.700 + * Sort lcr records by rand table. 1.701 + */ 1.702 +static int rand_lcrs(const void *m1, const void *m2) 1.703 +{ 1.704 + int result = -1; 1.705 + 1.706 + struct mi mi1 = *((struct mi *) m1); 1.707 + struct mi mi2 = *((struct mi *) m2); 1.708 + 1.709 + if (mi1.randomizer > mi2.randomizer) { 1.710 + result = 1; 1.711 + } else if (mi1.randomizer == mi2.randomizer) { 1.712 + result = 0; 1.713 + } 1.714 + 1.715 + return result; 1.716 +} 1.717 + 1.718 +/* 1.719 + * regcomp each prefix. 1.720 + */ 1.721 +static int load_prefix_regex(void) 1.722 +{ 1.723 + int i, status, result = 0; 1.724 + 1.725 + for (i = 0; i < MAX_NO_OF_LCRS; i++) { 1.726 + if ((*lcrs)[i].end_record != 0) { 1.727 + break; 1.728 + } 1.729 + if (prefix_reg[i].valid) { 1.730 + regfree(&(prefix_reg[i].re)); 1.731 + prefix_reg[i].valid = 0; 1.732 + } 1.733 + memset(&(prefix_reg[i].re), 0, sizeof(regex_t)); 1.734 + if ((status=regcomp(&(prefix_reg[i].re),(*lcrs)[i].prefix,0))!=0){ 1.735 + LM_ERR("bad prefix re <%s>, regcomp returned %d (check regex.h)\n", 1.736 + (*lcrs)[i].prefix, status); 1.737 + result = -1; 1.738 + break; 1.739 + } 1.740 + prefix_reg[i].valid = 1; 1.741 + } 1.742 + 1.743 + return result; 1.744 +} 1.745 + 1.746 +/* 1.747 + * regcomp each from_uri. 1.748 + */ 1.749 +static int load_from_uri_regex(void) 1.750 +{ 1.751 + int i, status, result = 0; 1.752 + 1.753 + for (i = 0; i < MAX_NO_OF_LCRS; i++) { 1.754 + if ((*lcrs)[i].end_record != 0) { 1.755 + break; 1.756 + } 1.757 + if (from_uri_reg[i].valid) { 1.758 + regfree(&(from_uri_reg[i].re)); 1.759 + from_uri_reg[i].valid = 0; 1.760 + } 1.761 + memset(&(from_uri_reg[i].re), 0, sizeof(regex_t)); 1.762 + if ((status=regcomp(&(from_uri_reg[i].re),(*lcrs)[i].from_uri,0))!=0){ 1.763 + LM_ERR("Bad from_uri re <%s>, regcomp returned %d (check regex.h)\n", 1.764 + (*lcrs)[i].from_uri, status); 1.765 + result = -1; 1.766 + break; 1.767 + } 1.768 + from_uri_reg[i].valid = 1; 1.769 + } 1.770 + 1.771 + if (result != -1) { 1.772 + reload_counter = *lcrs_ws_reload_counter; 1.773 + } 1.774 + return result; 1.775 +} 1.776 + 1.777 +static int load_all_regex(void) 1.778 +{ 1.779 + int result =0; 1.780 + 1.781 + if (prefix_mode_param != 0) { 1.782 + result = load_prefix_regex(); 1.783 + } 1.784 + 1.785 + if (result == 0) { 1.786 + result = load_from_uri_regex(); 1.787 + } else { 1.788 + LM_ERR("Unable to load prefix regex\n"); 1.789 + } 1.790 + 1.791 + if (result == 0) { 1.792 + reload_counter = *lcrs_ws_reload_counter; 1.793 + } else { 1.794 + LM_ERR("Unable to load from_uri regex\n"); 1.795 + } 1.796 + 1.797 + return result; 1.798 +} 1.799 + 1.800 +/* 1.801 + * Reload gws to unused gw table and lcrs to unused lcr table, and, when done 1.802 + * make unused gw and lcr table the one in use. 1.803 + */ 1.804 +int reload_gws(void) 1.805 +{ 1.806 + unsigned int i, port, strip, tag_len, prefix_len, from_uri_len, 1.807 + grp_id, priority; 1.808 + struct in_addr ip_addr; 1.809 + unsigned int flags; 1.810 + uri_type scheme; 1.811 + uri_transport transport; 1.812 + db_con_t* dbh; 1.813 + char *tag, *prefix, *from_uri; 1.814 + db_res_t* res = NULL; 1.815 + db_row_t* row; 1.816 + db_key_t gw_cols[8]; 1.817 + db_key_t lcr_cols[4]; 1.818 + 1.819 + gw_cols[0] = &ip_addr_col; 1.820 + gw_cols[1] = &port_col; 1.821 + gw_cols[2] = &uri_scheme_col; 1.822 + gw_cols[3] = &transport_col; 1.823 + gw_cols[4] = &strip_col; 1.824 + gw_cols[5] = &tag_col; 1.825 + /* FIXME: is this ok if we have different names for grp_id 1.826 + in the two tables? (ge vw lcr) */ 1.827 + gw_cols[6] = &grp_id_col; 1.828 + gw_cols[7] = &flags_col; 1.829 + 1.830 + lcr_cols[0] = &prefix_col; 1.831 + lcr_cols[1] = &from_uri_col; 1.832 + /* FIXME: is this ok if we have different names for grp_id 1.833 + in the two tables? (ge vw lcr) */ 1.834 + lcr_cols[2] = &grp_id_col; 1.835 + lcr_cols[3] = &priority_col; 1.836 + 1.837 + if (lcr_dbf.init==0){ 1.838 + LM_CRIT("Unbound database\n"); 1.839 + return -1; 1.840 + } 1.841 + dbh=lcr_dbf.init(&db_url); 1.842 + if (dbh==0){ 1.843 + LM_ERR("Unable to open database connection\n"); 1.844 + return -1; 1.845 + } 1.846 + 1.847 + if (lcr_dbf.use_table(dbh, &gw_table) < 0) { 1.848 + LM_ERR("Error while trying to use gw table\n"); 1.849 + return -1; 1.850 + } 1.851 + 1.852 + if (lcr_dbf.query(dbh, NULL, 0, NULL, gw_cols, 0, 8, 0, &res) < 0) { 1.853 + LM_ERR("Failed to query gw data\n"); 1.854 + lcr_dbf.close(dbh); 1.855 + return -1; 1.856 + } 1.857 + 1.858 + if (RES_ROW_N(res) + 1 > MAX_NO_OF_GWS) { 1.859 + LM_ERR("Too many gateways\n"); 1.860 + lcr_dbf.free_result(dbh, res); 1.861 + lcr_dbf.close(dbh); 1.862 + return -1; 1.863 + } 1.864 + 1.865 + for (i = 0; i < RES_ROW_N(res); i++) { 1.866 + row = RES_ROWS(res) + i; 1.867 + if (!((VAL_TYPE(ROW_VALUES(row)) == DB_STRING) && 1.868 + !VAL_NULL(ROW_VALUES(row)) && 1.869 + inet_aton((char *)VAL_STRING(ROW_VALUES(row)), &ip_addr) != 0)) { 1.870 + LM_ERR("Invalid IP address of gw <%s>\n", 1.871 + (char *)VAL_STRING(ROW_VALUES(row))); 1.872 + lcr_dbf.free_result(dbh, res); 1.873 + lcr_dbf.close(dbh); 1.874 + return -1; 1.875 + } 1.876 + if (VAL_NULL(ROW_VALUES(row) + 1) == 1) { 1.877 + port = 0; 1.878 + } else { 1.879 + port = (unsigned int)VAL_INT(ROW_VALUES(row) + 1); 1.880 + } 1.881 + if (port > 65536) { 1.882 + LM_ERR("Port of gw is too large <%u>\n", port); 1.883 + lcr_dbf.free_result(dbh, res); 1.884 + lcr_dbf.close(dbh); 1.885 + return -1; 1.886 + } 1.887 + if (VAL_NULL(ROW_VALUES(row) + 2) == 1) { 1.888 + scheme = SIP_URI_T; 1.889 + } else { 1.890 + scheme = (uri_type)VAL_INT(ROW_VALUES(row) + 2); 1.891 + if ((scheme != SIP_URI_T) && (scheme != SIPS_URI_T)) { 1.892 + LM_ERR("Unknown or unsupported URI scheme <%u>\n", 1.893 + (unsigned int)scheme); 1.894 + lcr_dbf.free_result(dbh, res); 1.895 + lcr_dbf.close(dbh); 1.896 + return -1; 1.897 + } 1.898 + } 1.899 + if (VAL_NULL(ROW_VALUES(row) + 3) == 1) { 1.900 + transport = PROTO_NONE; 1.901 + } else { 1.902 + transport = (uri_transport)VAL_INT(ROW_VALUES(row) + 3); 1.903 + if ((transport != PROTO_UDP) && (transport != PROTO_TCP) && 1.904 + (transport != PROTO_TLS)) { 1.905 + LM_ERR("Unknown or unsupported transport <%u>\n", 1.906 + (unsigned int)transport); 1.907 + lcr_dbf.free_result(dbh, res); 1.908 + lcr_dbf.close(dbh); 1.909 + return -1; 1.910 + } 1.911 + } 1.912 + if (VAL_NULL(ROW_VALUES(row) + 4) == 1) { 1.913 + strip = 0; 1.914 + } else { 1.915 + strip = (unsigned int)VAL_INT(ROW_VALUES(row) + 4); 1.916 + } 1.917 + if (VAL_NULL(ROW_VALUES(row) + 5) == 1) { 1.918 + tag_len = 0; 1.919 + tag = (char *)0; 1.920 + } else { 1.921 + tag = (char *)VAL_STRING(ROW_VALUES(row) + 5); 1.922 + tag_len = strlen(tag); 1.923 + if (tag_len > MAX_TAG_LEN) { 1.924 + LM_ERR("Too long gw tag <%u>\n", tag_len); 1.925 + lcr_dbf.free_result(dbh, res); 1.926 + lcr_dbf.close(dbh); 1.927 + return -1; 1.928 + } 1.929 + } 1.930 + if (VAL_NULL(ROW_VALUES(row) + 6) == 1) { 1.931 + grp_id = 0; 1.932 + } else { 1.933 + grp_id = VAL_INT(ROW_VALUES(row) + 6); 1.934 + } 1.935 + if (!VAL_NULL(ROW_VALUES(row) + 7) && 1.936 + (VAL_TYPE(ROW_VALUES(row) + 7) == DB_INT)) { 1.937 + flags = (unsigned int)VAL_INT(ROW_VALUES(row) + 7); 1.938 + } else { 1.939 + LM_ERR("Attribute flags is NULL or non-int\n"); 1.940 + lcr_dbf.free_result(dbh, res); 1.941 + lcr_dbf.close(dbh); 1.942 + return -1; 1.943 + } 1.944 + if (*gws == gws_1) { 1.945 + gws_2[i].ip_addr = (unsigned int)ip_addr.s_addr; 1.946 + gws_2[i].port = port; 1.947 + gws_2[i].grp_id = grp_id; 1.948 + gws_2[i].scheme = scheme; 1.949 + gws_2[i].transport = transport; 1.950 + gws_2[i].flags = flags; 1.951 + gws_2[i].strip = strip; 1.952 + gws_2[i].tag_len = tag_len; 1.953 + if (tag_len) 1.954 + memcpy(&(gws_2[i].tag[0]), tag, tag_len); 1.955 + } else { 1.956 + gws_1[i].ip_addr = (unsigned int)ip_addr.s_addr; 1.957 + gws_1[i].port = port; 1.958 + gws_1[i].grp_id = grp_id; 1.959 + gws_1[i].scheme = scheme; 1.960 + gws_1[i].transport = transport; 1.961 + gws_1[i].flags = flags; 1.962 + gws_1[i].strip = strip; 1.963 + gws_1[i].tag_len = tag_len; 1.964 + if (tag_len) 1.965 + memcpy(&(gws_1[i].tag[0]), tag, tag_len); 1.966 + } 1.967 + } 1.968 + 1.969 + lcr_dbf.free_result(dbh, res); 1.970 + 1.971 + if (*gws == gws_1) { 1.972 + gws_2[i].ip_addr = 0; 1.973 + *gws = gws_2; 1.974 + } else { 1.975 + gws_1[i].ip_addr = 0; 1.976 + *gws = gws_1; 1.977 + } 1.978 + 1.979 + 1.980 + if (lcr_dbf.use_table(dbh, &lcr_table) < 0) { 1.981 + LM_ERR("Error while trying to use lcr table\n"); 1.982 + return -1; 1.983 + } 1.984 + 1.985 + if (lcr_dbf.query(dbh, NULL, 0, NULL, lcr_cols, 0, 4, 0, &res) < 0) { 1.986 + LM_ERR("Failed to query lcr data\n"); 1.987 + lcr_dbf.close(dbh); 1.988 + return -1; 1.989 + } 1.990 + 1.991 + if (RES_ROW_N(res) + 1 > MAX_NO_OF_LCRS) { 1.992 + LM_ERR("Too many lcr entries <%d>\n", RES_ROW_N(res)); 1.993 + lcr_dbf.free_result(dbh, res); 1.994 + lcr_dbf.close(dbh); 1.995 + return -1; 1.996 + } 1.997 + for (i = 0; i < RES_ROW_N(res); i++) { 1.998 + row = RES_ROWS(res) + i; 1.999 + if (VAL_NULL(ROW_VALUES(row)) == 1) { 1.1000 + prefix_len = 0; 1.1001 + prefix = 0; 1.1002 + } else { 1.1003 + prefix = (char *)VAL_STRING(ROW_VALUES(row)); 1.1004 + prefix_len = strlen(prefix); 1.1005 + if (prefix_len > MAX_PREFIX_LEN) { 1.1006 + LM_ERR("Too long lcr prefix <%u>\n", prefix_len); 1.1007 + lcr_dbf.free_result(dbh, res); 1.1008 + lcr_dbf.close(dbh); 1.1009 + return -1; 1.1010 + } 1.1011 + } 1.1012 + if (VAL_NULL(ROW_VALUES(row) + 1) == 1) { 1.1013 + from_uri_len = 0; 1.1014 + from_uri = 0; 1.1015 + } else { 1.1016 + from_uri = (char *)VAL_STRING(ROW_VALUES(row) + 1); 1.1017 + from_uri_len = strlen(from_uri); 1.1018 + if (from_uri_len > MAX_FROM_URI_LEN) { 1.1019 + LM_ERR("Too long from_uri <%u>\n", from_uri_len); 1.1020 + lcr_dbf.free_result(dbh, res); 1.1021 + lcr_dbf.close(dbh); 1.1022 + return -1; 1.1023 + } 1.1024 + } 1.1025 + if (VAL_NULL(ROW_VALUES(row) + 2) == 1) { 1.1026 + LM_ERR("Route grp_id is NULL\n"); 1.1027 + lcr_dbf.free_result(dbh, res); 1.1028 + lcr_dbf.close(dbh); 1.1029 + return -1; 1.1030 + } 1.1031 + grp_id = (unsigned int)VAL_INT(ROW_VALUES(row) + 2); 1.1032 + if (VAL_NULL(ROW_VALUES(row) + 3) == 1) { 1.1033 + LM_ERR("Route priority is NULL\n"); 1.1034 + lcr_dbf.free_result(dbh, res); 1.1035 + lcr_dbf.close(dbh); 1.1036 + return -1; 1.1037 + } 1.1038 + priority = (unsigned int)VAL_INT(ROW_VALUES(row) + 3); 1.1039 + 1.1040 + if (*lcrs == lcrs_1) { 1.1041 + lcrs_2[i].prefix_len = prefix_len; 1.1042 + if (prefix_len) 1.1043 + memcpy(&(lcrs_2[i].prefix[0]), prefix, prefix_len); 1.1044 + lcrs_2[i].from_uri_len = from_uri_len; 1.1045 + if (from_uri_len) { 1.1046 + memcpy(&(lcrs_2[i].from_uri[0]), from_uri, from_uri_len); 1.1047 + lcrs_2[i].from_uri[from_uri_len] = '\0'; 1.1048 + } 1.1049 + lcrs_2[i].grp_id = grp_id; 1.1050 + lcrs_2[i].priority = priority; 1.1051 + lcrs_2[i].end_record = 0; 1.1052 + } else { 1.1053 + lcrs_1[i].prefix_len = prefix_len; 1.1054 + if (prefix_len) 1.1055 + memcpy(&(lcrs_1[i].prefix[0]), prefix, prefix_len); 1.1056 + lcrs_1[i].from_uri_len = from_uri_len; 1.1057 + if (from_uri_len) { 1.1058 + memcpy(&(lcrs_1[i].from_uri[0]), from_uri, from_uri_len); 1.1059 + lcrs_1[i].from_uri[from_uri_len] = '\0'; 1.1060 + } 1.1061 + lcrs_1[i].grp_id = grp_id; 1.1062 + lcrs_1[i].priority = priority; 1.1063 + lcrs_1[i].end_record = 0; 1.1064 + } 1.1065 + } 1.1066 + 1.1067 + lcr_dbf.free_result(dbh, res); 1.1068 + lcr_dbf.close(dbh); 1.1069 + 1.1070 + if (*lcrs == lcrs_1) { 1.1071 + lcrs_2[i].end_record = 1; 1.1072 + *lcrs = lcrs_2; 1.1073 + } else { 1.1074 + lcrs_1[i].end_record = 1; 1.1075 + *lcrs = lcrs_1; 1.1076 + } 1.1077 + 1.1078 + (*lcrs_ws_reload_counter)++; 1.1079 + if (0 != load_all_regex()) { 1.1080 + 1.1081 + return -1; 1.1082 + } 1.1083 + 1.1084 + return 1; 1.1085 +} 1.1086 + 1.1087 + 1.1088 +int mi_print_gws(struct mi_node* rpl) 1.1089 +{ 1.1090 + unsigned int i; 1.1091 + struct mi_attr* attr; 1.1092 + uri_transport transport; 1.1093 + char *transp; 1.1094 + struct mi_node* node; 1.1095 + struct ip_addr address; 1.1096 + char* p; 1.1097 + int len; 1.1098 + 1.1099 + for (i = 0; i < MAX_NO_OF_GWS; i++) { 1.1100 + 1.1101 + if ((*gws)[i].ip_addr == 0) 1.1102 + break; 1.1103 + 1.1104 + node= add_mi_node_child(rpl,0 ,"GW", 2, 0, 0); 1.1105 + if(node == NULL) 1.1106 + return -1; 1.1107 + 1.1108 + p = int2str((unsigned long)(*gws)[i].grp_id, &len ); 1.1109 + attr = add_mi_attr(node, MI_DUP_VALUE, "GRP_ID", 6, p, len ); 1.1110 + if(attr == NULL) 1.1111 + return -1; 1.1112 + 1.1113 + transport = (*gws)[i].transport; 1.1114 + if (transport == PROTO_UDP) 1.1115 + transp= ";transport=udp"; 1.1116 + else if (transport == PROTO_TCP) 1.1117 + transp= ";transport=tcp"; 1.1118 + else if (transport == PROTO_TLS) 1.1119 + transp= ";transport=tls"; 1.1120 + else 1.1121 + transp= ""; 1.1122 + 1.1123 + address.af = AF_INET; 1.1124 + address.len = 4; 1.1125 + address.u.addr32[0] = (*gws)[i].ip_addr; 1.1126 + attr= addf_mi_attr(node,0 ,"URI", 3,"%s:%s:%d%s", 1.1127 + ((*gws)[i].scheme == SIP_URI_T)?"sip":"sips", 1.1128 + ip_addr2a(&address), 1.1129 + ((*gws)[i].port == 0)?5060:(*gws)[i].port,transp); 1.1130 + if(attr == NULL) 1.1131 + return -1; 1.1132 + 1.1133 + p = int2str((unsigned long)(*gws)[i].strip, &len ); 1.1134 + attr = add_mi_attr(node, MI_DUP_VALUE, "STRIP", 5, p, len); 1.1135 + if(attr == NULL) 1.1136 + return -1; 1.1137 + 1.1138 + attr = add_mi_attr(node, MI_DUP_VALUE, "TAG", 3, 1.1139 + (*gws)[i].tag, (*gws)[i].tag_len ); 1.1140 + if(attr == NULL) 1.1141 + return -1; 1.1142 + 1.1143 + p = int2str((unsigned long)(*gws)[i].flags, &len ); 1.1144 + attr = add_mi_attr(node, MI_DUP_VALUE, "FLAGS", 5, p, len); 1.1145 + if(attr == NULL) 1.1146 + return -1; 1.1147 + } 1.1148 + 1.1149 + for (i = 0; i < MAX_NO_OF_LCRS; i++) { 1.1150 + if ((*lcrs)[i].end_record != 0) 1.1151 + break; 1.1152 + 1.1153 + node= add_mi_node_child(rpl, 0, "RULE", 4, 0, 0); 1.1154 + attr = add_mi_attr(node, 0, "PREFIX", 6, (*lcrs)[i].prefix, 1.1155 + (*lcrs)[i].prefix_len ); 1.1156 + if(attr== 0) 1.1157 + return -1; 1.1158 + 1.1159 + attr = add_mi_attr(node, 0, "FROM_URI", 8, (*lcrs)[i].from_uri, 1.1160 + (*lcrs)[i].from_uri_len ); 1.1161 + if(attr== 0) 1.1162 + return -1; 1.1163 + 1.1164 + p = int2str((unsigned long)(*lcrs)[i].grp_id, &len ); 1.1165 + attr = add_mi_attr(node, MI_DUP_VALUE, "GRP_ID", 6, p, len ); 1.1166 + if(attr == NULL) 1.1167 + return -1; 1.1168 + 1.1169 + p = int2str((unsigned long)(*lcrs)[i].priority, &len ); 1.1170 + attr = add_mi_attr(node, MI_DUP_VALUE, "PRIORITY", 8, p, len ); 1.1171 + if(attr == NULL) 1.1172 + return -1; 1.1173 + 1.1174 + } 1.1175 + 1.1176 + return 0; 1.1177 +} 1.1178 + 1.1179 + 1.1180 +/* 1.1181 + * Load info of matching GWs from database to gw_uri AVPs 1.1182 + */ 1.1183 +static int do_load_gws(struct sip_msg* _m, str *_from_uri, int _grp_id) 1.1184 +{ 1.1185 + str ruri_user, from_uri, value; 1.1186 + char from_uri_str[MAX_FROM_URI_LEN + 1]; 1.1187 + char ruri[MAX_URI_SIZE]; 1.1188 + unsigned int i, j, k, index, addr, port, strip, gw_index, 1.1189 + duplicated_gw, flags, have_rpid_avp; 1.1190 + uri_type scheme; 1.1191 + uri_transport transport; 1.1192 + struct ip_addr address; 1.1193 + str addr_str, port_str; 1.1194 + char *at, *tag, *strip_string, *flags_string; 1.1195 + struct usr_avp *avp; 1.1196 + int_str val; 1.1197 + struct mi matched_gws[MAX_NO_OF_GWS + 1]; 1.1198 + unsigned short tag_len, prefix_len, priority; 1.1199 + int randomizer_start, randomizer_end, randomizer_flag, 1.1200 + strip_len, flags_len; 1.1201 + struct lcr_info lcr_rec; 1.1202 + 1.1203 + /* Find Request-URI user */ 1.1204 + if ((parse_sip_msg_uri(_m) < 0) || (!_m->parsed_uri.user.s)) { 1.1205 + LM_ERR("Error while parsing R-URI\n"); 1.1206 + return -1; 1.1207 + } 1.1208 + ruri_user = _m->parsed_uri.user; 1.1209 + 1.1210 + if (_from_uri) { 1.1211 + /* take caller uri from _from_uri argument */ 1.1212 + from_uri = *_from_uri; 1.1213 + } else { 1.1214 + /* take caller uri from RPID or From URI */ 1.1215 + have_rpid_avp = 0; 1.1216 + avp = search_first_avp(rpid_avp_type, rpid_avp, &val, 0); 1.1217 + if (avp != NULL) { 1.1218 + /* Get URI user from RPID if not empty */ 1.1219 + if (avp->flags & AVP_VAL_STR) { 1.1220 + if (val.s.s && val.s.len) { 1.1221 + from_uri = val.s; 1.1222 + have_rpid_avp = 1; 1.1223 + } 1.1224 + } else { 1.1225 + from_uri.s = int2str(val.n, &from_uri.len); 1.1226 + have_rpid_avp = 1; 1.1227 + } 1.1228 + } 1.1229 + if (!have_rpid_avp) { 1.1230 + /* Get URI from From URI */ 1.1231 + if ((!_m->from) && (parse_headers(_m, HDR_FROM_F, 0) == -1)) { 1.1232 + LM_ERR("Error while parsing headers\n"); 1.1233 + return -1; 1.1234 + } 1.1235 + if (!_m->from) { 1.1236 + LM_ERR("From header field not found\n"); 1.1237 + return -1; 1.1238 + } 1.1239 + if ((!(_m->from)->parsed) && (parse_from_header(_m) < 0)) { 1.1240 + LM_ERR("Error while parsing From header\n"); 1.1241 + return -1; 1.1242 + } 1.1243 + from_uri = get_from(_m)->uri; 1.1244 + } 1.1245 + } 1.1246 + if (from_uri.len <= MAX_FROM_URI_LEN) { 1.1247 + strncpy(from_uri_str, from_uri.s, from_uri.len); 1.1248 + from_uri_str[from_uri.len] = '\0'; 1.1249 + } else { 1.1250 + LM_ERR("From URI is too long <%u>\n", from_uri.len); 1.1251 + return -1; 1.1252 + } 1.1253 + 1.1254 + /* 1.1255 + * Check if the gws and lcrs were reloaded 1.1256 + */ 1.1257 + if (reload_counter != *lcrs_ws_reload_counter) { 1.1258 + if (load_all_regex() != 0) { 1.1259 + return -1; 1.1260 + } 1.1261 + } 1.1262 + 1.1263 + /* 1.1264 + * Let's match the gws: 1.1265 + * 1. prefix matching 1.1266 + * 2. from_uri matching 1.1267 + * 3. _grp_id matching 1.1268 + * 1.1269 + * Note: A gateway must be in the list _only_ once. 1.1270 + */ 1.1271 + gw_index = 0; 1.1272 + duplicated_gw = 0; 1.1273 + for (i = 0; i < MAX_NO_OF_LCRS; i++) { 1.1274 + lcr_rec = (*lcrs)[i]; 1.1275 + if (lcr_rec.end_record != 0) { 1.1276 + break; 1.1277 + } 1.1278 + if ( ((prefix_mode_param == 0) && (lcr_rec.prefix_len <= ruri_user.len) && 1.1279 + (strncmp(lcr_rec.prefix, ruri_user.s, lcr_rec.prefix_len)==0)) || 1.1280 + ( (prefix_mode_param != 0) && ( (lcr_rec.prefix_len == 0) || 1.1281 + (prefix_reg[i].valid && 1.1282 + (regexec(&(prefix_reg[i].re), ruri_user.s, 0, 1.1283 + (regmatch_t *)NULL, 0) == 0)) ) ) ) { 1.1284 + /* 1. Prefix matching is done */ 1.1285 + if ((lcr_rec.from_uri_len == 0) || 1.1286 + (from_uri_reg[i].valid && 1.1287 + (regexec(&(from_uri_reg[i].re), from_uri_str, 0, 1.1288 + (regmatch_t *)NULL, 0) == 0))) { 1.1289 + /* 2. from_uri matching is done */ 1.1290 + for (j = 0; j < MAX_NO_OF_GWS; j++) { 1.1291 + if ((*gws)[j].ip_addr == 0) { 1.1292 + break; 1.1293 + } 1.1294 + if (lcr_rec.grp_id == (*gws)[j].grp_id && 1.1295 + (_grp_id < 0 || (*gws)[j].grp_id == _grp_id)) { 1.1296 + /* 3. _grp_id matching is done */ 1.1297 + for (k = 0; k < gw_index; k++) { 1.1298 + if ((*gws)[j].ip_addr == 1.1299 + (*gws)[matched_gws[k].gw_index].ip_addr) { 1.1300 + /* Found the same gw in the list */ 1.1301 + /* Let's keep the one with higher */ 1.1302 + /* match on prefix len */ 1.1303 + LM_DBG("Duplicate gw for index" 1.1304 + " %d [%d,%d] and current [%d,%d] \n", 1.1305 + k, matched_gws[k].route_index, 1.1306 + matched_gws[k].route_index, i, j); 1.1307 + duplicated_gw = 1; 1.1308 + if (lcr_rec.prefix_len > 1.1309 + (*lcrs)[matched_gws[k].route_index].prefix_len) { 1.1310 + /* Replace the old entry with the new one */ 1.1311 + LM_DBG("Replace [%d,%d]" 1.1312 + " with [%d,%d] on index %d:" 1.1313 + " prefix reason %d>%d\n", 1.1314 + matched_gws[k].route_index, 1.1315 + matched_gws[k].gw_index, i, j, k, 1.1316 + lcr_rec.prefix_len, 1.1317 + (*lcrs)[matched_gws[k].route_index].prefix_len); 1.1318 + matched_gws[k].route_index = i; 1.1319 + matched_gws[k].gw_index = j; 1.1320 + /* Stop searching in the matched_gws list */ 1.1321 + break; 1.1322 + } else if (lcr_rec.prefix_len == 1.1323 + (*lcrs)[matched_gws[k].route_index].prefix_len) { 1.1324 + if (lcr_rec.priority > 1.1325 + (*lcrs)[matched_gws[k].route_index].priority) { 1.1326 + /* Replace the old entry with the new one */ 1.1327 + LM_DBG("Replace [%d,%d] with" 1.1328 + " [%d,%d] on index %d:" 1.1329 + " priority reason %d>%d\n", 1.1330 + matched_gws[k].route_index, 1.1331 + matched_gws[k].gw_index, 1.1332 + i, j, k, lcr_rec.priority, 1.1333 + (*lcrs)[matched_gws[k].route_index].priority); 1.1334 + matched_gws[k].route_index = i; 1.1335 + matched_gws[k].gw_index = j; 1.1336 + /* Stop searching in the matched_gws list */ 1.1337 + break; 1.1338 + } 1.1339 + } 1.1340 + } 1.1341 + } 1.1342 + if (duplicated_gw == 0) { 1.1343 + /* This is a new gw */ 1.1344 + matched_gws[gw_index].route_index = i; 1.1345 + matched_gws[gw_index].gw_index = j; 1.1346 + LM_DBG("Added matched_gws[%d]=[%d,%d]\n", 1.1347 + gw_index, i, j); 1.1348 + gw_index++; 1.1349 + } else { 1.1350 + duplicated_gw = 0; 1.1351 + } 1.1352 + } 1.1353 + } 1.1354 + } 1.1355 + } 1.1356 + } 1.1357 + matched_gws[gw_index].route_index = -1; 1.1358 + matched_gws[gw_index].gw_index = -1; 1.1359 + 1.1360 + /* 1.1361 + * Sort the gateways based on: 1.1362 + * 1. prefix len 1.1363 + * 2. priority 1.1364 + */ 1.1365 + qsort(matched_gws, gw_index, sizeof(struct mi), comp_lcrs); 1.1366 + randomizer_start = 0; 1.1367 + 1.1368 + /* Randomizing the gateways with same prefix_len and same priority */ 1.1369 + randomizer_flag = 0; 1.1370 + prefix_len = (*lcrs)[matched_gws[0].route_index].prefix_len; 1.1371 + priority = (*lcrs)[matched_gws[0].route_index].priority; 1.1372 + for (i = 1; i < gw_index; i++) { 1.1373 + if ( prefix_len == (*lcrs)[matched_gws[i].route_index].prefix_len && 1.1374 + priority == (*lcrs)[matched_gws[i].route_index].priority) { 1.1375 + /* we have a match */ 1.1376 + if (randomizer_flag == 0) { 1.1377 + randomizer_flag = 1; 1.1378 + randomizer_start = i - 1; 1.1379 + } 1.1380 + matched_gws[i - 1].randomizer = rand(); 1.1381 + } 1.1382 + else { 1.1383 + if (randomizer_flag == 1) { 1.1384 + randomizer_end = i - 1; 1.1385 + randomizer_flag = 0; 1.1386 + qsort(&matched_gws[randomizer_start], 1.1387 + randomizer_end - randomizer_start + 1, 1.1388 + sizeof(struct mi), rand_lcrs); 1.1389 + } 1.1390 + prefix_len = (*lcrs)[matched_gws[i].route_index].prefix_len; 1.1391 + priority = (*lcrs)[matched_gws[i].route_index].priority; 1.1392 + } 1.1393 + } 1.1394 + if (randomizer_flag == 1) { 1.1395 + randomizer_end = gw_index - 1; 1.1396 + matched_gws[i - 1].randomizer = rand(); 1.1397 + qsort(&matched_gws[randomizer_start], 1.1398 + randomizer_end - randomizer_start + 1, 1.1399 + sizeof(struct mi), rand_lcrs); 1.1400 + } 1.1401 + 1.1402 + for (i = 0; i < MAX_NO_OF_GWS; i++) { 1.1403 + index = matched_gws[i].gw_index; 1.1404 + if (index == -1) { 1.1405 + break; 1.1406 + } 1.1407 + addr = (*gws)[index].ip_addr; 1.1408 + port = (*gws)[index].port; 1.1409 + scheme = (*gws)[index].scheme; 1.1410 + transport = (*gws)[index].transport; 1.1411 + flags = (*gws)[index].flags; 1.1412 + strip = (*gws)[index].strip; 1.1413 + if (strip > ruri_user.len) { 1.1414 + LM_ERR("Strip count of gw is too large <%u>\n", strip); 1.1415 + goto skip; 1.1416 + } 1.1417 + tag_len = (*gws)[index].tag_len; 1.1418 + tag = (*gws)[index].tag; 1.1419 + if (6 + tag_len + 40 /* flags + strip */ + 1 + 15 + 1 + 5 + 1 + 14 > 1.1420 + MAX_URI_SIZE) { 1.1421 + LM_ERR("Request URI would be too long\n"); 1.1422 + goto skip; 1.1423 + } 1.1424 + at = (char *)&(ruri[0]); 1.1425 + flags_string = int2str(flags, &flags_len); 1.1426 + memcpy(at, flags_string, flags_len); 1.1427 + at = at + flags_len; 1.1428 + if (scheme == SIP_URI_T) { 1.1429 + memcpy(at, "sip:", 4); at = at + 4; 1.1430 + } else if (scheme == SIPS_URI_T) { 1.1431 + memcpy(at, "sips:", 5); at = at + 5; 1.1432 + } else { 1.1433 + LM_ERR("Unknown or unsupported URI scheme <%u>\n", 1.1434 + (unsigned int)scheme); 1.1435 + goto skip; 1.1436 + } 1.1437 + if (tag_len) { 1.1438 + memcpy(at, tag, tag_len); at = at + tag_len; 1.1439 + } 1.1440 + /* Add strip in this form |number. 1.1441 + * For example: |3 means strip first 3 characters. 1.1442 + */ 1.1443 + *at = '|'; at = at + 1; 1.1444 + strip_string = int2str(strip, &strip_len); 1.1445 + memcpy(at, strip_string, strip_len); 1.1446 + at = at + strip_len; 1.1447 + *at = '@'; at = at + 1; 1.1448 + address.af = AF_INET; 1.1449 + address.len = 4; 1.1450 + address.u.addr32[0] = addr; 1.1451 + addr_str.s = ip_addr2a(&address); 1.1452 + addr_str.len = strlen(addr_str.s); 1.1453 + memcpy(at, addr_str.s, addr_str.len); at = at + addr_str.len; 1.1454 + if (port != 0) { 1.1455 + if (port > 65536) { 1.1456 + LM_ERR("Port of GW is too large <%u>\n", port); 1.1457 + goto skip; 1.1458 + } 1.1459 + *at = ':'; at = at + 1; 1.1460 + port_str.s = int2str(port, &port_str.len); 1.1461 + memcpy(at, port_str.s, port_str.len); at = at + port_str.len; 1.1462 + } 1.1463 + if (transport != PROTO_NONE) { 1.1464 + memcpy(at, ";transport=", 11); at = at + 11; 1.1465 + if (transport == PROTO_UDP) { 1.1466 + memcpy(at, "udp", 3); at = at + 3; 1.1467 + } else if (transport == PROTO_TCP) { 1.1468 + memcpy(at, "tcp", 3); at = at + 3; 1.1469 + } else if (transport == PROTO_TLS) { 1.1470 + memcpy(at, "tls", 3); at = at + 3; 1.1471 + } else { 1.1472 + LM_ERR("Unknown or unsupported transport <%u>\n", 1.1473 + (unsigned int)transport); 1.1474 + goto skip; 1.1475 + } 1.1476 + } 1.1477 + value.s = (char *)&(ruri[0]); 1.1478 + value.len = at - value.s; 1.1479 + val.s = value; 1.1480 + add_avp(gw_uri_avp_type|AVP_VAL_STR, gw_uri_avp, val); 1.1481 + LM_DBG("Added gw_uri_avp <%.*s>\n", value.len, value.s); 1.1482 + skip: 1.1483 + continue; 1.1484 + } 1.1485 + 1.1486 + return 1; 1.1487 +} 1.1488 + 1.1489 +/* 1.1490 + * Load info of matching GWs from database to gw_uri AVPs 1.1491 + * taking into account the given group id. Caller URI is taken 1.1492 + * from request. 1.1493 + */ 1.1494 +static int load_gws_from_grp(struct sip_msg* _m, char* _s1, char* _s2) 1.1495 +{ 1.1496 + str grp_s; 1.1497 + unsigned int grp_id; 1.1498 + 1.1499 + if(((pv_elem_p)_s1)->spec.getf!=NULL) 1.1500 + { 1.1501 + if(pv_printf_s(_m, (pv_elem_p)_s1, &grp_s)!=0) 1.1502 + return -1; 1.1503 + if(str2int(&grp_s, &grp_id)!=0) 1.1504 + return -1; 1.1505 + } else { 1.1506 + grp_id = ((pv_elem_p)_s1)->spec.pvp.pvn.u.isname.name.n; 1.1507 + } 1.1508 + if (grp_id > 0) return do_load_gws(_m, (str *)0, (int)grp_id); 1.1509 + else return -1; 1.1510 +} 1.1511 + 1.1512 + 1.1513 +/* 1.1514 + * Load info of matching GWs from database to gw_uri AVPs. 1.1515 + * Caller URI is taken from request. 1.1516 + */ 1.1517 +static int load_gws_0(struct sip_msg* _m, char* _s1, char* _s2) 1.1518 +{ 1.1519 + return do_load_gws(_m, (str *)0, -1); 1.1520 +} 1.1521 + 1.1522 + 1.1523 +/* 1.1524 + * Load info of matching GWs from database to gw_uri AVPs. 1.1525 + * Caller URI is taken from pseudo variable argument. 1.1526 + */ 1.1527 +static int load_gws_1(struct sip_msg* _m, char* _sp, char* _s2) 1.1528 +{ 1.1529 + pv_spec_t *sp; 1.1530 + pv_value_t pv_val; 1.1531 + sp = (pv_spec_t *)_sp; 1.1532 + 1.1533 + if (sp && (pv_get_spec_value(_m, sp, &pv_val) == 0)) { 1.1534 + if (pv_val.flags & PV_VAL_STR) { 1.1535 + if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) { 1.1536 + LM_DBG("missing from uri\n"); 1.1537 + return -1; 1.1538 + } 1.1539 + return do_load_gws(_m, &(pv_val.rs), -1); 1.1540 + } else { 1.1541 + LM_DBG("pseudo variable value is not string\n"); 1.1542 + return -1; 1.1543 + } 1.1544 + } else { 1.1545 + LM_DBG("cannot get pseudo variable value\n"); 1.1546 + return -1; 1.1547 + } 1.1548 +} 1.1549 + 1.1550 + 1.1551 +/* 1.1552 + * Rewrites scheme, host, port, and transport parts of R-URI based on first 1.1553 + * gw_uri AVP value, which is then destroyed. Also saves R-URI user to 1.1554 + * ruri_user AVP for later use in failure route block. 1.1555 + * If called from failure route block, appends a new branch to request 1.1556 + * where scheme, host, port, and transport of URI are taken from the first 1.1557 + * gw_uri AVP value, which is then destroyed. URI user is taken from 1.1558 + * ruri_user AVP value saved earlier. 1.1559 + * Returns 1 upon success and -1 upon failure. 1.1560 + */ 1.1561 +static int next_gw(struct sip_msg* _m, char* _s1, char* _s2) 1.1562 +{ 1.1563 + int_str gw_uri_val, ruri_user_val, val; 1.1564 + struct usr_avp *gu_avp, *ru_avp; 1.1565 + int rval; 1.1566 + str new_ruri; 1.1567 + char *at, *at_char, *strip_char, *endptr; 1.1568 + unsigned int strip; 1.1569 + 1.1570 + gu_avp = search_first_avp(gw_uri_avp_type, gw_uri_avp, &gw_uri_val, 0); 1.1571 + if (!gu_avp) return -1; 1.1572 + 1.1573 + /* Set flags_avp from integer at the beginning of of gw_uri */ 1.1574 + val.n = (int)strtoul(gw_uri_val.s.s, &at, 0); 1.1575 + add_avp(flags_avp_type, flags_avp, val); 1.1576 + LM_DBG("Added flags_avp <%u>\n", (unsigned int)val.n); 1.1577 + 1.1578 + gw_uri_val.s.len = gw_uri_val.s.len - (at - gw_uri_val.s.s); 1.1579 + gw_uri_val.s.s = at; 1.1580 + 1.1581 + /* Create new Request-URI taking URI user from ruri_user AVP 1.1582 + and other parts of from gateway URI AVP. */ 1.1583 + ru_avp = search_first_avp(ruri_user_avp_type, ruri_user_avp, 1.1584 + &ruri_user_val, 0); 1.1585 + if (!ru_avp) { 1.1586 + LM_DBG("ruri_user AVP no yet set -> use RURI\n"); 1.1587 + /* parse RURI and ger username */ 1.1588 + if (parse_sip_msg_uri(_m) < 0) { 1.1589 + LM_ERR("Parsing of R-URI failed\n"); 1.1590 + return -1; 1.1591 + } 1.1592 + ruri_user_val.s = _m->parsed_uri.user; 1.1593 + /* Save Request-URI user for use in FAILURE_ROUTE */ 1.1594 + val.s = _m->parsed_uri.user; 1.1595 + add_avp(ruri_user_avp_type|AVP_VAL_STR, ruri_user_avp, val); 1.1596 + LM_DBG("Added ruri_user_avp <%.*s>\n", val.s.len, val.s.s); 1.1597 + } 1.1598 + 1.1599 + new_ruri.s = pkg_malloc(gw_uri_val.s.len + ruri_user_val.s.len); 1.1600 + if (!new_ruri.s) { 1.1601 + LM_ERR("No memory for new R-URI.\n"); 1.1602 + return -1; 1.1603 + } 1.1604 + at_char = memchr(gw_uri_val.s.s, '@', gw_uri_val.s.len); 1.1605 + if (!at_char) { 1.1606 + pkg_free(new_ruri.s); 1.1607 + LM_ERR("No @ in gateway URI <%.*s>\n", 1.1608 + gw_uri_val.s.len, gw_uri_val.s.s); 1.1609 + return -1; 1.1610 + } 1.1611 + strip_char = memchr(gw_uri_val.s.s, '|', gw_uri_val.s.len); 1.1612 + if (!strip_char || strip_char + 1 >= at_char) { 1.1613 + pkg_free(new_ruri.s); 1.1614 + LM_ERR("No strip char | and at least one " 1.1615 + "char before @ in gateway URI <%.*s>\n", 1.1616 + gw_uri_val.s.len, gw_uri_val.s.s); 1.1617 + return -1; 1.1618 + } 1.1619 + at = new_ruri.s; 1.1620 + memcpy(at, gw_uri_val.s.s, strip_char - gw_uri_val.s.s); 1.1621 + at = at + (strip_char - gw_uri_val.s.s); 1.1622 + strip = strtol(strip_char + 1, &endptr, 10); 1.1623 + if (endptr != at_char) { 1.1624 + pkg_free(new_ruri.s); 1.1625 + LM_ERR("Non-digit char between | and @ chars in gw URI <%.*s>\n", 1.1626 + gw_uri_val.s.len, gw_uri_val.s.s); 1.1627 + return -1; 1.1628 + } 1.1629 + if (ruri_user_val.s.len - strip > 0) { 1.1630 + memcpy(at, ruri_user_val.s.s + strip, 1.1631 + ruri_user_val.s.len - strip); 1.1632 + at = at + ruri_user_val.s.len - strip; 1.1633 + } 1.1634 + if (*(at - 1) != ':') { 1.1635 + memcpy(at, at_char, gw_uri_val.s.len - (at_char - gw_uri_val.s.s)); 1.1636 + at = at + gw_uri_val.s.len - (at_char - gw_uri_val.s.s); 1.1637 + } else { 1.1638 + memcpy(at, at_char + 1, gw_uri_val.s.len - 1.1639 + (at_char + 1 - gw_uri_val.s.s)); 1.1640 + at = at + gw_uri_val.s.len - (at_char + 1 - gw_uri_val.s.s); 1.1641 + } 1.1642 + new_ruri.len = at - new_ruri.s; 1.1643 + 1.1644 + /* set new RURI */ 1.1645 + rval = set_ruri( _m, &new_ruri); 1.1646 + pkg_free(new_ruri.s); 1.1647 + destroy_avp(gu_avp); 1.1648 + if (rval!=0) { 1.1649 + LM_ERR("failed to set new RURI\n"); 1.1650 + return -1; 1.1651 + } 1.1652 + 1.1653 + return 1; 1.1654 +} 1.1655 + 1.1656 + 1.1657 +/* 1.1658 + * Checks if request comes from a gateway 1.1659 + */ 1.1660 +static int do_from_gw(struct sip_msg* _m, pv_spec_t *addr_sp, int grp_id) 1.1661 +{ 1.1662 + int i; 1.1663 + unsigned int src_addr; 1.1664 + pv_value_t pv_val; 1.1665 + struct ip_addr *ip; 1.1666 + int_str val; 1.1667 + 1.1668 + if (addr_sp && (pv_get_spec_value(_m, addr_sp, &pv_val) == 0)) { 1.1669 + if (pv_val.flags & PV_VAL_INT) { 1.1670 + src_addr = pv_val.ri; 1.1671 + } else if (pv_val.flags & PV_VAL_STR) { 1.1672 + if ( (ip=str2ip( &pv_val.rs)) == NULL) { 1.1673 + LM_ERR("failed to convert IP address string to in_addr\n"); 1.1674 + return -1; 1.1675 + } else { 1.1676 + src_addr = ip->u.addr32[0]; 1.1677 + } 1.1678 + } else { 1.1679 + LM_ERR("IP address PV empty value\n"); 1.1680 + return -1; 1.1681 + } 1.1682 + } else { 1.1683 + src_addr = _m->rcv.src_ip.u.addr32[0]; 1.1684 + } 1.1685 + 1.1686 + for (i = 0; i < MAX_NO_OF_GWS; i++) { 1.1687 + if ((*gws)[i].ip_addr == 0) { 1.1688 + return -1; 1.1689 + } 1.1690 + if ((*gws)[i].ip_addr == src_addr && 1.1691 + (grp_id < 0 || (*gws)[i].grp_id == grp_id)) { 1.1692 + LM_DBG("Request came from gw\n"); 1.1693 + val.n = (int)(*gws)[i].flags; 1.1694 + add_avp(flags_avp_type, flags_avp, val); 1.1695 + LM_DBG("Added flags_avp <%u>\n", (unsigned int)val.n); 1.1696 + return 1; 1.1697 + } 1.1698 + } 1.1699 + 1.1700 + LM_DBG("Request did not come from gw\n"); 1.1701 + return -1; 1.1702 +} 1.1703 + 1.1704 + 1.1705 +/* 1.1706 + * Checks if request comes from a gateway, taking source address from request 1.1707 + * and taking into account the group id. 1.1708 + */ 1.1709 +static int from_gw_grp(struct sip_msg* _m, char* _grp_id, char* _s2) 1.1710 +{ 1.1711 + return do_from_gw(_m, (pv_spec_t *)0, (int)(long)_grp_id); 1.1712 +} 1.1713 + 1.1714 + 1.1715 +/* 1.1716 + * Checks if request comes from a gateway, taking src_address from request 1.1717 + * and ignoring group id. 1.1718 + */ 1.1719 +static int from_gw_0(struct sip_msg* _m, char* _s1, char* _s2) 1.1720 +{ 1.1721 + return do_from_gw(_m, (pv_spec_t *)0, -1); 1.1722 +} 1.1723 + 1.1724 + 1.1725 +/* 1.1726 + * Checks if request comes from a gateway, taking source address from pw 1.1727 + * and ignoring group id. 1.1728 + */ 1.1729 +static int from_gw_1(struct sip_msg* _m, char* _addr_sp, char* _s2) 1.1730 +{ 1.1731 + return do_from_gw(_m, (pv_spec_t *)_addr_sp, -1); 1.1732 +} 1.1733 + 1.1734 + 1.1735 +/* 1.1736 + * Checks if in-dialog request goes to gateway 1.1737 + */ 1.1738 +static int do_to_gw(struct sip_msg* _m, int grp_id) 1.1739 +{ 1.1740 + char host[16]; 1.1741 + struct in_addr addr; 1.1742 + unsigned int i; 1.1743 + 1.1744 + if((_m->parsed_uri_ok == 0) && (parse_sip_msg_uri(_m) < 0)) { 1.1745 + LM_ERR("Error while parsing the R-URI\n"); 1.1746 + return -1; 1.1747 + } 1.1748 + 1.1749 + if (_m->parsed_uri.host.len > 15) { 1.1750 + return -1; 1.1751 + } 1.1752 + memcpy(host, _m->parsed_uri.host.s, _m->parsed_uri.host.len); 1.1753 + host[_m->parsed_uri.host.len] = 0; 1.1754 + 1.1755 + if (!inet_aton(host, &addr)) { 1.1756 + return -1; 1.1757 + } 1.1758 + 1.1759 + for (i = 0; i < MAX_NO_OF_GWS; i++) { 1.1760 + if ((*gws)[i].ip_addr == 0) { 1.1761 + return -1; 1.1762 + } 1.1763 + if ((*gws)[i].ip_addr == addr.s_addr && 1.1764 + (grp_id < 0 || (*gws)[i].grp_id == grp_id)) { 1.1765 + return 1; 1.1766 + } 1.1767 + } 1.1768 + 1.1769 + return -1; 1.1770 +} 1.1771 + 1.1772 + 1.1773 +/* 1.1774 + * Checks if in-dialog request goes to gateway, taking 1.1775 + * into account the group id. 1.1776 + */ 1.1777 +static int to_gw_grp(struct sip_msg* _m, char* _s1, char* _s2) 1.1778 +{ 1.1779 + int grp_id; 1.1780 + 1.1781 + grp_id = (int)(long)_s1; 1.1782 + return do_to_gw(_m, grp_id); 1.1783 +} 1.1784 + 1.1785 + 1.1786 +/* 1.1787 + * Checks if in-dialog request goes to gateway, ignoring 1.1788 + * the group id. 1.1789 + */ 1.1790 +static int to_gw(struct sip_msg* _m, char* _s1, char* _s2) 1.1791 +{ 1.1792 + return do_to_gw(_m, -1); 1.1793 +} 1.1794 + 1.1795 + 1.1796 +/* 1.1797 + * Frees contact list used by load_contacts function 1.1798 + */ 1.1799 +static inline void free_contact_list(struct contact *curr) { 1.1800 + struct contact *prev; 1.1801 + while (curr) { 1.1802 + prev = curr; 1.1803 + curr = curr->next; 1.1804 + pkg_free(prev); 1.1805 + } 1.1806 +} 1.1807 + 1.1808 +/* Encode branch info from contact struct to str */ 1.1809 +static inline int encode_branch_info(str *info, struct contact *con) 1.1810 +{ 1.1811 + char *at, *s; 1.1812 + int len; 1.1813 + 1.1814 + info->len = con->uri.len + con->dst_uri.len + 1.1815 + con->path.len + MAX_SOCKET_STR + INT2STR_MAX_LEN + 5; 1.1816 + info->s = pkg_malloc(info->len); 1.1817 + if (!info->s) { 1.1818 + LM_ERR("No memory left for branch info\n"); 1.1819 + return 0; 1.1820 + } 1.1821 + at = info->s; 1.1822 + memcpy(at, con->uri.s, con->uri.len); 1.1823 + at = at + con->uri.len; 1.1824 + *at = '\n'; 1.1825 + at++; 1.1826 + memcpy(at, con->dst_uri.s, con->dst_uri.len); 1.1827 + at = at + con->dst_uri.len; 1.1828 + *at = '\n'; 1.1829 + at++; 1.1830 + memcpy(at, con->path.s, con->path.len); 1.1831 + at = at + con->path.len; 1.1832 + *at = '\n'; 1.1833 + at++; 1.1834 + if (con->sock) { 1.1835 + len = MAX_SOCKET_STR; 1.1836 + if (!socket2str(con->sock, at, &len, 1)) { 1.1837 + LM_ERR("Failed to convert socket to str\n"); 1.1838 + return 0; 1.1839 + } 1.1840 + } else { 1.1841 + len = 0; 1.1842 + } 1.1843 + at = at + len; 1.1844 + *at = '\n'; 1.1845 + at++; 1.1846 + s = int2str(con->flags, &len); 1.1847 + memcpy(at, s, len); 1.1848 + at = at + len; 1.1849 + *at = '\n'; 1.1850 + info->len = at - info->s + 1; 1.1851 + 1.1852 + return 1; 1.1853 +} 1.1854 + 1.1855 + 1.1856 +/* Encode branch info from str */ 1.1857 +static inline int decode_branch_info(char *info, str *uri, str *dst, str *path, 1.1858 + struct socket_info **sock, unsigned int *flags) 1.1859 +{ 1.1860 + str s, host; 1.1861 + int port, proto; 1.1862 + char *pos, *at; 1.1863 + 1.1864 + pos = strchr(info, '\n'); 1.1865 + uri->len = pos - info; 1.1866 + if (uri->len) { 1.1867 + uri->s = info; 1.1868 + } else { 1.1869 + uri->s = 0; 1.1870 + } 1.1871 + at = pos + 1; 1.1872 + 1.1873 + pos = strchr(at, '\n'); 1.1874 + dst->len = pos - at; 1.1875 + if (dst->len) { 1.1876 + dst->s = at; 1.1877 + } else { 1.1878 + dst->s = 0; 1.1879 + } 1.1880 + at = pos + 1; 1.1881 + 1.1882 + pos = strchr(at, '\n'); 1.1883 + path->len = pos - at; 1.1884 + if (path->len) { 1.1885 + path->s = at; 1.1886 + } else { 1.1887 + path->s = 0; 1.1888 + } 1.1889 + at = pos + 1; 1.1890 + 1.1891 + pos = strchr(at, '\n'); 1.1892 + s.len = pos - at; 1.1893 + if (s.len) { 1.1894 + s.s = at; 1.1895 + if (parse_phostport(s.s, s.len, &host.s, &host.len, 1.1896 + &port, &proto) != 0) { 1.1897 + LM_ERR("Parsing of socket info <%.*s> failed\n", s.len, s.s); 1.1898 + return 0; 1.1899 + } 1.1900 + *sock = grep_sock_info(&host, (unsigned short)port, 1.1901 + (unsigned short)proto); 1.1902 + if (*sock == 0) { 1.1903 + LM_ERR("Invalid socket <%.*s>\n", s.len, s.s); 1.1904 + return 0; 1.1905 + } 1.1906 + } else { 1.1907 + *sock = 0; 1.1908 + } 1.1909 + at = pos + 1; 1.1910 + 1.1911 + pos = strchr(at, '\n'); 1.1912 + s.len = pos - at; 1.1913 + if (s.len) { 1.1914 + s.s = at; 1.1915 + if (str2int(&s, flags) != 0) { 1.1916 + LM_ERR("Failed to decode flags <%.*s>\n", s.len, s.s); 1.1917 + return 0; 1.1918 + } 1.1919 + } else { 1.1920 + *flags = 0; 1.1921 + } 1.1922 + 1.1923 + return 1; 1.1924 +} 1.1925 + 1.1926 + 1.1927 +/* 1.1928 + * Loads contacts in destination set into "lcr_contact" AVP in reverse 1.1929 + * priority order and associated each contact with Q_FLAG telling if 1.1930 + * contact is the last one in its priority class. Finally, removes 1.1931 + * all branches from destination set. 1.1932 + */ 1.1933 +static int load_contacts(struct sip_msg* msg, char* key, char* value) 1.1934 +{ 1.1935 + str uri, dst_uri, path, branch_info, *ruri; 1.1936 + qvalue_t q, ruri_q; 1.1937 + struct contact *contacts, *next, *prev, *curr; 1.1938 + int_str val; 1.1939 + int idx; 1.1940 + struct socket_info* sock; 1.1941 + unsigned int flags; 1.1942 + 1.1943 + /* Check if anything needs to be done */ 1.1944 + if (nr_branches == 0) { 1.1945 + LM_DBG("Nothing to do - no branches!\n"); 1.1946 + return 1; 1.1947 + } 1.1948 + 1.1949 + ruri = GET_RURI(msg); 1.1950 + if (!ruri) { 1.1951 + LM_ERR("No Request-URI found\n"); 1.1952 + return -1; 1.1953 + } 1.1954 + ruri_q = get_ruri_q(); 1.1955 + 1.1956 + for(idx = 0; (uri.s = get_branch(idx, &uri.len, &q, 0, 0, 0, 0)) != 0; 1.1957 + idx++) { 1.1958 + if (q != ruri_q) { 1.1959 + goto rest; 1.1960 + } 1.1961 + } 1.1962 + LM_DBG("Nothing to do - all contacts have same q!\n"); 1.1963 + return 1; 1.1964 + 1.1965 +rest: 1.1966 + /* Insert Request-URI branch to contact list */ 1.1967 + contacts = (struct contact *)pkg_malloc(sizeof(struct contact)); 1.1968 + if (!contacts) { 1.1969 + LM_ERR("No memory for contact info\n"); 1.1970 + return -1; 1.1971 + } 1.1972 + contacts->uri.s = ruri->s; 1.1973 + contacts->uri.len = ruri->len; 1.1974 + contacts->q = ruri_q; 1.1975 + contacts->dst_uri = msg->dst_uri; 1.1976 + contacts->sock = msg->force_send_socket; 1.1977 + contacts->flags = getb0flags(); 1.1978 + contacts->path = msg->path_vec; 1.1979 + contacts->next = (struct contact *)0; 1.1980 + 1.1981 + /* Insert branches to contact list in increasing q order */ 1.1982 + for(idx = 0; 1.1983 + (uri.s = get_branch(idx,&uri.len,&q,&dst_uri,&path,&flags,&sock)) 1.1984 + != 0; 1.1985 + idx++ ) { 1.1986 + next = (struct contact *)pkg_malloc(sizeof(struct contact)); 1.1987 + if (!next) { 1.1988 + LM_ERR("No memory for contact info\n"); 1.1989 + free_contact_list(contacts); 1.1990 + return -1; 1.1991 + } 1.1992 + next->uri = uri; 1.1993 + next->q = q; 1.1994 + next->dst_uri = dst_uri; 1.1995 + next->path = path; 1.1996 + next->flags = flags; 1.1997 + next->sock = sock; 1.1998 + next->next = (struct contact *)0; 1.1999 + prev = (struct contact *)0; 1.2000 + curr = contacts; 1.2001 + while (curr && (curr->q < q)) { 1.2002 + prev = curr; 1.2003 + curr = curr->next; 1.2004 + } 1.2005 + if (!curr) { 1.2006 + next->next = (struct contact *)0; 1.2007 + prev->next = next; 1.2008 + } else { 1.2009 + next->next = curr; 1.2010 + if (prev) { 1.2011 + prev->next = next; 1.2012 + } else { 1.2013 + contacts = next; 1.2014 + } 1.2015 + } 1.2016 + } 1.2017 + 1.2018 + /* Assign values for q_flags */ 1.2019 + curr = contacts; 1.2020 + curr->q_flag = 0; 1.2021 + while (curr->next) { 1.2022 + if (curr->q < curr->next->q) { 1.2023 + curr->next->q_flag = Q_FLAG; 1.2024 + } else { 1.2025 + curr->next->q_flag = 0; 1.2026 + } 1.2027 + curr = curr->next; 1.2028 + } 1.2029 + 1.2030 + /* Add contacts to "contacts" AVP */ 1.2031 + curr = contacts; 1.2032 + while (curr) { 1.2033 + if (encode_branch_info(&branch_info, curr) == 0) { 1.2034 + LM_ERR("Encoding of branch info failed\n"); 1.2035 + free_contact_list(contacts); 1.2036 + if (branch_info.s) pkg_free(branch_info.s); 1.2037 + return -1; 1.2038 + } 1.2039 + val.s = branch_info; 1.2040 + add_avp(contact_avp_type|AVP_VAL_STR|(curr->q_flag), 1.2041 + contact_avp, val); 1.2042 + pkg_free(branch_info.s); 1.2043 + LM_DBG("Loaded contact <%.*s> with q_flag <%d>\n", 1.2044 + val.s.len, val.s.s, curr->q_flag); 1.2045 + curr = curr->next; 1.2046 + } 1.2047 + 1.2048 + /* Clear all branches */ 1.2049 + clear_branches(); 1.2050 + 1.2051 + /* Free contact list */ 1.2052 + free_contact_list(contacts); 1.2053 + 1.2054 + return 1; 1.2055 +} 1.2056 + 1.2057 + 1.2058 +/* 1.2059 + * Adds to request a destination set that includes all highest priority 1.2060 + * class contacts in "lcr_contact" AVP. If called from a route block, 1.2061 + * rewrites the request uri with first contact and adds the remaining 1.2062 + * contacts as branches. If called from failure route block, adds all 1.2063 + * contacts as branches. Removes added contacts from "lcr_contact" AVP. 1.2064 + */ 1.2065 +static int next_contacts(struct sip_msg* msg, char* key, char* value) 1.2066 +{ 1.2067 + struct usr_avp *avp, *prev; 1.2068 + int_str val; 1.2069 + str uri, dst, path; 1.2070 + struct socket_info *sock; 1.2071 + unsigned int flags; 1.2072 + 1.2073 + /* Find first lcr_contact_avp value */ 1.2074 + avp = search_first_avp(contact_avp_type, contact_avp, &val, 0); 1.2075 + if (!avp) { 1.2076 + LM_DBG("No AVPs -- we are done!\n"); 1.2077 + return -1; 1.2078 + } 1.2079 + 1.2080 + LM_DBG("Next contact is <%s>\n", val.s.s); 1.2081 + 1.2082 + if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)== 0) { 1.2083 + LM_ERR("Decoding of branch info <%.*s> failed\n", 1.2084 + val.s.len, val.s.s); 1.2085 + destroy_avp(avp); 1.2086 + return -1; 1.2087 + } 1.2088 + 1.2089 + set_ruri(msg, &uri); 1.2090 + set_dst_uri(msg, &dst); 1.2091 + set_path_vector(msg, &path); 1.2092 + msg->force_send_socket = sock; 1.2093 + setb0flags(flags); 1.2094 + 1.2095 + if (avp->flags & Q_FLAG) { 1.2096 + destroy_avp(avp); 1.2097 + if (route_type == REQUEST_ROUTE) { 1.2098 + /* Set fr_inv_timer */ 1.2099 + val.n = fr_inv_timer_next; 1.2100 + if (add_avp(fr_inv_timer_avp_type, fr_inv_timer_avp, val) != 0) { 1.2101 + LM_ERR("Setting of fr_inv_timer_avp failed\n"); 1.2102 + return -1; 1.2103 + } 1.2104 + } 1.2105 + return 1; 1.2106 + } 1.2107 + 1.2108 + /* Append branches until out of branches or Q_FLAG is set */ 1.2109 + prev = avp; 1.2110 + while ((avp = search_next_avp(avp, &val))) { 1.2111 + destroy_avp(prev); 1.2112 + 1.2113 + LM_DBG("Next contact is <%s>\n", val.s.s); 1.2114 + 1.2115 + if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)== 0){ 1.2116 + LM_ERR("Decoding of branch info <%.*s> failed\n", 1.2117 + val.s.len, val.s.s); 1.2118 + destroy_avp(avp); 1.2119 + return -1; 1.2120 + } 1.2121 + 1.2122 + if (append_branch(msg, &uri, &dst, &path, 0, flags, sock) != 1) { 1.2123 + LM_ERR("Appending branch failed\n"); 1.2124 + destroy_avp(avp); 1.2125 + return -1; 1.2126 + } 1.2127 + 1.2128 + if (avp->flags & Q_FLAG) { 1.2129 + destroy_avp(avp); 1.2130 + if (route_type == REQUEST_ROUTE) { 1.2131 + val.n = fr_inv_timer_next; 1.2132 + if (add_avp(fr_inv_timer_avp_type, fr_inv_timer_avp, val)!= 0){ 1.2133 + LM_ERR("Setting of fr_inv_timer_avp failed\n"); 1.2134 + return -1; 1.2135 + } 1.2136 + } 1.2137 + return 1; 1.2138 + } 1.2139 + prev = avp; 1.2140 + } 1.2141 + 1.2142 + /* Restore fr_inv_timer */ 1.2143 + val.n = fr_inv_timer; 1.2144 + if (add_avp(fr_inv_timer_avp_type, fr_inv_timer_avp, val) != 0) { 1.2145 + LM_ERR("Setting of fr_inv_timer_avp failed\n"); 1.2146 + return -1; 1.2147 + } 1.2148 + 1.2149 + return 1; 1.2150 +} 1.2151 + 1.2152 + 1.2153 +/* 1.2154 + * Convert string parameter to integer for functions that expect an integer. 1.2155 + * Taken from sl module. 1.2156 + */ 1.2157 +static int fixstringloadgws(void **param, int param_count) 1.2158 +{ 1.2159 + pv_elem_t *model=NULL; 1.2160 + str s; 1.2161 + 1.2162 + /* convert to str */ 1.2163 + s.s = (char*)*param; 1.2164 + s.len = strlen(s.s); 1.2165 + 1.2166 + model=NULL; 1.2167 + if (param_count==1) { 1.2168 + if(s.len==0) { 1.2169 + LM_ERR("No param <%d>!\n", param_count); 1.2170 + return -1; 1.2171 + } 1.2172 + 1.2173 + if(pv_parse_format(&s,&model)<0 || model==NULL) { 1.2174 + LM_ERR("Wrong format <%s> for param <%d>!\n", s.s, param_count); 1.2175 + return -1; 1.2176 + } 1.2177 + if(model->spec.getf==NULL) { 1.2178 + if(param_count==1) { 1.2179 + if(str2int(&s, (unsigned int*)&model->spec.pvp.pvn.u.isname.name.n)!=0) { 1.2180 + LM_ERR("Wrong value <%s> for param <%d>!\n", 1.2181 + s.s, param_count); 1.2182 + return -1; 1.2183 + } 1.2184 + } 1.2185 + } 1.2186 + *param = (void*)model; 1.2187 + } 1.2188 + 1.2189 + return 0; 1.2190 +}
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/opensips/modules/uac/auth.c Wed Feb 10 21:14:04 2010 +0100 2.3 @@ -0,0 +1,468 @@ 2.4 +/* 2.5 + * $Id: auth.c 5901 2009-07-21 07:45:05Z bogdan_iancu $ 2.6 + * 2.7 + * Copyright (C) 2005 Voice Sistem SRL 2.8 + * 2.9 + * This file is part of opensips, a free SIP server. 2.10 + * 2.11 + * UAC OpenSIPS-module is free software; you can redistribute it and/or 2.12 + * modify it under the terms of the GNU General Public License 2.13 + * as published by the Free Software Foundation; either version 2 2.14 + * of the License, or (at your option) any later version. 2.15 + * 2.16 + * UAC OpenSIPS-module is distributed in the hope that it will be useful, 2.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 2.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 2.19 + * GNU General Public License for more details. 2.20 + * 2.21 + * You should have received a copy of the GNU General Public License 2.22 + * along with this program; if not, write to the Free Software 2.23 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 2.24 + * 2.25 + * 2.26 + * History: 2.27 + * --------- 2.28 + * 2005-01-31 first version (ramona) 2.29 + * 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan) 2.30 + */ 2.31 + 2.32 + 2.33 +#include <ctype.h> 2.34 +#include <string.h> 2.35 + 2.36 +#include "../../str.h" 2.37 +#include "../../dprint.h" 2.38 +#include "../../pvar.h" 2.39 +#include "../../data_lump.h" 2.40 +#include "../../mem/mem.h" 2.41 +#include "../tm/tm_load.h" 2.42 + 2.43 +#include "auth.h" 2.44 +#include "auth_alg.h" 2.45 +#include "auth_hdr.h" 2.46 + 2.47 + 2.48 +extern struct tm_binds uac_tmb; 2.49 +extern pv_spec_t auth_username_spec; 2.50 +extern pv_spec_t auth_realm_spec; 2.51 +extern pv_spec_t auth_password_spec; 2.52 + 2.53 + 2.54 +static struct uac_credential *crd_list = 0; 2.55 + 2.56 + 2.57 +#define duplicate_str(_strd, _strs, _error) \ 2.58 + do { \ 2.59 + _strd.s = (char*)pkg_malloc(_strs.len); \ 2.60 + if (_strd.s==0) \ 2.61 + { \ 2.62 + LM_ERR("no more pkg memory\n");\ 2.63 + goto _error; \ 2.64 + } \ 2.65 + memcpy( _strd.s, _strs.s, _strs.len); \ 2.66 + _strd.len = _strs.len; \ 2.67 + }while(0) 2.68 + 2.69 + 2.70 +#define WWW_AUTH_CODE 401 2.71 +#define WWW_AUTH_HDR "WWW-Authenticate" 2.72 +#define WWW_AUTH_HDR_LEN (sizeof(WWW_AUTH_HDR)-1) 2.73 +#define PROXY_AUTH_CODE 407 2.74 +#define PROXY_AUTH_HDR "Proxy-Authenticate" 2.75 +#define PROXY_AUTH_HDR_LEN (sizeof(PROXY_AUTH_HDR)-1) 2.76 + 2.77 +static str nc = {"00000001", 8}; 2.78 +static str cnonce = {"o", 1}; 2.79 + 2.80 +int has_credentials(void) 2.81 +{ 2.82 + return (crd_list!=0)?1:0; 2.83 +} 2.84 + 2.85 +void free_credential(struct uac_credential *crd) 2.86 +{ 2.87 + if (crd) 2.88 + { 2.89 + if (crd->realm.s) 2.90 + pkg_free(crd->realm.s); 2.91 + if (crd->user.s) 2.92 + pkg_free(crd->user.s); 2.93 + if (crd->passwd.s) 2.94 + pkg_free(crd->passwd.s); 2.95 + pkg_free(crd); 2.96 + } 2.97 +} 2.98 + 2.99 + 2.100 +int add_credential( unsigned int type, void *val) 2.101 +{ 2.102 + struct uac_credential *crd; 2.103 + char *p; 2.104 + str foo; 2.105 + 2.106 + p = (char*)val; 2.107 + crd = 0; 2.108 + 2.109 + if (p==0 || *p==0) 2.110 + goto error; 2.111 + 2.112 + crd = (struct uac_credential*)pkg_malloc(sizeof(struct uac_credential)); 2.113 + if (crd==0) 2.114 + { 2.115 + LM_ERR("no more pkg mem\n"); 2.116 + goto error; 2.117 + } 2.118 + memset( crd, 0, sizeof(struct uac_credential)); 2.119 + 2.120 + /*parse the user */ 2.121 + while (*p && isspace((int)*p)) p++; 2.122 + foo.s = p; 2.123 + while (*p && *p!=':' && !isspace((int)*p)) p++; 2.124 + if (foo.s==p || *p==0) 2.125 + /* missing or empty user */ 2.126 + goto parse_error; 2.127 + foo.len = p - foo.s; 2.128 + /* dulicate it */ 2.129 + duplicate_str( crd->user, foo, error); 2.130 + 2.131 + /* parse the ':' separator */ 2.132 + while (*p && isspace((int)*p)) p++; 2.133 + if (*p!=':') 2.134 + goto parse_error; 2.135 + p++; 2.136 + while (*p && isspace((int)*p)) p++; 2.137 + if (*p==0) 2.138 + goto parse_error; 2.139 + 2.140 + /*parse the realm */ 2.141 + while (*p && isspace((int)*p)) p++; 2.142 + foo.s = p; 2.143 + while (*p && *p!=':' && !isspace((int)*p)) p++; 2.144 + if (foo.s==p || *p==0) 2.145 + /* missing or empty realm */ 2.146 + goto parse_error; 2.147 + foo.len = p - foo.s; 2.148 + /* dulicate it */ 2.149 + duplicate_str( crd->realm, foo, error); 2.150 + 2.151 + /* parse the ':' separator */ 2.152 + while (*p && isspace((int)*p)) p++; 2.153 + if (*p!=':') 2.154 + goto parse_error; 2.155 + p++; 2.156 + while (*p && isspace((int)*p)) p++; 2.157 + if (*p==0) 2.158 + goto parse_error; 2.159 + 2.160 + /*parse the passwd */ 2.161 + while (*p && isspace((int)*p)) p++; 2.162 + foo.s = p; 2.163 + while (*p && !isspace((int)*p)) p++; 2.164 + if (foo.s==p) 2.165 + /* missing or empty passwd */ 2.166 + goto parse_error; 2.167 + foo.len = p - foo.s; 2.168 + /* dulicate it */ 2.169 + duplicate_str( crd->passwd, foo, error); 2.170 + 2.171 + /* end of string */ 2.172 + while (*p && isspace((int)*p)) p++; 2.173 + if (*p!=0) 2.174 + goto parse_error; 2.175 + 2.176 + /* link the new cred struct */ 2.177 + crd->next = crd_list; 2.178 + crd_list = crd; 2.179 + 2.180 + pkg_free(val); 2.181 + return 0; 2.182 +parse_error: 2.183 + LM_ERR("parse error in <%s> " 2.184 + "around %ld\n", (char*)val, (long)(p-(char*)val)); 2.185 +error: 2.186 + if (crd) 2.187 + free_credential(crd); 2.188 + return -1; 2.189 +} 2.190 + 2.191 + 2.192 +void destroy_credentials(void) 2.193 +{ 2.194 + struct uac_credential *foo; 2.195 + 2.196 + while (crd_list) 2.197 + { 2.198 + foo = crd_list; 2.199 + crd_list = crd_list->next; 2.200 + free_credential(foo); 2.201 + } 2.202 + crd_list = 0; 2.203 +} 2.204 + 2.205 + 2.206 +static inline struct hdr_field *get_autenticate_hdr(struct sip_msg *rpl, 2.207 + int rpl_code) 2.208 +{ 2.209 + struct hdr_field *hdr; 2.210 + str hdr_name; 2.211 + 2.212 + /* what hdr should we look for */ 2.213 + if (rpl_code==WWW_AUTH_CODE) 2.214 + { 2.215 + hdr_name.s = WWW_AUTH_HDR; 2.216 + hdr_name.len = WWW_AUTH_HDR_LEN; 2.217 + } else if (rpl_code==PROXY_AUTH_CODE) { 2.218 + hdr_name.s = PROXY_AUTH_HDR; 2.219 + hdr_name.len = PROXY_AUTH_HDR_LEN; 2.220 + } else { 2.221 + LM_ERR("reply is not an " 2.222 + "auth request\n"); 2.223 + goto error; 2.224 + } 2.225 + 2.226 + LM_DBG("looking for header \"%.*s\"\n", 2.227 + hdr_name.len, hdr_name.s); 2.228 + 2.229 + /* search the auth hdr, but first parse them all */ 2.230 + if (parse_headers( rpl, HDR_EOH_F, 0)<0) 2.231 + { 2.232 + LM_ERR("failed to parse reply\n"); 2.233 + goto error; 2.234 + } 2.235 + hdr = get_header_by_name( rpl , hdr_name.s, hdr_name.len); 2.236 + if (hdr) 2.237 + return hdr; 2.238 + 2.239 + LM_ERR("reply has no " 2.240 + "auth hdr (%.*s)\n", hdr_name.len, hdr_name.s); 2.241 +error: 2.242 + return 0; 2.243 +} 2.244 + 2.245 + 2.246 +static inline struct uac_credential *lookup_realm( str *realm) 2.247 +{ 2.248 + struct uac_credential *crd; 2.249 + 2.250 + for( crd=crd_list ; crd ; crd=crd->next ) 2.251 + if (realm->len==crd->realm.len && 2.252 + strncmp( realm->s, crd->realm.s, realm->len)==0 ) 2.253 + return crd; 2.254 + return 0; 2.255 +} 2.256 + 2.257 + 2.258 +static inline struct uac_credential *get_avp_credential(struct sip_msg *msg, 2.259 + str *realm) 2.260 +{ 2.261 + static struct uac_credential crd; 2.262 + pv_value_t pv_val; 2.263 + 2.264 + if(pv_get_spec_value( msg, &auth_realm_spec, &pv_val)!=0 2.265 + || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0) 2.266 + return 0; 2.267 + 2.268 + crd.realm = pv_val.rs; 2.269 + /* is it the domain we are looking for? */ 2.270 + if (realm->len!=crd.realm.len || 2.271 + strncmp( realm->s, crd.realm.s, realm->len)!=0 ) 2.272 + return 0; 2.273 + 2.274 + /* get username and password */ 2.275 + if(pv_get_spec_value( msg, &auth_username_spec, &pv_val)!=0 2.276 + || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0) 2.277 + return 0; 2.278 + crd.user = pv_val.rs; 2.279 + 2.280 + if(pv_get_spec_value( msg, &auth_password_spec, &pv_val)!=0 2.281 + || pv_val.flags&PV_VAL_NULL || pv_val.rs.len<=0) 2.282 + return 0; 2.283 + crd.passwd = pv_val.rs; 2.284 + 2.285 + return &crd; 2.286 +} 2.287 + 2.288 + 2.289 +static inline void do_uac_auth(struct sip_msg *req, str *uri, 2.290 + struct uac_credential *crd, struct authenticate_body *auth, 2.291 + HASHHEX response) 2.292 +{ 2.293 + HASHHEX ha1; 2.294 + HASHHEX ha2; 2.295 + 2.296 + if((auth->flags&QOP_AUTH) || (auth->flags&QOP_AUTH_INT)) 2.297 + { 2.298 + /* if qop generate nonce-count and cnonce */ 2.299 + cnonce.s = int2str(core_hash(&auth->nonce, 0, 0),&cnonce.len); 2.300 + 2.301 + /* do authentication */ 2.302 + uac_calc_HA1( crd, auth, &cnonce, ha1); 2.303 + uac_calc_HA2( &req->first_line.u.request.method, uri, 2.304 + auth, 0/*hentity*/, ha2 ); 2.305 + 2.306 + uac_calc_response( ha1, ha2, auth, &nc, &cnonce, response); 2.307 + auth->nc = &nc; 2.308 + auth->cnonce = &cnonce; 2.309 + } else { 2.310 + /* do authentication */ 2.311 + uac_calc_HA1( crd, auth, 0/*cnonce*/, ha1); 2.312 + uac_calc_HA2( &req->first_line.u.request.method, uri, 2.313 + auth, 0/*hentity*/, ha2 ); 2.314 + 2.315 + uac_calc_response( ha1, ha2, auth, 0/*nc*/, 0/*cnonce*/, response); 2.316 + } 2.317 +} 2.318 + 2.319 + 2.320 +static inline int apply_urihdr_changes( struct sip_msg *req, 2.321 + str *uri, str *hdr) 2.322 +{ 2.323 + struct lump* anchor; 2.324 + 2.325 + /* add the uri - move it to branch directly FIXME (bogdan)*/ 2.326 + if (req->new_uri.s) 2.327 + { 2.328 + pkg_free(req->new_uri.s); 2.329 + req->new_uri.len=0; 2.330 + } 2.331 + req->parsed_uri_ok=0; 2.332 + req->new_uri.s = (char*)pkg_malloc(uri->len+1); 2.333 + if (req->new_uri.s==0) 2.334 + { 2.335 + LM_ERR("no more pkg\n"); 2.336 + goto error; 2.337 + } 2.338 + memcpy( req->new_uri.s, uri->s, uri->len); 2.339 + req->new_uri.s[uri->len]=0; 2.340 + req->new_uri.len=uri->len; 2.341 + 2.342 + /* add the header */ 2.343 + if (parse_headers(req, HDR_EOH_F, 0) == -1) 2.344 + { 2.345 + LM_ERR("failed to parse message\n"); 2.346 + goto error; 2.347 + } 2.348 + 2.349 + anchor = anchor_lump(req, req->unparsed - req->buf, 0, 0); 2.350 + if (anchor==0) 2.351 + { 2.352 + LM_ERR("failed to get anchor\n"); 2.353 + goto error; 2.354 + } 2.355 + 2.356 + if (insert_new_lump_before(anchor, hdr->s, hdr->len, 0) == 0) 2.357 + { 2.358 + LM_ERR("faield to insert lump\n"); 2.359 + goto error; 2.360 + } 2.361 + 2.362 + return 0; 2.363 +error: 2.364 + pkg_free( hdr->s ); 2.365 + return -1; 2.366 +} 2.367 + 2.368 + 2.369 + 2.370 +int uac_auth( struct sip_msg *msg) 2.371 +{ 2.372 + static struct authenticate_body auth; 2.373 + struct uac_credential *crd; 2.374 + int code, branch; 2.375 + struct sip_msg *rpl; 2.376 + struct cell *t; 2.377 + struct hdr_field *hdr; 2.378 + HASHHEX response; 2.379 + str *new_hdr; 2.380 + 2.381 + /* get transaction */ 2.382 + t = uac_tmb.t_gett(); 2.383 + if (t==T_UNDEFINED || t==T_NULL_CELL) 2.384 + { 2.385 + LM_CRIT("no current transaction found\n"); 2.386 + goto error; 2.387 + } 2.388 + 2.389 + /* get the selected branch */ 2.390 + branch = uac_tmb.t_get_picked(); 2.391 + if (branch<0) { 2.392 + LM_CRIT("no picked branch (%d)\n",branch); 2.393 + goto error; 2.394 + } 2.395 + 2.396 + rpl = t->uac[branch].reply; 2.397 + code = t->uac[branch].last_received; 2.398 + LM_DBG("picked reply is %p, code %d\n",rpl,code); 2.399 + 2.400 + if (rpl==0) 2.401 + { 2.402 + LM_CRIT("empty reply on picked branch\n"); 2.403 + goto error; 2.404 + } 2.405 + if (rpl==FAKED_REPLY) 2.406 + { 2.407 + LM_ERR("cannot process a FAKED reply\n"); 2.408 + goto error; 2.409 + } 2.410 + 2.411 + hdr = get_autenticate_hdr( rpl, code); 2.412 + if (hdr==0) 2.413 + { 2.414 + LM_ERR("failed to extract authenticate hdr\n"); 2.415 + goto error; 2.416 + } 2.417 + 2.418 + LM_DBG("header found; body=<%.*s>\n", 2.419 + hdr->body.len, hdr->body.s); 2.420 + 2.421 + if (parse_authenticate_body( &hdr->body, &auth)<0) 2.422 + { 2.423 + LM_ERR("failed to parse auth hdr body\n"); 2.424 + goto error; 2.425 + } 2.426 + 2.427 + /* can we authenticate this realm? */ 2.428 + crd = 0; 2.429 + /* first look into AVP, if set */ 2.430 + if ( auth_realm_spec.type==PVT_AVP ) 2.431 + crd = get_avp_credential( msg, &auth.realm ); 2.432 + /* if not found, look into predefined credentials */ 2.433 + if (crd==0) 2.434 + crd = lookup_realm( &auth.realm ); 2.435 + /* found? */ 2.436 + if (crd==0) 2.437 + { 2.438 + LM_DBG("no credential for realm \"%.*s\"\n", 2.439 + auth.realm.len, auth.realm.s); 2.440 + goto error; 2.441 + } 2.442 + 2.443 + /* do authentication */ 2.444 + do_uac_auth( msg, &t->uac[branch].uri, crd, &auth, response); 2.445 + 2.446 + /* build the authorization header */ 2.447 + new_hdr = build_authorization_hdr( code, &t->uac[branch].uri, 2.448 + crd, &auth, response); 2.449 + if (new_hdr==0) 2.450 + { 2.451 + LM_ERR("failed to build authorization hdr\n"); 2.452 + goto error; 2.453 + } 2.454 + 2.455 + /* so far, so good -> add the header and set the proper RURI */ 2.456 + if ( apply_urihdr_changes( msg, &t->uac[branch].uri, new_hdr)<0 ) 2.457 + { 2.458 + LM_ERR("failed to apply changes\n"); 2.459 + goto error; 2.460 + } 2.461 + 2.462 + /* increas the Cseq nr */ 2.463 + 2.464 + 2.465 + return 0; 2.466 +error: 2.467 + return -1; 2.468 +} 2.469 + 2.470 + 2.471 +
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/opensips/modules/uac/uac.c Wed Feb 10 21:14:04 2010 +0100 3.3 @@ -0,0 +1,420 @@ 3.4 +/* 3.5 + * $Id: uac.c 6481 2009-12-29 13:49:37Z bogdan_iancu $ 3.6 + * 3.7 + * Copyright (C) 2005-2009 Voice Sistem SRL 3.8 + * 3.9 + * This file is part of opensips, a free SIP server. 3.10 + * 3.11 + * UAC OpenSIPS-module is free software; you can redistribute it and/or 3.12 + * modify it under the terms of the GNU General Public License 3.13 + * as published by the Free Software Foundation; either version 2 3.14 + * of the License, or (at your option) any later version. 3.15 + * 3.16 + * UAC OpenSIPS-module is distributed in the hope that it will be useful, 3.17 + * but WITHOUT ANY WARRANTY; without even the implied warranty of 3.18 + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 3.19 + * GNU General Public License for more details. 3.20 + * 3.21 + * You should have received a copy of the GNU General Public License 3.22 + * along with this program; if not, write to the Free Software 3.23 + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 3.24 + * 3.25 + * 3.26 + * History: 3.27 + * --------- 3.28 + * 2005-01-31 first version (ramona) 3.29 + * 2005-08-12 some TM callbacks replaced with RR callback - more efficient; 3.30 + * (bogdan) 3.31 + * 2006-03-02 UAC authentication looks first in AVPs for credential (bogdan) 3.32 + * 2006-03-03 the RR parameter is encrypted via XOR with a password 3.33 + * (bogdan) 3.34 + * 2009-08-22 TO header replacement added (bogdan) 3.35 + 3.36 + */ 3.37 + 3.38 + 3.39 +#include <stdio.h> 3.40 +#include <string.h> 3.41 +#include <stdlib.h> 3.42 + 3.43 +#include "../../sr_module.h" 3.44 +#include "../../dprint.h" 3.45 +#include "../../error.h" 3.46 +#include "../../pvar.h" 3.47 +#include "../../mem/mem.h" 3.48 +#include "../../parser/parse_from.h" 3.49 +#include "../tm/tm_load.h" 3.50 +#include "../tm/t_hooks.h" 3.51 +#include "../rr/api.h" 3.52 + 3.53 +#include "replace.h" 3.54 +#include "auth.h" 3.55 + 3.56 + 3.57 + 3.58 + 3.59 + 3.60 +/* local variable used for init */ 3.61 +static char* restore_mode_str = NULL; 3.62 +static char* auth_username_avp = NULL; 3.63 +static char* auth_realm_avp = NULL; 3.64 +static char* auth_password_avp = NULL; 3.65 + 3.66 +/* global param variables */ 3.67 +str rr_from_param = str_init("vsf"); 3.68 +str rr_to_param = str_init("vst"); 3.69 +str uac_passwd = str_init(""); 3.70 +int restore_mode = UAC_AUTO_RESTORE; 3.71 +struct tm_binds uac_tmb; 3.72 +struct rr_binds uac_rrb; 3.73 +pv_spec_t auth_username_spec; 3.74 +pv_spec_t auth_realm_spec; 3.75 +pv_spec_t auth_password_spec; 3.76 + 3.77 +static int w_replace_from(struct sip_msg* msg, char* p1, char* p2); 3.78 +static int w_restore_from(struct sip_msg* msg); 3.79 + 3.80 +static int w_replace_to(struct sip_msg* msg, char* p1, char* p2); 3.81 +static int w_restore_to(struct sip_msg* msg); 3.82 + 3.83 +static int w_uac_auth(struct sip_msg* msg, char* str, char* str2); 3.84 +static int fixup_replace_uri(void** param, int param_no); 3.85 +static int fixup_replace_disp_uri(void** param, int param_no); 3.86 +static int mod_init(void); 3.87 +static void mod_destroy(void); 3.88 + 3.89 + 3.90 +/* Exported functions */ 3.91 +static cmd_export_t cmds[]={ 3.92 + {"uac_replace_from", (cmd_function)w_replace_from, 2, 3.93 + fixup_replace_disp_uri, 0, 3.94 + REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, 3.95 + {"uac_replace_from", (cmd_function)w_replace_from, 1, 3.96 + fixup_replace_uri, 0, 3.97 + REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, 3.98 + {"uac_restore_from", (cmd_function)w_restore_from, 0, 3.99 + 0, 0, 3.100 + REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, 3.101 + {"uac_replace_to", (cmd_function)w_replace_to, 2, 3.102 + fixup_replace_disp_uri, 0, 3.103 + REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, 3.104 + {"uac_replace_to", (cmd_function)w_replace_to, 1, 3.105 + fixup_replace_uri, 0, 3.106 + REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, 3.107 + {"uac_restore_to", (cmd_function)w_restore_to, 0, 3.108 + 0, 0, 3.109 + REQUEST_ROUTE|BRANCH_ROUTE|FAILURE_ROUTE }, 3.110 + {"uac_auth", (cmd_function)w_uac_auth, 0, 3.111 + 0, 0, 3.112 + FAILURE_ROUTE }, 3.113 + {0,0,0,0,0,0} 3.114 +}; 3.115 + 3.116 + 3.117 + 3.118 +/* Exported parameters */ 3.119 +static param_export_t params[] = { 3.120 + {"rr_from_store_param", STR_PARAM, &rr_from_param.s }, 3.121 + {"rr_to_store_param", STR_PARAM, &rr_to_param.s }, 3.122 + {"restore_mode", STR_PARAM, &restore_mode_str }, 3.123 + {"restore_passwd", STR_PARAM, &uac_passwd.s }, 3.124 + {"credential", STR_PARAM|USE_FUNC_PARAM, (void*)&add_credential }, 3.125 + {"auth_username_avp", STR_PARAM, &auth_username_avp }, 3.126 + {"auth_realm_avp", STR_PARAM, &auth_realm_avp }, 3.127 + {"auth_password_avp", STR_PARAM, &auth_password_avp }, 3.128 + {0, 0, 0} 3.129 +}; 3.130 + 3.131 + 3.132 + 3.133 +struct module_exports exports= { 3.134 + "uac", 3.135 + MODULE_VERSION, 3.136 + DEFAULT_DLFLAGS, /* dlopen flags */ 3.137 + cmds, /* exported functions */ 3.138 + params, /* param exports */ 3.139 + 0, /* exported statistics */ 3.140 + 0, /* exported MI functions */ 3.141 + 0, /* exported pseudo-variables */ 3.142 + 0, /* extra processes */ 3.143 + mod_init, /* module initialization function */ 3.144 + (response_function) 0, 3.145 + mod_destroy, 3.146 + 0 /* per-child init function */ 3.147 +}; 3.148 + 3.149 + 3.150 +inline static int parse_auth_avp( char *avp_spec, pv_spec_t *avp, char *txt) 3.151 +{ 3.152 + str s; 3.153 + s.s = avp_spec; s.len = strlen(s.s); 3.154 + if (pv_parse_spec(&s, avp)==NULL) { 3.155 + LM_ERR("malformed or non AVP %s AVP definition\n",txt); 3.156 + return -1; 3.157 + } 3.158 + return 0; 3.159 +} 3.160 + 3.161 + 3.162 +static int mod_init(void) 3.163 +{ 3.164 + LM_INFO("initializing...\n"); 3.165 + 3.166 + if (restore_mode_str && *restore_mode_str) { 3.167 + if (strcasecmp(restore_mode_str,"none")==0) { 3.168 + restore_mode = UAC_NO_RESTORE; 3.169 + } else if (strcasecmp(restore_mode_str,"manual")==0) { 3.170 + restore_mode = UAC_MANUAL_RESTORE; 3.171 + } else if (strcasecmp(restore_mode_str,"auto")==0) { 3.172 + restore_mode = UAC_AUTO_RESTORE; 3.173 + } else { 3.174 + LM_ERR("unsupported value '%s' for restore_mode\n", 3.175 + restore_mode_str); 3.176 + goto error; 3.177 + } 3.178 + } 3.179 + 3.180 + rr_from_param.len = strlen(rr_from_param.s); 3.181 + rr_to_param.len = strlen(rr_to_param.s); 3.182 + if ( (rr_from_param.len==0 || rr_to_param.len==0) && 3.183 + restore_mode!=UAC_NO_RESTORE) 3.184 + { 3.185 + LM_ERR("rr_store_param cannot be empty if FROM is restoreable\n"); 3.186 + goto error; 3.187 + } 3.188 + 3.189 + uac_passwd.len = strlen(uac_passwd.s); 3.190 + 3.191 + /* parse the auth AVP spesc, if any */ 3.192 + if ( auth_username_avp || auth_password_avp || auth_realm_avp) { 3.193 + if (!auth_username_avp || !auth_password_avp || !auth_realm_avp) { 3.194 + LM_ERR("partial definition of auth AVP!"); 3.195 + goto error; 3.196 + } 3.197 + if ( parse_auth_avp(auth_realm_avp, &auth_realm_spec, "realm")<0 3.198 + || parse_auth_avp(auth_username_avp, &auth_username_spec, "username")<0 3.199 + || parse_auth_avp(auth_password_avp, &auth_password_spec, "password")<0 3.200 + ) { 3.201 + goto error; 3.202 + } 3.203 + } else { 3.204 + memset( &auth_realm_spec, 0, sizeof(pv_spec_t)); 3.205 + memset( &auth_password_spec, 0, sizeof(pv_spec_t)); 3.206 + memset( &auth_username_spec, 0, sizeof(pv_spec_t)); 3.207 + } 3.208 + 3.209 + /* load the TM API - FIXME it should be loaded only 3.210 + * if NO_RESTORE and AUTH */ 3.211 + if (load_tm_api(&uac_tmb)!=0) { 3.212 + LM_ERR("can't load TM API\n"); 3.213 + goto error; 3.214 + } 3.215 + 3.216 + if (restore_mode!=UAC_NO_RESTORE) { 3.217 + /* load the RR API */ 3.218 + if (load_rr_api(&uac_rrb)!=0) { 3.219 + LM_ERR("can't load RR API\n"); 3.220 + goto error; 3.221 + } 3.222 + 3.223 + if (restore_mode==UAC_AUTO_RESTORE) { 3.224 + /* we need the append_fromtag on in RR */ 3.225 + if (!uac_rrb.append_fromtag) { 3.226 + LM_ERR("'append_fromtag' RR param is not enabled!" 3.227 + " - required by AUTO restore mode\n"); 3.228 + goto error; 3.229 + } 3.230 + /* get all requests doing loose route */ 3.231 + if (uac_rrb.register_rrcb( rr_checker, 0)!=0) { 3.232 + LM_ERR("failed to install RR callback\n"); 3.233 + goto error; 3.234 + } 3.235 + } 3.236 + } 3.237 + 3.238 + init_from_replacer(); 3.239 + 3.240 + return 0; 3.241 +error: 3.242 + return -1; 3.243 +} 3.244 + 3.245 + 3.246 +static void mod_destroy(void) 3.247 +{ 3.248 + destroy_credentials(); 3.249 +} 3.250 + 3.251 + 3.252 + 3.253 +/************************** fixup functions ******************************/ 3.254 + 3.255 +static int fixup_replace_uri(void** param, int param_no) 3.256 +{ 3.257 + pv_elem_t *model; 3.258 + str s; 3.259 + 3.260 + model=NULL; 3.261 + s.s = (char*)(*param); s.len = strlen(s.s); 3.262 + if(pv_parse_format(&s, &model)<0) 3.263 + { 3.264 + LM_ERR("wrong format[%s]!\n",(char*)(*param)); 3.265 + return E_UNSPEC; 3.266 + } 3.267 + if (model==NULL) 3.268 + { 3.269 + LM_ERR("empty parameter!\n"); 3.270 + return E_UNSPEC; 3.271 + } 3.272 + *param = (void*)model; 3.273 + 3.274 + return 0; 3.275 +} 3.276 + 3.277 + 3.278 +static int fixup_replace_disp_uri(void** param, int param_no) 3.279 +{ 3.280 + pv_elem_t *model; 3.281 + char *p; 3.282 + str s; 3.283 + 3.284 + /* convert to str */ 3.285 + s.s = (char*)*param; 3.286 + s.len = strlen(s.s); 3.287 + 3.288 + model=NULL; 3.289 + if (param_no==1 && s.len) { 3.290 + /* put " around display name */ 3.291 + p = (char*)pkg_malloc(s.len+3); 3.292 + if (p==0) { 3.293 + LM_CRIT("no more pkg mem\n"); 3.294 + return E_OUT_OF_MEM; 3.295 + } 3.296 + p[0] = '\"'; 3.297 + memcpy(p+1, s.s, s.len); 3.298 + p[s.len+1] = '\"'; 3.299 + p[s.len+2] = '\0'; 3.300 + pkg_free(s.s); 3.301 + s.s = p; 3.302 + s.len += 2; 3.303 + } 3.304 + if(pv_parse_format(&s ,&model)<0) { 3.305 + LM_ERR("wrong format [%s] for param no %d!\n", s.s, param_no); 3.306 + pkg_free(s.s); 3.307 + return E_UNSPEC; 3.308 + } 3.309 + *param = (void*)model; 3.310 + 3.311 + return 0; 3.312 +} 3.313 + 3.314 + 3.315 + 3.316 +/************************** wrapper functions ******************************/ 3.317 + 3.318 +static int w_restore_from(struct sip_msg *msg) 3.319 +{ 3.320 + /* safety checks - must be a request */ 3.321 + if (msg->first_line.type!=SIP_REQUEST) { 3.322 + LM_ERR("called for something not request\n"); 3.323 + return -1; 3.324 + } 3.325 + 3.326 + return (restore_uri(msg,&rr_from_param,1)==0)?1:-1; 3.327 +} 3.328 + 3.329 + 3.330 +static int w_replace_from(struct sip_msg* msg, char* p1, char* p2) 3.331 +{ 3.332 + str uri_s; 3.333 + str dsp_s; 3.334 + str *uri; 3.335 + str *dsp; 3.336 + 3.337 + if (p2==NULL) { 3.338 + p2 = p1; 3.339 + p1 = NULL; 3.340 + dsp = NULL; 3.341 + } 3.342 + 3.343 + /* p1 dispaly , p2 uri */ 3.344 + 3.345 + if ( p1!=NULL ) { 3.346 + if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0) 3.347 + return -1; 3.348 + dsp = &dsp_s; 3.349 + } 3.350 + 3.351 + /* compute the URI string; if empty string -> make it NULL */ 3.352 + if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0) 3.353 + return -1; 3.354 + uri = uri_s.len?&uri_s:NULL; 3.355 + 3.356 + if (parse_from_header(msg)<0 ) { 3.357 + LM_ERR("failed to find/parse FROM hdr\n"); 3.358 + return -1; 3.359 + } 3.360 + 3.361 + LM_DBG("dsp=%p (len=%d) , uri=%p (len=%d)\n", 3.362 + dsp,dsp?dsp->len:0,uri,uri?uri->len:0); 3.363 + 3.364 + return (replace_uri(msg, dsp, uri, msg->from, &rr_from_param)==0)?1:-1; 3.365 +} 3.366 + 3.367 + 3.368 +static int w_restore_to(struct sip_msg *msg) 3.369 +{ 3.370 + /* safety checks - must be a request */ 3.371 + if (msg->first_line.type!=SIP_REQUEST) { 3.372 + LM_ERR("called for something not request\n"); 3.373 + return -1; 3.374 + } 3.375 + 3.376 + return (restore_uri(msg,&rr_to_param,0)==0)?1:-1; 3.377 +} 3.378 + 3.379 + 3.380 +static int w_replace_to(struct sip_msg* msg, char* p1, char* p2) 3.381 +{ 3.382 + str uri_s; 3.383 + str dsp_s; 3.384 + str *uri; 3.385 + str *dsp; 3.386 + 3.387 + if (p2==NULL) { 3.388 + p2 = p1; 3.389 + p1 = NULL; 3.390 + dsp = NULL; 3.391 + } 3.392 + 3.393 + /* p1 dispaly , p2 uri */ 3.394 + 3.395 + if ( p1!=NULL ) { 3.396 + if(pv_printf_s( msg, (pv_elem_p)p1, &dsp_s)!=0) 3.397 + return -1; 3.398 + dsp = &dsp_s; 3.399 + } 3.400 + 3.401 + /* compute the URI string; if empty string -> make it NULL */ 3.402 + if (pv_printf_s( msg, (pv_elem_p)p2, &uri_s)!=0) 3.403 + return -1; 3.404 + uri = uri_s.len?&uri_s:NULL; 3.405 + 3.406 + /* parse TO hdr */ 3.407 + if ( msg->to==0 && (parse_headers(msg,HDR_TO_F,0)!=0 || msg->to==0) ) { 3.408 + LM_ERR("failed to parse TO hdr\n"); 3.409 + return -1; 3.410 + } 3.411 + 3.412 + return (replace_uri(msg, dsp, uri, msg->to, &rr_to_param)==0)?1:-1; 3.413 +} 3.414 + 3.415 + 3.416 + 3.417 + 3.418 +static int w_uac_auth(struct sip_msg* msg, char* str, char* str2) 3.419 +{ 3.420 + return (uac_auth(msg)==0)?1:-1; 3.421 +} 3.422 + 3.423 +
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/opensips/scripts/db_berkeley/opensips/gw Wed Feb 10 21:14:04 2010 +0100 4.3 @@ -0,0 +1,10 @@ 4.4 +METADATA_COLUMNS 4.5 +id(int) gw_name(str) grp_id(int) ip_addr(str) port(int) uri_scheme(int) transport(int) strip(int) tag(str) flags(int) 4.6 +METADATA_KEY 4.7 +1 4.8 +METADATA_READONLY 4.9 +0 4.10 +METADATA_LOGFLAGS 4.11 +0 4.12 +METADATA_DEFAULTS 4.13 +NIL|NIL|NIL|NIL|NIL|NIL|NIL|NIL|NULL|0
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/opensips/scripts/dbtext/opensips/gw Wed Feb 10 21:14:04 2010 +0100 5.3 @@ -0,0 +1,1 @@ 5.4 +id(int,auto) gw_name(string) grp_id(int) ip_addr(string) port(int,null) uri_scheme(int,null) transport(int,null) strip(int,null) tag(string,null) flags(int)
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 6.2 +++ b/opensips/scripts/mysql/lcr-create.sql Wed Feb 10 21:14:04 2010 +0100 6.3 @@ -0,0 +1,30 @@ 6.4 +INSERT INTO version (table_name, table_version) values ('gw','8'); 6.5 +CREATE TABLE gw ( 6.6 + id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, 6.7 + gw_name CHAR(128) NOT NULL, 6.8 + grp_id INT UNSIGNED NOT NULL, 6.9 + ip_addr CHAR(15) NOT NULL, 6.10 + port SMALLINT UNSIGNED, 6.11 + uri_scheme TINYINT UNSIGNED, 6.12 + transport TINYINT UNSIGNED, 6.13 + strip TINYINT UNSIGNED, 6.14 + tag CHAR(16) DEFAULT NULL, 6.15 + flags INT UNSIGNED DEFAULT 0 NOT NULL, 6.16 + CONSTRAINT gw_name_idx UNIQUE (gw_name) 6.17 +) ENGINE=MyISAM; 6.18 + 6.19 +CREATE INDEX grp_id_idx ON gw (grp_id); 6.20 + 6.21 +INSERT INTO version (table_name, table_version) values ('lcr','3'); 6.22 +CREATE TABLE lcr ( 6.23 + id INT(10) UNSIGNED AUTO_INCREMENT PRIMARY KEY NOT NULL, 6.24 + prefix CHAR(16) DEFAULT NULL, 6.25 + from_uri CHAR(64) DEFAULT NULL, 6.26 + grp_id INT UNSIGNED NOT NULL, 6.27 + priority INT UNSIGNED NOT NULL 6.28 +) ENGINE=MyISAM; 6.29 + 6.30 +CREATE INDEX prefix_idx ON lcr (prefix); 6.31 +CREATE INDEX from_uri_idx ON lcr (from_uri); 6.32 +CREATE INDEX grp_id_idx ON lcr (grp_id); 6.33 +
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 7.2 +++ b/opensips/scripts/oracle/lcr-create.sql Wed Feb 10 21:14:04 2010 +0100 7.3 @@ -0,0 +1,46 @@ 7.4 +INSERT INTO version (table_name, table_version) values ('gw','8'); 7.5 +CREATE TABLE gw ( 7.6 + id NUMBER(10) PRIMARY KEY, 7.7 + gw_name VARCHAR2(128), 7.8 + grp_id NUMBER(10), 7.9 + ip_addr VARCHAR2(15), 7.10 + port NUMBER(5), 7.11 + uri_scheme NUMBER(5), 7.12 + transport NUMBER(5), 7.13 + strip NUMBER(5), 7.14 + tag VARCHAR2(16) DEFAULT NULL, 7.15 + flags NUMBER(10) DEFAULT 0 NOT NULL, 7.16 + CONSTRAINT gw_gw_name_idx UNIQUE (gw_name) 7.17 +); 7.18 + 7.19 +CREATE OR REPLACE TRIGGER gw_tr 7.20 +before insert on gw FOR EACH ROW 7.21 +BEGIN 7.22 + auto_id(:NEW.id); 7.23 +END gw_tr; 7.24 +/ 7.25 +BEGIN map2users('gw'); END; 7.26 +/ 7.27 +CREATE INDEX gw_grp_id_idx ON gw (grp_id); 7.28 + 7.29 +INSERT INTO version (table_name, table_version) values ('lcr','3'); 7.30 +CREATE TABLE lcr ( 7.31 + id NUMBER(10) PRIMARY KEY, 7.32 + prefix VARCHAR2(16) DEFAULT NULL, 7.33 + from_uri VARCHAR2(64) DEFAULT NULL, 7.34 + grp_id NUMBER(10), 7.35 + priority NUMBER(10) 7.36 +); 7.37 + 7.38 +CREATE OR REPLACE TRIGGER lcr_tr 7.39 +before insert on lcr FOR EACH ROW 7.40 +BEGIN 7.41 + auto_id(:NEW.id); 7.42 +END lcr_tr; 7.43 +/ 7.44 +BEGIN map2users('lcr'); END; 7.45 +/ 7.46 +CREATE INDEX lcr_prefix_idx ON lcr (prefix); 7.47 +CREATE INDEX lcr_from_uri_idx ON lcr (from_uri); 7.48 +CREATE INDEX lcr_grp_id_idx ON lcr (grp_id); 7.49 +
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 8.2 +++ b/opensips/scripts/postgres/lcr-create.sql Wed Feb 10 21:14:04 2010 +0100 8.3 @@ -0,0 +1,30 @@ 8.4 +INSERT INTO version (table_name, table_version) values ('gw','8'); 8.5 +CREATE TABLE gw ( 8.6 + id SERIAL PRIMARY KEY NOT NULL, 8.7 + gw_name VARCHAR(128) NOT NULL, 8.8 + grp_id INTEGER NOT NULL, 8.9 + ip_addr VARCHAR(15) NOT NULL, 8.10 + port SMALLINT, 8.11 + uri_scheme SMALLINT, 8.12 + transport SMALLINT, 8.13 + strip SMALLINT, 8.14 + tag VARCHAR(16) DEFAULT NULL, 8.15 + flags INTEGER DEFAULT 0 NOT NULL, 8.16 + CONSTRAINT gw_gw_name_idx UNIQUE (gw_name) 8.17 +); 8.18 + 8.19 +CREATE INDEX gw_grp_id_idx ON gw (grp_id); 8.20 + 8.21 +INSERT INTO version (table_name, table_version) values ('lcr','3'); 8.22 +CREATE TABLE lcr ( 8.23 + id SERIAL PRIMARY KEY NOT NULL, 8.24 + prefix VARCHAR(16) DEFAULT NULL, 8.25 + from_uri VARCHAR(64) DEFAULT NULL, 8.26 + grp_id INTEGER NOT NULL, 8.27 + priority INTEGER NOT NULL 8.28 +); 8.29 + 8.30 +CREATE INDEX lcr_prefix_idx ON lcr (prefix); 8.31 +CREATE INDEX lcr_from_uri_idx ON lcr (from_uri); 8.32 +CREATE INDEX lcr_grp_id_idx ON lcr (grp_id); 8.33 +