#include "rls_mod.h" #include "../../sr_module.h" #include "../../timer_ticks.h" #include "../../mem/mem.h" #include "../../mem/shm_mem.h" #include #include #include #include #include #include #include "rl_subscription.h" #include "rls_handler.h" #include "rpc.h" #include "uri_ops.h" #include "time_event_manager.h" #include MODULE_VERSION int rls_mod_init(void); void rls_mod_destroy(void); int rls_child_init(int _rank); static int rls_subscribe_fixup(void** param, int param_no); /* authorization parameters */ char *auth_type_str = NULL; /* type of authorization: none,implicit,xcap */ int db_mode = 0; /* 0 -> no DB, 1 -> write through */ char *db_url = NULL; int reduce_xcap_needs = 0; /* internal data members */ /* static ptr_vector_t *xcap_servers = NULL; */ db_con_t* rls_db = NULL; /* database connection handle */ db_func_t rls_dbf; /* database functions */ /* one shot timer for reloading data from DB - they can not be reloaded in init or child_init due to internal subscriptions to other modules (may be not itialised yet) */ static int init_timer_delay = 3; /* parameters for optimizations */ int max_notifications_at_once = 1000000; /* timer for processing notifications from QSA */ int rls_timer_interval = 10; /* ignore if NOTIFY times out (don't destroy subscription */ int rls_ignore_408_on_notify = 0; /* maximum nested list level (if 0, no nested lists are possible, * if 1 only one nested list level is possible, if 2 it is possible to * have lists in lists, ..., unlimited if -1) */ int max_list_nesting_level = -1; /** Exported functions */ static cmd_export_t cmds[]={ /* {"handle_r_subscription", handle_r_subscription, 0, subscribe_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, */ {"handle_rls_subscription", (cmd_function)handle_rls_subscription, 1, rls_subscribe_fixup, REQUEST_ROUTE | FAILURE_ROUTE}, {"is_simple_rls_target", is_simple_rls_target, 1, NULL, REQUEST_ROUTE | FAILURE_ROUTE}, {"query_rls_services", query_rls_services, 0, NULL, REQUEST_ROUTE | FAILURE_ROUTE}, {"query_resource_list", query_resource_list, 1, NULL, REQUEST_ROUTE | FAILURE_ROUTE}, {"have_flat_list", have_flat_list, 0, NULL, REQUEST_ROUTE | FAILURE_ROUTE}, {0, 0, 0, 0, 0} }; /** Exported parameters */ static param_export_t params[]={ {"min_expiration", PARAM_INT, &rls_min_expiration }, {"max_expiration", PARAM_INT, &rls_max_expiration }, {"default_expiration", PARAM_INT, &rls_default_expiration }, {"auth", PARAM_STRING, &auth_type_str }, /* type of authorization: none, implicit, xcap, ... */ {"db_mode", PARAM_INT, &db_mode }, {"db_url", PARAM_STRING, &db_url }, {"reduce_xcap_needs", PARAM_INT, &reduce_xcap_needs }, {"max_notifications_at_once", PARAM_INT, &max_notifications_at_once }, {"timer_interval", PARAM_INT, &rls_timer_interval }, {"max_list_nesting_level", PARAM_INT, &max_list_nesting_level }, {"expiration_timer_period", PARAM_INT, &rls_expiration_timer_period }, {"ignore_408_on_notify", PARAM_INT, &rls_ignore_408_on_notify }, {"init_timer_delay", PARAM_INT, &init_timer_delay }, /* timer for delayed DB reload (due to internal subscriptions can't be reloaded from init or child init) */ {0, 0, 0} }; struct module_exports exports = { "rls", cmds, /* Exported functions */ rls_rpc_methods, /* RPC methods */ params, /* Exported parameters */ rls_mod_init, /* module initialization function */ 0, /* response function*/ rls_mod_destroy, /* pa_destroy, / * destroy function */ 0, /* oncancel function */ rls_child_init /* per-child init function */ }; struct tm_binds tmb; dlg_func_t dlg_func; fill_xcap_params_func fill_xcap_params = NULL; int use_db = 0; int rls_min_expiration = 60; int rls_max_expiration = 7200; int rls_default_expiration = 3761; int rls_expiration_timer_period = 10; rls_auth_params_t rls_auth_params; /* structure filled according to parameters (common for all XCAP servers now) */ char *xcap_server = NULL; /* XCAP server URI */ /* TODO: settings of other xcap parameters (auth, ssl, ...) */ static int set_auth_params(rls_auth_params_t *dst, const char *auth_type_str) { if (!auth_type_str) { LOG(L_ERR, "no subscription authorization type given, using \'implicit\'!\n"); dst->type = rls_auth_none; return 0; } if (strcmp(auth_type_str, "xcap") == 0) { dst->type = rls_auth_xcap; return 0; } if (strcmp(auth_type_str, "none") == 0) { dst->type = rls_auth_none; LOG(L_WARN, "using \'none\' rls-subscription authorization!\n"); return 0; } if (strcmp(auth_type_str, "implicit") == 0) { dst->type = rls_auth_implicit; return 0; } LOG(L_ERR, "Can't resolve subscription authorization type: \'%s\'." " Use one of: none, implicit, xcap.\n", auth_type_str); return -1; } static ticks_t init_timer_cb(ticks_t ticks, struct timer_ln* tl, void* data) { /* initialization (like read data from database) which can trigger * database operations in other modules/... */ if (use_db && (rls_db)) { INFO("reading RLS data from database\n"); rls_lock(); db_load_rls(); rls_unlock(); } if (data) { mem_free(data); /* ERR("freeing myself!\n"); */ } return 0; /* one shot timer */ } int rls_mod_init(void) { load_tm_f load_tm; bind_dlg_mod_f bind_dlg; struct timer_ln *i_timer = NULL; DEBUG_LOG("RLS module initialization\n"); /* ??? if other module uses this libraries it might be a problem ??? */ xmlInitParser(); DEBUG_LOG(" ... common libraries\n"); qsa_initialize(); if (time_event_management_init() != 0) { LOG(L_ERR, "rls_mod_init(): Can't initialize time event management!\n"); return -1; } if (subscription_management_init() != 0) { LOG(L_ERR, "rls_mod_init(): Can't initialize time event management!\n"); return -1; } /* import the TM auto-loading function */ if ( !(load_tm=(load_tm_f)find_export("load_tm", NO_SCRIPT, 0))) { LOG(L_ERR, "rls_mod_init(): Can't import tm!\n"); return -1; } /* let the auto-loading function load all TM stuff */ if (load_tm(&tmb)==-1) { LOG(L_ERR, "rls_mod_init(): load_tm() failed\n"); return -1; } bind_dlg = (bind_dlg_mod_f)find_export("bind_dlg_mod", -1, 0); if (!bind_dlg) { LOG(L_ERR, "Can't import dlg\n"); return -1; } if (bind_dlg(&dlg_func) != 0) { return -1; } if (rls_init() != 0) { return -1; } if (vs_init() != 0) { return -1; } /* xcap_servers = (ptr_vector_t*)mem_alloc(sizeof(ptr_vector_t)); if (!xcap_servers) { LOG(L_ERR, "rls_mod_init(): can't allocate memory for XCAP servers vector\n"); return -1; } ptr_vector_init(xcap_servers, 8); */ /* set authorization type according to requested "auth type name" * and other (type specific) parameters */ if (set_auth_params(&rls_auth_params, auth_type_str) != 0) return -1; use_db = 0; if (db_mode > 0) { int db_url_len = db_url ? strlen(db_url) : 0; if (!db_url_len) { LOG(L_ERR, "rls_mod_init(): no db_url specified but db_mode > 0\n"); db_mode = 0; } } if (db_mode > 0) { if (bind_dbmod(db_url, &rls_dbf) < 0) { LOG(L_ERR, "rls_mod_init(): Can't bind database module via url %s\n", db_url); return -1; } if (!DB_CAPABILITY(rls_dbf, DB_CAP_ALL)) { /* ? */ LOG(L_ERR, "rls_mod_init(): Database module does not implement all functions needed by the module\n"); return -1; } use_db = 1; } /* once-shot timer for reloading data from DB - * needed because it can trigger database operations * in other modules and they mostly intialize their * database connection in child_init functions */ i_timer = timer_alloc(); if (!i_timer) { ERR("can't allocate memory for DB init timer\n"); return -1; } else { timer_init(i_timer, init_timer_cb, i_timer, 0); timer_add(i_timer, S_TO_TICKS(init_timer_delay)); } fill_xcap_params = (fill_xcap_params_func)find_export("fill_xcap_params", 0, -1); return 0; } int rls_child_init(int _rank) { rls_db = NULL; if (use_db) { if (_rank==PROC_INIT || _rank==PROC_MAIN || _rank==PROC_TCP_MAIN) return 0; /* do nothing for the main or tcp_main processes */ if (rls_dbf.init) rls_db = rls_dbf.init(db_url); if (!rls_db) { LOG(L_ERR, "ERROR: rls_child_init(%d): " "Error while connecting database\n", _rank); return -1; } /* if (_rank == 0) { rls_lock(); db_load_rls(); rls_unlock(); } */ } return 0; } void rls_mod_destroy(void) { /*int i, cnt; char *s;*/ DEBUG_LOG("RLS module cleanup\n"); /* destroy used XCAP servers */ /* DEBUG_LOG(" ... xcap servers\n"); if (xcap_servers) { cnt = ptr_vector_size(xcap_servers); DEBUG_LOG(" count = %d\n", cnt); for (i = 0; i < cnt; i++) { s = ptr_vector_get(xcap_servers, i); if (s) { DEBUG_LOG(" ... freeing %s (%p)\n", s, s); cds_free(s); } } ptr_vector_destroy(xcap_servers); mem_free(xcap_servers); xcap_servers = NULL; } */ DEBUG_LOG(" ... rls\n"); rls_destroy(); DEBUG_LOG(" ... vs\n"); vs_destroy(); DEBUG_LOG(" ... time event management\n"); time_event_management_destroy(); DEBUG_LOG(" %s: ... db\n", __func__); if (use_db) { if (rls_db && rls_dbf.close) rls_dbf.close(rls_db); rls_db = NULL; } DEBUG_LOG(" ... common libs\n"); qsa_cleanup(); /* ??? if other module uses this libraries it might be a problem ??? */ /* xmlCleanupParser(); */ DEBUG_LOG("RLS module cleanup finished\n"); } static int rls_subscribe_fixup(void** param, int param_no) { /* char *xcap_server = NULL; */ long send_errors = 0; /* if (param_no == 1) { if (!param) { LOG(L_ERR, "rls_subscribe_fixup(): XCAP server address not set!\n"); return E_UNSPEC; } xcap_server = zt_strdup((char *)*param); if (!xcap_server) { LOG(L_ERR, "rls_subscribe_fixup(): Can't set XCAP server address!\n"); return E_UNSPEC; } / * store not only the root string? (create a structure rather?) * / ptr_vector_add(xcap_servers, xcap_server); DEBUG_LOG("rls_subscribe_fixup(): XCAP server is %s (%p)\n", xcap_server, xcap_server); *param = (void*)xcap_server; } */ if (param_no == 1) { if (param) { if (*param) send_errors = atoi(*param); } DEBUG_LOG("rls_subscribe_fixup(): send errors: %ld\n", send_errors); *param = (void*)send_errors; } return 0; }