Wed, 10 Feb 2010 21:25:01 +0100
Extend uac_auth() of the UAC module to workaround CSEQ problems.
This logic is meant to complement that of changeset 17, which
added rich authentication credentials to the gw table and its
associated logic in the LCR 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 | } |