Wed, 10 Feb 2010 21:21:24 +0100
Introduce authentication credential logic into the LCR module.
This logic is meant to complement that of changeset 18, adding
additional authentication flexibility to the UAC module.
michael@16 | 1 | /* |
michael@16 | 2 | * $Id: lcr_mod.c 6015 2009-08-22 21:45:06Z bogdan_iancu $ |
michael@16 | 3 | * |
michael@16 | 4 | * Least Cost Routing module (also implements sequential forking) |
michael@16 | 5 | * |
michael@16 | 6 | * Copyright (C) 2005 Juha Heinanen |
michael@16 | 7 | * Copyright (C) 2006 Voice Sistem SRL |
michael@16 | 8 | * |
michael@16 | 9 | * This file is part of opensips, a free SIP server. |
michael@16 | 10 | * |
michael@16 | 11 | * opensips is free software; you can redistribute it and/or modify |
michael@16 | 12 | * it under the terms of the GNU General Public License as published by |
michael@16 | 13 | * the Free Software Foundation; either version 2 of the License, or |
michael@16 | 14 | * (at your option) any later version |
michael@16 | 15 | * |
michael@16 | 16 | * opensips is distributed in the hope that it will be useful, |
michael@16 | 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
michael@16 | 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
michael@16 | 19 | * GNU General Public License for more details. |
michael@16 | 20 | * |
michael@16 | 21 | * You should have received a copy of the GNU General Public License |
michael@16 | 22 | * along with this program; if not, write to the Free Software |
michael@16 | 23 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
michael@16 | 24 | * |
michael@16 | 25 | * History: |
michael@16 | 26 | * ------- |
michael@16 | 27 | * 2005-02-14: Introduced lcr module (jh) |
michael@16 | 28 | * 2005-02-20: Added sequential forking functions (jh) |
michael@16 | 29 | * 2005-02-25: Added support for int AVP names, combined addr and port |
michael@16 | 30 | * AVPs (jh) |
michael@16 | 31 | * 2005-07-28: Added support for gw URI scheme and transport, |
michael@16 | 32 | * backport from ser (kd) |
michael@16 | 33 | * 2005-08-20: Added support for gw prefixes (jh) |
michael@16 | 34 | * 2005-09-03: Request-URI user part can be modified between load_gws() |
michael@16 | 35 | * and first next_gw() calls. |
michael@16 | 36 | */ |
michael@16 | 37 | |
michael@16 | 38 | #include <stdio.h> |
michael@16 | 39 | #include <stdlib.h> |
michael@16 | 40 | #include <string.h> |
michael@16 | 41 | #include <sys/types.h> |
michael@16 | 42 | #include <sys/socket.h> |
michael@16 | 43 | #include <netinet/in.h> |
michael@16 | 44 | #include <arpa/inet.h> |
michael@16 | 45 | #include <regex.h> |
michael@16 | 46 | #include "../../sr_module.h" |
michael@16 | 47 | #include "../../dprint.h" |
michael@16 | 48 | #include "../../ut.h" |
michael@16 | 49 | #include "../../error.h" |
michael@16 | 50 | #include "../../mem/mem.h" |
michael@16 | 51 | #include "../../mem/shm_mem.h" |
michael@16 | 52 | #include "../../db/db.h" |
michael@16 | 53 | #include "../../usr_avp.h" |
michael@16 | 54 | #include "../../parser/parse_uri.h" |
michael@16 | 55 | #include "../../parser/parse_from.h" |
michael@16 | 56 | #include "../../parser/msg_parser.h" |
michael@16 | 57 | #include "../../action.h" |
michael@16 | 58 | #include "../../qvalue.h" |
michael@16 | 59 | #include "../../dset.h" |
michael@16 | 60 | #include "../../ip_addr.h" |
michael@16 | 61 | #include "../../resolve.h" |
michael@16 | 62 | #include "../../mi/mi.h" |
michael@16 | 63 | #include "../../mod_fix.h" |
michael@16 | 64 | #include "../../socket_info.h" |
michael@16 | 65 | #include "../../pvar.h" |
michael@16 | 66 | #include "../../mod_fix.h" |
michael@16 | 67 | #include "mi.h" |
michael@16 | 68 | |
michael@16 | 69 | |
michael@16 | 70 | |
michael@16 | 71 | /* |
michael@16 | 72 | * Version of gw and lcr tables required by the module, |
michael@16 | 73 | * increment this value if you change the table in |
michael@16 | 74 | * an backwards incompatible way |
michael@16 | 75 | */ |
michael@16 | 76 | #define GW_TABLE_VERSION 8 |
michael@16 | 77 | #define LCR_TABLE_VERSION 3 |
michael@16 | 78 | |
michael@16 | 79 | /* usr_avp flag for sequential forking */ |
michael@16 | 80 | #define Q_FLAG (1<<2) |
michael@16 | 81 | |
michael@16 | 82 | static void destroy(void); /* Module destroy function */ |
michael@16 | 83 | static int mi_child_init(void); |
michael@16 | 84 | static int mod_init(void); /* Module initialization function */ |
michael@16 | 85 | static int fixstringloadgws(void **param, int param_count); |
michael@16 | 86 | |
michael@16 | 87 | int reload_gws ( void ); |
michael@16 | 88 | |
michael@16 | 89 | #define GW_TABLE "gw" |
michael@16 | 90 | |
michael@16 | 91 | #define GW_NAME_COL "gw_name" |
michael@16 | 92 | |
michael@16 | 93 | #define GRP_ID_COL "grp_id" |
michael@16 | 94 | |
michael@16 | 95 | #define IP_ADDR_COL "ip_addr" |
michael@16 | 96 | |
michael@16 | 97 | #define PORT_COL "port" |
michael@16 | 98 | |
michael@16 | 99 | #define URI_SCHEME_COL "uri_scheme" |
michael@16 | 100 | |
michael@16 | 101 | #define TRANSPORT_COL "transport" |
michael@16 | 102 | |
michael@16 | 103 | #define STRIP_COL "strip" |
michael@16 | 104 | |
michael@16 | 105 | #define TAG_COL "tag" |
michael@16 | 106 | |
michael@16 | 107 | #define FLAGS_COL "flags" |
michael@16 | 108 | |
michael@16 | 109 | #define LCR_TABLE "lcr" |
michael@16 | 110 | |
michael@16 | 111 | #define PREFIX_COL "prefix" |
michael@16 | 112 | |
michael@16 | 113 | #define FROM_URI_COL "from_uri" |
michael@16 | 114 | |
michael@16 | 115 | #define PRIORITY_COL "priority" |
michael@16 | 116 | |
michael@17 | 117 | #define USER_COL "user" |
michael@17 | 118 | |
michael@17 | 119 | #define REALM_COL "realm" |
michael@17 | 120 | |
michael@17 | 121 | #define PASSWD_COL "passwd" |
michael@17 | 122 | |
michael@16 | 123 | #define MAX_NO_OF_GWS 32 |
michael@16 | 124 | #define MAX_NO_OF_LCRS 256 |
michael@16 | 125 | #define MAX_PREFIX_LEN 256 |
michael@17 | 126 | #define MAX_USER_LEN 64 |
michael@17 | 127 | #define MAX_REALM_LEN 64 |
michael@17 | 128 | #define MAX_PASSWD_LEN 64 |
michael@16 | 129 | #define MAX_TAG_LEN 16 |
michael@16 | 130 | #define MAX_FROM_URI_LEN 256 |
michael@16 | 131 | |
michael@16 | 132 | /* Default module parameter values */ |
michael@16 | 133 | #define DEF_FR_INV_TIMER 90 |
michael@16 | 134 | #define DEF_FR_INV_TIMER_NEXT 30 |
michael@16 | 135 | #define DEF_PREFIX_MODE 0 |
michael@16 | 136 | |
michael@16 | 137 | /* |
michael@16 | 138 | * Type definitions |
michael@16 | 139 | */ |
michael@16 | 140 | |
michael@16 | 141 | typedef enum sip_protos uri_transport; |
michael@16 | 142 | |
michael@16 | 143 | struct gw_info { |
michael@16 | 144 | unsigned int ip_addr; |
michael@16 | 145 | unsigned int port; |
michael@16 | 146 | unsigned int grp_id; |
michael@16 | 147 | uri_type scheme; |
michael@16 | 148 | uri_transport transport; |
michael@16 | 149 | unsigned int strip; |
michael@16 | 150 | char tag[MAX_TAG_LEN + 1]; |
michael@16 | 151 | unsigned short tag_len; |
michael@16 | 152 | unsigned int flags; |
michael@17 | 153 | char user[MAX_USER_LEN]; |
michael@17 | 154 | unsigned short user_len; |
michael@17 | 155 | char realm[MAX_REALM_LEN]; |
michael@17 | 156 | unsigned short realm_len; |
michael@17 | 157 | char passwd[MAX_PASSWD_LEN]; |
michael@17 | 158 | unsigned short passwd_len; |
michael@16 | 159 | }; |
michael@16 | 160 | |
michael@16 | 161 | struct lcr_info { |
michael@16 | 162 | char prefix[MAX_PREFIX_LEN + 1]; |
michael@16 | 163 | unsigned short prefix_len; |
michael@16 | 164 | char from_uri[MAX_FROM_URI_LEN + 1]; |
michael@16 | 165 | unsigned short from_uri_len; |
michael@16 | 166 | unsigned int grp_id; |
michael@16 | 167 | unsigned short priority; |
michael@16 | 168 | unsigned short end_record; |
michael@16 | 169 | }; |
michael@16 | 170 | |
michael@16 | 171 | struct prefix_regex { |
michael@16 | 172 | regex_t re; |
michael@16 | 173 | short int valid; |
michael@16 | 174 | }; |
michael@16 | 175 | |
michael@16 | 176 | struct from_uri_regex { |
michael@16 | 177 | regex_t re; |
michael@16 | 178 | short int valid; |
michael@16 | 179 | }; |
michael@16 | 180 | |
michael@16 | 181 | struct mi { |
michael@16 | 182 | int gw_index; |
michael@16 | 183 | int route_index; |
michael@16 | 184 | int randomizer; |
michael@16 | 185 | }; |
michael@16 | 186 | |
michael@16 | 187 | |
michael@16 | 188 | /* |
michael@16 | 189 | * Database variables |
michael@16 | 190 | */ |
michael@16 | 191 | static db_con_t* db_handle = 0; /* Database connection handle */ |
michael@16 | 192 | static db_func_t lcr_dbf; |
michael@16 | 193 | |
michael@16 | 194 | /* |
michael@16 | 195 | * Module parameter variables |
michael@16 | 196 | */ |
michael@16 | 197 | |
michael@16 | 198 | /* database */ |
michael@16 | 199 | static str db_url = str_init(DEFAULT_RODB_URL); |
michael@16 | 200 | static str gw_table = str_init(GW_TABLE); |
michael@16 | 201 | static str gw_name_col = str_init(GW_NAME_COL); |
michael@16 | 202 | static str grp_id_col = str_init(GRP_ID_COL); |
michael@16 | 203 | static str ip_addr_col = str_init(IP_ADDR_COL); |
michael@16 | 204 | static str port_col = str_init(PORT_COL); |
michael@16 | 205 | static str uri_scheme_col = str_init(URI_SCHEME_COL); |
michael@16 | 206 | static str transport_col = str_init(TRANSPORT_COL); |
michael@16 | 207 | static str strip_col = str_init(STRIP_COL); |
michael@16 | 208 | static str tag_col = str_init(TAG_COL); |
michael@16 | 209 | static str flags_col = str_init(FLAGS_COL); |
michael@16 | 210 | static str lcr_table = str_init(LCR_TABLE); |
michael@16 | 211 | static str prefix_col = str_init(PREFIX_COL); |
michael@16 | 212 | static str from_uri_col = str_init(FROM_URI_COL); |
michael@16 | 213 | static str priority_col = str_init(PRIORITY_COL); |
michael@17 | 214 | static str user_col = str_init(USER_COL); |
michael@17 | 215 | static str realm_col = str_init(REALM_COL); |
michael@17 | 216 | static str passwd_col = str_init(PASSWD_COL); |
michael@16 | 217 | |
michael@16 | 218 | /* timer */ |
michael@16 | 219 | int fr_inv_timer = DEF_FR_INV_TIMER; |
michael@16 | 220 | int fr_inv_timer_next = DEF_FR_INV_TIMER_NEXT; |
michael@16 | 221 | |
michael@16 | 222 | /* avps */ |
michael@16 | 223 | static char *fr_inv_timer_avp_param = NULL; |
michael@16 | 224 | static char *gw_uri_avp_param = NULL; |
michael@16 | 225 | static char *ruri_user_avp_param = NULL; |
michael@16 | 226 | static char *contact_avp_param = NULL; |
michael@16 | 227 | static char *rpid_avp_param = NULL; |
michael@16 | 228 | static char *flags_avp_param = NULL; |
michael@17 | 229 | static char *user_avp_param = NULL; |
michael@17 | 230 | static char *realm_avp_param = NULL; |
michael@17 | 231 | static char *passwd_avp_param = NULL; |
michael@16 | 232 | |
michael@16 | 233 | /* prefix mode */ |
michael@16 | 234 | int prefix_mode_param = DEF_PREFIX_MODE; |
michael@16 | 235 | |
michael@16 | 236 | /* |
michael@16 | 237 | * Other module types and variables |
michael@16 | 238 | */ |
michael@16 | 239 | |
michael@16 | 240 | struct contact { |
michael@16 | 241 | str uri; |
michael@16 | 242 | qvalue_t q; |
michael@16 | 243 | str dst_uri; |
michael@16 | 244 | str path; |
michael@16 | 245 | unsigned int flags; |
michael@16 | 246 | struct socket_info* sock; |
michael@16 | 247 | unsigned short q_flag; |
michael@16 | 248 | struct contact *next; |
michael@16 | 249 | }; |
michael@16 | 250 | |
michael@16 | 251 | static int fr_inv_timer_avp_type; |
michael@16 | 252 | static int_str fr_inv_timer_avp; |
michael@16 | 253 | static int gw_uri_avp_type; |
michael@16 | 254 | static int_str gw_uri_avp; |
michael@16 | 255 | static int ruri_user_avp_type; |
michael@16 | 256 | static int_str ruri_user_avp; |
michael@16 | 257 | static int contact_avp_type; |
michael@16 | 258 | static int_str contact_avp; |
michael@16 | 259 | static int rpid_avp_type; |
michael@16 | 260 | static int_str rpid_avp; |
michael@16 | 261 | static int flags_avp_type; |
michael@16 | 262 | static int_str flags_avp; |
michael@17 | 263 | static int user_avp_type; |
michael@17 | 264 | static int_str user_avp; |
michael@17 | 265 | static int realm_avp_type; |
michael@17 | 266 | static int_str realm_avp; |
michael@17 | 267 | static int passwd_avp_type; |
michael@17 | 268 | static int_str passwd_avp; |
michael@16 | 269 | |
michael@16 | 270 | struct gw_info **gws; /* Pointer to current gw table pointer */ |
michael@16 | 271 | struct gw_info *gws_1; /* Pointer to gw table 1 */ |
michael@16 | 272 | struct gw_info *gws_2; /* Pointer to gw table 2 */ |
michael@16 | 273 | |
michael@16 | 274 | struct lcr_info **lcrs; /* Pointer to current lcr table pointer */ |
michael@16 | 275 | struct lcr_info *lcrs_1; /* Pointer to lcr table 1 */ |
michael@16 | 276 | struct lcr_info *lcrs_2; /* Pointer to lcr table 2 */ |
michael@16 | 277 | |
michael@16 | 278 | unsigned int *lcrs_ws_reload_counter; |
michael@16 | 279 | unsigned int reload_counter; |
michael@16 | 280 | |
michael@16 | 281 | struct prefix_regex prefix_reg[MAX_NO_OF_LCRS]; |
michael@16 | 282 | struct from_uri_regex from_uri_reg[MAX_NO_OF_LCRS]; |
michael@16 | 283 | |
michael@16 | 284 | /* |
michael@16 | 285 | * Module functions that are defined later |
michael@16 | 286 | */ |
michael@16 | 287 | static int load_gws_0(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 288 | static int load_gws_1(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 289 | static int load_gws_from_grp(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 290 | static int next_gw(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 291 | static int from_gw_0(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 292 | static int from_gw_1(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 293 | static int from_gw_grp(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 294 | static int to_gw(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 295 | static int to_gw_grp(struct sip_msg* _m, char* _s1, char* _s2); |
michael@16 | 296 | static int load_contacts (struct sip_msg*, char*, char*); |
michael@16 | 297 | static int next_contacts (struct sip_msg*, char*, char*); |
michael@16 | 298 | |
michael@16 | 299 | |
michael@16 | 300 | /* |
michael@16 | 301 | * Exported functions |
michael@16 | 302 | */ |
michael@16 | 303 | static cmd_export_t cmds[] = { |
michael@16 | 304 | {"load_gws", (cmd_function)load_gws_0, 0, 0, 0, REQUEST_ROUTE}, |
michael@16 | 305 | {"load_gws", (cmd_function)load_gws_1, 1, fixup_pvar_null, |
michael@16 | 306 | fixup_free_pvar_null, REQUEST_ROUTE}, |
michael@16 | 307 | {"load_gws_from_grp", (cmd_function)load_gws_from_grp, 1, |
michael@16 | 308 | fixstringloadgws, 0, REQUEST_ROUTE}, |
michael@16 | 309 | {"next_gw", (cmd_function)next_gw, 0, 0, 0, |
michael@16 | 310 | REQUEST_ROUTE | FAILURE_ROUTE}, |
michael@16 | 311 | {"from_gw", (cmd_function)from_gw_0, 0, 0, 0, |
michael@16 | 312 | REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE}, |
michael@16 | 313 | {"from_gw", (cmd_function)from_gw_1, 1, fixup_pvar_null, |
michael@16 | 314 | fixup_free_pvar_null, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE}, |
michael@16 | 315 | {"from_gw_grp", (cmd_function)from_gw_grp, 1, fixup_uint_null, 0, |
michael@16 | 316 | REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE}, |
michael@16 | 317 | {"to_gw", (cmd_function)to_gw, 0, 0, 0, |
michael@16 | 318 | REQUEST_ROUTE | FAILURE_ROUTE}, |
michael@16 | 319 | {"to_gw", (cmd_function)to_gw_grp, 1, fixup_uint_null, 0, |
michael@16 | 320 | REQUEST_ROUTE | FAILURE_ROUTE}, |
michael@16 | 321 | {"load_contacts", (cmd_function)load_contacts, 0, 0, 0, |
michael@16 | 322 | REQUEST_ROUTE}, |
michael@16 | 323 | {"next_contacts", (cmd_function)next_contacts, 0, 0, 0, |
michael@16 | 324 | REQUEST_ROUTE | FAILURE_ROUTE}, |
michael@16 | 325 | {0, 0, 0, 0, 0, 0} |
michael@16 | 326 | }; |
michael@16 | 327 | |
michael@16 | 328 | |
michael@16 | 329 | /* |
michael@16 | 330 | * Exported parameters |
michael@16 | 331 | */ |
michael@16 | 332 | static param_export_t params[] = { |
michael@16 | 333 | {"db_url", STR_PARAM, &db_url.s }, |
michael@16 | 334 | {"gw_table", STR_PARAM, &gw_table.s }, |
michael@16 | 335 | {"gw_name_column", STR_PARAM, &gw_name_col.s }, |
michael@16 | 336 | {"grp_id_column", STR_PARAM, &grp_id_col.s }, |
michael@16 | 337 | {"ip_addr_column", STR_PARAM, &ip_addr_col.s }, |
michael@16 | 338 | {"port_column", STR_PARAM, &port_col.s }, |
michael@16 | 339 | {"uri_scheme_column", STR_PARAM, &uri_scheme_col.s }, |
michael@16 | 340 | {"transport_column", STR_PARAM, &transport_col.s }, |
michael@16 | 341 | {"strip_column", STR_PARAM, &strip_col.s }, |
michael@16 | 342 | {"tag_column", STR_PARAM, &tag_col.s }, |
michael@16 | 343 | {"flags_column", STR_PARAM, &flags_col.s }, |
michael@16 | 344 | {"lcr_table", STR_PARAM, &lcr_table.s }, |
michael@16 | 345 | {"prefix_column", STR_PARAM, &prefix_col.s }, |
michael@16 | 346 | {"from_uri_column", STR_PARAM, &from_uri_col.s }, |
michael@16 | 347 | {"priority_column", STR_PARAM, &priority_col.s }, |
michael@16 | 348 | {"fr_inv_timer_avp", STR_PARAM, &fr_inv_timer_avp_param }, |
michael@16 | 349 | {"gw_uri_avp", STR_PARAM, &gw_uri_avp_param }, |
michael@16 | 350 | {"ruri_user_avp", STR_PARAM, &ruri_user_avp_param }, |
michael@16 | 351 | {"contact_avp", STR_PARAM, &contact_avp_param }, |
michael@16 | 352 | {"rpid_avp", STR_PARAM, &rpid_avp_param }, |
michael@16 | 353 | {"flags_avp", STR_PARAM, &flags_avp_param }, |
michael@16 | 354 | {"fr_inv_timer", INT_PARAM, &fr_inv_timer }, |
michael@16 | 355 | {"fr_inv_timer_next", INT_PARAM, &fr_inv_timer_next }, |
michael@16 | 356 | {"prefix_mode", INT_PARAM, &prefix_mode_param }, |
michael@17 | 357 | {"user_column", STR_PARAM, &user_col.s }, |
michael@17 | 358 | {"realm_column", STR_PARAM, &realm_col.s }, |
michael@17 | 359 | {"passwd_column", STR_PARAM, &passwd_col.s }, |
michael@17 | 360 | {"auth_username_avp", STR_PARAM, &user_avp_param }, |
michael@17 | 361 | {"auth_realm_avp", STR_PARAM, &realm_avp_param }, |
michael@17 | 362 | {"auth_password_avp", STR_PARAM, &passwd_avp_param }, |
michael@16 | 363 | {0, 0, 0} |
michael@16 | 364 | }; |
michael@16 | 365 | |
michael@16 | 366 | |
michael@16 | 367 | /* |
michael@16 | 368 | * Exported MI functions |
michael@16 | 369 | */ |
michael@16 | 370 | static mi_export_t mi_cmds[] = { |
michael@16 | 371 | { MI_LCR_RELOAD, mi_lcr_reload, MI_NO_INPUT_FLAG, 0, mi_child_init }, |
michael@16 | 372 | { MI_LCR_DUMP, mi_lcr_dump, MI_NO_INPUT_FLAG, 0, 0 }, |
michael@16 | 373 | { 0, 0, 0, 0 ,0} |
michael@16 | 374 | }; |
michael@16 | 375 | |
michael@16 | 376 | |
michael@16 | 377 | /* |
michael@16 | 378 | * Module interface |
michael@16 | 379 | */ |
michael@16 | 380 | struct module_exports exports = { |
michael@16 | 381 | "lcr", |
michael@16 | 382 | MODULE_VERSION, |
michael@16 | 383 | DEFAULT_DLFLAGS, /* dlopen flags */ |
michael@16 | 384 | cmds, /* Exported functions */ |
michael@16 | 385 | params, /* Exported parameters */ |
michael@16 | 386 | 0, /* exported statistics */ |
michael@16 | 387 | mi_cmds, /* exported MI functions */ |
michael@16 | 388 | 0, /* exported pseudo-variables */ |
michael@16 | 389 | 0, /* extra processes */ |
michael@16 | 390 | mod_init, /* module initialization function */ |
michael@16 | 391 | 0, /* response function */ |
michael@16 | 392 | destroy, /* destroy function */ |
michael@16 | 393 | 0 /* child initialization function */ |
michael@16 | 394 | }; |
michael@16 | 395 | |
michael@16 | 396 | |
michael@16 | 397 | static int lcr_db_init(const str* db_url) |
michael@16 | 398 | { |
michael@16 | 399 | if (lcr_dbf.init==0){ |
michael@16 | 400 | LM_CRIT("Null lcr_dbf\n"); |
michael@16 | 401 | goto error; |
michael@16 | 402 | } |
michael@16 | 403 | db_handle=lcr_dbf.init(db_url); |
michael@16 | 404 | if (db_handle==0){ |
michael@16 | 405 | LM_ERR("Unable to connect to the database\n"); |
michael@16 | 406 | goto error; |
michael@16 | 407 | } |
michael@16 | 408 | return 0; |
michael@16 | 409 | error: |
michael@16 | 410 | return -1; |
michael@16 | 411 | } |
michael@16 | 412 | |
michael@16 | 413 | |
michael@16 | 414 | |
michael@16 | 415 | static int lcr_db_bind(const str* db_url) |
michael@16 | 416 | { |
michael@16 | 417 | if (db_bind_mod(db_url, &lcr_dbf)<0){ |
michael@16 | 418 | LM_ERR("Unable to bind to the database module\n"); |
michael@16 | 419 | return -1; |
michael@16 | 420 | } |
michael@16 | 421 | |
michael@16 | 422 | if (!DB_CAPABILITY(lcr_dbf, DB_CAP_QUERY)) { |
michael@16 | 423 | LM_ERR("Database module does not implement 'query' function\n"); |
michael@16 | 424 | return -1; |
michael@16 | 425 | } |
michael@16 | 426 | |
michael@16 | 427 | return 0; |
michael@16 | 428 | } |
michael@16 | 429 | |
michael@16 | 430 | |
michael@16 | 431 | static void lcr_db_close(void) |
michael@16 | 432 | { |
michael@16 | 433 | if (db_handle && lcr_dbf.close){ |
michael@16 | 434 | lcr_dbf.close(db_handle); |
michael@16 | 435 | db_handle=0; |
michael@16 | 436 | } |
michael@16 | 437 | } |
michael@16 | 438 | |
michael@16 | 439 | |
michael@16 | 440 | static int mi_child_init(void) |
michael@16 | 441 | { |
michael@16 | 442 | return lcr_db_init(&db_url); |
michael@16 | 443 | } |
michael@16 | 444 | |
michael@16 | 445 | |
michael@16 | 446 | /* |
michael@16 | 447 | * Module initialization function that is called before the main process forks |
michael@16 | 448 | */ |
michael@16 | 449 | static int mod_init(void) |
michael@16 | 450 | { |
michael@16 | 451 | int i; |
michael@16 | 452 | pv_spec_t avp_spec; |
michael@16 | 453 | str s; |
michael@16 | 454 | unsigned short avp_flags; |
michael@16 | 455 | |
michael@16 | 456 | LM_DBG("Initializing\n"); |
michael@16 | 457 | |
michael@16 | 458 | /* Update length of module variables */ |
michael@16 | 459 | db_url.len = strlen(db_url.s); |
michael@16 | 460 | gw_table.len = strlen(gw_table.s); |
michael@16 | 461 | gw_name_col.len = strlen(gw_name_col.s); |
michael@16 | 462 | grp_id_col.len = strlen(grp_id_col.s); |
michael@16 | 463 | ip_addr_col.len = strlen(ip_addr_col.s); |
michael@16 | 464 | port_col.len = strlen(port_col.s); |
michael@16 | 465 | uri_scheme_col.len = strlen(uri_scheme_col.s); |
michael@16 | 466 | transport_col.len = strlen(transport_col.s); |
michael@16 | 467 | strip_col.len = strlen(strip_col.s); |
michael@16 | 468 | tag_col.len = strlen(tag_col.s); |
michael@16 | 469 | flags_col.len = strlen(flags_col.s); |
michael@16 | 470 | lcr_table.len = strlen(lcr_table.s); |
michael@16 | 471 | prefix_col.len = strlen(prefix_col.s); |
michael@16 | 472 | from_uri_col.len = strlen(from_uri_col.s); |
michael@16 | 473 | priority_col.len = strlen(priority_col.s); |
michael@17 | 474 | user_col.len = strlen(user_col.s); |
michael@17 | 475 | realm_col.len = strlen(realm_col.s); |
michael@17 | 476 | passwd_col.len = strlen(passwd_col.s); |
michael@16 | 477 | |
michael@16 | 478 | /* Bind database */ |
michael@16 | 479 | if (lcr_db_bind(&db_url)) { |
michael@16 | 480 | LM_ERR("No database module found\n"); |
michael@16 | 481 | return -1; |
michael@16 | 482 | } |
michael@16 | 483 | |
michael@16 | 484 | /* Check value of prefix_mode */ |
michael@16 | 485 | if ((prefix_mode_param != 0) && (prefix_mode_param != 1)) { |
michael@16 | 486 | LM_ERR("Invalid prefix_mode value <%d>\n", prefix_mode_param); |
michael@16 | 487 | return -1; |
michael@16 | 488 | } |
michael@16 | 489 | |
michael@16 | 490 | /* Process AVP params */ |
michael@16 | 491 | if (fr_inv_timer_avp_param && *fr_inv_timer_avp_param) { |
michael@16 | 492 | s.s = fr_inv_timer_avp_param; s.len = strlen(s.s); |
michael@16 | 493 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@16 | 494 | || avp_spec.type!=PVT_AVP) { |
michael@16 | 495 | LM_ERR("Malformed or non AVP definition <%s>\n", |
michael@16 | 496 | fr_inv_timer_avp_param); |
michael@16 | 497 | return -1; |
michael@16 | 498 | } |
michael@16 | 499 | |
michael@16 | 500 | if(pv_get_avp_name(0, &(avp_spec.pvp), &fr_inv_timer_avp, &avp_flags)!=0) { |
michael@16 | 501 | LM_ERR("Invalid AVP definition <%s>\n", fr_inv_timer_avp_param); |
michael@16 | 502 | return -1; |
michael@16 | 503 | } |
michael@16 | 504 | fr_inv_timer_avp_type = avp_flags; |
michael@16 | 505 | } else { |
michael@16 | 506 | LM_ERR("AVP fr_inv_timer_avp has not been defined\n"); |
michael@16 | 507 | return -1; |
michael@16 | 508 | } |
michael@16 | 509 | |
michael@16 | 510 | if (gw_uri_avp_param && *gw_uri_avp_param) { |
michael@16 | 511 | s.s = gw_uri_avp_param; s.len = strlen(s.s); |
michael@16 | 512 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@16 | 513 | || avp_spec.type!=PVT_AVP) { |
michael@16 | 514 | LM_ERR("Malformed or non AVP definition <%s>\n", gw_uri_avp_param); |
michael@16 | 515 | return -1; |
michael@16 | 516 | } |
michael@16 | 517 | |
michael@16 | 518 | if(pv_get_avp_name(0, &(avp_spec.pvp), &gw_uri_avp, &avp_flags)!=0) { |
michael@16 | 519 | LM_ERR("Invalid AVP definition <%s>\n", gw_uri_avp_param); |
michael@16 | 520 | return -1; |
michael@16 | 521 | } |
michael@16 | 522 | gw_uri_avp_type = avp_flags; |
michael@16 | 523 | } else { |
michael@16 | 524 | LM_ERR("AVP gw_uri_avp has not been defined\n"); |
michael@16 | 525 | return -1; |
michael@16 | 526 | } |
michael@16 | 527 | |
michael@16 | 528 | if (ruri_user_avp_param && *ruri_user_avp_param) { |
michael@16 | 529 | s.s = ruri_user_avp_param; s.len = strlen(s.s); |
michael@16 | 530 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@16 | 531 | || avp_spec.type!=PVT_AVP) { |
michael@16 | 532 | LM_ERR("Malformed or non AVP definition <%s>\n", |
michael@16 | 533 | ruri_user_avp_param); |
michael@16 | 534 | return -1; |
michael@16 | 535 | } |
michael@16 | 536 | |
michael@16 | 537 | if(pv_get_avp_name(0, &(avp_spec.pvp), &ruri_user_avp, &avp_flags)!=0) { |
michael@16 | 538 | LM_ERR("Invalid AVP definition <%s>\n", ruri_user_avp_param); |
michael@16 | 539 | return -1; |
michael@16 | 540 | } |
michael@16 | 541 | ruri_user_avp_type = avp_flags; |
michael@16 | 542 | } else { |
michael@16 | 543 | LM_ERR("AVP ruri_user_avp has not been defined\n"); |
michael@16 | 544 | return -1; |
michael@16 | 545 | } |
michael@16 | 546 | |
michael@16 | 547 | if (contact_avp_param && *contact_avp_param) { |
michael@16 | 548 | s.s = contact_avp_param; s.len = strlen(s.s); |
michael@16 | 549 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@16 | 550 | || avp_spec.type!=PVT_AVP) { |
michael@16 | 551 | LM_ERR("Malformed or non AVP definition <%s>\n", |
michael@16 | 552 | contact_avp_param); |
michael@16 | 553 | return -1; |
michael@16 | 554 | } |
michael@16 | 555 | |
michael@16 | 556 | if(pv_get_avp_name(0, &(avp_spec.pvp), &contact_avp, &avp_flags)!=0) { |
michael@16 | 557 | LM_ERR("Invalid AVP definition <%s>\n", contact_avp_param); |
michael@16 | 558 | return -1; |
michael@16 | 559 | } |
michael@16 | 560 | contact_avp_type = avp_flags; |
michael@16 | 561 | } else { |
michael@16 | 562 | LM_ERR("AVP contact_avp has not been defined\n"); |
michael@16 | 563 | return -1; |
michael@16 | 564 | } |
michael@16 | 565 | |
michael@16 | 566 | if (rpid_avp_param && *rpid_avp_param) { |
michael@16 | 567 | s.s = rpid_avp_param; s.len = strlen(s.s); |
michael@16 | 568 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@16 | 569 | || avp_spec.type!=PVT_AVP) { |
michael@16 | 570 | LM_ERR("Malformed or non AVP definition <%s>\n", rpid_avp_param); |
michael@16 | 571 | return -1; |
michael@16 | 572 | } |
michael@16 | 573 | |
michael@16 | 574 | if(pv_get_avp_name(0, &(avp_spec.pvp), &rpid_avp, &avp_flags)!=0) { |
michael@16 | 575 | LM_ERR("Invalid AVP definition <%s>\n", rpid_avp_param); |
michael@16 | 576 | return -1; |
michael@16 | 577 | } |
michael@16 | 578 | rpid_avp_type = avp_flags; |
michael@16 | 579 | } else { |
michael@16 | 580 | LM_ERR("AVP rpid_avp has not been defined\n"); |
michael@16 | 581 | return -1; |
michael@16 | 582 | } |
michael@16 | 583 | |
michael@16 | 584 | if (flags_avp_param && *flags_avp_param) { |
michael@16 | 585 | s.s = flags_avp_param; s.len = strlen(s.s); |
michael@16 | 586 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@16 | 587 | || avp_spec.type!=PVT_AVP) { |
michael@16 | 588 | LM_ERR("Malformed or non AVP definition <%s>\n", flags_avp_param); |
michael@16 | 589 | return -1; |
michael@16 | 590 | } |
michael@16 | 591 | |
michael@16 | 592 | if(pv_get_avp_name(0, &(avp_spec.pvp), &flags_avp, &avp_flags)!=0) { |
michael@16 | 593 | LM_ERR("Invalid AVP definition <%s>\n", flags_avp_param); |
michael@16 | 594 | return -1; |
michael@16 | 595 | } |
michael@16 | 596 | flags_avp_type = avp_flags; |
michael@16 | 597 | } else { |
michael@16 | 598 | LM_ERR("AVP flags_avp has not been defined\n"); |
michael@16 | 599 | return -1; |
michael@16 | 600 | } |
michael@16 | 601 | |
michael@17 | 602 | if (user_avp_param && *user_avp_param) { |
michael@17 | 603 | s.s = user_avp_param; s.len = strlen(s.s); |
michael@17 | 604 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@17 | 605 | || avp_spec.type!=PVT_AVP) { |
michael@17 | 606 | LM_ERR("Malformed or non AVP definition <%s>\n", user_avp_param); |
michael@17 | 607 | return -1; |
michael@17 | 608 | } |
michael@17 | 609 | |
michael@17 | 610 | if(pv_get_avp_name(0, &(avp_spec.pvp), &user_avp, &avp_flags)!=0) { |
michael@17 | 611 | LM_ERR("Invalid AVP definition <%s>\n", user_avp_param); |
michael@17 | 612 | return -1; |
michael@17 | 613 | } |
michael@17 | 614 | user_avp_type = avp_flags; |
michael@17 | 615 | } else { |
michael@17 | 616 | LM_ERR("AVP user_avp has not been defined\n"); |
michael@17 | 617 | return -1; |
michael@17 | 618 | } |
michael@17 | 619 | |
michael@17 | 620 | if (realm_avp_param && *realm_avp_param) { |
michael@17 | 621 | s.s = realm_avp_param; s.len = strlen(s.s); |
michael@17 | 622 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@17 | 623 | || avp_spec.type!=PVT_AVP) { |
michael@17 | 624 | LM_ERR("Malformed or non AVP definition <%s>\n", realm_avp_param); |
michael@17 | 625 | return -1; |
michael@17 | 626 | } |
michael@17 | 627 | |
michael@17 | 628 | if(pv_get_avp_name(0, &(avp_spec.pvp), &realm_avp, &avp_flags)!=0) { |
michael@17 | 629 | LM_ERR("Invalid AVP definition <%s>\n", realm_avp_param); |
michael@17 | 630 | return -1; |
michael@17 | 631 | } |
michael@17 | 632 | realm_avp_type = avp_flags; |
michael@17 | 633 | } else { |
michael@17 | 634 | LM_ERR("AVP realm_avp has not been defined\n"); |
michael@17 | 635 | return -1; |
michael@17 | 636 | } |
michael@17 | 637 | |
michael@17 | 638 | if (passwd_avp_param && *passwd_avp_param) { |
michael@17 | 639 | s.s = passwd_avp_param; s.len = strlen(s.s); |
michael@17 | 640 | if (pv_parse_spec(&s, &avp_spec)==0 |
michael@17 | 641 | || avp_spec.type!=PVT_AVP) { |
michael@17 | 642 | LM_ERR("Malformed or non AVP definition <%s>\n", passwd_avp_param); |
michael@17 | 643 | return -1; |
michael@17 | 644 | } |
michael@17 | 645 | |
michael@17 | 646 | if(pv_get_avp_name(0, &(avp_spec.pvp), &passwd_avp, &avp_flags)!=0) { |
michael@17 | 647 | LM_ERR("Invalid AVP definition <%s>\n", passwd_avp_param); |
michael@17 | 648 | return -1; |
michael@17 | 649 | } |
michael@17 | 650 | passwd_avp_type = avp_flags; |
michael@17 | 651 | } else { |
michael@17 | 652 | LM_ERR("AVP passwd_avp has not been defined\n"); |
michael@17 | 653 | return -1; |
michael@17 | 654 | } |
michael@17 | 655 | |
michael@16 | 656 | /* Check table version */ |
michael@16 | 657 | db_con_t* dbh; |
michael@16 | 658 | if (lcr_dbf.init==0){ |
michael@16 | 659 | LM_CRIT("Unbound database\n"); |
michael@16 | 660 | return -1; |
michael@16 | 661 | } |
michael@16 | 662 | dbh=lcr_dbf.init(&db_url); |
michael@16 | 663 | if (dbh==0){ |
michael@16 | 664 | LM_ERR("Unable to open database connection\n"); |
michael@16 | 665 | return -1; |
michael@16 | 666 | } |
michael@16 | 667 | if((db_check_table_version(&lcr_dbf, dbh, &gw_table, GW_TABLE_VERSION) < 0) || |
michael@16 | 668 | (db_check_table_version(&lcr_dbf, dbh, &lcr_table, LCR_TABLE_VERSION) < 0)) { |
michael@16 | 669 | LM_ERR("error during table version check.\n"); |
michael@16 | 670 | lcr_dbf.close(dbh); |
michael@16 | 671 | goto err; |
michael@16 | 672 | } |
michael@16 | 673 | lcr_dbf.close(dbh); |
michael@16 | 674 | |
michael@16 | 675 | /* Initializing gw tables and gw table pointer variable */ |
michael@16 | 676 | gws_1 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) * |
michael@16 | 677 | (MAX_NO_OF_GWS + 1)); |
michael@16 | 678 | if (gws_1 == 0) { |
michael@16 | 679 | LM_ERR("No memory for gw table\n"); |
michael@16 | 680 | goto err; |
michael@16 | 681 | } |
michael@16 | 682 | gws_2 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) * |
michael@16 | 683 | (MAX_NO_OF_GWS + 1)); |
michael@16 | 684 | if (gws_2 == 0) { |
michael@16 | 685 | LM_ERR("No memory for gw table\n"); |
michael@16 | 686 | goto err; |
michael@16 | 687 | } |
michael@16 | 688 | for (i = 0; i < MAX_NO_OF_GWS + 1; i++) { |
michael@16 | 689 | gws_1[i].ip_addr = gws_2[i].ip_addr = 0; |
michael@16 | 690 | } |
michael@16 | 691 | gws = (struct gw_info **)shm_malloc(sizeof(struct gw_info *)); |
michael@16 | 692 | if (gws == 0) { |
michael@16 | 693 | LM_ERR("No memory for gw table pointer\n"); |
michael@16 | 694 | } |
michael@16 | 695 | *gws = gws_1; |
michael@16 | 696 | |
michael@16 | 697 | /* Initializing lcr tables and lcr table pointer variable */ |
michael@16 | 698 | lcrs_1 = (struct lcr_info *)shm_malloc(sizeof(struct lcr_info) * |
michael@16 | 699 | (MAX_NO_OF_LCRS + 1)); |
michael@16 | 700 | if (lcrs_1 == 0) { |
michael@16 | 701 | LM_ERR("No memory for lcr table\n"); |
michael@16 | 702 | goto err; |
michael@16 | 703 | } |
michael@16 | 704 | lcrs_2 = (struct lcr_info *)shm_malloc(sizeof(struct lcr_info) * |
michael@16 | 705 | (MAX_NO_OF_LCRS + 1)); |
michael@16 | 706 | if (lcrs_2 == 0) { |
michael@16 | 707 | LM_ERR("No memory for lcr table\n"); |
michael@16 | 708 | goto err; |
michael@16 | 709 | } |
michael@16 | 710 | for (i = 0; i < MAX_NO_OF_LCRS + 1; i++) { |
michael@16 | 711 | lcrs_1[i].end_record = lcrs_2[i].end_record = 0; |
michael@16 | 712 | } |
michael@16 | 713 | lcrs = (struct lcr_info **)shm_malloc(sizeof(struct lcr_info *)); |
michael@16 | 714 | if (lcrs == 0) { |
michael@16 | 715 | LM_ERR("No memory for lcr table pointer\n"); |
michael@16 | 716 | goto err; |
michael@16 | 717 | } |
michael@16 | 718 | *lcrs = lcrs_1; |
michael@16 | 719 | |
michael@16 | 720 | lcrs_ws_reload_counter = (unsigned int *)shm_malloc(sizeof(unsigned int)); |
michael@16 | 721 | if (lcrs_ws_reload_counter == 0) { |
michael@16 | 722 | LM_ERR("No memory for reload counter\n"); |
michael@16 | 723 | goto err; |
michael@16 | 724 | } |
michael@16 | 725 | *lcrs_ws_reload_counter = reload_counter = 0; |
michael@16 | 726 | |
michael@16 | 727 | memset(prefix_reg, 0, sizeof(struct prefix_regex) * MAX_NO_OF_LCRS); |
michael@16 | 728 | memset(from_uri_reg, 0, sizeof(struct from_uri_regex) * MAX_NO_OF_LCRS); |
michael@16 | 729 | |
michael@16 | 730 | /* First reload */ |
michael@16 | 731 | if (reload_gws() == -1) { |
michael@16 | 732 | LM_CRIT("Failed to reload gateways and routes\n"); |
michael@16 | 733 | goto err; |
michael@16 | 734 | } |
michael@16 | 735 | |
michael@16 | 736 | return 0; |
michael@16 | 737 | |
michael@16 | 738 | err: |
michael@16 | 739 | return -1; |
michael@16 | 740 | } |
michael@16 | 741 | |
michael@16 | 742 | |
michael@16 | 743 | static void destroy(void) |
michael@16 | 744 | { |
michael@16 | 745 | lcr_db_close(); |
michael@16 | 746 | } |
michael@16 | 747 | |
michael@16 | 748 | /* |
michael@16 | 749 | * Sort lcr records by prefix_len and priority. |
michael@16 | 750 | */ |
michael@16 | 751 | static int comp_lcrs(const void *m1, const void *m2) |
michael@16 | 752 | { |
michael@16 | 753 | int result = -1; |
michael@16 | 754 | |
michael@16 | 755 | struct mi *mi1 = (struct mi *) m1; |
michael@16 | 756 | struct mi *mi2 = (struct mi *) m2; |
michael@16 | 757 | |
michael@16 | 758 | struct lcr_info lcr_record1 = (*lcrs)[mi1->route_index]; |
michael@16 | 759 | struct lcr_info lcr_record2 = (*lcrs)[mi2->route_index]; |
michael@16 | 760 | |
michael@16 | 761 | if (prefix_mode_param == 0) { |
michael@16 | 762 | /* Sort by prefix. */ |
michael@16 | 763 | if (lcr_record1.prefix_len > lcr_record2.prefix_len) { |
michael@16 | 764 | result = 1; |
michael@16 | 765 | } else if (lcr_record1.prefix_len == lcr_record2.prefix_len) { |
michael@16 | 766 | /* Sort by priority. */ |
michael@16 | 767 | if (lcr_record1.priority < lcr_record2.priority) { |
michael@16 | 768 | result = 1; |
michael@16 | 769 | } else if (lcr_record1.priority == lcr_record2.priority) { |
michael@16 | 770 | /* Nothing to do. */ |
michael@16 | 771 | result = 0; |
michael@16 | 772 | } |
michael@16 | 773 | } |
michael@16 | 774 | } else { |
michael@16 | 775 | if (lcr_record1.priority < lcr_record2.priority) { |
michael@16 | 776 | result = 1; |
michael@16 | 777 | } else if (lcr_record1.priority == lcr_record2.priority) { |
michael@16 | 778 | /* Nothing to do. */ |
michael@16 | 779 | result = 0; |
michael@16 | 780 | } |
michael@16 | 781 | } |
michael@16 | 782 | |
michael@16 | 783 | return result; |
michael@16 | 784 | } |
michael@16 | 785 | |
michael@16 | 786 | /* |
michael@16 | 787 | * Sort lcr records by rand table. |
michael@16 | 788 | */ |
michael@16 | 789 | static int rand_lcrs(const void *m1, const void *m2) |
michael@16 | 790 | { |
michael@16 | 791 | int result = -1; |
michael@16 | 792 | |
michael@16 | 793 | struct mi mi1 = *((struct mi *) m1); |
michael@16 | 794 | struct mi mi2 = *((struct mi *) m2); |
michael@16 | 795 | |
michael@16 | 796 | if (mi1.randomizer > mi2.randomizer) { |
michael@16 | 797 | result = 1; |
michael@16 | 798 | } else if (mi1.randomizer == mi2.randomizer) { |
michael@16 | 799 | result = 0; |
michael@16 | 800 | } |
michael@16 | 801 | |
michael@16 | 802 | return result; |
michael@16 | 803 | } |
michael@16 | 804 | |
michael@16 | 805 | /* |
michael@16 | 806 | * regcomp each prefix. |
michael@16 | 807 | */ |
michael@16 | 808 | static int load_prefix_regex(void) |
michael@16 | 809 | { |
michael@16 | 810 | int i, status, result = 0; |
michael@16 | 811 | |
michael@16 | 812 | for (i = 0; i < MAX_NO_OF_LCRS; i++) { |
michael@16 | 813 | if ((*lcrs)[i].end_record != 0) { |
michael@16 | 814 | break; |
michael@16 | 815 | } |
michael@16 | 816 | if (prefix_reg[i].valid) { |
michael@16 | 817 | regfree(&(prefix_reg[i].re)); |
michael@16 | 818 | prefix_reg[i].valid = 0; |
michael@16 | 819 | } |
michael@16 | 820 | memset(&(prefix_reg[i].re), 0, sizeof(regex_t)); |
michael@16 | 821 | if ((status=regcomp(&(prefix_reg[i].re),(*lcrs)[i].prefix,0))!=0){ |
michael@16 | 822 | LM_ERR("bad prefix re <%s>, regcomp returned %d (check regex.h)\n", |
michael@16 | 823 | (*lcrs)[i].prefix, status); |
michael@16 | 824 | result = -1; |
michael@16 | 825 | break; |
michael@16 | 826 | } |
michael@16 | 827 | prefix_reg[i].valid = 1; |
michael@16 | 828 | } |
michael@16 | 829 | |
michael@16 | 830 | return result; |
michael@16 | 831 | } |
michael@16 | 832 | |
michael@16 | 833 | /* |
michael@16 | 834 | * regcomp each from_uri. |
michael@16 | 835 | */ |
michael@16 | 836 | static int load_from_uri_regex(void) |
michael@16 | 837 | { |
michael@16 | 838 | int i, status, result = 0; |
michael@16 | 839 | |
michael@16 | 840 | for (i = 0; i < MAX_NO_OF_LCRS; i++) { |
michael@16 | 841 | if ((*lcrs)[i].end_record != 0) { |
michael@16 | 842 | break; |
michael@16 | 843 | } |
michael@16 | 844 | if (from_uri_reg[i].valid) { |
michael@16 | 845 | regfree(&(from_uri_reg[i].re)); |
michael@16 | 846 | from_uri_reg[i].valid = 0; |
michael@16 | 847 | } |
michael@16 | 848 | memset(&(from_uri_reg[i].re), 0, sizeof(regex_t)); |
michael@16 | 849 | if ((status=regcomp(&(from_uri_reg[i].re),(*lcrs)[i].from_uri,0))!=0){ |
michael@16 | 850 | LM_ERR("Bad from_uri re <%s>, regcomp returned %d (check regex.h)\n", |
michael@16 | 851 | (*lcrs)[i].from_uri, status); |
michael@16 | 852 | result = -1; |
michael@16 | 853 | break; |
michael@16 | 854 | } |
michael@16 | 855 | from_uri_reg[i].valid = 1; |
michael@16 | 856 | } |
michael@16 | 857 | |
michael@16 | 858 | if (result != -1) { |
michael@16 | 859 | reload_counter = *lcrs_ws_reload_counter; |
michael@16 | 860 | } |
michael@16 | 861 | return result; |
michael@16 | 862 | } |
michael@16 | 863 | |
michael@16 | 864 | static int load_all_regex(void) |
michael@16 | 865 | { |
michael@16 | 866 | int result =0; |
michael@16 | 867 | |
michael@16 | 868 | if (prefix_mode_param != 0) { |
michael@16 | 869 | result = load_prefix_regex(); |
michael@16 | 870 | } |
michael@16 | 871 | |
michael@16 | 872 | if (result == 0) { |
michael@16 | 873 | result = load_from_uri_regex(); |
michael@16 | 874 | } else { |
michael@16 | 875 | LM_ERR("Unable to load prefix regex\n"); |
michael@16 | 876 | } |
michael@16 | 877 | |
michael@16 | 878 | if (result == 0) { |
michael@16 | 879 | reload_counter = *lcrs_ws_reload_counter; |
michael@16 | 880 | } else { |
michael@16 | 881 | LM_ERR("Unable to load from_uri regex\n"); |
michael@16 | 882 | } |
michael@16 | 883 | |
michael@16 | 884 | return result; |
michael@16 | 885 | } |
michael@16 | 886 | |
michael@16 | 887 | /* |
michael@16 | 888 | * Reload gws to unused gw table and lcrs to unused lcr table, and, when done |
michael@16 | 889 | * make unused gw and lcr table the one in use. |
michael@16 | 890 | */ |
michael@16 | 891 | int reload_gws(void) |
michael@16 | 892 | { |
michael@16 | 893 | unsigned int i, port, strip, tag_len, prefix_len, from_uri_len, |
michael@17 | 894 | user_len, realm_len, passwd_len, grp_id, priority; |
michael@16 | 895 | struct in_addr ip_addr; |
michael@16 | 896 | unsigned int flags; |
michael@16 | 897 | uri_type scheme; |
michael@16 | 898 | uri_transport transport; |
michael@16 | 899 | db_con_t* dbh; |
michael@16 | 900 | char *tag, *prefix, *from_uri; |
michael@17 | 901 | char *user, *realm, *passwd; |
michael@16 | 902 | db_res_t* res = NULL; |
michael@16 | 903 | db_row_t* row; |
michael@17 | 904 | db_key_t gw_cols[11]; |
michael@16 | 905 | db_key_t lcr_cols[4]; |
michael@16 | 906 | |
michael@16 | 907 | gw_cols[0] = &ip_addr_col; |
michael@16 | 908 | gw_cols[1] = &port_col; |
michael@16 | 909 | gw_cols[2] = &uri_scheme_col; |
michael@16 | 910 | gw_cols[3] = &transport_col; |
michael@16 | 911 | gw_cols[4] = &strip_col; |
michael@16 | 912 | gw_cols[5] = &tag_col; |
michael@16 | 913 | /* FIXME: is this ok if we have different names for grp_id |
michael@16 | 914 | in the two tables? (ge vw lcr) */ |
michael@16 | 915 | gw_cols[6] = &grp_id_col; |
michael@16 | 916 | gw_cols[7] = &flags_col; |
michael@17 | 917 | gw_cols[8] = &user_col; |
michael@17 | 918 | gw_cols[9] = &realm_col; |
michael@17 | 919 | gw_cols[10] = &passwd_col; |
michael@16 | 920 | |
michael@16 | 921 | lcr_cols[0] = &prefix_col; |
michael@16 | 922 | lcr_cols[1] = &from_uri_col; |
michael@16 | 923 | /* FIXME: is this ok if we have different names for grp_id |
michael@16 | 924 | in the two tables? (ge vw lcr) */ |
michael@16 | 925 | lcr_cols[2] = &grp_id_col; |
michael@16 | 926 | lcr_cols[3] = &priority_col; |
michael@16 | 927 | |
michael@16 | 928 | if (lcr_dbf.init==0){ |
michael@16 | 929 | LM_CRIT("Unbound database\n"); |
michael@16 | 930 | return -1; |
michael@16 | 931 | } |
michael@16 | 932 | dbh=lcr_dbf.init(&db_url); |
michael@16 | 933 | if (dbh==0){ |
michael@16 | 934 | LM_ERR("Unable to open database connection\n"); |
michael@16 | 935 | return -1; |
michael@16 | 936 | } |
michael@16 | 937 | |
michael@16 | 938 | if (lcr_dbf.use_table(dbh, &gw_table) < 0) { |
michael@16 | 939 | LM_ERR("Error while trying to use gw table\n"); |
michael@16 | 940 | return -1; |
michael@16 | 941 | } |
michael@16 | 942 | |
michael@17 | 943 | if (lcr_dbf.query(dbh, NULL, 0, NULL, gw_cols, 0, 11, 0, &res) < 0) { |
michael@16 | 944 | LM_ERR("Failed to query gw data\n"); |
michael@16 | 945 | lcr_dbf.close(dbh); |
michael@16 | 946 | return -1; |
michael@16 | 947 | } |
michael@16 | 948 | |
michael@16 | 949 | if (RES_ROW_N(res) + 1 > MAX_NO_OF_GWS) { |
michael@16 | 950 | LM_ERR("Too many gateways\n"); |
michael@16 | 951 | lcr_dbf.free_result(dbh, res); |
michael@16 | 952 | lcr_dbf.close(dbh); |
michael@16 | 953 | return -1; |
michael@16 | 954 | } |
michael@16 | 955 | |
michael@16 | 956 | for (i = 0; i < RES_ROW_N(res); i++) { |
michael@16 | 957 | row = RES_ROWS(res) + i; |
michael@16 | 958 | if (!((VAL_TYPE(ROW_VALUES(row)) == DB_STRING) && |
michael@16 | 959 | !VAL_NULL(ROW_VALUES(row)) && |
michael@16 | 960 | inet_aton((char *)VAL_STRING(ROW_VALUES(row)), &ip_addr) != 0)) { |
michael@16 | 961 | LM_ERR("Invalid IP address of gw <%s>\n", |
michael@16 | 962 | (char *)VAL_STRING(ROW_VALUES(row))); |
michael@16 | 963 | lcr_dbf.free_result(dbh, res); |
michael@16 | 964 | lcr_dbf.close(dbh); |
michael@16 | 965 | return -1; |
michael@16 | 966 | } |
michael@16 | 967 | if (VAL_NULL(ROW_VALUES(row) + 1) == 1) { |
michael@16 | 968 | port = 0; |
michael@16 | 969 | } else { |
michael@16 | 970 | port = (unsigned int)VAL_INT(ROW_VALUES(row) + 1); |
michael@16 | 971 | } |
michael@16 | 972 | if (port > 65536) { |
michael@16 | 973 | LM_ERR("Port of gw is too large <%u>\n", port); |
michael@16 | 974 | lcr_dbf.free_result(dbh, res); |
michael@16 | 975 | lcr_dbf.close(dbh); |
michael@16 | 976 | return -1; |
michael@16 | 977 | } |
michael@16 | 978 | if (VAL_NULL(ROW_VALUES(row) + 2) == 1) { |
michael@16 | 979 | scheme = SIP_URI_T; |
michael@16 | 980 | } else { |
michael@16 | 981 | scheme = (uri_type)VAL_INT(ROW_VALUES(row) + 2); |
michael@16 | 982 | if ((scheme != SIP_URI_T) && (scheme != SIPS_URI_T)) { |
michael@16 | 983 | LM_ERR("Unknown or unsupported URI scheme <%u>\n", |
michael@16 | 984 | (unsigned int)scheme); |
michael@16 | 985 | lcr_dbf.free_result(dbh, res); |
michael@16 | 986 | lcr_dbf.close(dbh); |
michael@16 | 987 | return -1; |
michael@16 | 988 | } |
michael@16 | 989 | } |
michael@16 | 990 | if (VAL_NULL(ROW_VALUES(row) + 3) == 1) { |
michael@16 | 991 | transport = PROTO_NONE; |
michael@16 | 992 | } else { |
michael@16 | 993 | transport = (uri_transport)VAL_INT(ROW_VALUES(row) + 3); |
michael@16 | 994 | if ((transport != PROTO_UDP) && (transport != PROTO_TCP) && |
michael@16 | 995 | (transport != PROTO_TLS)) { |
michael@16 | 996 | LM_ERR("Unknown or unsupported transport <%u>\n", |
michael@16 | 997 | (unsigned int)transport); |
michael@16 | 998 | lcr_dbf.free_result(dbh, res); |
michael@16 | 999 | lcr_dbf.close(dbh); |
michael@16 | 1000 | return -1; |
michael@16 | 1001 | } |
michael@16 | 1002 | } |
michael@16 | 1003 | if (VAL_NULL(ROW_VALUES(row) + 4) == 1) { |
michael@16 | 1004 | strip = 0; |
michael@16 | 1005 | } else { |
michael@16 | 1006 | strip = (unsigned int)VAL_INT(ROW_VALUES(row) + 4); |
michael@16 | 1007 | } |
michael@16 | 1008 | if (VAL_NULL(ROW_VALUES(row) + 5) == 1) { |
michael@16 | 1009 | tag_len = 0; |
michael@16 | 1010 | tag = (char *)0; |
michael@16 | 1011 | } else { |
michael@16 | 1012 | tag = (char *)VAL_STRING(ROW_VALUES(row) + 5); |
michael@16 | 1013 | tag_len = strlen(tag); |
michael@16 | 1014 | if (tag_len > MAX_TAG_LEN) { |
michael@16 | 1015 | LM_ERR("Too long gw tag <%u>\n", tag_len); |
michael@16 | 1016 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1017 | lcr_dbf.close(dbh); |
michael@16 | 1018 | return -1; |
michael@16 | 1019 | } |
michael@16 | 1020 | } |
michael@16 | 1021 | if (VAL_NULL(ROW_VALUES(row) + 6) == 1) { |
michael@16 | 1022 | grp_id = 0; |
michael@16 | 1023 | } else { |
michael@16 | 1024 | grp_id = VAL_INT(ROW_VALUES(row) + 6); |
michael@16 | 1025 | } |
michael@16 | 1026 | if (!VAL_NULL(ROW_VALUES(row) + 7) && |
michael@16 | 1027 | (VAL_TYPE(ROW_VALUES(row) + 7) == DB_INT)) { |
michael@16 | 1028 | flags = (unsigned int)VAL_INT(ROW_VALUES(row) + 7); |
michael@16 | 1029 | } else { |
michael@16 | 1030 | LM_ERR("Attribute flags is NULL or non-int\n"); |
michael@16 | 1031 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1032 | lcr_dbf.close(dbh); |
michael@16 | 1033 | return -1; |
michael@16 | 1034 | } |
michael@17 | 1035 | if (VAL_NULL(ROW_VALUES(row) + 8) == 1) { |
michael@17 | 1036 | user_len = 0; |
michael@17 | 1037 | user = (char *)0; |
michael@17 | 1038 | } else { |
michael@17 | 1039 | user = (char *)VAL_STRING(ROW_VALUES(row) + 8); |
michael@17 | 1040 | user_len = strlen(user); |
michael@17 | 1041 | if (user_len > MAX_USER_LEN) { |
michael@17 | 1042 | LM_ERR("Too long gw user <%u>\n", user_len); |
michael@17 | 1043 | lcr_dbf.free_result(dbh, res); |
michael@17 | 1044 | lcr_dbf.close(dbh); |
michael@17 | 1045 | return -1; |
michael@17 | 1046 | } |
michael@17 | 1047 | } |
michael@17 | 1048 | if (VAL_NULL(ROW_VALUES(row) + 9) == 1) { |
michael@17 | 1049 | realm_len = 0; |
michael@17 | 1050 | realm = (char *)0; |
michael@17 | 1051 | } else { |
michael@17 | 1052 | realm = (char *)VAL_STRING(ROW_VALUES(row) + 9); |
michael@17 | 1053 | realm_len = strlen(realm); |
michael@17 | 1054 | if (realm_len > MAX_REALM_LEN) { |
michael@17 | 1055 | LM_ERR("Too long gw realm <%u>\n", realm_len); |
michael@17 | 1056 | lcr_dbf.free_result(dbh, res); |
michael@17 | 1057 | lcr_dbf.close(dbh); |
michael@17 | 1058 | return -1; |
michael@17 | 1059 | } |
michael@17 | 1060 | } |
michael@17 | 1061 | if (VAL_NULL(ROW_VALUES(row) + 10) == 1) { |
michael@17 | 1062 | passwd_len = 0; |
michael@17 | 1063 | passwd = (char *)0; |
michael@17 | 1064 | } else { |
michael@17 | 1065 | passwd = (char *)VAL_STRING(ROW_VALUES(row) + 10); |
michael@17 | 1066 | passwd_len = strlen(passwd); |
michael@17 | 1067 | if (passwd_len > MAX_PASSWD_LEN) { |
michael@17 | 1068 | LM_ERR("Too long gw passwd <%u>\n", passwd_len); |
michael@17 | 1069 | lcr_dbf.free_result(dbh, res); |
michael@17 | 1070 | lcr_dbf.close(dbh); |
michael@17 | 1071 | return -1; |
michael@17 | 1072 | } |
michael@17 | 1073 | } |
michael@16 | 1074 | if (*gws == gws_1) { |
michael@16 | 1075 | gws_2[i].ip_addr = (unsigned int)ip_addr.s_addr; |
michael@16 | 1076 | gws_2[i].port = port; |
michael@16 | 1077 | gws_2[i].grp_id = grp_id; |
michael@16 | 1078 | gws_2[i].scheme = scheme; |
michael@16 | 1079 | gws_2[i].transport = transport; |
michael@16 | 1080 | gws_2[i].flags = flags; |
michael@16 | 1081 | gws_2[i].strip = strip; |
michael@16 | 1082 | gws_2[i].tag_len = tag_len; |
michael@16 | 1083 | if (tag_len) |
michael@16 | 1084 | memcpy(&(gws_2[i].tag[0]), tag, tag_len); |
michael@17 | 1085 | gws_2[i].user_len = user_len; |
michael@17 | 1086 | if (user_len) |
michael@17 | 1087 | memcpy(&(gws_2[i].user[0]), user, user_len); |
michael@17 | 1088 | gws_2[i].realm_len = realm_len; |
michael@17 | 1089 | if (realm_len) |
michael@17 | 1090 | memcpy(&(gws_2[i].realm[0]), realm, realm_len); |
michael@17 | 1091 | gws_2[i].passwd_len = passwd_len; |
michael@17 | 1092 | if (passwd_len) |
michael@17 | 1093 | memcpy(&(gws_2[i].passwd[0]), passwd, passwd_len); |
michael@16 | 1094 | } else { |
michael@16 | 1095 | gws_1[i].ip_addr = (unsigned int)ip_addr.s_addr; |
michael@16 | 1096 | gws_1[i].port = port; |
michael@16 | 1097 | gws_1[i].grp_id = grp_id; |
michael@16 | 1098 | gws_1[i].scheme = scheme; |
michael@16 | 1099 | gws_1[i].transport = transport; |
michael@16 | 1100 | gws_1[i].flags = flags; |
michael@16 | 1101 | gws_1[i].strip = strip; |
michael@16 | 1102 | gws_1[i].tag_len = tag_len; |
michael@16 | 1103 | if (tag_len) |
michael@16 | 1104 | memcpy(&(gws_1[i].tag[0]), tag, tag_len); |
michael@17 | 1105 | gws_1[i].user_len = user_len; |
michael@17 | 1106 | if (user_len) |
michael@17 | 1107 | memcpy(&(gws_1[i].user[0]), user, user_len); |
michael@17 | 1108 | gws_1[i].realm_len = realm_len; |
michael@17 | 1109 | if (realm_len) |
michael@17 | 1110 | memcpy(&(gws_1[i].realm[0]), realm, realm_len); |
michael@17 | 1111 | gws_1[i].passwd_len = passwd_len; |
michael@17 | 1112 | if (passwd_len) |
michael@17 | 1113 | memcpy(&(gws_1[i].passwd[0]), passwd, passwd_len); |
michael@16 | 1114 | } |
michael@16 | 1115 | } |
michael@16 | 1116 | |
michael@16 | 1117 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1118 | |
michael@16 | 1119 | if (*gws == gws_1) { |
michael@16 | 1120 | gws_2[i].ip_addr = 0; |
michael@16 | 1121 | *gws = gws_2; |
michael@16 | 1122 | } else { |
michael@16 | 1123 | gws_1[i].ip_addr = 0; |
michael@16 | 1124 | *gws = gws_1; |
michael@16 | 1125 | } |
michael@16 | 1126 | |
michael@16 | 1127 | |
michael@16 | 1128 | if (lcr_dbf.use_table(dbh, &lcr_table) < 0) { |
michael@16 | 1129 | LM_ERR("Error while trying to use lcr table\n"); |
michael@16 | 1130 | return -1; |
michael@16 | 1131 | } |
michael@16 | 1132 | |
michael@16 | 1133 | if (lcr_dbf.query(dbh, NULL, 0, NULL, lcr_cols, 0, 4, 0, &res) < 0) { |
michael@16 | 1134 | LM_ERR("Failed to query lcr data\n"); |
michael@16 | 1135 | lcr_dbf.close(dbh); |
michael@16 | 1136 | return -1; |
michael@16 | 1137 | } |
michael@16 | 1138 | |
michael@16 | 1139 | if (RES_ROW_N(res) + 1 > MAX_NO_OF_LCRS) { |
michael@16 | 1140 | LM_ERR("Too many lcr entries <%d>\n", RES_ROW_N(res)); |
michael@16 | 1141 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1142 | lcr_dbf.close(dbh); |
michael@16 | 1143 | return -1; |
michael@16 | 1144 | } |
michael@16 | 1145 | for (i = 0; i < RES_ROW_N(res); i++) { |
michael@16 | 1146 | row = RES_ROWS(res) + i; |
michael@16 | 1147 | if (VAL_NULL(ROW_VALUES(row)) == 1) { |
michael@16 | 1148 | prefix_len = 0; |
michael@16 | 1149 | prefix = 0; |
michael@16 | 1150 | } else { |
michael@16 | 1151 | prefix = (char *)VAL_STRING(ROW_VALUES(row)); |
michael@16 | 1152 | prefix_len = strlen(prefix); |
michael@16 | 1153 | if (prefix_len > MAX_PREFIX_LEN) { |
michael@16 | 1154 | LM_ERR("Too long lcr prefix <%u>\n", prefix_len); |
michael@16 | 1155 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1156 | lcr_dbf.close(dbh); |
michael@16 | 1157 | return -1; |
michael@16 | 1158 | } |
michael@16 | 1159 | } |
michael@16 | 1160 | if (VAL_NULL(ROW_VALUES(row) + 1) == 1) { |
michael@16 | 1161 | from_uri_len = 0; |
michael@16 | 1162 | from_uri = 0; |
michael@16 | 1163 | } else { |
michael@16 | 1164 | from_uri = (char *)VAL_STRING(ROW_VALUES(row) + 1); |
michael@16 | 1165 | from_uri_len = strlen(from_uri); |
michael@16 | 1166 | if (from_uri_len > MAX_FROM_URI_LEN) { |
michael@16 | 1167 | LM_ERR("Too long from_uri <%u>\n", from_uri_len); |
michael@16 | 1168 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1169 | lcr_dbf.close(dbh); |
michael@16 | 1170 | return -1; |
michael@16 | 1171 | } |
michael@16 | 1172 | } |
michael@16 | 1173 | if (VAL_NULL(ROW_VALUES(row) + 2) == 1) { |
michael@16 | 1174 | LM_ERR("Route grp_id is NULL\n"); |
michael@16 | 1175 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1176 | lcr_dbf.close(dbh); |
michael@16 | 1177 | return -1; |
michael@16 | 1178 | } |
michael@16 | 1179 | grp_id = (unsigned int)VAL_INT(ROW_VALUES(row) + 2); |
michael@16 | 1180 | if (VAL_NULL(ROW_VALUES(row) + 3) == 1) { |
michael@16 | 1181 | LM_ERR("Route priority is NULL\n"); |
michael@16 | 1182 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1183 | lcr_dbf.close(dbh); |
michael@16 | 1184 | return -1; |
michael@16 | 1185 | } |
michael@16 | 1186 | priority = (unsigned int)VAL_INT(ROW_VALUES(row) + 3); |
michael@16 | 1187 | |
michael@16 | 1188 | if (*lcrs == lcrs_1) { |
michael@16 | 1189 | lcrs_2[i].prefix_len = prefix_len; |
michael@16 | 1190 | if (prefix_len) |
michael@16 | 1191 | memcpy(&(lcrs_2[i].prefix[0]), prefix, prefix_len); |
michael@16 | 1192 | lcrs_2[i].from_uri_len = from_uri_len; |
michael@16 | 1193 | if (from_uri_len) { |
michael@16 | 1194 | memcpy(&(lcrs_2[i].from_uri[0]), from_uri, from_uri_len); |
michael@16 | 1195 | lcrs_2[i].from_uri[from_uri_len] = '\0'; |
michael@16 | 1196 | } |
michael@16 | 1197 | lcrs_2[i].grp_id = grp_id; |
michael@16 | 1198 | lcrs_2[i].priority = priority; |
michael@16 | 1199 | lcrs_2[i].end_record = 0; |
michael@16 | 1200 | } else { |
michael@16 | 1201 | lcrs_1[i].prefix_len = prefix_len; |
michael@16 | 1202 | if (prefix_len) |
michael@16 | 1203 | memcpy(&(lcrs_1[i].prefix[0]), prefix, prefix_len); |
michael@16 | 1204 | lcrs_1[i].from_uri_len = from_uri_len; |
michael@16 | 1205 | if (from_uri_len) { |
michael@16 | 1206 | memcpy(&(lcrs_1[i].from_uri[0]), from_uri, from_uri_len); |
michael@16 | 1207 | lcrs_1[i].from_uri[from_uri_len] = '\0'; |
michael@16 | 1208 | } |
michael@16 | 1209 | lcrs_1[i].grp_id = grp_id; |
michael@16 | 1210 | lcrs_1[i].priority = priority; |
michael@16 | 1211 | lcrs_1[i].end_record = 0; |
michael@16 | 1212 | } |
michael@16 | 1213 | } |
michael@16 | 1214 | |
michael@16 | 1215 | lcr_dbf.free_result(dbh, res); |
michael@16 | 1216 | lcr_dbf.close(dbh); |
michael@16 | 1217 | |
michael@16 | 1218 | if (*lcrs == lcrs_1) { |
michael@16 | 1219 | lcrs_2[i].end_record = 1; |
michael@16 | 1220 | *lcrs = lcrs_2; |
michael@16 | 1221 | } else { |
michael@16 | 1222 | lcrs_1[i].end_record = 1; |
michael@16 | 1223 | *lcrs = lcrs_1; |
michael@16 | 1224 | } |
michael@16 | 1225 | |
michael@16 | 1226 | (*lcrs_ws_reload_counter)++; |
michael@16 | 1227 | if (0 != load_all_regex()) { |
michael@16 | 1228 | |
michael@16 | 1229 | return -1; |
michael@16 | 1230 | } |
michael@16 | 1231 | |
michael@16 | 1232 | return 1; |
michael@16 | 1233 | } |
michael@16 | 1234 | |
michael@16 | 1235 | |
michael@16 | 1236 | int mi_print_gws(struct mi_node* rpl) |
michael@16 | 1237 | { |
michael@16 | 1238 | unsigned int i; |
michael@16 | 1239 | struct mi_attr* attr; |
michael@16 | 1240 | uri_transport transport; |
michael@16 | 1241 | char *transp; |
michael@16 | 1242 | struct mi_node* node; |
michael@16 | 1243 | struct ip_addr address; |
michael@16 | 1244 | char* p; |
michael@16 | 1245 | int len; |
michael@16 | 1246 | |
michael@16 | 1247 | for (i = 0; i < MAX_NO_OF_GWS; i++) { |
michael@16 | 1248 | |
michael@16 | 1249 | if ((*gws)[i].ip_addr == 0) |
michael@16 | 1250 | break; |
michael@16 | 1251 | |
michael@16 | 1252 | node= add_mi_node_child(rpl,0 ,"GW", 2, 0, 0); |
michael@16 | 1253 | if(node == NULL) |
michael@16 | 1254 | return -1; |
michael@16 | 1255 | |
michael@16 | 1256 | p = int2str((unsigned long)(*gws)[i].grp_id, &len ); |
michael@16 | 1257 | attr = add_mi_attr(node, MI_DUP_VALUE, "GRP_ID", 6, p, len ); |
michael@16 | 1258 | if(attr == NULL) |
michael@16 | 1259 | return -1; |
michael@16 | 1260 | |
michael@16 | 1261 | transport = (*gws)[i].transport; |
michael@16 | 1262 | if (transport == PROTO_UDP) |
michael@16 | 1263 | transp= ";transport=udp"; |
michael@16 | 1264 | else if (transport == PROTO_TCP) |
michael@16 | 1265 | transp= ";transport=tcp"; |
michael@16 | 1266 | else if (transport == PROTO_TLS) |
michael@16 | 1267 | transp= ";transport=tls"; |
michael@16 | 1268 | else |
michael@16 | 1269 | transp= ""; |
michael@16 | 1270 | |
michael@16 | 1271 | address.af = AF_INET; |
michael@16 | 1272 | address.len = 4; |
michael@16 | 1273 | address.u.addr32[0] = (*gws)[i].ip_addr; |
michael@16 | 1274 | attr= addf_mi_attr(node,0 ,"URI", 3,"%s:%s:%d%s", |
michael@16 | 1275 | ((*gws)[i].scheme == SIP_URI_T)?"sip":"sips", |
michael@16 | 1276 | ip_addr2a(&address), |
michael@16 | 1277 | ((*gws)[i].port == 0)?5060:(*gws)[i].port,transp); |
michael@16 | 1278 | if(attr == NULL) |
michael@16 | 1279 | return -1; |
michael@16 | 1280 | |
michael@16 | 1281 | p = int2str((unsigned long)(*gws)[i].strip, &len ); |
michael@16 | 1282 | attr = add_mi_attr(node, MI_DUP_VALUE, "STRIP", 5, p, len); |
michael@16 | 1283 | if(attr == NULL) |
michael@16 | 1284 | return -1; |
michael@16 | 1285 | |
michael@16 | 1286 | attr = add_mi_attr(node, MI_DUP_VALUE, "TAG", 3, |
michael@16 | 1287 | (*gws)[i].tag, (*gws)[i].tag_len ); |
michael@16 | 1288 | if(attr == NULL) |
michael@16 | 1289 | return -1; |
michael@16 | 1290 | |
michael@16 | 1291 | p = int2str((unsigned long)(*gws)[i].flags, &len ); |
michael@16 | 1292 | attr = add_mi_attr(node, MI_DUP_VALUE, "FLAGS", 5, p, len); |
michael@16 | 1293 | if(attr == NULL) |
michael@16 | 1294 | return -1; |
michael@17 | 1295 | |
michael@17 | 1296 | attr = add_mi_attr(node, MI_DUP_VALUE, "USER", 6, |
michael@17 | 1297 | (*gws)[i].user, (*gws)[i].user_len ); |
michael@17 | 1298 | if(attr == NULL) |
michael@17 | 1299 | return -1; |
michael@17 | 1300 | |
michael@17 | 1301 | attr = add_mi_attr(node, MI_DUP_VALUE, "REALM", 6, |
michael@17 | 1302 | (*gws)[i].realm, (*gws)[i].realm_len ); |
michael@17 | 1303 | if(attr == NULL) |
michael@17 | 1304 | return -1; |
michael@17 | 1305 | |
michael@17 | 1306 | attr = add_mi_attr(node, MI_DUP_VALUE, "PASSWD", 6, |
michael@17 | 1307 | (*gws)[i].passwd, (*gws)[i].passwd_len ); |
michael@17 | 1308 | if(attr == NULL) |
michael@17 | 1309 | return -1; |
michael@16 | 1310 | } |
michael@16 | 1311 | |
michael@16 | 1312 | for (i = 0; i < MAX_NO_OF_LCRS; i++) { |
michael@16 | 1313 | if ((*lcrs)[i].end_record != 0) |
michael@16 | 1314 | break; |
michael@16 | 1315 | |
michael@16 | 1316 | node= add_mi_node_child(rpl, 0, "RULE", 4, 0, 0); |
michael@16 | 1317 | attr = add_mi_attr(node, 0, "PREFIX", 6, (*lcrs)[i].prefix, |
michael@16 | 1318 | (*lcrs)[i].prefix_len ); |
michael@16 | 1319 | if(attr== 0) |
michael@16 | 1320 | return -1; |
michael@16 | 1321 | |
michael@16 | 1322 | attr = add_mi_attr(node, 0, "FROM_URI", 8, (*lcrs)[i].from_uri, |
michael@16 | 1323 | (*lcrs)[i].from_uri_len ); |
michael@16 | 1324 | if(attr== 0) |
michael@16 | 1325 | return -1; |
michael@16 | 1326 | |
michael@16 | 1327 | p = int2str((unsigned long)(*lcrs)[i].grp_id, &len ); |
michael@16 | 1328 | attr = add_mi_attr(node, MI_DUP_VALUE, "GRP_ID", 6, p, len ); |
michael@16 | 1329 | if(attr == NULL) |
michael@16 | 1330 | return -1; |
michael@16 | 1331 | |
michael@16 | 1332 | p = int2str((unsigned long)(*lcrs)[i].priority, &len ); |
michael@16 | 1333 | attr = add_mi_attr(node, MI_DUP_VALUE, "PRIORITY", 8, p, len ); |
michael@16 | 1334 | if(attr == NULL) |
michael@16 | 1335 | return -1; |
michael@16 | 1336 | |
michael@16 | 1337 | } |
michael@16 | 1338 | |
michael@16 | 1339 | return 0; |
michael@16 | 1340 | } |
michael@16 | 1341 | |
michael@16 | 1342 | |
michael@16 | 1343 | /* |
michael@16 | 1344 | * Load info of matching GWs from database to gw_uri AVPs |
michael@16 | 1345 | */ |
michael@16 | 1346 | static int do_load_gws(struct sip_msg* _m, str *_from_uri, int _grp_id) |
michael@16 | 1347 | { |
michael@16 | 1348 | str ruri_user, from_uri, value; |
michael@16 | 1349 | char from_uri_str[MAX_FROM_URI_LEN + 1]; |
michael@16 | 1350 | char ruri[MAX_URI_SIZE]; |
michael@16 | 1351 | unsigned int i, j, k, index, addr, port, strip, gw_index, |
michael@16 | 1352 | duplicated_gw, flags, have_rpid_avp; |
michael@17 | 1353 | char *user; |
michael@17 | 1354 | char *realm; |
michael@17 | 1355 | char *passwd; |
michael@16 | 1356 | uri_type scheme; |
michael@16 | 1357 | uri_transport transport; |
michael@16 | 1358 | struct ip_addr address; |
michael@16 | 1359 | str addr_str, port_str; |
michael@16 | 1360 | char *at, *tag, *strip_string, *flags_string; |
michael@16 | 1361 | struct usr_avp *avp; |
michael@16 | 1362 | int_str val; |
michael@16 | 1363 | struct mi matched_gws[MAX_NO_OF_GWS + 1]; |
michael@16 | 1364 | unsigned short tag_len, prefix_len, priority; |
michael@16 | 1365 | int randomizer_start, randomizer_end, randomizer_flag, |
michael@16 | 1366 | strip_len, flags_len; |
michael@16 | 1367 | struct lcr_info lcr_rec; |
michael@16 | 1368 | |
michael@16 | 1369 | /* Find Request-URI user */ |
michael@16 | 1370 | if ((parse_sip_msg_uri(_m) < 0) || (!_m->parsed_uri.user.s)) { |
michael@16 | 1371 | LM_ERR("Error while parsing R-URI\n"); |
michael@16 | 1372 | return -1; |
michael@16 | 1373 | } |
michael@16 | 1374 | ruri_user = _m->parsed_uri.user; |
michael@16 | 1375 | |
michael@16 | 1376 | if (_from_uri) { |
michael@16 | 1377 | /* take caller uri from _from_uri argument */ |
michael@16 | 1378 | from_uri = *_from_uri; |
michael@16 | 1379 | } else { |
michael@16 | 1380 | /* take caller uri from RPID or From URI */ |
michael@16 | 1381 | have_rpid_avp = 0; |
michael@16 | 1382 | avp = search_first_avp(rpid_avp_type, rpid_avp, &val, 0); |
michael@16 | 1383 | if (avp != NULL) { |
michael@16 | 1384 | /* Get URI user from RPID if not empty */ |
michael@16 | 1385 | if (avp->flags & AVP_VAL_STR) { |
michael@16 | 1386 | if (val.s.s && val.s.len) { |
michael@16 | 1387 | from_uri = val.s; |
michael@16 | 1388 | have_rpid_avp = 1; |
michael@16 | 1389 | } |
michael@16 | 1390 | } else { |
michael@16 | 1391 | from_uri.s = int2str(val.n, &from_uri.len); |
michael@16 | 1392 | have_rpid_avp = 1; |
michael@16 | 1393 | } |
michael@16 | 1394 | } |
michael@16 | 1395 | if (!have_rpid_avp) { |
michael@16 | 1396 | /* Get URI from From URI */ |
michael@16 | 1397 | if ((!_m->from) && (parse_headers(_m, HDR_FROM_F, 0) == -1)) { |
michael@16 | 1398 | LM_ERR("Error while parsing headers\n"); |
michael@16 | 1399 | return -1; |
michael@16 | 1400 | } |
michael@16 | 1401 | if (!_m->from) { |
michael@16 | 1402 | LM_ERR("From header field not found\n"); |
michael@16 | 1403 | return -1; |
michael@16 | 1404 | } |
michael@16 | 1405 | if ((!(_m->from)->parsed) && (parse_from_header(_m) < 0)) { |
michael@16 | 1406 | LM_ERR("Error while parsing From header\n"); |
michael@16 | 1407 | return -1; |
michael@16 | 1408 | } |
michael@16 | 1409 | from_uri = get_from(_m)->uri; |
michael@16 | 1410 | } |
michael@16 | 1411 | } |
michael@16 | 1412 | if (from_uri.len <= MAX_FROM_URI_LEN) { |
michael@16 | 1413 | strncpy(from_uri_str, from_uri.s, from_uri.len); |
michael@16 | 1414 | from_uri_str[from_uri.len] = '\0'; |
michael@16 | 1415 | } else { |
michael@16 | 1416 | LM_ERR("From URI is too long <%u>\n", from_uri.len); |
michael@16 | 1417 | return -1; |
michael@16 | 1418 | } |
michael@16 | 1419 | |
michael@16 | 1420 | /* |
michael@16 | 1421 | * Check if the gws and lcrs were reloaded |
michael@16 | 1422 | */ |
michael@16 | 1423 | if (reload_counter != *lcrs_ws_reload_counter) { |
michael@16 | 1424 | if (load_all_regex() != 0) { |
michael@16 | 1425 | return -1; |
michael@16 | 1426 | } |
michael@16 | 1427 | } |
michael@16 | 1428 | |
michael@16 | 1429 | /* |
michael@16 | 1430 | * Let's match the gws: |
michael@16 | 1431 | * 1. prefix matching |
michael@16 | 1432 | * 2. from_uri matching |
michael@16 | 1433 | * 3. _grp_id matching |
michael@16 | 1434 | * |
michael@16 | 1435 | * Note: A gateway must be in the list _only_ once. |
michael@16 | 1436 | */ |
michael@16 | 1437 | gw_index = 0; |
michael@16 | 1438 | duplicated_gw = 0; |
michael@16 | 1439 | for (i = 0; i < MAX_NO_OF_LCRS; i++) { |
michael@16 | 1440 | lcr_rec = (*lcrs)[i]; |
michael@16 | 1441 | if (lcr_rec.end_record != 0) { |
michael@16 | 1442 | break; |
michael@16 | 1443 | } |
michael@16 | 1444 | if ( ((prefix_mode_param == 0) && (lcr_rec.prefix_len <= ruri_user.len) && |
michael@16 | 1445 | (strncmp(lcr_rec.prefix, ruri_user.s, lcr_rec.prefix_len)==0)) || |
michael@16 | 1446 | ( (prefix_mode_param != 0) && ( (lcr_rec.prefix_len == 0) || |
michael@16 | 1447 | (prefix_reg[i].valid && |
michael@16 | 1448 | (regexec(&(prefix_reg[i].re), ruri_user.s, 0, |
michael@16 | 1449 | (regmatch_t *)NULL, 0) == 0)) ) ) ) { |
michael@16 | 1450 | /* 1. Prefix matching is done */ |
michael@16 | 1451 | if ((lcr_rec.from_uri_len == 0) || |
michael@16 | 1452 | (from_uri_reg[i].valid && |
michael@16 | 1453 | (regexec(&(from_uri_reg[i].re), from_uri_str, 0, |
michael@16 | 1454 | (regmatch_t *)NULL, 0) == 0))) { |
michael@16 | 1455 | /* 2. from_uri matching is done */ |
michael@16 | 1456 | for (j = 0; j < MAX_NO_OF_GWS; j++) { |
michael@16 | 1457 | if ((*gws)[j].ip_addr == 0) { |
michael@16 | 1458 | break; |
michael@16 | 1459 | } |
michael@16 | 1460 | if (lcr_rec.grp_id == (*gws)[j].grp_id && |
michael@16 | 1461 | (_grp_id < 0 || (*gws)[j].grp_id == _grp_id)) { |
michael@16 | 1462 | /* 3. _grp_id matching is done */ |
michael@16 | 1463 | for (k = 0; k < gw_index; k++) { |
michael@16 | 1464 | if ((*gws)[j].ip_addr == |
michael@16 | 1465 | (*gws)[matched_gws[k].gw_index].ip_addr) { |
michael@16 | 1466 | /* Found the same gw in the list */ |
michael@16 | 1467 | /* Let's keep the one with higher */ |
michael@16 | 1468 | /* match on prefix len */ |
michael@16 | 1469 | LM_DBG("Duplicate gw for index" |
michael@16 | 1470 | " %d [%d,%d] and current [%d,%d] \n", |
michael@16 | 1471 | k, matched_gws[k].route_index, |
michael@16 | 1472 | matched_gws[k].route_index, i, j); |
michael@16 | 1473 | duplicated_gw = 1; |
michael@16 | 1474 | if (lcr_rec.prefix_len > |
michael@16 | 1475 | (*lcrs)[matched_gws[k].route_index].prefix_len) { |
michael@16 | 1476 | /* Replace the old entry with the new one */ |
michael@16 | 1477 | LM_DBG("Replace [%d,%d]" |
michael@16 | 1478 | " with [%d,%d] on index %d:" |
michael@16 | 1479 | " prefix reason %d>%d\n", |
michael@16 | 1480 | matched_gws[k].route_index, |
michael@16 | 1481 | matched_gws[k].gw_index, i, j, k, |
michael@16 | 1482 | lcr_rec.prefix_len, |
michael@16 | 1483 | (*lcrs)[matched_gws[k].route_index].prefix_len); |
michael@16 | 1484 | matched_gws[k].route_index = i; |
michael@16 | 1485 | matched_gws[k].gw_index = j; |
michael@16 | 1486 | /* Stop searching in the matched_gws list */ |
michael@16 | 1487 | break; |
michael@16 | 1488 | } else if (lcr_rec.prefix_len == |
michael@16 | 1489 | (*lcrs)[matched_gws[k].route_index].prefix_len) { |
michael@16 | 1490 | if (lcr_rec.priority > |
michael@16 | 1491 | (*lcrs)[matched_gws[k].route_index].priority) { |
michael@16 | 1492 | /* Replace the old entry with the new one */ |
michael@16 | 1493 | LM_DBG("Replace [%d,%d] with" |
michael@16 | 1494 | " [%d,%d] on index %d:" |
michael@16 | 1495 | " priority reason %d>%d\n", |
michael@16 | 1496 | matched_gws[k].route_index, |
michael@16 | 1497 | matched_gws[k].gw_index, |
michael@16 | 1498 | i, j, k, lcr_rec.priority, |
michael@16 | 1499 | (*lcrs)[matched_gws[k].route_index].priority); |
michael@16 | 1500 | matched_gws[k].route_index = i; |
michael@16 | 1501 | matched_gws[k].gw_index = j; |
michael@16 | 1502 | /* Stop searching in the matched_gws list */ |
michael@16 | 1503 | break; |
michael@16 | 1504 | } |
michael@16 | 1505 | } |
michael@16 | 1506 | } |
michael@16 | 1507 | } |
michael@16 | 1508 | if (duplicated_gw == 0) { |
michael@16 | 1509 | /* This is a new gw */ |
michael@16 | 1510 | matched_gws[gw_index].route_index = i; |
michael@16 | 1511 | matched_gws[gw_index].gw_index = j; |
michael@16 | 1512 | LM_DBG("Added matched_gws[%d]=[%d,%d]\n", |
michael@16 | 1513 | gw_index, i, j); |
michael@16 | 1514 | gw_index++; |
michael@16 | 1515 | } else { |
michael@16 | 1516 | duplicated_gw = 0; |
michael@16 | 1517 | } |
michael@16 | 1518 | } |
michael@16 | 1519 | } |
michael@16 | 1520 | } |
michael@16 | 1521 | } |
michael@16 | 1522 | } |
michael@16 | 1523 | matched_gws[gw_index].route_index = -1; |
michael@16 | 1524 | matched_gws[gw_index].gw_index = -1; |
michael@16 | 1525 | |
michael@16 | 1526 | /* |
michael@16 | 1527 | * Sort the gateways based on: |
michael@16 | 1528 | * 1. prefix len |
michael@16 | 1529 | * 2. priority |
michael@16 | 1530 | */ |
michael@16 | 1531 | qsort(matched_gws, gw_index, sizeof(struct mi), comp_lcrs); |
michael@16 | 1532 | randomizer_start = 0; |
michael@16 | 1533 | |
michael@16 | 1534 | /* Randomizing the gateways with same prefix_len and same priority */ |
michael@16 | 1535 | randomizer_flag = 0; |
michael@16 | 1536 | prefix_len = (*lcrs)[matched_gws[0].route_index].prefix_len; |
michael@16 | 1537 | priority = (*lcrs)[matched_gws[0].route_index].priority; |
michael@16 | 1538 | for (i = 1; i < gw_index; i++) { |
michael@16 | 1539 | if ( prefix_len == (*lcrs)[matched_gws[i].route_index].prefix_len && |
michael@16 | 1540 | priority == (*lcrs)[matched_gws[i].route_index].priority) { |
michael@16 | 1541 | /* we have a match */ |
michael@16 | 1542 | if (randomizer_flag == 0) { |
michael@16 | 1543 | randomizer_flag = 1; |
michael@16 | 1544 | randomizer_start = i - 1; |
michael@16 | 1545 | } |
michael@16 | 1546 | matched_gws[i - 1].randomizer = rand(); |
michael@16 | 1547 | } |
michael@16 | 1548 | else { |
michael@16 | 1549 | if (randomizer_flag == 1) { |
michael@16 | 1550 | randomizer_end = i - 1; |
michael@16 | 1551 | randomizer_flag = 0; |
michael@16 | 1552 | qsort(&matched_gws[randomizer_start], |
michael@16 | 1553 | randomizer_end - randomizer_start + 1, |
michael@16 | 1554 | sizeof(struct mi), rand_lcrs); |
michael@16 | 1555 | } |
michael@16 | 1556 | prefix_len = (*lcrs)[matched_gws[i].route_index].prefix_len; |
michael@16 | 1557 | priority = (*lcrs)[matched_gws[i].route_index].priority; |
michael@16 | 1558 | } |
michael@16 | 1559 | } |
michael@16 | 1560 | if (randomizer_flag == 1) { |
michael@16 | 1561 | randomizer_end = gw_index - 1; |
michael@16 | 1562 | matched_gws[i - 1].randomizer = rand(); |
michael@16 | 1563 | qsort(&matched_gws[randomizer_start], |
michael@16 | 1564 | randomizer_end - randomizer_start + 1, |
michael@16 | 1565 | sizeof(struct mi), rand_lcrs); |
michael@16 | 1566 | } |
michael@16 | 1567 | |
michael@16 | 1568 | for (i = 0; i < MAX_NO_OF_GWS; i++) { |
michael@16 | 1569 | index = matched_gws[i].gw_index; |
michael@16 | 1570 | if (index == -1) { |
michael@16 | 1571 | break; |
michael@16 | 1572 | } |
michael@16 | 1573 | addr = (*gws)[index].ip_addr; |
michael@16 | 1574 | port = (*gws)[index].port; |
michael@16 | 1575 | scheme = (*gws)[index].scheme; |
michael@16 | 1576 | transport = (*gws)[index].transport; |
michael@16 | 1577 | flags = (*gws)[index].flags; |
michael@16 | 1578 | strip = (*gws)[index].strip; |
michael@17 | 1579 | user = (*gws)[index].user; |
michael@17 | 1580 | realm = (*gws)[index].realm; |
michael@17 | 1581 | passwd = (*gws)[index].passwd; |
michael@16 | 1582 | if (strip > ruri_user.len) { |
michael@16 | 1583 | LM_ERR("Strip count of gw is too large <%u>\n", strip); |
michael@16 | 1584 | goto skip; |
michael@16 | 1585 | } |
michael@16 | 1586 | tag_len = (*gws)[index].tag_len; |
michael@16 | 1587 | tag = (*gws)[index].tag; |
michael@16 | 1588 | if (6 + tag_len + 40 /* flags + strip */ + 1 + 15 + 1 + 5 + 1 + 14 > |
michael@16 | 1589 | MAX_URI_SIZE) { |
michael@16 | 1590 | LM_ERR("Request URI would be too long\n"); |
michael@16 | 1591 | goto skip; |
michael@16 | 1592 | } |
michael@16 | 1593 | at = (char *)&(ruri[0]); |
michael@16 | 1594 | flags_string = int2str(flags, &flags_len); |
michael@16 | 1595 | memcpy(at, flags_string, flags_len); |
michael@16 | 1596 | at = at + flags_len; |
michael@16 | 1597 | if (scheme == SIP_URI_T) { |
michael@16 | 1598 | memcpy(at, "sip:", 4); at = at + 4; |
michael@16 | 1599 | } else if (scheme == SIPS_URI_T) { |
michael@16 | 1600 | memcpy(at, "sips:", 5); at = at + 5; |
michael@16 | 1601 | } else { |
michael@16 | 1602 | LM_ERR("Unknown or unsupported URI scheme <%u>\n", |
michael@16 | 1603 | (unsigned int)scheme); |
michael@16 | 1604 | goto skip; |
michael@16 | 1605 | } |
michael@16 | 1606 | if (tag_len) { |
michael@16 | 1607 | memcpy(at, tag, tag_len); at = at + tag_len; |
michael@16 | 1608 | } |
michael@16 | 1609 | /* Add strip in this form |number. |
michael@16 | 1610 | * For example: |3 means strip first 3 characters. |
michael@16 | 1611 | */ |
michael@16 | 1612 | *at = '|'; at = at + 1; |
michael@16 | 1613 | strip_string = int2str(strip, &strip_len); |
michael@16 | 1614 | memcpy(at, strip_string, strip_len); |
michael@16 | 1615 | at = at + strip_len; |
michael@16 | 1616 | *at = '@'; at = at + 1; |
michael@16 | 1617 | address.af = AF_INET; |
michael@16 | 1618 | address.len = 4; |
michael@16 | 1619 | address.u.addr32[0] = addr; |
michael@16 | 1620 | addr_str.s = ip_addr2a(&address); |
michael@16 | 1621 | addr_str.len = strlen(addr_str.s); |
michael@16 | 1622 | memcpy(at, addr_str.s, addr_str.len); at = at + addr_str.len; |
michael@16 | 1623 | if (port != 0) { |
michael@16 | 1624 | if (port > 65536) { |
michael@16 | 1625 | LM_ERR("Port of GW is too large <%u>\n", port); |
michael@16 | 1626 | goto skip; |
michael@16 | 1627 | } |
michael@16 | 1628 | *at = ':'; at = at + 1; |
michael@16 | 1629 | port_str.s = int2str(port, &port_str.len); |
michael@16 | 1630 | memcpy(at, port_str.s, port_str.len); at = at + port_str.len; |
michael@16 | 1631 | } |
michael@16 | 1632 | if (transport != PROTO_NONE) { |
michael@16 | 1633 | memcpy(at, ";transport=", 11); at = at + 11; |
michael@16 | 1634 | if (transport == PROTO_UDP) { |
michael@16 | 1635 | memcpy(at, "udp", 3); at = at + 3; |
michael@16 | 1636 | } else if (transport == PROTO_TCP) { |
michael@16 | 1637 | memcpy(at, "tcp", 3); at = at + 3; |
michael@16 | 1638 | } else if (transport == PROTO_TLS) { |
michael@16 | 1639 | memcpy(at, "tls", 3); at = at + 3; |
michael@16 | 1640 | } else { |
michael@16 | 1641 | LM_ERR("Unknown or unsupported transport <%u>\n", |
michael@16 | 1642 | (unsigned int)transport); |
michael@16 | 1643 | goto skip; |
michael@16 | 1644 | } |
michael@16 | 1645 | } |
michael@16 | 1646 | value.s = (char *)&(ruri[0]); |
michael@16 | 1647 | value.len = at - value.s; |
michael@16 | 1648 | val.s = value; |
michael@16 | 1649 | add_avp(gw_uri_avp_type|AVP_VAL_STR, gw_uri_avp, val); |
michael@16 | 1650 | LM_DBG("Added gw_uri_avp <%.*s>\n", value.len, value.s); |
michael@17 | 1651 | |
michael@17 | 1652 | value.s = user; |
michael@17 | 1653 | value.len = strlen(value.s); |
michael@17 | 1654 | val.s = value; |
michael@17 | 1655 | add_avp(user_avp_type|AVP_VAL_STR, user_avp, val); |
michael@17 | 1656 | LM_DBG("Added user_avp <%.*s>\n", value.len, value.s); |
michael@17 | 1657 | |
michael@17 | 1658 | value.s = realm; |
michael@17 | 1659 | value.len = strlen(value.s); |
michael@17 | 1660 | val.s = value; |
michael@17 | 1661 | add_avp(realm_avp_type|AVP_VAL_STR, realm_avp, val); |
michael@17 | 1662 | LM_DBG("Added realm_avp <%.*s>\n", value.len, value.s); |
michael@17 | 1663 | |
michael@17 | 1664 | value.s = passwd; |
michael@17 | 1665 | value.len = strlen(value.s); |
michael@17 | 1666 | val.s = value; |
michael@17 | 1667 | add_avp(passwd_avp_type|AVP_VAL_STR, passwd_avp, val); |
michael@17 | 1668 | LM_DBG("Added passwd_avp <%.*s>\n", value.len, value.s); |
michael@17 | 1669 | |
michael@16 | 1670 | skip: |
michael@16 | 1671 | continue; |
michael@16 | 1672 | } |
michael@16 | 1673 | |
michael@16 | 1674 | return 1; |
michael@16 | 1675 | } |
michael@16 | 1676 | |
michael@16 | 1677 | /* |
michael@16 | 1678 | * Load info of matching GWs from database to gw_uri AVPs |
michael@16 | 1679 | * taking into account the given group id. Caller URI is taken |
michael@16 | 1680 | * from request. |
michael@16 | 1681 | */ |
michael@16 | 1682 | static int load_gws_from_grp(struct sip_msg* _m, char* _s1, char* _s2) |
michael@16 | 1683 | { |
michael@16 | 1684 | str grp_s; |
michael@16 | 1685 | unsigned int grp_id; |
michael@16 | 1686 | |
michael@16 | 1687 | if(((pv_elem_p)_s1)->spec.getf!=NULL) |
michael@16 | 1688 | { |
michael@16 | 1689 | if(pv_printf_s(_m, (pv_elem_p)_s1, &grp_s)!=0) |
michael@16 | 1690 | return -1; |
michael@16 | 1691 | if(str2int(&grp_s, &grp_id)!=0) |
michael@16 | 1692 | return -1; |
michael@16 | 1693 | } else { |
michael@16 | 1694 | grp_id = ((pv_elem_p)_s1)->spec.pvp.pvn.u.isname.name.n; |
michael@16 | 1695 | } |
michael@16 | 1696 | if (grp_id > 0) return do_load_gws(_m, (str *)0, (int)grp_id); |
michael@16 | 1697 | else return -1; |
michael@16 | 1698 | } |
michael@16 | 1699 | |
michael@16 | 1700 | |
michael@16 | 1701 | /* |
michael@16 | 1702 | * Load info of matching GWs from database to gw_uri AVPs. |
michael@16 | 1703 | * Caller URI is taken from request. |
michael@16 | 1704 | */ |
michael@16 | 1705 | static int load_gws_0(struct sip_msg* _m, char* _s1, char* _s2) |
michael@16 | 1706 | { |
michael@16 | 1707 | return do_load_gws(_m, (str *)0, -1); |
michael@16 | 1708 | } |
michael@16 | 1709 | |
michael@16 | 1710 | |
michael@16 | 1711 | /* |
michael@16 | 1712 | * Load info of matching GWs from database to gw_uri AVPs. |
michael@16 | 1713 | * Caller URI is taken from pseudo variable argument. |
michael@16 | 1714 | */ |
michael@16 | 1715 | static int load_gws_1(struct sip_msg* _m, char* _sp, char* _s2) |
michael@16 | 1716 | { |
michael@16 | 1717 | pv_spec_t *sp; |
michael@16 | 1718 | pv_value_t pv_val; |
michael@16 | 1719 | sp = (pv_spec_t *)_sp; |
michael@16 | 1720 | |
michael@16 | 1721 | if (sp && (pv_get_spec_value(_m, sp, &pv_val) == 0)) { |
michael@16 | 1722 | if (pv_val.flags & PV_VAL_STR) { |
michael@16 | 1723 | if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) { |
michael@16 | 1724 | LM_DBG("missing from uri\n"); |
michael@16 | 1725 | return -1; |
michael@16 | 1726 | } |
michael@16 | 1727 | return do_load_gws(_m, &(pv_val.rs), -1); |
michael@16 | 1728 | } else { |
michael@16 | 1729 | LM_DBG("pseudo variable value is not string\n"); |
michael@16 | 1730 | return -1; |
michael@16 | 1731 | } |
michael@16 | 1732 | } else { |
michael@16 | 1733 | LM_DBG("cannot get pseudo variable value\n"); |
michael@16 | 1734 | return -1; |
michael@16 | 1735 | } |
michael@16 | 1736 | } |
michael@16 | 1737 | |
michael@16 | 1738 | |
michael@16 | 1739 | /* |
michael@16 | 1740 | * Rewrites scheme, host, port, and transport parts of R-URI based on first |
michael@16 | 1741 | * gw_uri AVP value, which is then destroyed. Also saves R-URI user to |
michael@16 | 1742 | * ruri_user AVP for later use in failure route block. |
michael@16 | 1743 | * If called from failure route block, appends a new branch to request |
michael@16 | 1744 | * where scheme, host, port, and transport of URI are taken from the first |
michael@16 | 1745 | * gw_uri AVP value, which is then destroyed. URI user is taken from |
michael@16 | 1746 | * ruri_user AVP value saved earlier. |
michael@16 | 1747 | * Returns 1 upon success and -1 upon failure. |
michael@16 | 1748 | */ |
michael@16 | 1749 | static int next_gw(struct sip_msg* _m, char* _s1, char* _s2) |
michael@16 | 1750 | { |
michael@16 | 1751 | int_str gw_uri_val, ruri_user_val, val; |
michael@17 | 1752 | int_str user_val, realm_val, passwd_val; |
michael@17 | 1753 | struct usr_avp *gu_avp, *ru_avp, *usr_avp, *rlm_avp, *pwd_avp; |
michael@16 | 1754 | int rval; |
michael@16 | 1755 | str new_ruri; |
michael@16 | 1756 | char *at, *at_char, *strip_char, *endptr; |
michael@16 | 1757 | unsigned int strip; |
michael@16 | 1758 | |
michael@16 | 1759 | gu_avp = search_first_avp(gw_uri_avp_type, gw_uri_avp, &gw_uri_val, 0); |
michael@16 | 1760 | if (!gu_avp) return -1; |
michael@16 | 1761 | |
michael@16 | 1762 | /* Set flags_avp from integer at the beginning of of gw_uri */ |
michael@16 | 1763 | val.n = (int)strtoul(gw_uri_val.s.s, &at, 0); |
michael@16 | 1764 | add_avp(flags_avp_type, flags_avp, val); |
michael@16 | 1765 | LM_DBG("Added flags_avp <%u>\n", (unsigned int)val.n); |
michael@16 | 1766 | |
michael@16 | 1767 | gw_uri_val.s.len = gw_uri_val.s.len - (at - gw_uri_val.s.s); |
michael@16 | 1768 | gw_uri_val.s.s = at; |
michael@16 | 1769 | |
michael@17 | 1770 | /* Save gateway AVPs for use in script */ |
michael@17 | 1771 | usr_avp = search_first_avp(user_avp_type, user_avp, &user_val, 0); |
michael@17 | 1772 | rlm_avp = search_first_avp(realm_avp_type, realm_avp, &realm_val, 0); |
michael@17 | 1773 | pwd_avp = search_first_avp(passwd_avp_type, passwd_avp, &passwd_val, 0); |
michael@17 | 1774 | if (!usr_avp) { |
michael@17 | 1775 | LM_DBG("User AVP no set\n"); |
michael@17 | 1776 | return -1; |
michael@17 | 1777 | } |
michael@17 | 1778 | else { |
michael@17 | 1779 | add_avp(user_avp_type|AVP_VAL_STR, user_avp, user_val); |
michael@17 | 1780 | LM_DBG("Added user_avp <%.*s>\n", user_val.s.len, user_val.s.s); |
michael@17 | 1781 | } |
michael@17 | 1782 | if (!rlm_avp) { |
michael@17 | 1783 | LM_DBG("Realm AVP no set\n"); |
michael@17 | 1784 | return -1; |
michael@17 | 1785 | } |
michael@17 | 1786 | else { |
michael@17 | 1787 | add_avp(realm_avp_type|AVP_VAL_STR, realm_avp, realm_val); |
michael@17 | 1788 | LM_DBG("Added realm_avp <%.*s>\n", realm_val.s.len, realm_val.s.s); |
michael@17 | 1789 | } |
michael@17 | 1790 | if (!pwd_avp) { |
michael@17 | 1791 | LM_DBG("Passwd AVP no set\n"); |
michael@17 | 1792 | return -1; |
michael@17 | 1793 | } |
michael@17 | 1794 | else { |
michael@17 | 1795 | add_avp(passwd_avp_type|AVP_VAL_STR, passwd_avp, passwd_val); |
michael@17 | 1796 | LM_DBG("Added passwd_avp <%.*s>\n", passwd_val.s.len, passwd_val.s.s); |
michael@17 | 1797 | } |
michael@17 | 1798 | |
michael@16 | 1799 | /* Create new Request-URI taking URI user from ruri_user AVP |
michael@16 | 1800 | and other parts of from gateway URI AVP. */ |
michael@16 | 1801 | ru_avp = search_first_avp(ruri_user_avp_type, ruri_user_avp, |
michael@16 | 1802 | &ruri_user_val, 0); |
michael@16 | 1803 | if (!ru_avp) { |
michael@16 | 1804 | LM_DBG("ruri_user AVP no yet set -> use RURI\n"); |
michael@16 | 1805 | /* parse RURI and ger username */ |
michael@16 | 1806 | if (parse_sip_msg_uri(_m) < 0) { |
michael@16 | 1807 | LM_ERR("Parsing of R-URI failed\n"); |
michael@16 | 1808 | return -1; |
michael@16 | 1809 | } |
michael@16 | 1810 | ruri_user_val.s = _m->parsed_uri.user; |
michael@16 | 1811 | /* Save Request-URI user for use in FAILURE_ROUTE */ |
michael@16 | 1812 | val.s = _m->parsed_uri.user; |
michael@16 | 1813 | add_avp(ruri_user_avp_type|AVP_VAL_STR, ruri_user_avp, val); |
michael@16 | 1814 | LM_DBG("Added ruri_user_avp <%.*s>\n", val.s.len, val.s.s); |
michael@16 | 1815 | } |
michael@16 | 1816 | |
michael@16 | 1817 | new_ruri.s = pkg_malloc(gw_uri_val.s.len + ruri_user_val.s.len); |
michael@16 | 1818 | if (!new_ruri.s) { |
michael@16 | 1819 | LM_ERR("No memory for new R-URI.\n"); |
michael@16 | 1820 | return -1; |
michael@16 | 1821 | } |
michael@16 | 1822 | at_char = memchr(gw_uri_val.s.s, '@', gw_uri_val.s.len); |
michael@16 | 1823 | if (!at_char) { |
michael@16 | 1824 | pkg_free(new_ruri.s); |
michael@16 | 1825 | LM_ERR("No @ in gateway URI <%.*s>\n", |
michael@16 | 1826 | gw_uri_val.s.len, gw_uri_val.s.s); |
michael@16 | 1827 | return -1; |
michael@16 | 1828 | } |
michael@16 | 1829 | strip_char = memchr(gw_uri_val.s.s, '|', gw_uri_val.s.len); |
michael@16 | 1830 | if (!strip_char || strip_char + 1 >= at_char) { |
michael@16 | 1831 | pkg_free(new_ruri.s); |
michael@16 | 1832 | LM_ERR("No strip char | and at least one " |
michael@16 | 1833 | "char before @ in gateway URI <%.*s>\n", |
michael@16 | 1834 | gw_uri_val.s.len, gw_uri_val.s.s); |
michael@16 | 1835 | return -1; |
michael@16 | 1836 | } |
michael@16 | 1837 | at = new_ruri.s; |
michael@16 | 1838 | memcpy(at, gw_uri_val.s.s, strip_char - gw_uri_val.s.s); |
michael@16 | 1839 | at = at + (strip_char - gw_uri_val.s.s); |
michael@16 | 1840 | strip = strtol(strip_char + 1, &endptr, 10); |
michael@16 | 1841 | if (endptr != at_char) { |
michael@16 | 1842 | pkg_free(new_ruri.s); |
michael@16 | 1843 | LM_ERR("Non-digit char between | and @ chars in gw URI <%.*s>\n", |
michael@16 | 1844 | gw_uri_val.s.len, gw_uri_val.s.s); |
michael@16 | 1845 | return -1; |
michael@16 | 1846 | } |
michael@16 | 1847 | if (ruri_user_val.s.len - strip > 0) { |
michael@16 | 1848 | memcpy(at, ruri_user_val.s.s + strip, |
michael@16 | 1849 | ruri_user_val.s.len - strip); |
michael@16 | 1850 | at = at + ruri_user_val.s.len - strip; |
michael@16 | 1851 | } |
michael@16 | 1852 | if (*(at - 1) != ':') { |
michael@16 | 1853 | memcpy(at, at_char, gw_uri_val.s.len - (at_char - gw_uri_val.s.s)); |
michael@16 | 1854 | at = at + gw_uri_val.s.len - (at_char - gw_uri_val.s.s); |
michael@16 | 1855 | } else { |
michael@16 | 1856 | memcpy(at, at_char + 1, gw_uri_val.s.len - |
michael@16 | 1857 | (at_char + 1 - gw_uri_val.s.s)); |
michael@16 | 1858 | at = at + gw_uri_val.s.len - (at_char + 1 - gw_uri_val.s.s); |
michael@16 | 1859 | } |
michael@16 | 1860 | new_ruri.len = at - new_ruri.s; |
michael@16 | 1861 | |
michael@16 | 1862 | /* set new RURI */ |
michael@16 | 1863 | rval = set_ruri( _m, &new_ruri); |
michael@16 | 1864 | pkg_free(new_ruri.s); |
michael@16 | 1865 | destroy_avp(gu_avp); |
michael@16 | 1866 | if (rval!=0) { |
michael@16 | 1867 | LM_ERR("failed to set new RURI\n"); |
michael@16 | 1868 | return -1; |
michael@16 | 1869 | } |
michael@16 | 1870 | |
michael@16 | 1871 | return 1; |
michael@16 | 1872 | } |
michael@16 | 1873 | |
michael@16 | 1874 | |
michael@16 | 1875 | /* |
michael@16 | 1876 | * Checks if request comes from a gateway |
michael@16 | 1877 | */ |
michael@16 | 1878 | static int do_from_gw(struct sip_msg* _m, pv_spec_t *addr_sp, int grp_id) |
michael@16 | 1879 | { |
michael@16 | 1880 | int i; |
michael@16 | 1881 | unsigned int src_addr; |
michael@16 | 1882 | pv_value_t pv_val; |
michael@16 | 1883 | struct ip_addr *ip; |
michael@16 | 1884 | int_str val; |
michael@16 | 1885 | |
michael@16 | 1886 | if (addr_sp && (pv_get_spec_value(_m, addr_sp, &pv_val) == 0)) { |
michael@16 | 1887 | if (pv_val.flags & PV_VAL_INT) { |
michael@16 | 1888 | src_addr = pv_val.ri; |
michael@16 | 1889 | } else if (pv_val.flags & PV_VAL_STR) { |
michael@16 | 1890 | if ( (ip=str2ip( &pv_val.rs)) == NULL) { |
michael@16 | 1891 | LM_ERR("failed to convert IP address string to in_addr\n"); |
michael@16 | 1892 | return -1; |
michael@16 | 1893 | } else { |
michael@16 | 1894 | src_addr = ip->u.addr32[0]; |
michael@16 | 1895 | } |
michael@16 | 1896 | } else { |
michael@16 | 1897 | LM_ERR("IP address PV empty value\n"); |
michael@16 | 1898 | return -1; |
michael@16 | 1899 | } |
michael@16 | 1900 | } else { |
michael@16 | 1901 | src_addr = _m->rcv.src_ip.u.addr32[0]; |
michael@16 | 1902 | } |
michael@16 | 1903 | |
michael@16 | 1904 | for (i = 0; i < MAX_NO_OF_GWS; i++) { |
michael@16 | 1905 | if ((*gws)[i].ip_addr == 0) { |
michael@16 | 1906 | return -1; |
michael@16 | 1907 | } |
michael@16 | 1908 | if ((*gws)[i].ip_addr == src_addr && |
michael@16 | 1909 | (grp_id < 0 || (*gws)[i].grp_id == grp_id)) { |
michael@16 | 1910 | LM_DBG("Request came from gw\n"); |
michael@16 | 1911 | val.n = (int)(*gws)[i].flags; |
michael@16 | 1912 | add_avp(flags_avp_type, flags_avp, val); |
michael@16 | 1913 | LM_DBG("Added flags_avp <%u>\n", (unsigned int)val.n); |
michael@16 | 1914 | return 1; |
michael@16 | 1915 | } |
michael@16 | 1916 | } |
michael@16 | 1917 | |
michael@16 | 1918 | LM_DBG("Request did not come from gw\n"); |
michael@16 | 1919 | return -1; |
michael@16 | 1920 | } |
michael@16 | 1921 | |
michael@16 | 1922 | |
michael@16 | 1923 | /* |
michael@16 | 1924 | * Checks if request comes from a gateway, taking source address from request |
michael@16 | 1925 | * and taking into account the group id. |
michael@16 | 1926 | */ |
michael@16 | 1927 | static int from_gw_grp(struct sip_msg* _m, char* _grp_id, char* _s2) |
michael@16 | 1928 | { |
michael@16 | 1929 | return do_from_gw(_m, (pv_spec_t *)0, (int)(long)_grp_id); |
michael@16 | 1930 | } |
michael@16 | 1931 | |
michael@16 | 1932 | |
michael@16 | 1933 | /* |
michael@16 | 1934 | * Checks if request comes from a gateway, taking src_address from request |
michael@16 | 1935 | * and ignoring group id. |
michael@16 | 1936 | */ |
michael@16 | 1937 | static int from_gw_0(struct sip_msg* _m, char* _s1, char* _s2) |
michael@16 | 1938 | { |
michael@16 | 1939 | return do_from_gw(_m, (pv_spec_t *)0, -1); |
michael@16 | 1940 | } |
michael@16 | 1941 | |
michael@16 | 1942 | |
michael@16 | 1943 | /* |
michael@16 | 1944 | * Checks if request comes from a gateway, taking source address from pw |
michael@16 | 1945 | * and ignoring group id. |
michael@16 | 1946 | */ |
michael@16 | 1947 | static int from_gw_1(struct sip_msg* _m, char* _addr_sp, char* _s2) |
michael@16 | 1948 | { |
michael@16 | 1949 | return do_from_gw(_m, (pv_spec_t *)_addr_sp, -1); |
michael@16 | 1950 | } |
michael@16 | 1951 | |
michael@16 | 1952 | |
michael@16 | 1953 | /* |
michael@16 | 1954 | * Checks if in-dialog request goes to gateway |
michael@16 | 1955 | */ |
michael@16 | 1956 | static int do_to_gw(struct sip_msg* _m, int grp_id) |
michael@16 | 1957 | { |
michael@16 | 1958 | char host[16]; |
michael@16 | 1959 | struct in_addr addr; |
michael@16 | 1960 | unsigned int i; |
michael@16 | 1961 | |
michael@16 | 1962 | if((_m->parsed_uri_ok == 0) && (parse_sip_msg_uri(_m) < 0)) { |
michael@16 | 1963 | LM_ERR("Error while parsing the R-URI\n"); |
michael@16 | 1964 | return -1; |
michael@16 | 1965 | } |
michael@16 | 1966 | |
michael@16 | 1967 | if (_m->parsed_uri.host.len > 15) { |
michael@16 | 1968 | return -1; |
michael@16 | 1969 | } |
michael@16 | 1970 | memcpy(host, _m->parsed_uri.host.s, _m->parsed_uri.host.len); |
michael@16 | 1971 | host[_m->parsed_uri.host.len] = 0; |
michael@16 | 1972 | |
michael@16 | 1973 | if (!inet_aton(host, &addr)) { |
michael@16 | 1974 | return -1; |
michael@16 | 1975 | } |
michael@16 | 1976 | |
michael@16 | 1977 | for (i = 0; i < MAX_NO_OF_GWS; i++) { |
michael@16 | 1978 | if ((*gws)[i].ip_addr == 0) { |
michael@16 | 1979 | return -1; |
michael@16 | 1980 | } |
michael@16 | 1981 | if ((*gws)[i].ip_addr == addr.s_addr && |
michael@16 | 1982 | (grp_id < 0 || (*gws)[i].grp_id == grp_id)) { |
michael@16 | 1983 | return 1; |
michael@16 | 1984 | } |
michael@16 | 1985 | } |
michael@16 | 1986 | |
michael@16 | 1987 | return -1; |
michael@16 | 1988 | } |
michael@16 | 1989 | |
michael@16 | 1990 | |
michael@16 | 1991 | /* |
michael@16 | 1992 | * Checks if in-dialog request goes to gateway, taking |
michael@16 | 1993 | * into account the group id. |
michael@16 | 1994 | */ |
michael@16 | 1995 | static int to_gw_grp(struct sip_msg* _m, char* _s1, char* _s2) |
michael@16 | 1996 | { |
michael@16 | 1997 | int grp_id; |
michael@16 | 1998 | |
michael@16 | 1999 | grp_id = (int)(long)_s1; |
michael@16 | 2000 | return do_to_gw(_m, grp_id); |
michael@16 | 2001 | } |
michael@16 | 2002 | |
michael@16 | 2003 | |
michael@16 | 2004 | /* |
michael@16 | 2005 | * Checks if in-dialog request goes to gateway, ignoring |
michael@16 | 2006 | * the group id. |
michael@16 | 2007 | */ |
michael@16 | 2008 | static int to_gw(struct sip_msg* _m, char* _s1, char* _s2) |
michael@16 | 2009 | { |
michael@16 | 2010 | return do_to_gw(_m, -1); |
michael@16 | 2011 | } |
michael@16 | 2012 | |
michael@16 | 2013 | |
michael@16 | 2014 | /* |
michael@16 | 2015 | * Frees contact list used by load_contacts function |
michael@16 | 2016 | */ |
michael@16 | 2017 | static inline void free_contact_list(struct contact *curr) { |
michael@16 | 2018 | struct contact *prev; |
michael@16 | 2019 | while (curr) { |
michael@16 | 2020 | prev = curr; |
michael@16 | 2021 | curr = curr->next; |
michael@16 | 2022 | pkg_free(prev); |
michael@16 | 2023 | } |
michael@16 | 2024 | } |
michael@16 | 2025 | |
michael@16 | 2026 | /* Encode branch info from contact struct to str */ |
michael@16 | 2027 | static inline int encode_branch_info(str *info, struct contact *con) |
michael@16 | 2028 | { |
michael@16 | 2029 | char *at, *s; |
michael@16 | 2030 | int len; |
michael@16 | 2031 | |
michael@16 | 2032 | info->len = con->uri.len + con->dst_uri.len + |
michael@16 | 2033 | con->path.len + MAX_SOCKET_STR + INT2STR_MAX_LEN + 5; |
michael@16 | 2034 | info->s = pkg_malloc(info->len); |
michael@16 | 2035 | if (!info->s) { |
michael@16 | 2036 | LM_ERR("No memory left for branch info\n"); |
michael@16 | 2037 | return 0; |
michael@16 | 2038 | } |
michael@16 | 2039 | at = info->s; |
michael@16 | 2040 | memcpy(at, con->uri.s, con->uri.len); |
michael@16 | 2041 | at = at + con->uri.len; |
michael@16 | 2042 | *at = '\n'; |
michael@16 | 2043 | at++; |
michael@16 | 2044 | memcpy(at, con->dst_uri.s, con->dst_uri.len); |
michael@16 | 2045 | at = at + con->dst_uri.len; |
michael@16 | 2046 | *at = '\n'; |
michael@16 | 2047 | at++; |
michael@16 | 2048 | memcpy(at, con->path.s, con->path.len); |
michael@16 | 2049 | at = at + con->path.len; |
michael@16 | 2050 | *at = '\n'; |
michael@16 | 2051 | at++; |
michael@16 | 2052 | if (con->sock) { |
michael@16 | 2053 | len = MAX_SOCKET_STR; |
michael@16 | 2054 | if (!socket2str(con->sock, at, &len, 1)) { |
michael@16 | 2055 | LM_ERR("Failed to convert socket to str\n"); |
michael@16 | 2056 | return 0; |
michael@16 | 2057 | } |
michael@16 | 2058 | } else { |
michael@16 | 2059 | len = 0; |
michael@16 | 2060 | } |
michael@16 | 2061 | at = at + len; |
michael@16 | 2062 | *at = '\n'; |
michael@16 | 2063 | at++; |
michael@16 | 2064 | s = int2str(con->flags, &len); |
michael@16 | 2065 | memcpy(at, s, len); |
michael@16 | 2066 | at = at + len; |
michael@16 | 2067 | *at = '\n'; |
michael@16 | 2068 | info->len = at - info->s + 1; |
michael@16 | 2069 | |
michael@16 | 2070 | return 1; |
michael@16 | 2071 | } |
michael@16 | 2072 | |
michael@16 | 2073 | |
michael@16 | 2074 | /* Encode branch info from str */ |
michael@16 | 2075 | static inline int decode_branch_info(char *info, str *uri, str *dst, str *path, |
michael@16 | 2076 | struct socket_info **sock, unsigned int *flags) |
michael@16 | 2077 | { |
michael@16 | 2078 | str s, host; |
michael@16 | 2079 | int port, proto; |
michael@16 | 2080 | char *pos, *at; |
michael@16 | 2081 | |
michael@16 | 2082 | pos = strchr(info, '\n'); |
michael@16 | 2083 | uri->len = pos - info; |
michael@16 | 2084 | if (uri->len) { |
michael@16 | 2085 | uri->s = info; |
michael@16 | 2086 | } else { |
michael@16 | 2087 | uri->s = 0; |
michael@16 | 2088 | } |
michael@16 | 2089 | at = pos + 1; |
michael@16 | 2090 | |
michael@16 | 2091 | pos = strchr(at, '\n'); |
michael@16 | 2092 | dst->len = pos - at; |
michael@16 | 2093 | if (dst->len) { |
michael@16 | 2094 | dst->s = at; |
michael@16 | 2095 | } else { |
michael@16 | 2096 | dst->s = 0; |
michael@16 | 2097 | } |
michael@16 | 2098 | at = pos + 1; |
michael@16 | 2099 | |
michael@16 | 2100 | pos = strchr(at, '\n'); |
michael@16 | 2101 | path->len = pos - at; |
michael@16 | 2102 | if (path->len) { |
michael@16 | 2103 | path->s = at; |
michael@16 | 2104 | } else { |
michael@16 | 2105 | path->s = 0; |
michael@16 | 2106 | } |
michael@16 | 2107 | at = pos + 1; |
michael@16 | 2108 | |
michael@16 | 2109 | pos = strchr(at, '\n'); |
michael@16 | 2110 | s.len = pos - at; |
michael@16 | 2111 | if (s.len) { |
michael@16 | 2112 | s.s = at; |
michael@16 | 2113 | if (parse_phostport(s.s, s.len, &host.s, &host.len, |
michael@16 | 2114 | &port, &proto) != 0) { |
michael@16 | 2115 | LM_ERR("Parsing of socket info <%.*s> failed\n", s.len, s.s); |
michael@16 | 2116 | return 0; |
michael@16 | 2117 | } |
michael@16 | 2118 | *sock = grep_sock_info(&host, (unsigned short)port, |
michael@16 | 2119 | (unsigned short)proto); |
michael@16 | 2120 | if (*sock == 0) { |
michael@16 | 2121 | LM_ERR("Invalid socket <%.*s>\n", s.len, s.s); |
michael@16 | 2122 | return 0; |
michael@16 | 2123 | } |
michael@16 | 2124 | } else { |
michael@16 | 2125 | *sock = 0; |
michael@16 | 2126 | } |
michael@16 | 2127 | at = pos + 1; |
michael@16 | 2128 | |
michael@16 | 2129 | pos = strchr(at, '\n'); |
michael@16 | 2130 | s.len = pos - at; |
michael@16 | 2131 | if (s.len) { |
michael@16 | 2132 | s.s = at; |
michael@16 | 2133 | if (str2int(&s, flags) != 0) { |
michael@16 | 2134 | LM_ERR("Failed to decode flags <%.*s>\n", s.len, s.s); |
michael@16 | 2135 | return 0; |
michael@16 | 2136 | } |
michael@16 | 2137 | } else { |
michael@16 | 2138 | *flags = 0; |
michael@16 | 2139 | } |
michael@16 | 2140 | |
michael@16 | 2141 | return 1; |
michael@16 | 2142 | } |
michael@16 | 2143 | |
michael@16 | 2144 | |
michael@16 | 2145 | /* |
michael@16 | 2146 | * Loads contacts in destination set into "lcr_contact" AVP in reverse |
michael@16 | 2147 | * priority order and associated each contact with Q_FLAG telling if |
michael@16 | 2148 | * contact is the last one in its priority class. Finally, removes |
michael@16 | 2149 | * all branches from destination set. |
michael@16 | 2150 | */ |
michael@16 | 2151 | static int load_contacts(struct sip_msg* msg, char* key, char* value) |
michael@16 | 2152 | { |
michael@16 | 2153 | str uri, dst_uri, path, branch_info, *ruri; |
michael@16 | 2154 | qvalue_t q, ruri_q; |
michael@16 | 2155 | struct contact *contacts, *next, *prev, *curr; |
michael@16 | 2156 | int_str val; |
michael@16 | 2157 | int idx; |
michael@16 | 2158 | struct socket_info* sock; |
michael@16 | 2159 | unsigned int flags; |
michael@16 | 2160 | |
michael@16 | 2161 | /* Check if anything needs to be done */ |
michael@16 | 2162 | if (nr_branches == 0) { |
michael@16 | 2163 | LM_DBG("Nothing to do - no branches!\n"); |
michael@16 | 2164 | return 1; |
michael@16 | 2165 | } |
michael@16 | 2166 | |
michael@16 | 2167 | ruri = GET_RURI(msg); |
michael@16 | 2168 | if (!ruri) { |
michael@16 | 2169 | LM_ERR("No Request-URI found\n"); |
michael@16 | 2170 | return -1; |
michael@16 | 2171 | } |
michael@16 | 2172 | ruri_q = get_ruri_q(); |
michael@16 | 2173 | |
michael@16 | 2174 | for(idx = 0; (uri.s = get_branch(idx, &uri.len, &q, 0, 0, 0, 0)) != 0; |
michael@16 | 2175 | idx++) { |
michael@16 | 2176 | if (q != ruri_q) { |
michael@16 | 2177 | goto rest; |
michael@16 | 2178 | } |
michael@16 | 2179 | } |
michael@16 | 2180 | LM_DBG("Nothing to do - all contacts have same q!\n"); |
michael@16 | 2181 | return 1; |
michael@16 | 2182 | |
michael@16 | 2183 | rest: |
michael@16 | 2184 | /* Insert Request-URI branch to contact list */ |
michael@16 | 2185 | contacts = (struct contact *)pkg_malloc(sizeof(struct contact)); |
michael@16 | 2186 | if (!contacts) { |
michael@16 | 2187 | LM_ERR("No memory for contact info\n"); |
michael@16 | 2188 | return -1; |
michael@16 | 2189 | } |
michael@16 | 2190 | contacts->uri.s = ruri->s; |
michael@16 | 2191 | contacts->uri.len = ruri->len; |
michael@16 | 2192 | contacts->q = ruri_q; |
michael@16 | 2193 | contacts->dst_uri = msg->dst_uri; |
michael@16 | 2194 | contacts->sock = msg->force_send_socket; |
michael@16 | 2195 | contacts->flags = getb0flags(); |
michael@16 | 2196 | contacts->path = msg->path_vec; |
michael@16 | 2197 | contacts->next = (struct contact *)0; |
michael@16 | 2198 | |
michael@16 | 2199 | /* Insert branches to contact list in increasing q order */ |
michael@16 | 2200 | for(idx = 0; |
michael@16 | 2201 | (uri.s = get_branch(idx,&uri.len,&q,&dst_uri,&path,&flags,&sock)) |
michael@16 | 2202 | != 0; |
michael@16 | 2203 | idx++ ) { |
michael@16 | 2204 | next = (struct contact *)pkg_malloc(sizeof(struct contact)); |
michael@16 | 2205 | if (!next) { |
michael@16 | 2206 | LM_ERR("No memory for contact info\n"); |
michael@16 | 2207 | free_contact_list(contacts); |
michael@16 | 2208 | return -1; |
michael@16 | 2209 | } |
michael@16 | 2210 | next->uri = uri; |
michael@16 | 2211 | next->q = q; |
michael@16 | 2212 | next->dst_uri = dst_uri; |
michael@16 | 2213 | next->path = path; |
michael@16 | 2214 | next->flags = flags; |
michael@16 | 2215 | next->sock = sock; |
michael@16 | 2216 | next->next = (struct contact *)0; |
michael@16 | 2217 | prev = (struct contact *)0; |
michael@16 | 2218 | curr = contacts; |
michael@16 | 2219 | while (curr && (curr->q < q)) { |
michael@16 | 2220 | prev = curr; |
michael@16 | 2221 | curr = curr->next; |
michael@16 | 2222 | } |
michael@16 | 2223 | if (!curr) { |
michael@16 | 2224 | next->next = (struct contact *)0; |
michael@16 | 2225 | prev->next = next; |
michael@16 | 2226 | } else { |
michael@16 | 2227 | next->next = curr; |
michael@16 | 2228 | if (prev) { |
michael@16 | 2229 | prev->next = next; |
michael@16 | 2230 | } else { |
michael@16 | 2231 | contacts = next; |
michael@16 | 2232 | } |
michael@16 | 2233 | } |
michael@16 | 2234 | } |
michael@16 | 2235 | |
michael@16 | 2236 | /* Assign values for q_flags */ |
michael@16 | 2237 | curr = contacts; |
michael@16 | 2238 | curr->q_flag = 0; |
michael@16 | 2239 | while (curr->next) { |
michael@16 | 2240 | if (curr->q < curr->next->q) { |
michael@16 | 2241 | curr->next->q_flag = Q_FLAG; |
michael@16 | 2242 | } else { |
michael@16 | 2243 | curr->next->q_flag = 0; |
michael@16 | 2244 | } |
michael@16 | 2245 | curr = curr->next; |
michael@16 | 2246 | } |
michael@16 | 2247 | |
michael@16 | 2248 | /* Add contacts to "contacts" AVP */ |
michael@16 | 2249 | curr = contacts; |
michael@16 | 2250 | while (curr) { |
michael@16 | 2251 | if (encode_branch_info(&branch_info, curr) == 0) { |
michael@16 | 2252 | LM_ERR("Encoding of branch info failed\n"); |
michael@16 | 2253 | free_contact_list(contacts); |
michael@16 | 2254 | if (branch_info.s) pkg_free(branch_info.s); |
michael@16 | 2255 | return -1; |
michael@16 | 2256 | } |
michael@16 | 2257 | val.s = branch_info; |
michael@16 | 2258 | add_avp(contact_avp_type|AVP_VAL_STR|(curr->q_flag), |
michael@16 | 2259 | contact_avp, val); |
michael@16 | 2260 | pkg_free(branch_info.s); |
michael@16 | 2261 | LM_DBG("Loaded contact <%.*s> with q_flag <%d>\n", |
michael@16 | 2262 | val.s.len, val.s.s, curr->q_flag); |
michael@16 | 2263 | curr = curr->next; |
michael@16 | 2264 | } |
michael@16 | 2265 | |
michael@16 | 2266 | /* Clear all branches */ |
michael@16 | 2267 | clear_branches(); |
michael@16 | 2268 | |
michael@16 | 2269 | /* Free contact list */ |
michael@16 | 2270 | free_contact_list(contacts); |
michael@16 | 2271 | |
michael@16 | 2272 | return 1; |
michael@16 | 2273 | } |
michael@16 | 2274 | |
michael@16 | 2275 | |
michael@16 | 2276 | /* |
michael@16 | 2277 | * Adds to request a destination set that includes all highest priority |
michael@16 | 2278 | * class contacts in "lcr_contact" AVP. If called from a route block, |
michael@16 | 2279 | * rewrites the request uri with first contact and adds the remaining |
michael@16 | 2280 | * contacts as branches. If called from failure route block, adds all |
michael@16 | 2281 | * contacts as branches. Removes added contacts from "lcr_contact" AVP. |
michael@16 | 2282 | */ |
michael@16 | 2283 | static int next_contacts(struct sip_msg* msg, char* key, char* value) |
michael@16 | 2284 | { |
michael@16 | 2285 | struct usr_avp *avp, *prev; |
michael@16 | 2286 | int_str val; |
michael@16 | 2287 | str uri, dst, path; |
michael@16 | 2288 | struct socket_info *sock; |
michael@16 | 2289 | unsigned int flags; |
michael@16 | 2290 | |
michael@16 | 2291 | /* Find first lcr_contact_avp value */ |
michael@16 | 2292 | avp = search_first_avp(contact_avp_type, contact_avp, &val, 0); |
michael@16 | 2293 | if (!avp) { |
michael@16 | 2294 | LM_DBG("No AVPs -- we are done!\n"); |
michael@16 | 2295 | return -1; |
michael@16 | 2296 | } |
michael@16 | 2297 | |
michael@16 | 2298 | LM_DBG("Next contact is <%s>\n", val.s.s); |
michael@16 | 2299 | |
michael@16 | 2300 | if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)== 0) { |
michael@16 | 2301 | LM_ERR("Decoding of branch info <%.*s> failed\n", |
michael@16 | 2302 | val.s.len, val.s.s); |
michael@16 | 2303 | destroy_avp(avp); |
michael@16 | 2304 | return -1; |
michael@16 | 2305 | } |
michael@16 | 2306 | |
michael@16 | 2307 | set_ruri(msg, &uri); |
michael@16 | 2308 | set_dst_uri(msg, &dst); |
michael@16 | 2309 | set_path_vector(msg, &path); |
michael@16 | 2310 | msg->force_send_socket = sock; |
michael@16 | 2311 | setb0flags(flags); |
michael@16 | 2312 | |
michael@16 | 2313 | if (avp->flags & Q_FLAG) { |
michael@16 | 2314 | destroy_avp(avp); |
michael@16 | 2315 | if (route_type == REQUEST_ROUTE) { |
michael@16 | 2316 | /* Set fr_inv_timer */ |
michael@16 | 2317 | val.n = fr_inv_timer_next; |
michael@16 | 2318 | if (add_avp(fr_inv_timer_avp_type, fr_inv_timer_avp, val) != 0) { |
michael@16 | 2319 | LM_ERR("Setting of fr_inv_timer_avp failed\n"); |
michael@16 | 2320 | return -1; |
michael@16 | 2321 | } |
michael@16 | 2322 | } |
michael@16 | 2323 | return 1; |
michael@16 | 2324 | } |
michael@16 | 2325 | |
michael@16 | 2326 | /* Append branches until out of branches or Q_FLAG is set */ |
michael@16 | 2327 | prev = avp; |
michael@16 | 2328 | while ((avp = search_next_avp(avp, &val))) { |
michael@16 | 2329 | destroy_avp(prev); |
michael@16 | 2330 | |
michael@16 | 2331 | LM_DBG("Next contact is <%s>\n", val.s.s); |
michael@16 | 2332 | |
michael@16 | 2333 | if (decode_branch_info(val.s.s, &uri, &dst, &path, &sock, &flags)== 0){ |
michael@16 | 2334 | LM_ERR("Decoding of branch info <%.*s> failed\n", |
michael@16 | 2335 | val.s.len, val.s.s); |
michael@16 | 2336 | destroy_avp(avp); |
michael@16 | 2337 | return -1; |
michael@16 | 2338 | } |
michael@16 | 2339 | |
michael@16 | 2340 | if (append_branch(msg, &uri, &dst, &path, 0, flags, sock) != 1) { |
michael@16 | 2341 | LM_ERR("Appending branch failed\n"); |
michael@16 | 2342 | destroy_avp(avp); |
michael@16 | 2343 | return -1; |
michael@16 | 2344 | } |
michael@16 | 2345 | |
michael@16 | 2346 | if (avp->flags & Q_FLAG) { |
michael@16 | 2347 | destroy_avp(avp); |
michael@16 | 2348 | if (route_type == REQUEST_ROUTE) { |
michael@16 | 2349 | val.n = fr_inv_timer_next; |
michael@16 | 2350 | if (add_avp(fr_inv_timer_avp_type, fr_inv_timer_avp, val)!= 0){ |
michael@16 | 2351 | LM_ERR("Setting of fr_inv_timer_avp failed\n"); |
michael@16 | 2352 | return -1; |
michael@16 | 2353 | } |
michael@16 | 2354 | } |
michael@16 | 2355 | return 1; |
michael@16 | 2356 | } |
michael@16 | 2357 | prev = avp; |
michael@16 | 2358 | } |
michael@16 | 2359 | |
michael@16 | 2360 | /* Restore fr_inv_timer */ |
michael@16 | 2361 | val.n = fr_inv_timer; |
michael@16 | 2362 | if (add_avp(fr_inv_timer_avp_type, fr_inv_timer_avp, val) != 0) { |
michael@16 | 2363 | LM_ERR("Setting of fr_inv_timer_avp failed\n"); |
michael@16 | 2364 | return -1; |
michael@16 | 2365 | } |
michael@16 | 2366 | |
michael@16 | 2367 | return 1; |
michael@16 | 2368 | } |
michael@16 | 2369 | |
michael@16 | 2370 | |
michael@16 | 2371 | /* |
michael@16 | 2372 | * Convert string parameter to integer for functions that expect an integer. |
michael@16 | 2373 | * Taken from sl module. |
michael@16 | 2374 | */ |
michael@16 | 2375 | static int fixstringloadgws(void **param, int param_count) |
michael@16 | 2376 | { |
michael@16 | 2377 | pv_elem_t *model=NULL; |
michael@16 | 2378 | str s; |
michael@16 | 2379 | |
michael@16 | 2380 | /* convert to str */ |
michael@16 | 2381 | s.s = (char*)*param; |
michael@16 | 2382 | s.len = strlen(s.s); |
michael@16 | 2383 | |
michael@16 | 2384 | model=NULL; |
michael@16 | 2385 | if (param_count==1) { |
michael@16 | 2386 | if(s.len==0) { |
michael@16 | 2387 | LM_ERR("No param <%d>!\n", param_count); |
michael@16 | 2388 | return -1; |
michael@16 | 2389 | } |
michael@16 | 2390 | |
michael@16 | 2391 | if(pv_parse_format(&s,&model)<0 || model==NULL) { |
michael@16 | 2392 | LM_ERR("Wrong format <%s> for param <%d>!\n", s.s, param_count); |
michael@16 | 2393 | return -1; |
michael@16 | 2394 | } |
michael@16 | 2395 | if(model->spec.getf==NULL) { |
michael@16 | 2396 | if(param_count==1) { |
michael@16 | 2397 | if(str2int(&s, (unsigned int*)&model->spec.pvp.pvn.u.isname.name.n)!=0) { |
michael@16 | 2398 | LM_ERR("Wrong value <%s> for param <%d>!\n", |
michael@16 | 2399 | s.s, param_count); |
michael@16 | 2400 | return -1; |
michael@16 | 2401 | } |
michael@16 | 2402 | } |
michael@16 | 2403 | } |
michael@16 | 2404 | *param = (void*)model; |
michael@16 | 2405 | } |
michael@16 | 2406 | |
michael@16 | 2407 | return 0; |
michael@16 | 2408 | } |