lcr_mod.c

Go to the documentation of this file.
00001 /*
00002  * $Id: lcr_mod.c 5749 2009-03-20 18:09:53Z ibc_sf $
00003  *
00004  * Least Cost Routing module (also implements sequential forking)
00005  *
00006  * Copyright (C) 2005-2008 Juha Heinanen
00007  * Copyright (C) 2006 Voice Sistem SRL
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  * History:
00026  * -------
00027  *  2005-02-14: Introduced lcr module (jh)
00028  *  2005-02-20: Added sequential forking functions (jh)
00029  *  2005-02-25: Added support for int AVP names, combined addr and port
00030  *              AVPs (jh)
00031  *  2005-07-28: Added support for gw URI scheme and transport, 
00032  *              backport from ser (kd)
00033  *  2005-08-20: Added support for gw prefixes (jh)
00034  *  2005-09-03: Request-URI user part can be modified between load_gws()
00035  *              and first next_gw() calls.
00036  *  2008-10-10: Database values are now checked and from/to_gw functions
00037  *              execute in O(logN) time.
00038  *  2008-11-26: Added timer based check of gateways (shurik)
00039  */
00040 
00041 #include <stdio.h>
00042 #include <stdlib.h>
00043 #include <string.h>
00044 #include <arpa/inet.h>
00045 #include <pcre.h>
00046 #include "../../locking.h"
00047 #include "../../sr_module.h"
00048 #include "../../dprint.h"
00049 #include "../../ut.h"
00050 #include "../../error.h"
00051 #include "../../mem/mem.h"
00052 #include "../../mem/shm_mem.h"
00053 #include "../../db/db.h"
00054 #include "../../usr_avp.h"
00055 #include "../../parser/parse_uri.h"
00056 #include "../../parser/parse_from.h"
00057 #include "../../parser/msg_parser.h"
00058 #include "../../action.h"
00059 #include "../../qvalue.h"
00060 #include "../../dset.h"
00061 #include "../../ip_addr.h"
00062 #include "../../resolve.h"
00063 #include "../../mi/mi.h"
00064 #include "../../mod_fix.h"
00065 #include "../../socket_info.h"
00066 #include "../tm/tm_load.h"
00067 #include "../../pvar.h"
00068 #include "../../mod_fix.h"
00069 #include "hash.h"
00070 #include "mi.h"
00071 
00072 MODULE_VERSION
00073 
00074 /*
00075  * Version of gw and lcr tables required by the module,
00076  * increment this value if you change the table in
00077  * an backwards incompatible way
00078  */
00079 #define GW_TABLE_VERSION 9
00080 #define LCR_TABLE_VERSION 2
00081 
00082 /* usr_avp flag for sequential forking */
00083 #define Q_FLAG      (1<<2)
00084 
00085 static void destroy(void);       /* Module destroy function */
00086 static int mi_child_init(void);
00087 static int mod_init(void);       /* Module initialization function */
00088 static void free_shared_memory(void);
00089 static int fixstringloadgws(void **param, int param_count);
00090 
00091 #define GW_TABLE "gw"
00092 
00093 #define GW_NAME_COL "gw_name"
00094 
00095 #define GRP_ID_COL "grp_id"
00096 
00097 #define IP_ADDR_COL "ip_addr"
00098 
00099 #define HOSTNAME_COL "hostname"
00100 
00101 #define PORT_COL "port"
00102 
00103 #define URI_SCHEME_COL "uri_scheme"
00104 
00105 #define TRANSPORT_COL "transport"
00106 
00107 #define STRIP_COL "strip"
00108 
00109 #define TAG_COL "tag"
00110 
00111 #define WEIGHT_COL "weight"
00112 
00113 #define FLAGS_COL "flags"
00114 
00115 #define PING_COL "ping"
00116 
00117 #define LCR_TABLE "lcr"
00118 
00119 #define PREFIX_COL "prefix"
00120 
00121 #define FROM_URI_COL "from_uri"
00122 
00123 #define PRIORITY_COL "priority"
00124 
00125 #define MAX_NO_OF_GWS 128
00126 #define MAX_TAG_LEN 16
00127 #define MAX_HOST_LEN 64
00128 #define MAX_USER_LEN 64
00129 
00130 /* Default module parameter values */
00131 #define DEF_LCR_HASH_SIZE 128
00132 #define DEF_FETCH_ROWS 2000
00133 #define DEF_PING_TIMER 180
00134 #define MAX_CODES 10
00135 
00136 /*
00137  * Type definitions
00138  */
00139 
00140 /* TMB Structure */
00141 struct tm_binds tmb;
00142 
00143 typedef enum sip_protos uri_transport;
00144 
00145 struct gw_info {
00146     unsigned int ip_addr;
00147     char hostname[MAX_HOST_LEN];
00148     unsigned short hostname_len;
00149     unsigned int port;
00150     unsigned int grp_id;
00151     uri_type scheme;
00152     uri_transport transport;
00153     unsigned int strip;
00154     char tag[MAX_TAG_LEN + 1];
00155     unsigned short tag_len;
00156     unsigned short weight;
00157     unsigned int flags;
00158     unsigned short ping;
00159     unsigned int next;  /* index of next gw in the same group */
00160 };
00161 
00162 struct gw_grp {
00163     unsigned int grp_id;
00164     unsigned int first;   /* index to first gw of group in gw table */
00165 };
00166 
00167 struct matched_gw_info {
00168     unsigned short gw_index;
00169     unsigned short prefix_len;
00170     unsigned short priority;
00171     unsigned int weight;
00172 };
00173 
00174 /*
00175  * Database variables
00176  */
00177 static db_con_t* db_handle = 0;   /* Database connection handle */
00178 static db_func_t lcr_dbf;
00179 
00180 /*
00181  * Locking variables
00182  */
00183 gen_lock_t *reload_lock;
00184 
00185 /*
00186  * Module parameter variables
00187  */
00188 
00189 /* database tables */
00190 static str db_url           = str_init(DEFAULT_RODB_URL);
00191 static str gw_table         = str_init(GW_TABLE);
00192 static str gw_name_col      = str_init(GW_NAME_COL);
00193 static str grp_id_col       = str_init(GRP_ID_COL);
00194 static str ip_addr_col      = str_init(IP_ADDR_COL);
00195 static str hostname_col     = str_init(HOSTNAME_COL);
00196 static str port_col         = str_init(PORT_COL);
00197 static str uri_scheme_col   = str_init(URI_SCHEME_COL);
00198 static str transport_col    = str_init(TRANSPORT_COL);
00199 static str strip_col        = str_init(STRIP_COL);
00200 static str tag_col          = str_init(TAG_COL);
00201 static str weight_col       = str_init(WEIGHT_COL);
00202 static str flags_col        = str_init(FLAGS_COL);
00203 static str ping_col         = str_init(PING_COL);
00204 static str lcr_table        = str_init(LCR_TABLE);
00205 static str prefix_col       = str_init(PREFIX_COL);
00206 static str from_uri_col     = str_init(FROM_URI_COL);
00207 static str priority_col     = str_init(PRIORITY_COL);
00208 
00209 /* number of rows to fetch at a shot */
00210 static int fetch_rows_param = DEF_FETCH_ROWS;
00211 
00212 /* OPTIONS timer */
00213 static void timer(unsigned int ticks, void* param);  /* Timer handler */
00214 int ping_interval = 0;  /* Timer interval in seconds */
00215 
00216 /* OPTIONS From URI */
00217 static str ping_from   = {"sip:127.0.0.1", 20};
00218 static str ping_method = {"OPTIONS", 7};
00219 
00220 /* codes */
00221 int positive_codes[MAX_CODES];
00222 int negative_codes[MAX_CODES];
00223 
00224 static str positive_codes_str   = {"200;501;403;404", 15};
00225 static str negative_codes_str   = {"408", 3};
00226 
00227 /* avps */
00228 static char *gw_uri_avp_param = NULL;
00229 static char *ruri_user_avp_param = NULL;
00230 static char *rpid_avp_param = NULL;
00231 static char *flags_avp_param = NULL;
00232 
00233 /* size of prefix hash table */
00234 unsigned int lcr_hash_size_param = DEF_LCR_HASH_SIZE;
00235 
00236 /*
00237  * Other module types and variables
00238  */
00239 
00240 static int     gw_uri_avp_type;
00241 static int_str gw_uri_avp;
00242 static int     ruri_user_avp_type;
00243 static int_str ruri_user_avp;
00244 static int     rpid_avp_type;
00245 static int_str rpid_avp;
00246 static int     flags_avp_type;
00247 static int_str flags_avp;
00248 
00249 struct gw_info **gws;   /* Pointer to current gw table pointer */
00250 struct gw_info *gws_1;  /* Pointer to gw table 1 */
00251 struct gw_info *gws_2;  /* Pointer to gw table 2 */
00252 
00253 struct lcr_info ***lcrs;  /* Pointer to current lcr hash table pointer */
00254 struct lcr_info **lcrs_1; /* Pointer to lcr hash table 1 */
00255 struct lcr_info **lcrs_2; /* Pointer to lcr hash table 2 */
00256 
00257 
00258 /*
00259  * Functions that are defined later
00260  */
00261 static int load_gws_0(struct sip_msg* _m, char* _s1, char* _s2);
00262 static int load_gws_1(struct sip_msg* _m, char* _s1, char* _s2);
00263 static int load_gws_from_grp(struct sip_msg* _m, char* _s1, char* _s2);
00264 static int next_gw(struct sip_msg* _m, char* _s1, char* _s2);
00265 static int from_gw_0(struct sip_msg* _m, char* _s1, char* _s2);
00266 static int from_gw_1(struct sip_msg* _m, char* _s1, char* _s2);
00267 static int from_gw_grp(struct sip_msg* _m, char* _s1, char* _s2);
00268 static int to_gw_0(struct sip_msg* _m, char* _s1, char* _s2);
00269 static int to_gw_1(struct sip_msg* _m, char* _s1, char* _s2);
00270 static int to_gw_grp(struct sip_msg* _m, char* _s1, char* _s2);
00271 static int add_code_to_array(str *codes, int local_codes[]);
00272 
00273 /*
00274  * Exported functions
00275  */
00276 static cmd_export_t cmds[] = {
00277     {"load_gws", (cmd_function)load_gws_0, 0, 0, 0, REQUEST_ROUTE |
00278      FAILURE_ROUTE},
00279     {"load_gws", (cmd_function)load_gws_1, 1, fixup_pvar_null,
00280      fixup_free_pvar_null, REQUEST_ROUTE | FAILURE_ROUTE},
00281     {"load_gws_from_grp", (cmd_function)load_gws_from_grp, 1,
00282      fixstringloadgws, fixup_free_pvar_null, REQUEST_ROUTE | FAILURE_ROUTE},
00283     {"next_gw", (cmd_function)next_gw, 0, 0, 0,
00284      REQUEST_ROUTE | FAILURE_ROUTE},
00285     {"from_gw", (cmd_function)from_gw_0, 0, 0, 0,
00286      REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
00287     {"from_gw", (cmd_function)from_gw_1, 1, fixup_pvar_null,
00288      fixup_free_pvar_null, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
00289     {"from_gw_grp", (cmd_function)from_gw_grp, 1, fixup_uint_null, 0,
00290      REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
00291     {"to_gw", (cmd_function)to_gw_0, 0, 0, 0,
00292      REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
00293     {"to_gw", (cmd_function)to_gw_1, 1, fixup_pvar_null,
00294      fixup_free_pvar_null, REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
00295     {"to_gw_grp", (cmd_function)to_gw_grp, 1, fixup_uint_null, 0,
00296      REQUEST_ROUTE | FAILURE_ROUTE | ONREPLY_ROUTE},
00297     {0, 0, 0, 0, 0, 0}
00298 };
00299 
00300 
00301 /*
00302  * Exported parameters
00303  */
00304 static param_export_t params[] = {
00305     {"db_url",                   STR_PARAM, &db_url.s       },
00306     {"gw_table",                 STR_PARAM, &gw_table.s     },
00307     {"gw_name_column",           STR_PARAM, &gw_name_col.s  },
00308     {"grp_id_column",            STR_PARAM, &grp_id_col.s   },
00309     {"ip_addr_column",           STR_PARAM, &ip_addr_col.s  },
00310     {"hostname_column",          STR_PARAM, &hostname_col.s },
00311     {"port_column",              STR_PARAM, &port_col.s     },
00312     {"uri_scheme_column",        STR_PARAM, &uri_scheme_col.s },
00313     {"transport_column",         STR_PARAM, &transport_col.s },
00314     {"strip_column",             STR_PARAM, &strip_col.s    },
00315     {"tag_column",               STR_PARAM, &tag_col.s      },
00316     {"weight_column",            STR_PARAM, &weight_col.s   },
00317     {"flags_column",             STR_PARAM, &flags_col.s    },
00318     {"lcr_table",                STR_PARAM, &lcr_table.s    },
00319     {"prefix_column",            STR_PARAM, &prefix_col.s   },
00320     {"from_uri_column",          STR_PARAM, &from_uri_col.s },
00321     {"priority_column",          STR_PARAM, &priority_col.s },
00322     {"ping_column",              STR_PARAM, &ping_col.s     },
00323     {"gw_uri_avp",               STR_PARAM, &gw_uri_avp_param },
00324     {"ruri_user_avp",            STR_PARAM, &ruri_user_avp_param },
00325     {"rpid_avp",                 STR_PARAM, &rpid_avp_param },
00326     {"flags_avp",                STR_PARAM, &flags_avp_param },
00327     {"lcr_hash_size",            INT_PARAM, &lcr_hash_size_param },
00328     {"fetch_rows",               INT_PARAM, &fetch_rows_param },
00329     {"ping_interval",       INT_PARAM, &ping_interval },
00330     {"ping_from",                STR_PARAM, &ping_from.s    },
00331     {"ping_method",              STR_PARAM, &ping_method.s  },
00332     {"positive_codes",           STR_PARAM, &positive_codes_str.s },
00333     {"negative_codes",           STR_PARAM, &negative_codes_str.s },
00334     {0, 0, 0}
00335 };
00336 
00337 
00338 /*
00339  * Exported MI functions
00340  */
00341 static mi_export_t mi_cmds[] = {
00342     { MI_LCR_RELOAD, mi_lcr_reload, MI_NO_INPUT_FLAG, 0, mi_child_init },
00343     { MI_LCR_GW_DUMP, mi_lcr_gw_dump, MI_NO_INPUT_FLAG, 0, 0 },
00344     { MI_LCR_LCR_DUMP, mi_lcr_lcr_dump, MI_NO_INPUT_FLAG, 0, 0 },
00345     { 0, 0, 0, 0 ,0}
00346 };
00347 
00348 
00349 /*
00350  * Module interface
00351  */
00352 struct module_exports exports = {
00353    "lcr", 
00354    DEFAULT_DLFLAGS, /* dlopen flags */
00355    cmds,      /* Exported functions */
00356    params,    /* Exported parameters */
00357    0,         /* exported statistics */
00358    mi_cmds,   /* exported MI functions */
00359    0,         /* exported pseudo-variables */
00360    0,         /* extra processes */
00361    mod_init,  /* module initialization function */
00362    0,         /* response function */
00363    destroy,   /* destroy function */
00364    0          /* child initialization function */
00365 };
00366 
00367 
00368 static int lcr_db_init(const str* db_url)
00369 {  
00370    if (lcr_dbf.init==0){
00371       LM_CRIT("null lcr_dbf\n");
00372       goto error;
00373    }
00374    db_handle=lcr_dbf.init(db_url);
00375    if (db_handle==0){
00376       LM_ERR("unable to connect to the database\n");
00377       goto error;
00378    }
00379    return 0;
00380 error:
00381    return -1;
00382 }
00383 
00384 
00385 
00386 static int lcr_db_bind(const str* db_url)
00387 {
00388     if (db_bind_mod(db_url, &lcr_dbf)<0){
00389    LM_ERR("unable to bind to the database module\n");
00390    return -1;
00391     }
00392 
00393     if (!DB_CAPABILITY(lcr_dbf, DB_CAP_QUERY)) {
00394    LM_ERR("database module does not implement 'query' function\n");
00395    return -1;
00396     }
00397 
00398     return 0;
00399 }
00400 
00401 
00402 static void lcr_db_close(void)
00403 {
00404    if (db_handle && lcr_dbf.close){
00405       lcr_dbf.close(db_handle);
00406       db_handle=0;
00407    }
00408 }
00409 
00410 
00411 static int mi_child_init(void)
00412 {
00413    return lcr_db_init(&db_url);
00414 }
00415 
00416 
00417 /*
00418  * Module initialization function that is called before the main process forks
00419  */
00420 static int mod_init(void)
00421 {
00422     pv_spec_t avp_spec;
00423     str s;
00424     unsigned short avp_flags;
00425 
00426     /* Update length of module variables */
00427     db_url.len = strlen(db_url.s);
00428     gw_table.len = strlen(gw_table.s);
00429     gw_name_col.len = strlen(gw_name_col.s);
00430     grp_id_col.len = strlen(grp_id_col.s);
00431     ip_addr_col.len = strlen(ip_addr_col.s);
00432     hostname_col.len = strlen(hostname_col.s);
00433     port_col.len = strlen(port_col.s);
00434     uri_scheme_col.len = strlen(uri_scheme_col.s);
00435     transport_col.len = strlen(transport_col.s);
00436     strip_col.len = strlen(strip_col.s);
00437     tag_col.len = strlen(tag_col.s);
00438     weight_col.len = strlen(weight_col.s);
00439     flags_col.len = strlen(flags_col.s);
00440     lcr_table.len = strlen(lcr_table.s);
00441     prefix_col.len = strlen(prefix_col.s);
00442     from_uri_col.len = strlen(from_uri_col.s);
00443     priority_col.len = strlen(priority_col.s);
00444     ping_col.len = strlen(ping_col.s);
00445     ping_from.len = strlen(ping_from.s);
00446     ping_method.len = strlen(ping_method.s);
00447     positive_codes_str.len = strlen(positive_codes_str.s);
00448     negative_codes_str.len = strlen(negative_codes_str.s);
00449 
00450     /* Bind database */
00451     if (lcr_db_bind(&db_url)) {
00452    LM_ERR("no database module found\n");
00453    return -1;
00454     }
00455 
00456     /* Check value of prefix_hash_size */
00457     if (lcr_hash_size_param <= 0) {
00458    LM_ERR("invalid prefix_hash_size value <%d>\n", lcr_hash_size_param);
00459    return -1;
00460     }
00461 
00462     /* Load the TM API */
00463     if (load_tm_api(&tmb) != 0) {
00464         LM_ERR("failed to load TM API\n");
00465         return -1;
00466     }
00467 
00468     /* Register OPTIONS timer. Timer should be minimum 180 seconds. */
00469     if (ping_interval) {
00470    if (ping_interval < DEF_PING_TIMER) { 
00471        ping_interval = DEF_PING_TIMER;              
00472        LM_DBG("set OPTIONS timer to default value <%d>\n", DEF_PING_TIMER);
00473    }
00474    register_timer(timer, 0, ping_interval);
00475    LM_DBG("started OPTIONS timer. Interval value <%d>\n", ping_interval);
00476     }
00477     
00478     /* Parse Codes */ 
00479     if (add_code_to_array(&positive_codes_str, positive_codes) != 0) {
00480    LM_ERR("couldn't parse positive codes\n");
00481    return -1;
00482     }
00483 
00484     if (add_code_to_array(&negative_codes_str, negative_codes) != 0) {
00485    LM_ERR("couldn't parse negative codes\n");
00486    return -1;
00487     }
00488 
00489     /* Process AVP params */
00490 
00491     if (gw_uri_avp_param && *gw_uri_avp_param) {
00492    s.s = gw_uri_avp_param; s.len = strlen(s.s);
00493    if (pv_parse_spec(&s, &avp_spec)==0
00494        || avp_spec.type!=PVT_AVP) {
00495        LM_ERR("malformed or non AVP definition <%s>\n", gw_uri_avp_param);
00496        return -1;
00497    }
00498    
00499    if (pv_get_avp_name(0, &(avp_spec.pvp), &gw_uri_avp, &avp_flags) != 0) {
00500        LM_ERR("invalid AVP definition <%s>\n", gw_uri_avp_param);
00501        return -1;
00502    }
00503    gw_uri_avp_type = avp_flags;
00504     } else {
00505    LM_ERR("AVP gw_uri_avp has not been defined\n");
00506    return -1;
00507     }
00508 
00509     if (ruri_user_avp_param && *ruri_user_avp_param) {
00510    s.s = ruri_user_avp_param; s.len = strlen(s.s);
00511    if (pv_parse_spec(&s, &avp_spec)==0
00512        || avp_spec.type!=PVT_AVP) {
00513        LM_ERR("malformed or non AVP definition <%s>\n",
00514          ruri_user_avp_param);
00515        return -1;
00516    }
00517    
00518    if (pv_get_avp_name(0, &(avp_spec.pvp), &ruri_user_avp, &avp_flags)
00519        != 0) {
00520        LM_ERR("invalid AVP definition <%s>\n", ruri_user_avp_param);
00521        return -1;
00522    }
00523    ruri_user_avp_type = avp_flags;
00524     } else {
00525    LM_ERR("AVP ruri_user_avp has not been defined\n");
00526    return -1;
00527     }
00528 
00529     if (rpid_avp_param && *rpid_avp_param) {
00530    s.s = rpid_avp_param; s.len = strlen(s.s);
00531    if (pv_parse_spec(&s, &avp_spec)==0
00532        || avp_spec.type!=PVT_AVP) {
00533        LM_ERR("malformed or non AVP definition <%s>\n", rpid_avp_param);
00534        return -1;
00535    }
00536    
00537    if (pv_get_avp_name(0, &(avp_spec.pvp), &rpid_avp, &avp_flags) != 0) {
00538        LM_ERR("invalid AVP definition <%s>\n", rpid_avp_param);
00539        return -1;
00540    }
00541    rpid_avp_type = avp_flags;
00542     } else {
00543    LM_ERR("AVP rpid_avp has not been defined\n");
00544    return -1;
00545     }
00546 
00547     if (flags_avp_param && *flags_avp_param) {
00548    s.s = flags_avp_param; s.len = strlen(s.s);
00549    if (pv_parse_spec(&s, &avp_spec)==0
00550        || avp_spec.type!=PVT_AVP) {
00551        LM_ERR("malformed or non AVP definition <%s>\n", flags_avp_param);
00552        return -1;
00553    }
00554    
00555    if (pv_get_avp_name(0, &(avp_spec.pvp), &flags_avp, &avp_flags) != 0) {
00556        LM_ERR("invalid AVP definition <%s>\n", flags_avp_param);
00557        return -1;
00558    }
00559    flags_avp_type = avp_flags;
00560     } else {
00561    LM_ERR("AVP flags_avp has not been defined\n");
00562    return -1;
00563     }
00564 
00565     if (fetch_rows_param < 1) {
00566    LM_ERR("invalid fetch_rows module parameter value <%d>\n",
00567           fetch_rows_param);
00568    return -1;
00569     }
00570 
00571     /* Check table version */
00572     db_con_t* dbh;
00573     if (lcr_dbf.init==0){
00574    LM_CRIT("unbound database\n");
00575    return -1;
00576     }
00577     dbh=lcr_dbf.init(&db_url);
00578     if (dbh==0){
00579    LM_ERR("unable to open database connection\n");
00580    return -1;
00581     }
00582     if ((db_check_table_version(&lcr_dbf, dbh, &gw_table, GW_TABLE_VERSION)
00583     < 0) ||
00584    (db_check_table_version(&lcr_dbf, dbh, &lcr_table, LCR_TABLE_VERSION)
00585     < 0)) { 
00586    LM_ERR("error during table version check\n");
00587    lcr_dbf.close(dbh);
00588    goto err;
00589     }
00590     lcr_dbf.close(dbh);
00591 
00592     /* Reset all shm pointers */
00593     gws_1 = gws_2 = (struct gw_info *)NULL;
00594     gws = (struct gw_info **)NULL;
00595     lcrs_1 = lcrs_2 = (struct lcr_info **)NULL;
00596     lcrs = (struct lcr_info ***)NULL;
00597     reload_lock = (gen_lock_t *)NULL;
00598 
00599     /* Initializing gw tables and gw table pointer variable */
00600     /* ip_addr of first entry contains the number of gws in table */
00601     gws_1 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) *
00602                 (MAX_NO_OF_GWS + 1));
00603     if (gws_1 == 0) {
00604    LM_ERR("no memory for gw table\n");
00605    goto err;
00606     }
00607     gws_2 = (struct gw_info *)shm_malloc(sizeof(struct gw_info) *
00608                 (MAX_NO_OF_GWS + 1));
00609     if (gws_2 == 0) {
00610    LM_ERR("no memory for gw table\n");
00611    goto err;
00612     }
00613     gws = (struct gw_info **)shm_malloc(sizeof(struct gw_info *));
00614     if (gws == 0) {
00615    LM_ERR("no memory for gw table pointer\n");
00616     }
00617     gws_1[0].ip_addr = 0;    /* Number of gateways in table */
00618     *gws = gws_1;
00619 
00620     /* Initializing lcr hash tables and hash table pointer variable */
00621     /* Last entry in hash table contains list of different prefix lengths */
00622     lcrs_1 = (struct lcr_info **)
00623    shm_malloc(sizeof(struct lcr_info *) * (lcr_hash_size_param + 1));
00624     if (lcrs_1 == 0) {
00625    LM_ERR("no memory for lcr hash table\n");
00626    goto err;
00627     }
00628     memset(lcrs_1, 0, sizeof(struct lcr_info *) * (lcr_hash_size_param + 1));
00629     lcrs_2 = (struct lcr_info **)
00630    shm_malloc(sizeof(struct lcr_info *) * (lcr_hash_size_param + 1));
00631     if (lcrs_1 == 0) {
00632    LM_ERR("no memory for lcr hash table\n");
00633    goto err;
00634     }
00635     memset(lcrs_2, 0, sizeof(struct lcr_info *) * (lcr_hash_size_param + 1));
00636     lcrs = (struct lcr_info ***)shm_malloc(sizeof(struct lcr_info *));
00637     if (lcrs == 0) {
00638    LM_ERR("no memory for lcr hash table pointer\n");
00639    goto err;
00640     }
00641     *lcrs = lcrs_1;
00642 
00643     /* Allocate and initialize locks */
00644     reload_lock = lock_alloc();
00645     if (reload_lock == NULL) {
00646    LM_ERR("cannot allocate reload_lock\n");
00647    goto err;
00648     }
00649     if (lock_init(reload_lock) == NULL) {
00650    LM_ERR("cannot init reload_lock\n");
00651    goto err;
00652     }
00653 
00654     /* First reload */
00655     lock_get(reload_lock);
00656     if (reload_gws_and_lcrs() == -1) {
00657    lock_release(reload_lock);
00658    LM_CRIT("failed to reload gateways and routes\n");
00659    goto err;
00660     }
00661     lock_release(reload_lock);
00662 
00663     return 0;
00664 
00665 err:
00666     free_shared_memory();
00667     return -1;
00668 }
00669 
00670 
00671 static void destroy(void)
00672 {
00673     lcr_db_close();
00674 
00675     free_shared_memory();
00676 }
00677 
00678 /* Free shared memory */
00679 static void free_shared_memory(void)
00680 {
00681     if (gws_1) {
00682         shm_free(gws_1);
00683     }
00684     if (gws_2) {
00685         shm_free(gws_2);
00686     }
00687     if (gws) {
00688         shm_free(gws);
00689     }
00690     if (lcrs_1) {
00691         lcr_hash_table_contents_free(lcrs_1);
00692         shm_free(lcrs_1);
00693     }
00694     if (lcrs_2) {
00695         lcr_hash_table_contents_free(lcrs_2);
00696         shm_free(lcrs_2);
00697     }
00698     if (lcrs) {
00699         shm_free(lcrs);
00700     }
00701     if (reload_lock) {
00702    lock_destroy(reload_lock);
00703    lock_dealloc(reload_lock);
00704     }
00705 }
00706    
00707 
00708 /* 
00709  * Convert string parameter to integer for functions that expect an integer.
00710  * Taken from sl module.
00711  */
00712 static int fixstringloadgws(void **param, int param_count)
00713 {
00714     pv_elem_t *model=NULL;
00715     str s;
00716 
00717     /* convert to str */
00718     s.s = (char*)*param;
00719     s.len = strlen(s.s);
00720 
00721     model=NULL;
00722     if (param_count==1) {
00723    if(s.len==0) {
00724        LM_ERR("no param <%d>!\n", param_count);
00725        return -1;
00726    }
00727    
00728    if(pv_parse_format(&s,&model)<0 || model==NULL) {
00729        LM_ERR("wrong format <%s> for param <%d>!\n", s.s, param_count);
00730        return -1;
00731    }
00732    if(model->spec.getf==NULL) {
00733        if(param_count==1) {
00734       if(str2int(&s, (unsigned int*)&model->spec.pvp.pvn.u.isname.name.n)!=0) {
00735           LM_ERR("wrong value <%s> for param <%d>!\n",
00736             s.s, param_count);
00737           return -1;
00738       }
00739        }
00740    }
00741    *param = (void*)model;
00742     }
00743 
00744     return 0;
00745 }
00746 
00747 
00748 /*
00749  * Compare matched gateways based on prefix_len, priority, and randomized
00750  * weight.
00751  */
00752 static int comp_matched(const void *m1, const void *m2)
00753 {
00754     struct matched_gw_info *mi1 = (struct matched_gw_info *) m1;
00755     struct matched_gw_info *mi2 = (struct matched_gw_info *) m2;
00756 
00757     /* Sort by prefix_len */
00758     if (mi1->prefix_len > mi2->prefix_len) return 1;
00759     if (mi1->prefix_len == mi2->prefix_len) {
00760    /* Sort by priority */
00761    if (mi1->priority < mi2->priority) return 1;
00762    if (mi1->priority == mi2->priority) {
00763        /* Sort by randomized weigth */
00764        if (mi1->weight > mi2->weight) return 1;
00765        if (mi1->weight == mi2->weight) return 0;
00766        return -1;
00767    }
00768    return -1;
00769     }
00770     return -1;
00771 }
00772 
00773 
00774 /* Compile pattern into shared memory and return pointer to it. */
00775 static pcre *reg_ex_comp(const char *pattern)
00776 {
00777     pcre *re, *result;
00778     const char *error;
00779     int rc, size, err_offset;
00780 
00781     re = pcre_compile(pattern, 0, &error, &err_offset, NULL);
00782     if (re == NULL) {
00783    LM_ERR("pcre compilation of '%s' failed at offset %d: %s\n",
00784           pattern, err_offset, error);
00785    return (pcre *)0;
00786     }
00787     rc = pcre_fullinfo(re, NULL, PCRE_INFO_SIZE, &size);
00788     if (rc != 0) {
00789    LM_ERR("pcre_fullinfo on compiled pattern '%s' yielded error: %d\n",
00790           pattern, rc);
00791    return (pcre *)0;
00792     }
00793     result = (pcre *)shm_malloc(size);
00794     if (result == NULL) {
00795    pcre_free(re);
00796    LM_ERR("not enough shared memory for compiled PCRE pattern\n");
00797    return (pcre *)0;
00798     }
00799     memcpy(result, re, size);
00800     pcre_free(re);
00801     return result;
00802 }
00803 
00804 
00805 /*
00806  * Compare gateways based on their IP address and group id
00807  */
00808 static int comp_gw_grps(const void *_g1, const void *_g2)
00809 {
00810     struct gw_info *g1 = (struct gw_info *)_g1;
00811     struct gw_info *g2 = (struct gw_info *)_g2;
00812 
00813     if (g1->ip_addr < g2->ip_addr) return -1;
00814     if (g1->ip_addr > g2->ip_addr) return 1;
00815 
00816     if (g1->grp_id < g2->grp_id) return -1;
00817     if (g1->grp_id > g2->grp_id) return 1;
00818 
00819     return 0;
00820 }
00821 
00822 
00823 /*
00824  * Compare gateways based on their IP address
00825  */
00826 static int comp_gws(const void *_g1, const void *_g2)
00827 {
00828     struct gw_info *g1 = (struct gw_info *)_g1;
00829     struct gw_info *g2 = (struct gw_info *)_g2;
00830 
00831     if (g1->ip_addr < g2->ip_addr) return -1;
00832     if (g1->ip_addr > g2->ip_addr) return 1;
00833 
00834     return 0;
00835 }
00836 
00837 
00838 /*
00839  * Check if ip_addr/grp_id of gateway is unique.
00840  */
00841 static int gw_unique(const struct gw_info *gws, const unsigned int count,
00842            const unsigned int ip_addr, const unsigned int grp_id)
00843 {
00844     unsigned int i;
00845 
00846     for (i = 1; i <= count; i++) {
00847    if ((gws[i].ip_addr == ip_addr) &&
00848        (gws[i].grp_id == grp_id))
00849        return 0;
00850     }
00851 
00852     return 1;
00853 }
00854 
00855 static int insert_gw(struct gw_info *gws, unsigned int i, unsigned int ip_addr,
00856            char *hostname, unsigned int hostname_len,
00857            unsigned int grp_id, char *ip_string, unsigned int port,
00858            unsigned int scheme, unsigned int transport,
00859            unsigned int flags, unsigned int strip, char *tag,
00860            unsigned int tag_len, unsigned short weight,
00861            unsigned short ping)
00862 {
00863     if (gw_unique(gws, i - 1, ip_addr, grp_id) == 0) {
00864    LM_ERR("ip_addr/grp_id <%s/%u> of gw is not unique\n",
00865           ip_string, grp_id);
00866    return 0;
00867     }
00868     gws[i].ip_addr = ip_addr;
00869     if (hostname_len) memcpy(&(gws[i].hostname[0]), hostname, hostname_len);
00870     gws[i].hostname_len = hostname_len;
00871     gws[i].ip_addr = ip_addr;
00872     gws[i].port = port;
00873     gws[i].grp_id = grp_id;
00874     gws[i].scheme = scheme;
00875     gws[i].transport = transport;
00876     gws[i].flags = flags;
00877     gws[i].strip = strip;
00878     gws[i].tag_len = tag_len;
00879     if (tag_len) memcpy(&(gws[i].tag[0]), tag, tag_len);
00880     gws[i].weight = weight;
00881     gws[i].ping = ping;
00882     gws[i].next = 0;
00883 
00884     return 1;
00885 }
00886 
00887 /*
00888  * Links gws that belong to same group via next field, sets gw_grps
00889  * array with first indexes of each group, and sets grp_cnt to number of
00890  * different gw groups.
00891  */
00892 static void link_gw_grps(struct gw_info *gws, struct gw_grp *gw_grps,
00893           unsigned int *grp_cnt)
00894 {
00895     unsigned int i, j;
00896 
00897     *grp_cnt = 0;
00898     
00899     for (i = 1; i <= gws[0].ip_addr; i++) {
00900    for (j = 1; j < i; j++) {
00901        if (gws[j].grp_id == gws[i].grp_id) {
00902       gws[i].next = gws[j].next;
00903       gws[j].next = i;
00904       goto found;
00905        }
00906    }
00907    gw_grps[*grp_cnt].grp_id = gws[i].grp_id;
00908    gw_grps[*grp_cnt].first = i;
00909    *grp_cnt = *grp_cnt + 1;
00910     found:
00911    continue;
00912     }
00913 }
00914 
00915 /*
00916  * Return gw table index of first gw in given group or 0 if no gws in
00917  * the group.
00918  */
00919 static int find_first_gw(struct gw_grp *gw_grps, unsigned int grp_cnt,
00920           unsigned int grp_id)
00921 {
00922     unsigned int i;
00923     
00924     for (i = 0; i < grp_cnt; i++) {
00925    if (gw_grps[i].grp_id == grp_id) {
00926        return gw_grps[i].first;
00927    }
00928     }
00929 
00930     return 0;
00931 }
00932 
00933 /*
00934  * Insert prefix_len into list pointed by last lcr hash table entry 
00935  * if not there already. Keep list in decending prefix_len order.
00936  */
00937 static int prefix_len_insert(struct lcr_info **table, unsigned short prefix_len)
00938 {
00939     struct lcr_info *lcr_rec, **previous, *this;
00940     
00941     previous = &(table[lcr_hash_size_param]);
00942     this = table[lcr_hash_size_param];
00943 
00944     while (this) {
00945    if (this->prefix_len == prefix_len)
00946        return 1;
00947    if (this->prefix_len < prefix_len) {
00948        lcr_rec = shm_malloc(sizeof(struct lcr_info));
00949        if (lcr_rec == NULL) {
00950       LM_ERR("no shared memory for lcr_info\n");
00951       return 0;
00952        }
00953        memset(lcr_rec, 0, sizeof(struct lcr_info));
00954        lcr_rec->prefix_len = prefix_len;
00955        lcr_rec->next = this;
00956        *previous = lcr_rec;
00957        return 1;
00958    }
00959    previous = &(this->next);
00960    this = this->next;
00961     }
00962 
00963     lcr_rec = shm_malloc(sizeof(struct lcr_info));
00964     if (lcr_rec == NULL) {
00965    LM_ERR("no shared memory for lcr_info\n");
00966    return 0;
00967     }
00968     memset(lcr_rec, 0, sizeof(struct lcr_info));
00969     lcr_rec->prefix_len = prefix_len;
00970     lcr_rec->next = NULL;
00971     *previous = lcr_rec;
00972     return 1;
00973 }
00974 
00975 
00976 /*
00977  * Reload gws to unused gw table, lcrs to unused lcr hash table, and
00978  * prefix lens to a new prefix_len list.  When done, make these tables
00979  * and list the current ones.
00980  */
00981 int reload_gws_and_lcrs(void)
00982 {
00983     unsigned int i, n, port, strip, tag_len, prefix_len, from_uri_len,
00984    grp_id,  grp_cnt, priority, flags, first_gw, weight, gw_cnt,
00985    hostname_len, ping;
00986     struct in_addr ip_addr;
00987     uri_type scheme;
00988     uri_transport transport;
00989     db_con_t* dbh;
00990     char *ip_string, *hostname, *tag, *prefix, *from_uri;
00991     db_res_t* res = NULL;
00992     db_row_t* row;
00993     db_key_t gw_cols[11];
00994     db_key_t lcr_cols[4];
00995     pcre *from_uri_re;
00996     struct gw_grp gw_grps[MAX_NO_OF_GWS];
00997 
00998     gw_cols[0] = &ip_addr_col;
00999     gw_cols[1] = &port_col;
01000     gw_cols[2] = &uri_scheme_col;
01001     gw_cols[3] = &transport_col;
01002     gw_cols[4] = &strip_col;
01003     gw_cols[5] = &tag_col;
01004     gw_cols[6] = &grp_id_col;
01005     gw_cols[7] = &flags_col;
01006     gw_cols[8] = &weight_col;
01007     gw_cols[9] = &hostname_col;
01008     gw_cols[10] = &ping_col;
01009 
01010     lcr_cols[0] = &prefix_col;
01011     lcr_cols[1] = &from_uri_col;
01012     lcr_cols[2] = &grp_id_col;
01013     lcr_cols[3] = &priority_col;
01014 
01015     /* Reload gws */
01016 
01017     if (lcr_dbf.init == 0) {
01018    LM_CRIT("unbound database\n");
01019    return -1;
01020     }
01021     dbh = lcr_dbf.init(&db_url);
01022     if (dbh == 0) {
01023    LM_ERR("unable to open database connection\n");
01024    return -1;
01025     }
01026 
01027     if (lcr_dbf.use_table(dbh, &gw_table) < 0) {
01028    LM_ERR("error while trying to use gw table\n");
01029    return -1;
01030     }
01031 
01032     if (lcr_dbf.query(dbh, NULL, 0, NULL, gw_cols, 0, 11, 0, &res) < 0) {
01033    LM_ERR("failed to query gw data\n");
01034    lcr_dbf.close(dbh);
01035    return -1;
01036     }
01037 
01038     if (RES_ROW_N(res) + 1 > MAX_NO_OF_GWS) {
01039    LM_ERR("too many gateways\n");
01040    goto gw_err;
01041     }
01042 
01043     for (i = 0; i < RES_ROW_N(res); i++) {
01044    row = RES_ROWS(res) + i;
01045    if (VAL_NULL(ROW_VALUES(row)) ||
01046        (VAL_TYPE(ROW_VALUES(row)) != DB_STRING)) {
01047        LM_ERR("gw ip address at row <%u> is null or not string\n", i);
01048        goto gw_err;
01049    }
01050    ip_string = (char *)VAL_STRING(ROW_VALUES(row));
01051    if (inet_aton(ip_string, &ip_addr) == 0) {
01052        LM_ERR("gateway ip address <%s> at row <%u> is invalid\n",
01053          ip_string, i);
01054        goto gw_err;
01055    }
01056    if (VAL_NULL(ROW_VALUES(row) + 1) == 1) {
01057        port = 0;
01058    } else {
01059        if (VAL_TYPE(ROW_VALUES(row) + 1) != DB_INT) {
01060       LM_ERR("port of gw <%s> at row <%u> is not int\n",
01061              ip_string, i);
01062       goto gw_err;
01063        }
01064        port = (unsigned int)VAL_INT(ROW_VALUES(row) + 1);
01065    }
01066    if (port > 65536) {
01067        LM_ERR("port <%d> of gw <%s> at row <%u> is too large\n",
01068          port, ip_string, i);
01069        goto gw_err;
01070    }
01071    if (VAL_NULL(ROW_VALUES(row) + 2) == 1) {
01072        scheme = SIP_URI_T;
01073    } else {
01074        if (VAL_TYPE(ROW_VALUES(row) + 2) != DB_INT) {
01075       LM_ERR("uri scheme of gw <%s> at row <%u> is not int\n",
01076              ip_string, i);
01077       goto gw_err;
01078        }
01079        scheme = (uri_type)VAL_INT(ROW_VALUES(row) + 2);
01080    }
01081    if ((scheme != SIP_URI_T) && (scheme != SIPS_URI_T)) {
01082        LM_ERR("unknown or unsupported URI scheme <%u> of gw <%s> at "
01083          "row <%u>\n", (unsigned int)scheme, ip_string, i);
01084        goto gw_err;
01085    }
01086    if (VAL_NULL(ROW_VALUES(row) + 3) == 1) {
01087        transport = PROTO_NONE;
01088    } else {
01089        if (VAL_TYPE(ROW_VALUES(row) + 3) != DB_INT) {
01090       LM_ERR("transport of gw <%s> at row <%u> is not int\n",
01091              ip_string, i);
01092       goto gw_err;
01093        }
01094        transport = (uri_transport)VAL_INT(ROW_VALUES(row) + 3);   
01095    }
01096    if ((transport != PROTO_UDP) && (transport != PROTO_TCP) &&
01097        (transport != PROTO_TLS) && (transport != PROTO_SCTP) &&
01098        (transport != PROTO_NONE)) {
01099        LM_ERR("unknown or unsupported transport <%u> of gw <%s> at "
01100          " row <%u>\n", (unsigned int)transport, ip_string, i);
01101        goto gw_err;
01102    }
01103    if ((scheme == SIPS_URI_T) && (transport == PROTO_UDP)) {
01104        LM_ERR("wrong transport <%u> for SIPS URI scheme of gw <%s> at "
01105          "row <%u>\n", transport, ip_string, i); 
01106        goto gw_err;
01107    }
01108    if (VAL_NULL(ROW_VALUES(row) + 4) == 1) {
01109        strip = 0;
01110    } else {
01111        if (VAL_TYPE(ROW_VALUES(row) + 4) != DB_INT) {
01112       LM_ERR("strip count of gw <%s> at row <%u> is not int\n",
01113              ip_string, i);
01114       goto gw_err;
01115        }
01116        strip = (unsigned int)VAL_INT(ROW_VALUES(row) + 4);
01117    }
01118    if (strip > MAX_USER_LEN) {
01119        LM_ERR("strip count <%u> of gw <%s> at row <%u> it too large\n",
01120          strip, ip_string, i);
01121        goto gw_err;
01122    }
01123    if (VAL_NULL(ROW_VALUES(row) + 5) == 1) {
01124        tag_len = 0;
01125        tag = (char *)0;
01126    } else {
01127        if (VAL_TYPE(ROW_VALUES(row) + 5) != DB_STRING) {
01128       LM_ERR("tag of gw <%s> at row <%u> is not string\n",
01129              ip_string, i);
01130       goto gw_err;
01131        }
01132        tag = (char *)VAL_STRING(ROW_VALUES(row) + 5);
01133        tag_len = strlen(tag);
01134    }
01135    if (tag_len > MAX_TAG_LEN) {
01136        LM_ERR("tag length <%u> of gw <%s> at row <%u> it too large\n",
01137          tag_len, ip_string, i);
01138        goto gw_err;
01139    }
01140    if (VAL_NULL(ROW_VALUES(row) + 6) == 1) {
01141        grp_id = 0;
01142    } else {
01143        if (VAL_TYPE(ROW_VALUES(row) + 6) != DB_INT) {
01144       LM_ERR("grp_id of gw <%s> at row <%u> is not int\n",
01145              ip_string, i);
01146       goto gw_err;
01147        }
01148        grp_id = VAL_INT(ROW_VALUES(row) + 6);
01149    }
01150    if (!VAL_NULL(ROW_VALUES(row) + 7) &&
01151        (VAL_TYPE(ROW_VALUES(row) + 7) == DB_INT)) {
01152        flags = (unsigned int)VAL_INT(ROW_VALUES(row) + 7);
01153    } else {
01154        LM_ERR("flags of gw <%s> at row <%u> is NULL or not int\n",
01155          ip_string, i);
01156        goto gw_err;
01157    }
01158    if (VAL_NULL(ROW_VALUES(row) + 8) == 1) {
01159        weight = 1;
01160    } else {
01161        if (VAL_TYPE(ROW_VALUES(row) + 8) != DB_INT) {
01162       LM_ERR("weight of gw <%s> at row <%u> is not int\n",
01163              ip_string, i);
01164       goto gw_err;
01165        }
01166        weight = (unsigned int)VAL_INT(ROW_VALUES(row) + 8);
01167    }
01168    if ((weight < 1) || (weight > 254)) {
01169        LM_ERR("weight <%d> of gw <%s> at row <%u> is not 1-254\n",
01170          weight, ip_string, i);
01171        goto gw_err;
01172    }
01173    if (VAL_NULL(ROW_VALUES(row) + 9) == 1) {
01174        hostname_len = 0;
01175        hostname = (char *)0;
01176    } else {
01177        if (VAL_TYPE(ROW_VALUES(row) + 9) != DB_STRING) {
01178       LM_ERR("hostname of gw <%s> at row <%u> is not string\n",
01179              ip_string, i);
01180       goto gw_err;
01181        }
01182        hostname = (char *)VAL_STRING(ROW_VALUES(row) + 9);
01183        hostname_len = strlen(hostname);
01184    }
01185    if (hostname_len > MAX_HOST_LEN) {
01186        LM_ERR("hostname length <%u> of gw <%s> at row <%u> it too large\n",
01187          hostname_len, ip_string, i);
01188        goto gw_err;
01189    }
01190    if (!VAL_NULL(ROW_VALUES(row) + 10) &&
01191        (VAL_TYPE(ROW_VALUES(row) + 10) == DB_INT)) {
01192        ping = (unsigned int)VAL_INT(ROW_VALUES(row) + 10);
01193    } else {
01194        LM_ERR("ping of gw <%s> at row <%u> is NULL or not int\n",
01195          ip_string, i);
01196        goto gw_err;
01197    }  
01198    if (ping > 2) {
01199        LM_ERR("ping <%d> of gw <%s> at row <%u> is not 0, 1, or 2\n",
01200          ping, ip_string, i);
01201        goto gw_err;
01202    }
01203    if (*gws == gws_1) {
01204        if (!insert_gw(gws_2, i + 1, (unsigned int)ip_addr.s_addr, 
01205             hostname, hostname_len, grp_id,
01206             ip_string, port, scheme, transport, flags, strip,
01207             tag, tag_len, weight, ping)) {
01208       goto gw_err;
01209        }
01210    } else {
01211        if (!insert_gw(gws_1, i + 1, (unsigned int)ip_addr.s_addr,
01212             hostname, hostname_len, grp_id,
01213             ip_string, port, scheme, transport, flags, strip,
01214             tag, tag_len, weight, ping)) {
01215       goto gw_err;
01216        }
01217    }
01218     }
01219 
01220     lcr_dbf.free_result(dbh, res);
01221     res = NULL;
01222     
01223     gw_cnt = i;
01224 
01225     if (*gws == gws_1) {
01226    qsort(&(gws_2[1]), gw_cnt, sizeof(struct gw_info), comp_gw_grps);
01227    gws_2[0].ip_addr = gw_cnt;
01228    link_gw_grps(gws_2, gw_grps, &grp_cnt);
01229     } else {
01230    qsort(&(gws_1[1]), gw_cnt, sizeof(struct gw_info), comp_gw_grps);
01231    gws_1[0].ip_addr = gw_cnt;
01232    link_gw_grps(gws_1, gw_grps, &grp_cnt);
01233     }
01234 
01235     for (i = 0; i < grp_cnt; i++) {
01236    LM_DBG("gw_grps[%d].grp_id <%d>, gw_grps[%d].first <%d>\n",
01237       i, gw_grps[i].grp_id, i, gw_grps[i].first);
01238     }
01239 
01240     /* Reload lcrs */
01241 
01242     if (*lcrs == lcrs_1) {
01243    lcr_hash_table_contents_free(lcrs_2);
01244     } else {
01245    lcr_hash_table_contents_free(lcrs_1);
01246     }
01247 
01248     if (lcr_dbf.use_table(dbh, &lcr_table) < 0) {
01249    LM_ERR("error while trying to use lcr table\n");
01250    return -1;
01251     }
01252 
01253     if (DB_CAPABILITY(lcr_dbf, DB_CAP_FETCH)) {
01254    if (lcr_dbf.query(dbh, 0, 0, 0, lcr_cols, 0, 4, 0, 0) < 0) {
01255        LM_ERR("db query on lcr table failed\n");
01256        lcr_dbf.close(dbh);
01257        return -1;
01258    }
01259    if (lcr_dbf.fetch_result(dbh, &res, fetch_rows_param) < 0) {
01260        LM_ERR("failed to fetch rows from lcr table\n");
01261        lcr_dbf.close(dbh);
01262        return -1;
01263    }
01264     } else {
01265    if (lcr_dbf.query(dbh, 0, 0, 0, lcr_cols, 0, 4, 0, &res) < 0) {
01266        LM_ERR("db query on lcr table failed\n");
01267        lcr_dbf.close(dbh);
01268        return -1;
01269    }
01270     }
01271 
01272     n = 0;
01273     from_uri_re = 0;
01274     
01275     do {
01276    LM_DBG("loading, cycle %d with <%d> rows", n++, RES_ROW_N(res));
01277    for (i = 0; i < RES_ROW_N(res); i++) {
01278        from_uri_re = 0;
01279        row = RES_ROWS(res) + i;
01280        if (VAL_NULL(ROW_VALUES(row)) == 1) {
01281       prefix_len = 0;
01282       prefix = 0;
01283        } else {
01284       if (VAL_TYPE(ROW_VALUES(row)) != DB_STRING) {
01285           LM_ERR("lcr prefix at row <%u> is not string\n", i);
01286           goto lcr_err;
01287       }
01288       prefix = (char *)VAL_STRING(ROW_VALUES(row));
01289       prefix_len = strlen(prefix);
01290        }
01291        if (prefix_len > MAX_PREFIX_LEN) {
01292       LM_ERR("length <%u> of lcr prefix at row <%u> is too large\n",
01293              prefix_len, i);
01294       goto lcr_err;
01295        }
01296        if (VAL_NULL(ROW_VALUES(row) + 1) == 1) {
01297       from_uri_len = 0;
01298       from_uri = 0;
01299        } else {
01300       if (VAL_TYPE(ROW_VALUES(row) + 1) != DB_STRING) {
01301           LM_ERR("lcr from_uri at row <%u> is not string\n", i);
01302           goto lcr_err;
01303       }
01304       from_uri = (char *)VAL_STRING(ROW_VALUES(row) + 1);
01305       from_uri_len = strlen(from_uri);
01306        }
01307        if (from_uri_len > MAX_URI_LEN) {
01308       LM_ERR("length <%u> of lcr from_uri at row <%u> is too large\n",
01309              from_uri_len, i);
01310       goto lcr_err;
01311        }
01312        if (from_uri_len > 0) {
01313       from_uri_re = reg_ex_comp(from_uri);
01314       if (from_uri_re == 0) {
01315           LM_ERR("failed to compile lcr from_uri <%s> at row <%u>\n",
01316             from_uri, i);
01317           goto lcr_err;
01318       }
01319        } else {
01320       from_uri_re = 0;
01321        }
01322        if ((VAL_NULL(ROW_VALUES(row) + 2) == 1) ||
01323       (VAL_TYPE(ROW_VALUES(row) + 2) != DB_INT)) {
01324       LM_ERR("lcr grp_id at row <%u> is null or not int\n", i);
01325       goto lcr_err;
01326        }
01327        grp_id = (unsigned int)VAL_INT(ROW_VALUES(row) + 2);
01328        first_gw = find_first_gw(gw_grps, grp_cnt, grp_id);
01329        if (first_gw == 0) {
01330       LM_ERR("gw grp_id <%u> of prefix <%.*s> has no gateways\n",
01331              grp_id, prefix_len, prefix);
01332       goto lcr_err;
01333        }
01334        if ((VAL_NULL(ROW_VALUES(row) + 3) == 1) ||
01335       (VAL_TYPE(ROW_VALUES(row) + 3) != DB_INT)) {
01336       LM_ERR("lcr priority at row <%u> is null or not int\n", i);
01337       goto lcr_err;
01338        }
01339        priority = (unsigned int)VAL_INT(ROW_VALUES(row) + 3);
01340 
01341        if (*lcrs == lcrs_1) {
01342       if (!lcr_hash_table_insert(lcrs_2, prefix_len, prefix,
01343                   from_uri_len, from_uri, from_uri_re,
01344                   grp_id, first_gw, priority) ||
01345           !prefix_len_insert(lcrs_2, prefix_len)) {
01346           lcr_hash_table_contents_free(lcrs_2);
01347           goto lcr_err;
01348       }
01349        } else {
01350       if (!lcr_hash_table_insert(lcrs_1, prefix_len, prefix,
01351                   from_uri_len, from_uri, from_uri_re,
01352                   grp_id, first_gw, priority) ||
01353           !prefix_len_insert(lcrs_1, prefix_len)) {
01354           lcr_hash_table_contents_free(lcrs_1);
01355           goto lcr_err;
01356       }
01357        }
01358    }
01359    if (DB_CAPABILITY(lcr_dbf, DB_CAP_FETCH)) {
01360        if (lcr_dbf.fetch_result(dbh, &res, fetch_rows_param) < 0) {
01361       LM_ERR("fetching of rows from lcr table failed\n");
01362       goto lcr_err;
01363        }
01364    } else {
01365        break;
01366    }
01367     } while (RES_ROW_N(res) > 0);
01368 
01369     lcr_dbf.free_result(dbh, res);
01370     lcr_dbf.close(dbh);
01371 
01372     /* Switch current gw and lcr tables */
01373     if (*gws == gws_1) {
01374    *gws = gws_2;
01375    *lcrs = lcrs_2;
01376     } else {
01377    *gws = gws_1;
01378    *lcrs = lcrs_1;
01379     }
01380 
01381     return 1;
01382 
01383  lcr_err:
01384     if (from_uri_re) shm_free(from_uri_re);
01385 
01386  gw_err:
01387     lcr_dbf.free_result(dbh, res);
01388     lcr_dbf.close(dbh);
01389     return -1;
01390 }
01391 
01392 
01393 /* Print gateways from gws table */
01394 int mi_print_gws(struct mi_node* rpl)
01395 {
01396     unsigned int i;
01397     struct mi_attr* attr;
01398     uri_transport transport;
01399     char *transp;
01400     struct mi_node* node;
01401     struct ip_addr address;
01402     char* p;
01403     int len;
01404 
01405     for (i = 1; i <= (*gws)[0].ip_addr; i++) {
01406 
01407    node = add_mi_node_child(rpl,0 ,"GW", 2, 0, 0);
01408    if (node == NULL) goto err;
01409 
01410    p = int2str((unsigned long)(*gws)[i].grp_id, &len );
01411    attr = add_mi_attr(node, MI_DUP_VALUE, "GRP_ID", 6, p, len );
01412    if (attr == NULL) goto err;
01413 
01414    address.af = AF_INET;
01415    address.len = 4;
01416    address.u.addr32[0] = (*gws)[i].ip_addr;
01417    attr = addf_mi_attr(node, 0, "IP_ADDR", 6, "%s", ip_addr2a(&address));
01418    if (attr == NULL) goto err;
01419 
01420    attr = add_mi_attr(node, MI_DUP_VALUE, "HOSTNAME", 8,
01421             (*gws)[i].hostname, (*gws)[i].hostname_len );
01422    if (attr == NULL) goto err;
01423 
01424    if ((*gws)[i].port > 0) {
01425        p = int2str((unsigned long)(*gws)[i].port, &len );
01426        attr = add_mi_attr(node, MI_DUP_VALUE, "PORT", 4, p, len);
01427    } else {
01428        attr = add_mi_attr(node, MI_DUP_VALUE, "PORT", 4, (char *)0, 0);
01429    }      
01430    if (attr == NULL) goto err;
01431 
01432    if ((*gws)[i].scheme == SIP_URI_T) {
01433        attr = add_mi_attr(node, MI_DUP_VALUE, "SCHEME", 6, "sip", 3);
01434    } else {
01435        attr = add_mi_attr(node, MI_DUP_VALUE, "SCHEME", 6, "sips", 4);
01436    }
01437    if (attr == NULL) goto err;
01438 
01439    transport = (*gws)[i].transport;
01440    switch (transport) {
01441    case PROTO_UDP:
01442        transp= "udp";
01443        break;
01444    case PROTO_TCP:
01445        transp= "tcp";
01446        break;
01447    case PROTO_TLS:
01448        transp= "tls";
01449        break;
01450    case PROTO_SCTP:
01451        transp= "sctp";
01452        break;
01453    default:
01454        transp = "";
01455    }
01456    attr = add_mi_attr(node, MI_DUP_VALUE, "TRANSPORT", 9,
01457             transp, strlen(transp));
01458    if (attr == NULL) goto err;
01459 
01460    p = int2str((unsigned long)(*gws)[i].strip, &len );
01461    attr = add_mi_attr(node, MI_DUP_VALUE, "STRIP", 5, p, len);
01462    if (attr == NULL) goto err;
01463 
01464    attr = add_mi_attr(node, MI_DUP_VALUE, "TAG", 3,
01465             (*gws)[i].tag, (*gws)[i].tag_len );
01466    if (attr == NULL) goto err;
01467 
01468    p = int2str((unsigned long)(*gws)[i].weight, &len);
01469    attr = add_mi_attr(node, MI_DUP_VALUE, "WEIGHT", 6, p, len);
01470    if (attr == NULL) goto err;
01471 
01472    p = int2str((unsigned long)(*gws)[i].flags, &len);
01473    attr = add_mi_attr(node, MI_DUP_VALUE, "FLAGS", 5, p, len);
01474    if (attr == NULL) goto err;
01475    
01476    p = int2str((unsigned long)(*gws)[i].ping, &len);
01477    attr = add_mi_attr(node, MI_DUP_VALUE, "PING", 4, p, len);
01478    if (attr == NULL) goto err;   
01479     }
01480 
01481     return 0;
01482 
01483  err:
01484     return -1;
01485 }
01486 
01487 /* Print lcrs from lcrs table */
01488 int mi_print_lcrs(struct mi_node* rpl)
01489 {
01490     unsigned int i;
01491     struct mi_attr* attr;
01492     struct mi_node* node;
01493     char* p;
01494     int len;
01495     struct lcr_info *lcr_rec;
01496 
01497     for (i = 0; i < lcr_hash_size_param; i++) {
01498 
01499    lcr_rec = (*lcrs)[i];
01500 
01501    while (lcr_rec) {
01502 
01503        node = add_mi_node_child(rpl, 0, "RULE", 4, 0, 0);
01504        if (node == NULL) goto err;
01505 
01506        attr = add_mi_attr(node, 0, "PREFIX", 6, lcr_rec->prefix,
01507                 lcr_rec->prefix_len);
01508        if (attr == NULL) goto err;
01509 
01510        attr = add_mi_attr(node, 0, "FROM_URI", 8, lcr_rec->from_uri,
01511                 lcr_rec->from_uri_len);
01512        if (attr == NULL) goto err;
01513    
01514        p = int2str((unsigned long)lcr_rec->grp_id, &len );
01515        attr = add_mi_attr(node, MI_DUP_VALUE, "GRP_ID", 6, p, len);
01516        if (attr == NULL) goto err;
01517 
01518        p = int2str((unsigned long)lcr_rec->priority, &len);
01519        attr = add_mi_attr(node, MI_DUP_VALUE, "PRIORITY", 8, p, len);
01520        if (attr == NULL) goto err;
01521 
01522        lcr_rec = lcr_rec->next;
01523    }
01524     }
01525 
01526     lcr_rec = (*lcrs)[lcr_hash_size_param];
01527 
01528     while (lcr_rec) {
01529 
01530    node = add_mi_node_child(rpl, 0, "PREFIX_LENS", 11, 0, 0);
01531    if (node == NULL) goto err;
01532 
01533    p = int2str((unsigned long)lcr_rec->prefix_len, &len );
01534    attr = add_mi_attr(node, MI_DUP_VALUE, "PREFIX_LEN", 10, p, len);
01535    if (attr == NULL) goto err;
01536 
01537    lcr_rec = lcr_rec->next;
01538     }
01539 
01540     return 0;
01541 
01542  err:
01543     return -1;
01544 }
01545 
01546 inline int encode_avp_value(char *value, uri_type scheme, unsigned int strip,
01547              char *tag, unsigned int tag_len,
01548              unsigned int ip_addr, char *hostname,
01549              unsigned int hostname_len, unsigned int port,
01550              uri_transport transport, unsigned int flags)
01551 {
01552     char *at, *string;
01553     int len;
01554     
01555     /* scheme */
01556     at = value;
01557     string = int2str(scheme, &len);
01558     append_str(at, string, len);
01559     append_chr(at, '|');
01560     /* strip */
01561     string = int2str(strip, &len);
01562     append_str(at, string, len);
01563     append_chr(at, '|');
01564     /* tag */
01565     append_str(at, tag, tag_len);
01566     append_chr(at, '|');
01567     /* ip_addr */
01568     string = int2str(ip_addr, &len);
01569     append_str(at, string, len);
01570     append_chr(at, '|');
01571     /* hostname */
01572     append_str(at, hostname, hostname_len);
01573     append_chr(at, '|');
01574     /* port */
01575     string = int2str(port, &len);
01576     append_str(at, string, len);
01577     append_chr(at, '|');
01578     /* transport */
01579     string = int2str(transport, &len);
01580     append_str(at, string, len);
01581     append_chr(at, '|');
01582     /* flags */
01583     string = int2str(flags, &len);
01584     append_str(at, string, len);
01585     return at - value;
01586 }
01587 
01588 inline int decode_avp_value(char *value, str *scheme, unsigned int *strip,
01589              str *tag, str *addr, str *hostname,
01590              str *port, str *transport, unsigned int *flags)
01591 {
01592     str s;
01593     unsigned int u;
01594     char *sep;
01595     struct ip_addr a;
01596 
01597     /* scheme */
01598     s.s = value;
01599     sep = index(s.s, '|');
01600     if (sep == NULL) {
01601    LM_ERR("scheme was not found in AVP value\n");
01602    return 0;
01603     }
01604     s.len = sep - s.s;
01605     str2int(&s, &u);
01606     if (u == SIP_URI_T) {
01607    scheme->s = "sip:";
01608    scheme->len = 4;
01609     } else {
01610    scheme->s = "sips:";
01611    scheme->len = 5;
01612     }
01613     /* strip */
01614     s.s = sep + 1;
01615     sep = index(s.s, '|');
01616     if (sep == NULL) {
01617    LM_ERR("strip was not found in AVP value\n");
01618    return 0;
01619     }
01620     s.len = sep - s.s;
01621     str2int(&s, strip);
01622     /* tag */
01623     tag->s = sep + 1;
01624     sep = index(tag->s, '|');
01625     if (sep == NULL) {
01626    LM_ERR("tag was not found in AVP value\n");
01627    return 0;
01628     }
01629     tag->len = sep - tag->s;
01630     /* addr */
01631     s.s = sep + 1;
01632     sep = index(s.s, '|');
01633     if (sep == NULL) {
01634    LM_ERR("ip_addr was not found in AVP value\n");
01635    return 0;
01636     }
01637     s.len = sep - s.s;
01638     str2int(&s, &u);
01639     a.af = AF_INET;
01640     a.len = 4;
01641     a.u.addr32[0] = u;
01642     addr->s = ip_addr2a(&a);
01643     addr->len = strlen(addr->s);
01644     /* hostname */
01645     hostname->s = sep + 1;
01646     sep = index(hostname->s, '|');
01647     if (sep == NULL) {
01648    LM_ERR("hostname was not found in AVP value\n");
01649    return 0;
01650     }
01651     hostname->len = sep - hostname->s;
01652     /* port */
01653     port->s = sep + 1;
01654     sep = index(port->s, '|');
01655     if (sep == NULL) {
01656    LM_ERR("scheme was not found in AVP value\n");
01657    return 0;
01658     }
01659     port->len = sep - port->s;
01660     /* transport */
01661     s.s = sep + 1;
01662     sep = index(s.s, '|');
01663     if (sep == NULL) {
01664    LM_ERR("transport was not found in AVP value\n");
01665    return 0;
01666     }
01667     s.len = sep - s.s;
01668     str2int(&s, &u);
01669     switch (u) {
01670     case PROTO_NONE:
01671     case PROTO_UDP:
01672    transport->s = (char *)0;
01673    transport->len = 0;
01674    break;
01675     case PROTO_TCP:
01676    transport->s = ";transport=tcp";
01677    transport->len = 14;
01678    break;
01679     case PROTO_TLS:
01680    transport->s = ";transport=tls";
01681    transport->len = 14;
01682     default:
01683    transport->s = ";transport=sctp";
01684    transport->len = 15;
01685    break;
01686     }
01687     /* flags */
01688     s.s = sep + 1;
01689     s.len = strlen(s.s);
01690     str2int(&s, flags);
01691 
01692     return 1;
01693 }
01694     
01695 
01696 /* Add gateways in matched_gws array into gw_uri_avps */
01697 void add_gws_into_avps(struct matched_gw_info *matched_gws,
01698              unsigned int gw_cnt, str *ruri_user)
01699 {
01700     unsigned int i, index, strip, hostname_len;
01701     int tag_len;
01702     str value;
01703     char encoded_value[MAX_URI_LEN];
01704     int_str val;
01705 
01706     for (i = 0; i < gw_cnt; i++) {
01707    index = matched_gws[i].gw_index;
01708          hostname_len = (*gws)[index].hostname_len;
01709    strip = (*gws)[index].strip;
01710    if (strip > ruri_user->len) {
01711        LM_ERR("strip count of gw is too large <%u>\n", strip);
01712        goto skip;
01713    }
01714    tag_len = (*gws)[index].tag_len;
01715    if (5 /* scheme */ + 4 /* strip */ + tag_len + 1 /* @ */ +
01716        ((hostname_len > 15)?hostname_len:15) + 6 /* port */ +
01717        15 /* transport */ + 10 /* flags */ + 7 /* separators */
01718        > MAX_URI_LEN) {
01719        LM_ERR("too long AVP value\n");
01720        goto skip;
01721    }
01722    value.len = 
01723        encode_avp_value(encoded_value, (*gws)[index].scheme, strip,
01724               (*gws)[index].tag, tag_len, (*gws)[index].ip_addr,
01725               (*gws)[index].hostname, hostname_len,
01726               (*gws)[index].port, (*gws)[index].transport,
01727               (*gws)[index].flags);
01728    value.s = (char *)&(encoded_value[0]);
01729    val.s = value;
01730    add_avp(gw_uri_avp_type|AVP_VAL_STR, gw_uri_avp, val);
01731    LM_DBG("added gw_uri_avp <%.*s> with weight <%u>\n",
01732           value.len, value.s, matched_gws[i].weight);
01733     skip:
01734    continue;
01735     }
01736 }
01737 
01738 
01739 /*
01740  * Load info of matching GWs into gw_uri_avps
01741  */
01742 static int do_load_gws(struct sip_msg* _m, str *_from_uri)
01743 {
01744     str ruri_user, from_uri;
01745     unsigned int j, k, gw_index, have_rpid_avp, gw_count;
01746     struct usr_avp *avp;
01747     int_str val;
01748     struct matched_gw_info matched_gws[MAX_NO_OF_GWS + 1];
01749     struct lcr_info *lcr_rec, *pl;
01750 
01751     /* Find Request-URI user */
01752     if (parse_sip_msg_uri(_m) < 0) {
01753        LM_ERR("error while parsing R-URI\n");
01754        return -1;
01755     }
01756     ruri_user = _m->parsed_uri.user;
01757 
01758     if (_from_uri) {
01759    /* take caller uri from _from_uri argument */
01760    from_uri = *_from_uri;
01761     } else {
01762    /* take caller uri from RPID or From URI */
01763    have_rpid_avp = 0;
01764    avp = search_first_avp(rpid_avp_type, rpid_avp, &val, 0);
01765    if (avp != NULL) {
01766        /* Get URI user from RPID if not empty */
01767        if (avp->flags & AVP_VAL_STR) {
01768       if (val.s.s && val.s.len) {
01769           from_uri = val.s;
01770           have_rpid_avp = 1;
01771       }
01772        } else {
01773       from_uri.s = int2str(val.n, &from_uri.len);
01774       have_rpid_avp = 1;
01775        }
01776    }
01777    if (!have_rpid_avp) {
01778        /* Get URI from From URI */
01779        if ((!_m->from) && (parse_headers(_m, HDR_FROM_F, 0) == -1)) {
01780       LM_ERR("error while parsing headers\n");
01781       return -1;
01782        }
01783        if (!_m->from) {
01784       LM_ERR("from header field not found\n");
01785       return -1;
01786        }
01787        if ((!(_m->from)->parsed) && (parse_from_header(_m) < 0)) {
01788       LM_ERR("error while parsing From header\n");
01789       return -1;
01790        }
01791        from_uri = get_from(_m)->uri;
01792    }
01793     }
01794 
01795     /*
01796      * Find lcr entries that match based on prefix and from_uri and collect
01797      * gateways of matching entries into matched_gws array so that each
01798      * gateway appears in the array only once.
01799      */
01800 
01801     pl = (*lcrs)[lcr_hash_size_param];
01802     gw_index = 0;
01803     gw_count = (*gws)[0].ip_addr;
01804 
01805     while (pl) {
01806    if (ruri_user.len < pl->prefix_len) {
01807        pl = pl->next;
01808        continue;
01809    }
01810    lcr_rec = lcr_hash_table_lookup(*lcrs, pl->prefix_len, ruri_user.s);
01811    while (lcr_rec) {
01812        /* Match prefix */
01813        if ((lcr_rec->prefix_len == pl->prefix_len) && 
01814       (strncmp(lcr_rec->prefix, ruri_user.s, pl->prefix_len) == 0)) {
01815       /* Match from uri */
01816       if ((lcr_rec->from_uri_len == 0) ||
01817           (pcre_exec(lcr_rec->from_uri_re, NULL, from_uri.s,
01818                 from_uri.len, 0, 0, NULL, 0) >= 0)) {
01819           /* Load unique gws of the group of this lcr entry */
01820           j = lcr_rec->first_gw;
01821           while (j) {
01822                         /* If this destination is failure, skip it */
01823               if ((*gws)[j].ping == 2) {
01824              goto gw_found;
01825                         }
01826          for (k = 0; k < gw_index; k++) {
01827              if ((*gws)[j].ip_addr ==
01828             (*gws)[matched_gws[k].gw_index].ip_addr)
01829             /* Skip already existing gw */
01830             goto gw_found;
01831          }
01832          /* This is a new gw */
01833          matched_gws[gw_index].gw_index = j;
01834          matched_gws[gw_index].prefix_len = pl->prefix_len;
01835          matched_gws[gw_index].priority = lcr_rec->priority;
01836          matched_gws[gw_index].weight = (*gws)[j].weight *
01837              (rand() >> 8);
01838          LM_DBG("added matched_gws[%d]=[%u, %u, %u, %u]\n",
01839                 gw_index, j, pl->prefix_len, lcr_rec->priority,
01840                 matched_gws[gw_index].weight);
01841          gw_index++;
01842           gw_found:
01843          j = (*gws)[j].next;
01844           }
01845       }
01846        }
01847        lcr_rec = lcr_rec->next;
01848    }
01849    pl = pl->next;
01850     }
01851 
01852     /* Sort gateways based on prefix_len, priority, and randomized weight */
01853     qsort(matched_gws, gw_index, sizeof(struct matched_gw_info), comp_matched);
01854 
01855     /* Add gateways into gw_uris_avp */
01856     add_gws_into_avps(matched_gws, gw_index, &ruri_user);
01857 
01858     return 1;
01859 }
01860 
01861 
01862 /*
01863  * Load info of matching GWs from database to gw_uri AVPs.
01864  * Caller URI is taken from request.
01865  */
01866 static int load_gws_0(struct sip_msg* _m, char* _s1, char* _s2)
01867 {
01868     return do_load_gws(_m, (str *)0);
01869 }
01870 
01871 
01872 /*
01873  * Load info of matching GWs from database to gw_uri AVPs.
01874  * Caller URI is taken from pseudo variable argument.
01875  */
01876 static int load_gws_1(struct sip_msg* _m, char* _sp, char* _s2)
01877 {
01878     pv_spec_t *sp;
01879     pv_value_t pv_val;
01880     sp = (pv_spec_t *)_sp;
01881 
01882     if (sp && (pv_get_spec_value(_m, sp, &pv_val) == 0)) {
01883    if (pv_val.flags & PV_VAL_STR) {
01884        if (pv_val.rs.len == 0 || pv_val.rs.s == NULL) {
01885       LM_DBG("missing from uri\n");
01886       return -1;
01887        }
01888        return do_load_gws(_m, &(pv_val.rs));
01889    } else {
01890       LM_DBG("pseudo variable value is not string\n");
01891       return -1;
01892    }
01893     } else {
01894    LM_DBG("cannot get pseudo variable value\n");
01895    return -1;
01896     }
01897 }
01898 
01899 
01900 /*
01901  * Load info of matching GWs from database to gw_uri AVPs taking into
01902  * account the given group id.
01903  */
01904 static int load_gws_from_grp(struct sip_msg* _m, char* _s1, char* _s2)
01905 {
01906     str grp_s, ruri_user;
01907     unsigned int i, grp_id, gw_index, gw_cnt, next_index;
01908     struct matched_gw_info matched_gws[MAX_NO_OF_GWS + 1];
01909 
01910     /* Get grp_id from parameter */
01911     if(((pv_elem_p)_s1)->spec.getf != NULL) {
01912    if (pv_printf_s(_m, (pv_elem_p)_s1, &grp_s) != 0) {
01913        LM_ERR("cannot print grp_id parameter value as string\n");
01914        return -1;
01915    }
01916    if (str2int(&grp_s, &grp_id) != 0) {
01917        LM_ERR("cannot convert grp_id string <%.*s> to int\n",
01918          grp_s.len, grp_s.s);
01919        return -1;
01920    }
01921     } else {
01922    grp_id = ((pv_elem_p)_s1)->spec.pvp.pvn.u.isname.name.n;
01923     }
01924 
01925     /* Find Request-URI user */
01926     if (parse_sip_msg_uri(_m) < 0) {
01927    LM_ERR("error while parsing R-URI\n");
01928    return -1;
01929     }
01930 
01931     ruri_user = _m->parsed_uri.user;
01932 
01933     /* Find gws of the given group */
01934     LM_DBG("finding gateways of grp_id <%d>\n", grp_id);
01935     gw_cnt = (*gws)[0].ip_addr;
01936     gw_index = 0;
01937     for (i = 1; i <= gw_cnt; i++) {
01938    if ((*gws)[i].grp_id == grp_id) {
01939        next_index = i;
01940        while (next_index) {
01941       if ((*gws)[next_index].ping != 2) {
01942           matched_gws[gw_index].gw_index = next_index;
01943           matched_gws[gw_index].prefix_len = 0;
01944           matched_gws[gw_index].priority = 1;
01945           matched_gws[gw_index].weight = rand();
01946           LM_DBG("added matched_gws[%d]=[%u, %u, %u, %u]\n",
01947             gw_index, next_index, 0, 1, 
01948             matched_gws[gw_index].weight);
01949           gw_index++;
01950       }
01951       next_index = (*gws)[next_index].next;
01952        }
01953        break;
01954    }
01955     }
01956 
01957     /* Sort gateways based on random number stored in weight field */
01958     qsort(matched_gws, gw_index, sizeof(struct matched_gw_info), comp_matched);
01959 
01960     /* Add gateways into AVPs */
01961     add_gws_into_avps(matched_gws, gw_index, &ruri_user);
01962 
01963     return 1;
01964 }
01965 
01966 
01967 /* Generate Request-URI and Destination URI */
01968 static int generate_uris(char *r_uri, str *r_uri_user, unsigned int *r_uri_len,
01969           char *dst_uri, unsigned int *dst_uri_len,
01970           unsigned int *flags)
01971 {
01972     int_str gw_uri_val;
01973     struct usr_avp *gu_avp;
01974     str scheme, tag, addr, hostname, port, transport;
01975     char *at;
01976     unsigned int strip;
01977     
01978     gu_avp = search_first_avp(gw_uri_avp_type, gw_uri_avp, &gw_uri_val, 0);
01979 
01980     if (!gu_avp) return 0; /* No more gateways left */
01981 
01982     decode_avp_value(gw_uri_val.s.s, &scheme, &strip, &tag, &addr,
01983            &hostname, &port, &transport, flags);
01984 
01985     if (scheme.len + r_uri_user->len - strip + tag.len + addr.len +
01986    1 /* @ */ + ((hostname.len > 15)?hostname.len:15) + 1 /* : */ +
01987    port.len + transport.len + 1 /* null */ > MAX_URI_LEN) {
01988    LM_ERR("too long Request URI or DST URI\n");
01989    return 0;
01990     }
01991 
01992     at = r_uri;
01993     
01994     append_str(at, scheme.s, scheme.len);
01995     append_str(at, tag.s, tag.len);
01996    
01997     if (strip > r_uri_user->len) {
01998    LM_ERR("strip count <%u> is largen that R-URI user <%.*s>\n",
01999           strip, r_uri_user->len, r_uri_user->s);
02000    return 0;
02001     }
02002     append_str(at, r_uri_user->s + strip, r_uri_user->len - strip);
02003 
02004     append_chr(at, '@');
02005    
02006     if (hostname.len == 0) {
02007    append_str(at, addr.s, addr.len);
02008    if (port.len > 0) {
02009        append_chr(at, ':');
02010        append_str(at, port.s, port.len);
02011    }
02012    if (transport.len > 0) {
02013        append_str(at, transport.s, transport.len);
02014    }
02015    *at = '\0';
02016    *r_uri_len = at - r_uri;
02017    *dst_uri_len = 0;
02018     } else {
02019    append_str(at, hostname.s, hostname.len);
02020    *at = '\0';
02021    *r_uri_len = at - r_uri;
02022    at = dst_uri;
02023    append_str(at, scheme.s, scheme.len);
02024    append_str(at, addr.s, addr.len);
02025    if (port.len > 0) {
02026        append_chr(at, ':');
02027        append_str(at, port.s, port.len);
02028    }
02029    if (transport.len > 0) {
02030        append_str(at, transport.s, transport.len);
02031    }
02032    *at = '\0';
02033    *dst_uri_len = at - dst_uri;
02034     }
02035 
02036     destroy_avp(gu_avp);
02037    
02038     LM_DBG("r_uri <%.*s>, dst_uri <%.*s>\n",
02039       *r_uri_len, r_uri, *dst_uri_len, dst_uri);
02040 
02041     return 1;
02042 }
02043 
02044 
02045 /*
02046  * When called first time in route block, rewrites scheme, host, port, and
02047  * transport parts of R-URI based on first gw_uri_avp value, which is then
02048  * destroyed.  Saves R-URI user to ruri_user_avp for later use.
02049  *
02050  * On other calls appends a new branch to request, where scheme, host, port,
02051  * and transport of URI are taken from the first gw_uri_avp value, 
02052  * which is then destroyed. URI user is taken either from R-URI (first
02053  * call in failure route block) or from ruri_user_avp value saved earlier.
02054  *
02055  * Returns 1 upon success and -1 upon failure.
02056  */
02057 static int next_gw(struct sip_msg* _m, char* _s1, char* _s2)
02058 {
02059     int_str ruri_user_val, val;
02060     struct action act;
02061     struct usr_avp *ru_avp;
02062     int rval;
02063     str uri_str;
02064     unsigned int flags, r_uri_len, dst_uri_len;
02065     char r_uri[MAX_URI_LEN], dst_uri[MAX_URI_LEN];
02066 
02067     ru_avp = search_first_avp(ruri_user_avp_type, ruri_user_avp,
02068                &ruri_user_val, 0);
02069     
02070     if (ru_avp == NULL) {
02071    
02072    /* First invocation either in route or failure route block.
02073     * Take Request-URI user from Request-URI and generate Request
02074          * and Destination URIs. */
02075    if (parse_sip_msg_uri(_m) < 0) {
02076        LM_ERR("parsing of R-URI failed\n");
02077        return -1;
02078    }
02079    if (generate_uris(r_uri, &(_m->parsed_uri.user), &r_uri_len, dst_uri,
02080            &dst_uri_len, &flags) == 0) {
02081        return -1;
02082    }
02083 
02084    /* Save Request-URI user into uri_user_avp for use in subsequent
02085          * invocations. */
02086    val.s = _m->parsed_uri.user;
02087    add_avp(ruri_user_avp_type|AVP_VAL_STR, ruri_user_avp, val);
02088    LM_DBG("added ruri_user_avp <%.*s>\n", val.s.len, val.s.s);
02089 
02090     } else {
02091    
02092    /* Subsequent invocation either in route or failure route block.
02093     * Take Request-URI user from ruri_user_avp and generate Request
02094          * and Destination URIs. */
02095    if (generate_uris(r_uri, &(ruri_user_val.s), &r_uri_len, dst_uri,
02096            &dst_uri_len, &flags) == 0) {
02097        return -1;
02098    }
02099     }
02100 
02101     if ((route_type == REQUEST_ROUTE) && (ru_avp == NULL)) {
02102 
02103    /* First invocation in route block => Rewrite Request URI. */
02104    act.type = SET_URI_T;
02105    act.elem[0].type = STRING_ST;
02106    act.elem[0].u.string = r_uri;
02107    rval = do_action(&act, _m);
02108    if (rval != 1) {
02109        LM_ERR("calling do_action failed with return value <%d>\n", rval);
02110        return -1;
02111    }
02112 
02113     } else {
02114    
02115    /* Subsequent invocation in route block or any invocation in
02116          * failure route block => append new branch. */
02117    uri_str.s = r_uri;
02118    uri_str.len = r_uri_len;
02119    act.type = APPEND_BRANCH_T;
02120    act.elem[0].type = STRING_ST;
02121    act.elem[0].u.s = uri_str;
02122    act.elem[1].type = NUMBER_ST;
02123    act.elem[1].u.number = 0;
02124    rval = do_action(&act, _m);
02125    if (rval != 1) {
02126        LM_ERR("calling do_action failed with return value <%d>\n", rval);
02127        return -1;
02128    }
02129     }
02130     
02131     /* Set Destination URI if not empty */
02132     if (dst_uri_len > 0) {
02133    uri_str.s = dst_uri;
02134    uri_str.len = dst_uri_len;
02135    act.type = SET_DSTURI_T;
02136    act.elem[0].type = STRING_ST;
02137    act.elem[0].u.s = uri_str;
02138    act.next = 0;
02139    rval = do_action(&act, _m);
02140    if (rval != 1) {
02141        LM_ERR("calling do_action failed with return value <%d>\n", rval);
02142        return -1;
02143    }
02144     }
02145 
02146     /* Set flags_avp */
02147     val.n = flags;
02148     add_avp(flags_avp_type, flags_avp, val);
02149     LM_DBG("added flags_avp <%u>\n", (unsigned int)val.n);
02150 
02151     return 1;
02152 }
02153 
02154 
02155 /*
02156  * Checks if request comes from a gateway
02157  */
02158 static int do_from_gw(struct sip_msg* _m, pv_spec_t *addr_sp, int grp_id)
02159 {
02160     unsigned int src_addr;
02161     pv_value_t pv_val;
02162     struct ip_addr *ip;
02163     int_str val;
02164     struct gw_info gw, *res;
02165 
02166     if (addr_sp && (pv_get_spec_value(_m, addr_sp, &pv_val) == 0)) {
02167    if (pv_val.flags & PV_VAL_INT) {
02168        src_addr = pv_val.ri;
02169    } else if (pv_val.flags & PV_VAL_STR) {
02170        if ((ip = str2ip(&pv_val.rs)) == NULL) {
02171       LM_DBG("request did not come from gw "
02172              "(pvar value is not an IP address)\n");
02173       return -1;
02174        } else {
02175       src_addr = ip->u.addr32[0];
02176        }
02177    } else {
02178        LM_ERR("pvar has no value\n");
02179        return -1;
02180    }
02181     } else {
02182    src_addr = _m->rcv.src_ip.u.addr32[0];
02183     }
02184 
02185     if (grp_id < 0) {
02186    res = (struct gw_info *)bsearch(&src_addr, &((*gws)[1]),
02187                (*gws)[0].ip_addr,
02188                sizeof(struct gw_info), comp_gws);
02189     } else {
02190    gw.ip_addr = src_addr;
02191    gw.grp_id = grp_id;
02192    res = (struct gw_info *)bsearch(&gw, &((*gws)[1]),
02193                (*gws)[0].ip_addr,
02194                sizeof(struct gw_info), comp_gw_grps);
02195     }
02196 
02197     if (res == NULL) {
02198    LM_DBG("request did not come from gw\n");
02199    return -1;
02200     } else {
02201    LM_DBG("request game from gw\n");
02202    val.n = res->flags;
02203    add_avp(flags_avp_type, flags_avp, val);
02204    LM_DBG("added flags_avp <%u>\n", (unsigned int)val.n);
02205    return 1;
02206     }
02207 }
02208 
02209 
02210 /*
02211  * Checks if request comes from a gateway, taking source address from request
02212  * and taking into account the group id.
02213  */
02214 static int from_gw_grp(struct sip_msg* _m, char* _grp_id, char* _s2)
02215 {
02216     return do_from_gw(_m, (pv_spec_t *)0, (int)(long)_grp_id);
02217 }
02218 
02219 
02220 /*
02221  * Checks if request comes from a gateway, taking src_address from request
02222  * and ignoring group id.
02223  */
02224 static int from_gw_0(struct sip_msg* _m, char* _s1, char* _s2)
02225 {
02226     return do_from_gw(_m, (pv_spec_t *)0, -1);
02227 }
02228 
02229 
02230 /*
02231  * Checks if request comes from a gateway, taking source address from pv
02232  * and ignoring group id.
02233  */
02234 static int from_gw_1(struct sip_msg* _m, char* _addr_sp, char* _s2)
02235 {
02236     return do_from_gw(_m, (pv_spec_t *)_addr_sp, -1);
02237 }
02238 
02239 
02240 /*
02241  * Checks if in-dialog request goes to gateway
02242  */
02243 static int do_to_gw(struct sip_msg* _m, pv_spec_t *addr_sp, int grp_id)
02244 {
02245     unsigned int dst_addr;
02246     pv_value_t pv_val;
02247     struct ip_addr *ip;
02248     struct gw_info gw, *res;
02249 
02250     if (addr_sp && (pv_get_spec_value(_m, addr_sp, &pv_val) == 0)) {
02251    if (pv_val.flags & PV_VAL_INT) {
02252        dst_addr = pv_val.ri;
02253    } else if (pv_val.flags & PV_VAL_STR) {
02254        if ((ip = str2ip(&pv_val.rs)) == NULL) {
02255       LM_DBG("request is not going to gw "
02256              "(pvar value is not an IP address)\n");
02257       return -1;
02258        } else {
02259       dst_addr = ip->u.addr32[0];
02260        }
02261    } else {
02262        LM_ERR("pvar has no value\n");
02263        return -1;
02264    }
02265     } else {
02266    if ((_m->parsed_uri_ok == 0) && (parse_sip_msg_uri(_m) < 0)) {
02267        LM_ERR("Error while parsing the R-URI\n");
02268        return -1;
02269    }
02270    if (_m->parsed_uri.host.len > 15) {
02271        LM_DBG("request is not going to gw "
02272          "(Request-URI host is not an IP address)\n");
02273        return -1;
02274    }
02275    if ((ip = str2ip(&(_m->parsed_uri.host))) == NULL) {
02276        LM_DBG("request is not going to gw "
02277          "(Request-URI host is not an IP address)\n");
02278        return -1;
02279    } else {
02280        dst_addr = ip->u.addr32[0];
02281    }
02282     }
02283 
02284     if (grp_id < 0) {
02285    res = (struct gw_info *)bsearch(&dst_addr, &((*gws)[1]),
02286                (*gws)[0].ip_addr,
02287                sizeof(struct gw_info), comp_gws);
02288     } else {
02289    gw.ip_addr = dst_addr;
02290    gw.grp_id = grp_id;
02291    res = (struct gw_info *)bsearch(&gw, &((*gws)[1]),
02292                (*gws)[0].ip_addr,
02293                sizeof(struct gw_info), comp_gw_grps);
02294     }
02295 
02296     if (res == NULL) {
02297    LM_DBG("request is not going to gw\n");
02298    return -1;
02299     } else {
02300    LM_DBG("request goes to gw\n");
02301    return 1;
02302     }
02303 }
02304 
02305 
02306 /*
02307  * Checks if in-dialog request goes to gateway, taking destination address
02308  * from request and taking into account group id.
02309  */
02310 static int to_gw_grp(struct sip_msg* _m, char* _grp_id, char* _s2)
02311 {
02312     return do_to_gw(_m, (pv_spec_t *)0, (int)(long)_grp_id);
02313 }
02314 
02315 
02316 /*
02317  * Checks if request goes to a gateway, taking destination address from request
02318  * and ignoring group id.
02319  */
02320 static int to_gw_0(struct sip_msg* _m, char* _s1, char* _s2)
02321 {
02322     return do_to_gw(_m, (pv_spec_t *)0, -1);
02323 }
02324 
02325 
02326 /*
02327  * Checks if request goes to a gateway, taking destination address from pv
02328  * and ignoring group id.
02329  */
02330 static int to_gw_1(struct sip_msg* _m, char* _addr_sp, char* _s2)
02331 {
02332     return do_to_gw(_m, (pv_spec_t *)_addr_sp, -1);
02333 }
02334 
02335 
02336 /* Set PING Flag in our Structure */
02337 int gw_set_state(int index, struct sip_uri *uri, int ping) 
02338 {
02339     int addr, port;
02340     struct ip_addr address;
02341     uri_type scheme;
02342     uri_transport transport;
02343     str addr_str;
02344                      
02345     if ((*gws)[index].ip_addr == 0) { 
02346    return -1;
02347     }
02348 
02349     addr = (*gws)[index].ip_addr;
02350     port = (*gws)[index].port;
02351     scheme = (*gws)[index].scheme;
02352     transport = (*gws)[index].transport;
02353                 
02354     /* Check Scheme */
02355     if (scheme != uri->type) {
02356    LM_ERR("URI scheme is not equals <%u>\n", (unsigned int)scheme);
02357    return -1;
02358     }
02359     
02360     address.af = AF_INET;
02361     address.len = 4;
02362     address.u.addr32[0] = addr;
02363     addr_str.s = ip_addr2a(&address);
02364     addr_str.len = strlen(addr_str.s);
02365         
02366     /* Check IP */
02367     if (strncmp(addr_str.s, uri->host.s, addr_str.len)) {
02368    LM_ERR("IP of the response <%.*s> is not equal to gw IP <%.*s>\n",
02369           uri->host.len, uri->host.s, addr_str.len, addr_str.s);
02370    return -1;
02371     }
02372 
02373     /* Check Port */
02374     if (port != uri->port_no) {
02375    LM_ERR("Port of the response <%u> is not equal to gw port <%u>\n",
02376           uri->port_no, port);
02377    return -1;
02378     }        
02379 
02380     if ((*gws)[index].ping != ping) {
02381 
02382    /* Send notice to syslog */
02383    switch(ping) {                
02384 
02385    case 2: /* offline */
02386        LM_NOTICE("trunk \"%.*s:%d\" from group: <%d> is OFFLINE!",
02387             addr_str.len, addr_str.s, port, (*gws)[index].grp_id);
02388        break;
02389 
02390    default: /* online */ 
02391        LM_NOTICE("trunk \"%.*s:%d\" from group: <%d> is ONLINE!",
02392             addr_str.len, addr_str.s, port, (*gws)[index].grp_id);
02393        break;
02394    }
02395     }
02396 
02397     /* Set our destination */
02398     (*gws)[index].ping = ping;
02399         
02400     LM_DBG("set ping flag <%d> for index: <%u> destination: <%.*s>\n",
02401       ping, index, uri->host.len, uri->host.s);
02402 
02403     return 0;
02404 }
02405 
02406 
02407 /*! \brief
02408  * Callback-Function for the OPTIONS-Request
02409  * This Function is called, as soon as the Transaction is finished
02410  * (e. g. a Response came in, the timeout was hit, ...)
02411  * Some part of this code was imported from dispatcher module
02412  *
02413  */
02414 static void check_options_callback(struct cell *t, int type,
02415                struct tmcb_params *ps)
02416 {
02417     int index = 0;
02418     str uri = {0, 0};
02419     struct sip_uri to_uri;
02420     int i = 0;
02421                 
02422     /* Param should contain the index, in which the failed host
02423      * can be found */
02424     if (*ps->param == NULL) {
02425    LM_DBG("no parameter provided; OPTIONS-Request was finished"
02426           " with code %d\n", ps->code);
02427    return;
02428     }
02429     /* Param is a (void*) pointer, so we need to dereference it and
02430      *  cast it to an int */
02431     index = (int)(long)(*ps->param);
02432         
02433     /* SIP URI is taken from the transaction;
02434      * Remove the "To: " (s+4) and the trailing new-line (s - 4 (To: )
02435      * - 2 (\r\n)). */
02436     uri.s = t->to.s + 4;
02437     uri.len = t->to.len - 6;
02438         
02439     LM_DBG("trying to get domain from uri\n");
02440 
02441     if (parse_uri(uri.s, uri.len, &to_uri) || !to_uri.host.len) {
02442    LM_ERR("unable to extract domain name from To URI\n");
02443    return;
02444     }
02445 
02446     LM_DBG("OPTIONS request was finished with code %d (to %.*s, index %d) "
02447       "(domain: %.*s)\n",
02448       ps->code, uri.len, uri.s, index, to_uri.host.len, to_uri.host.s);
02449 
02450     /* Check for positive response */ 
02451     for (i = 0; i < MAX_CODES; i++) {
02452 
02453    if (!positive_codes[i]) break;
02454 
02455    if (ps->code == positive_codes[i]) {
02456        /* Set the gw state back to "active" */
02457        if (gw_set_state(index, &to_uri, 1) != 0) {
02458       LM_ERR("setting the active state failed (%.*s, index %d)\n",
02459              uri.len, uri.s, index);
02460        }
02461        return;
02462    }
02463     }
02464 
02465     /* Check for negative response */
02466     for (i = 0; i < MAX_CODES; i++) {
02467    
02468    if (!negative_codes[i]) break;
02469 
02470    if (ps->code == negative_codes[i]) {
02471        /* Set the gw state to "inactive" */
02472        if (gw_set_state(index, &to_uri, 2) != 0) {
02473       LM_ERR("Setting the inactive state failed (%.*s, index %d)\n",
02474              uri.len, uri.s, index);
02475        }
02476        break;
02477    }
02478     }
02479     
02480     return;
02481 }
02482 
02483 
02484 /*
02485  * Here we send OPTIONS packet to the GW 
02486  */
02487 int send_sip_options_request(str *to, int index)
02488 {
02489     str hdrs = {0, 0};
02490     int res;
02491     char *p;
02492     int max_forward = 10;
02493     char* max_forward_s = NULL;
02494     int len = 0;
02495 
02496     /* Length */
02497     hdrs.len =  CRLF_LEN;
02498     hdrs.len += 14; /* "Max-Forwards: "*/ 
02499    
02500     /* Convert to char */
02501     max_forward_s = int2str(max_forward, &len);
02502     hdrs.len += len;
02503 
02504     hdrs.s = (char*)pkg_malloc(hdrs.len);
02505     if (!hdrs.s) {
02506    LM_ERR("no more pkg memory!\n");
02507    return -1;
02508     }
02509     p = hdrs.s;
02510     append_str(p, "Max-Forwards: ", 14);
02511     append_str(p, max_forward_s, len);
02512     append_str(p, CRLF, CRLF_LEN);
02513 
02514     /* Send the request */
02515     res = tmb.t_request(&ping_method,   /* request type */
02516                         0,              /* Request-URI */
02517                         to,             /* To */
02518                         &ping_from,     /* From */
02519                         &hdrs,          /* Additional headers including CRLF */
02520                         0,              /* Message body */
02521                         0,    /* outbound uri */
02522                         check_options_callback,   /* Callback function */
02523                         (void*)(long)index     /* Callback parameter */
02524          );
02525     pkg_free(hdrs.s);
02526     return res;
02527 }
02528 
02529 
02530 /*
02531  *  Gateway Loop Checker
02532  */ 
02533 int check_our_gws(void) 
02534 {
02535     unsigned int i, addr, port;  
02536     struct ip_addr address;
02537     char ruri[MAX_URI_SIZE];
02538     uri_type scheme;
02539     uri_transport transport;
02540     str addr_str, port_str, to_uri;
02541     char *at;
02542         
02543     /* Find gws and check them */
02544     LM_DBG("check our gateways!\n");
02545                      
02546     for (i = 1; i <= (*gws)[0].ip_addr; i++) {
02547 
02548    if ((*gws)[i].ip_addr == 0) break;
02549 
02550    if ((*gws)[i].ping == 0) goto skip;
02551    
02552    addr = (*gws)[i].ip_addr;
02553    port = (*gws)[i].port;
02554    scheme = (*gws)[i].scheme;
02555    transport = (*gws)[i].transport;
02556 
02557    at = (char *)&(ruri[0]);        
02558    
02559    if (scheme == SIP_URI_T) {
02560        append_str(at, "sip:", 4);
02561    } else if (scheme == SIPS_URI_T) {
02562        append_str(at, "sips:", 5);
02563    } else {
02564        LM_ERR("unknown or unsupported URI scheme <%u>\n",
02565          (unsigned int)scheme);
02566        goto skip;
02567    }
02568    address.af = AF_INET;
02569    address.len = 4;
02570    address.u.addr32[0] = addr;
02571    addr_str.s = ip_addr2a(&address);
02572    addr_str.len = strlen(addr_str.s);
02573    append_str(at, addr_str.s, addr_str.len);
02574    if (port != 0) {
02575        if (port > 65536) {
02576       LM_ERR("port of gw is too large <%u>\n", port);
02577       goto skip;
02578        }
02579        append_chr(at, ':');
02580        port_str.s = int2str(port, &port_str.len);
02581        append_str(at, port_str.s, port_str.len);
02582    }
02583 
02584    if (transport != PROTO_NONE) {
02585        append_str(at, ";transport=", 11);
02586        switch(transport) {
02587        case PROTO_UDP:
02588       append_str(at, "udp", 3);
02589       break;
02590        case PROTO_TCP:
02591       append_str(at, "tcp", 3);
02592       break;
02593        case PROTO_TLS:
02594       append_str(at, "tls", 3);
02595       break;
02596        case PROTO_SCTP:
02597       append_str(at, "sctp", 4);
02598       break;
02599        default:
02600       LM_ERR("Unknown or unsupported transport <%u>\n",
02601              (unsigned int)transport);
02602       goto skip;
02603       break;                                        
02604        }                    
02605    }
02606 
02607    to_uri.s = (char *)&(ruri[0]);
02608    to_uri.len = at - to_uri.s;
02609                 
02610    LM_DBG("check URI (%.*s)\n", to_uri.len, to_uri.s);
02611 
02612    if (!send_sip_options_request(&to_uri, i)) return -1;
02613    
02614     skip:
02615    continue;               
02616     }   
02617             
02618     return 0;         
02619 }
02620 
02621 
02622 /*
02623  * Timer handler
02624  */
02625 static void timer(unsigned int ticks, void* param)
02626 {
02627     if (check_our_gws() != 0) {
02628    LM_ERR("gw checkd failed\n");
02629     }
02630 }
02631 
02632 
02633 /*
02634  * Function used by mod_init.
02635  */
02636 int add_code_to_array( str *codes, int local_codes[])
02637 {
02638     char *p;
02639     char *d;
02640     str code_str;
02641     unsigned int int_code;
02642     int i = 0;
02643 
02644     if (codes->s==NULL || codes->len==0 )
02645    return 0;                
02646 
02647     p = codes->s;
02648     do {        
02649    if (i > MAX_CODES) {
02650        LM_ERR("too many MAX_CODES = %d\n", i);
02651        return -1;
02652    }
02653 
02654    /* Locate code_str of profile */
02655    code_str.s = p;
02656    d = strchr( p, ';');
02657    if (d) {
02658        code_str.len = d-p;
02659        d++;
02660    } else {
02661        code_str.len = strlen(p);
02662    }
02663 
02664    /* We have the code_str -> trim it for spaces */
02665    trim_spaces_lr(code_str);
02666    
02667    /* check len code_str */
02668    if (code_str.len==0)
02669        /* ignore */
02670        continue;
02671 
02672    if (str2int(&code_str, &int_code) <  0) {
02673        LM_ERR("converting string to int [code]= %.*s\n",
02674          code_str.len, code_str.s);
02675        return -1;
02676    }
02677 
02678    if ((int_code < 100) || (int_code > 700)) {
02679        LM_ERR("wrong code %u\n", int_code);
02680        return -1;
02681    }
02682 
02683    local_codes[i]=int_code;
02684    
02685    i++;
02686 
02687     } while ((p=d) != NULL);
02688 
02689     return 0;
02690 }

Generated on Wed May 23 08:00:57 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6