From a2c0da53f368f0b11340c3a72814c93b182753b7 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 11 Feb 2011 23:10:12 -0600 Subject: [PATCH] add centralized registration db to core db and use it from mod_sofia --- src/include/switch_core.h | 5 + .../applications/mod_commands/mod_commands.c | 153 ++++++++++++++++++ src/mod/endpoints/mod_sofia/mod_sofia.c | 1 + src/mod/endpoints/mod_sofia/sofia_reg.c | 13 +- src/switch_core_sqldb.c | 114 ++++++++++++- 5 files changed, 283 insertions(+), 3 deletions(-) diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 69b06420a3..984b54fac7 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -2227,6 +2227,11 @@ SWITCH_DECLARE(const char *) switch_core_banner(void); SWITCH_DECLARE(switch_bool_t) switch_core_session_in_thread(switch_core_session_t *session); SWITCH_DECLARE(uint32_t) switch_default_ptime(const char *name, uint32_t number); +SWITCH_DECLARE(switch_status_t) switch_core_add_registration(const char *user, const char *realm, const char *token, const char *url, uint32_t expires, + const char *network_ip, const char *network_port, const char *network_proto); +SWITCH_DECLARE(switch_status_t) switch_core_del_registration(const char *user, const char *realm, const char *token); +SWITCH_DECLARE(switch_status_t) switch_core_expire_registration(int force); + SWITCH_END_EXTERN_C #endif /* For Emacs: diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index f34042a54f..030cb8e867 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -45,6 +45,149 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_commands_shutdown); SWITCH_MODULE_DEFINITION(mod_commands, mod_commands_load, mod_commands_shutdown, NULL); + +struct cb_helper { + uint32_t row_process; + switch_stream_handle_t *stream; +}; + +static int url_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct cb_helper *cb = (struct cb_helper *) pArg; + + cb->row_process++; + + if (!zstr(argv[0])) { + cb->stream->write_function(cb->stream, "%s,", argv[0]); + } + + return 0; +} + +static switch_status_t select_url(const char *user, + const char *domain, + const char *concat, + const char *exclude_contact, + switch_stream_handle_t *stream) +{ + struct cb_helper cb; + char *sql, *errmsg = NULL; + switch_core_flag_t cflags = switch_core_flags(); + switch_cache_db_handle_t *db = NULL; + + if (!(cflags & SCF_USE_SQL)) { + stream->write_function(stream, "-ERR SQL DISABLED NO DATA AVAILABLE!\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (switch_core_db_handle(&db) != SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "%s", "-ERR Databse Error!\n"); + return SWITCH_STATUS_SUCCESS; + } + + cb.row_process = 0; + cb.stream = stream; + + if (exclude_contact) { + sql = switch_mprintf("select url, '%q' " + "from registrations where user='%q' and realm='%q' " + "and url not like '%%%s%%'", (concat != NULL) ? concat : "", user, domain, exclude_contact); + } else { + sql = switch_mprintf("select url, '%q' " + "from registrations where user='%q' and realm='%q'", + (concat != NULL) ? concat : "", user, domain); + } + + switch_assert(sql); + switch_cache_db_execute_sql_callback(db, sql, url_callback, &cb, &errmsg); + + if (errmsg) { + stream->write_function(stream, "-ERR SQL Error [%s]\n", errmsg); + free(errmsg); + errmsg = NULL; + } + + switch_safe_free(sql); + + if (db) { + switch_cache_db_release_db_handle(&db); + } + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_STANDARD_API(reg_url_function) +{ + char *data; + char *user = NULL; + char *domain = NULL, *dup_domain = NULL; + char *concat = NULL; + const char *exclude_contact = NULL; + char *reply = "error/facility_not_subscribed"; + switch_stream_handle_t mystream = { 0 }; + + + if (!cmd) { + stream->write_function(stream, "%s", ""); + return SWITCH_STATUS_SUCCESS; + } + + if (session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + exclude_contact = switch_channel_get_variable(channel, "sip_exclude_contact"); + } + + + data = strdup(cmd); + switch_assert(data); + + user = data; + + if ((domain = strchr(user, '@'))) { + *domain++ = '\0'; + if ((concat = strchr(domain, '/'))) { + *concat++ = '\0'; + } + } else { + if ((concat = strchr(user, '/'))) { + *concat++ = '\0'; + } + } + + if (zstr(domain)) { + dup_domain = switch_core_get_variable_dup("domain"); + domain = dup_domain; + } + + if (!user) goto end; + + + SWITCH_STANDARD_STREAM(mystream); + switch_assert(mystream.data); + + select_url(user, domain, concat, exclude_contact, &mystream); + reply = mystream.data; + + + end: + + if (zstr(reply)) { + reply = "error/user_not_registered"; + } else if (end_of(reply) == ',') { + end_of(reply) = '\0'; + } + + stream->write_function(stream, "%s", reply); + reply = NULL; + + switch_safe_free(mystream.data); + + switch_safe_free(data); + switch_safe_free(dup_domain); + + return SWITCH_STATUS_SUCCESS; +} + SWITCH_STANDARD_API(banner_function) { stream->write_function(stream, "%s", switch_core_banner()); @@ -3738,6 +3881,14 @@ SWITCH_STANDARD_API(show_function) as = argv[3]; } } + } else if (!strcasecmp(command, "registrations")) { + sprintf(sql, "select * from registrations where hostname='%s'", hostname); + if (argv[1] && !strcasecmp(argv[1], "count")) { + holder.justcount = 1; + if (argv[3] && !strcasecmp(argv[2], "as")) { + as = argv[3]; + } + } } else if (!strcasecmp(command, "channels") && argv[1] && !strcasecmp(argv[1], "like")) { if (argv[2]) { char *p; @@ -4890,6 +5041,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "tone_detect", "Start Tone Detection on a channel", tone_detect_session_function, TONE_DETECT_SYNTAX); SWITCH_ADD_API(commands_api_interface, "unload", "Unload Module", unload_function, UNLOAD_SYNTAX); SWITCH_ADD_API(commands_api_interface, "unsched_api", "Unschedule an api command", unsched_api_function, UNSCHED_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "reg_url", "", reg_url_function, "@"); SWITCH_ADD_API(commands_api_interface, "url_decode", "url decode a string", url_decode_function, ""); SWITCH_ADD_API(commands_api_interface, "url_encode", "url encode a string", url_encode_function, ""); SWITCH_ADD_API(commands_api_interface, "user_data", "find user data", user_data_function, "@ [var|param|attr] "); @@ -5000,6 +5152,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) switch_console_set_complete("add show management"); switch_console_set_complete("add show modules"); switch_console_set_complete("add show nat_map"); + switch_console_set_complete("add show registrations"); switch_console_set_complete("add show say"); switch_console_set_complete("add show timer"); switch_console_set_complete("add shutdown"); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 07c285fa66..4853dff3bf 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -3314,6 +3314,7 @@ static int contact_callback(void *pArg, int argc, char **argv, char **columnName return 0; } + static int sql2str_callback(void *pArg, int argc, char **argv, char **columnNames) { struct cb_helper_sql2str *cbt = (struct cb_helper_sql2str *) pArg; diff --git a/src/mod/endpoints/mod_sofia/sofia_reg.c b/src/mod/endpoints/mod_sofia/sofia_reg.c index 631cbdb14b..76b1dccd6b 100644 --- a/src/mod/endpoints/mod_sofia/sofia_reg.c +++ b/src/mod/endpoints/mod_sofia/sofia_reg.c @@ -877,6 +877,7 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand const char *agent = "unknown"; const char *pres_on_reg = NULL; int send_pres = 0; + int is_tls = 0, is_tcp = 0; delete_subs = sofia_test_pflag(profile, PFLAG_DEL_SUBS_ON_REG); @@ -944,8 +945,6 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand char *path_encoded = NULL; int path_encoded_len = 0; const char *proto = "sip"; - int is_tls = 0, is_tcp = 0; - if (switch_stristr("transport=tls", sip->sip_contact->m_url->url_params)) { is_tls += 1; @@ -1292,6 +1291,8 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand char guess_ip4[256]; const char *username = "unknown"; const char *realm = reg_host; + char *url = NULL; + char *contact = NULL; if (auth_params) { username = switch_event_get_header(auth_params, "sip_auth_username"); @@ -1327,7 +1328,15 @@ uint8_t sofia_reg_handle_register(nua_t *nua, sofia_profile_t *profile, nua_hand switch_find_local_ip(guess_ip4, sizeof(guess_ip4), NULL, AF_INET); + contact = sofia_glue_get_url_from_contact(contact_str, 1); + url = switch_mprintf("sofia/%q/sip:%q", profile->name, sofia_glue_strip_proto(contact)); + switch_core_add_registration(to_user, reg_host, call_id, url, (long) switch_epoch_time_now(NULL) + (long) exptime + 60, + network_ip, network_port_c, is_tls ? "tls" : is_tcp ? "tcp" : "udp"); + + switch_safe_free(url); + switch_safe_free(contact); + sql = switch_mprintf("insert into sip_registrations " "(call_id,sip_user,sip_host,presence_hosts,contact,status,rpid,expires," "user_agent,server_user,server_host,profile_name,hostname,network_ip,network_port,sip_username,sip_realm," diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 73890a1e4f..ba92ebcda7 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -87,6 +87,7 @@ SWITCH_DECLARE(switch_status_t) _switch_core_db_handle(switch_cache_db_handle_t #define SQL_CACHE_TIMEOUT 120 +#define SQL_REG_TIMEOUT 15 static void sql_close(time_t prune) { @@ -906,7 +907,7 @@ SWITCH_DECLARE(switch_bool_t) switch_cache_db_test_reactive(switch_cache_db_hand static void *SWITCH_THREAD_FUNC switch_core_sql_db_thread(switch_thread_t *thread, void *obj) { - int sec = 0; + int sec = 0, reg_sec = 0;; sql_manager.db_thread_running = 1; @@ -916,6 +917,11 @@ static void *SWITCH_THREAD_FUNC switch_core_sql_db_thread(switch_thread_t *threa wake_thread(0); sec = 0; } + + if (++reg_sec == SQL_REG_TIMEOUT) { + switch_core_expire_registration(0); + reg_sec = 0; + } switch_yield(1000000); } @@ -1616,6 +1622,108 @@ static char create_nat_sql[] = " hostname VARCHAR(256)\n" ");\n"; + +static char create_registrations_sql[] = + "CREATE TABLE registrations (\n" + " user VARCHAR(256),\n" + " realm VARCHAR(256),\n" + " token VARCHAR(256),\n" + " url TEXT,\n" + " expires INTEGER,\n" + " network_ip VARCHAR(256),\n" + " network_port VARCHAR(256),\n" + " network_proto VARCHAR(256),\n" + " hostname VARCHAR(256)\n" + ");\n" + "create index regindex1 on registrations (user,real,hostname);\n"; + + +SWITCH_DECLARE(switch_status_t) switch_core_add_registration(const char *user, const char *realm, const char *token, const char *url, uint32_t expires, + const char *network_ip, const char *network_port, const char *network_proto) +{ + switch_cache_db_handle_t *dbh; + char *sql; + + if (switch_core_db_handle(&dbh) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n"); + return SWITCH_STATUS_FALSE; + } + + sql = switch_mprintf("delete from registrations where hostname='%q' and (url='%q' or token='%q')", switch_core_get_hostname(), url, switch_str_nil(token)); + switch_cache_db_execute_sql(dbh, sql, NULL); + free(sql); + + sql = switch_mprintf("insert into registrations (user,realm,token,url,expires,network_ip,network_port,network_proto,hostname) " + "values ('%q','%q','%q','%q',%ld,'%q','%q','%q','%q')", + switch_str_nil(user), + switch_str_nil(realm), + switch_str_nil(token), + switch_str_nil(url), + expires, + switch_str_nil(network_ip), + switch_str_nil(network_port), + switch_str_nil(network_proto), + switch_core_get_hostname() + ); + + switch_cache_db_execute_sql(dbh, sql, NULL); + switch_cache_db_release_db_handle(&dbh); + + free(sql); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(switch_status_t) switch_core_del_registration(const char *user, const char *realm, const char *token) +{ + + switch_cache_db_handle_t *dbh; + char *sql; + + if (switch_core_db_handle(&dbh) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n"); + return SWITCH_STATUS_FALSE; + } + + sql = switch_mprintf("delete from registrations where user='%q' and realm='%q' and hostname='%q'", user, realm, switch_core_get_hostname()); + + switch_cache_db_execute_sql(dbh, sql, NULL); + switch_cache_db_release_db_handle(&dbh); + + free(sql); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_DECLARE(switch_status_t) switch_core_expire_registration(int force) +{ + + switch_cache_db_handle_t *dbh; + char *sql; + switch_time_t now; + + if (switch_core_db_handle(&dbh) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n"); + return SWITCH_STATUS_FALSE; + } + + now = switch_epoch_time_now(NULL); + + if (force) { + sql = switch_mprintf("delete from registrations where hostname='%q'", switch_core_get_hostname()); + } else { + sql = switch_mprintf("delete from registrations where expires <= %ld and hostname='%q'", now, switch_core_get_hostname()); + } + + switch_cache_db_execute_sql(dbh, sql, NULL); + switch_cache_db_release_db_handle(&dbh); + + free(sql); + + return SWITCH_STATUS_SUCCESS; + +} + switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_t manage) { switch_threadattr_t *thd_attr; @@ -1690,6 +1798,8 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ switch_cache_db_test_reactive(dbh, "select hostname from complete", "DROP TABLE complete", create_complete_sql); switch_cache_db_test_reactive(dbh, "select hostname from aliases", "DROP TABLE aliases", create_alias_sql); switch_cache_db_test_reactive(dbh, "select hostname from nat", "DROP TABLE nat", create_nat_sql); + switch_cache_db_test_reactive(dbh, "delete from registrations where network_proto='tcp' or network_proto='tls'", + "DROP TABLE registrations", create_registrations_sql); switch (dbh->type) { @@ -1706,6 +1816,8 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ } switch_cache_db_test_reactive(dbh, "select ikey from interfaces", "DROP TABLE interfaces", create_interfaces_sql); switch_cache_db_test_reactive(dbh, "select hostname from tasks", "DROP TABLE tasks", create_tasks_sql); + switch_cache_db_test_reactive(dbh, "delete from registrations where network_proto='tcp' or network_proto='tls'", + "DROP TABLE registrations", create_registrations_sql); if (runtime.odbc_dbtype == DBTYPE_DEFAULT) { switch_cache_db_execute_sql(dbh, "begin;delete from channels where hostname='';delete from channels where hostname='';commit;", &err);