freeswitch/src/switch_core.c
Anthony Minessale 6c7a868c6e add global_setvar/getvar api command
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@6195 d0543943-73ff-0310-b7d9-9358b9ac24b2
2007-11-09 16:12:11 +00:00

947 lines
27 KiB
C

/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
* Michael Jerris <mike@jerris.com>
* Paul D. Tinsley <pdt at jackhammer.org>
* Marcel Barbulescu <marcelbarbulescu@gmail.com>
*
*
* switch_core.c -- Main Core Library
*
*/
#include <switch.h>
#include <switch_version.h>
#include "private/switch_core_pvt.h"
SWITCH_DECLARE_DATA switch_directories SWITCH_GLOBAL_dirs = { 0 };
/* The main runtime obj we keep this hidden for ourselves */
struct switch_runtime runtime;
static void send_heartbeat(void)
{
switch_event_t *event;
switch_core_time_duration_t duration;
switch_core_measure_time(switch_core_uptime(), &duration);
if (switch_event_create(&event, SWITCH_EVENT_HEARTBEAT) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Event-Info", "System Ready");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Up-Time",
"%u year%s, "
"%u day%s, "
"%u hour%s, "
"%u minute%s, "
"%u second%s, "
"%u millisecond%s, "
"%u microsecond%s",
duration.yr, duration.yr == 1 ? "" : "s",
duration.day, duration.day == 1 ? "" : "s",
duration.hr, duration.hr == 1 ? "" : "s",
duration.min, duration.min == 1 ? "" : "s",
duration.sec, duration.sec == 1 ? "" : "s",
duration.ms, duration.ms == 1 ? "" : "s", duration.mms, duration.mms == 1 ? "" : "s");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Session-Count", "%u", switch_core_session_count());
switch_event_fire(&event);
}
}
SWITCH_STANDARD_SCHED_FUNC(heartbeat_callback)
{
send_heartbeat();
/* reschedule this task */
task->runtime = time(NULL) + 20;
}
SWITCH_DECLARE(switch_time_t) switch_timestamp_now(void)
{
return runtime.timestamp ? runtime.timestamp : switch_time_now();
}
SWITCH_DECLARE(switch_status_t) switch_core_set_console(const char *console)
{
if ((runtime.console = fopen(console, "a")) == 0) {
fprintf(stderr, "Cannot open output file %s.\n", console);
return SWITCH_STATUS_FALSE;
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(FILE *) switch_core_get_console(void)
{
return runtime.console;
}
SWITCH_DECLARE(FILE *) switch_core_data_channel(switch_text_channel_t channel)
{
FILE *handle = stdout;
switch (channel) {
case SWITCH_CHANNEL_ID_LOG:
case SWITCH_CHANNEL_ID_LOG_CLEAN:
handle = runtime.console;
break;
default:
handle = runtime.console;
break;
}
return handle;
}
SWITCH_DECLARE(int) switch_core_add_state_handler(const switch_state_handler_table_t *state_handler)
{
int index = runtime.state_handler_index++;
if (runtime.state_handler_index >= SWITCH_MAX_STATE_HANDLERS) {
return -1;
}
runtime.state_handlers[index] = state_handler;
return index;
}
SWITCH_DECLARE(const switch_state_handler_table_t *) switch_core_get_state_handler(int index)
{
if (index > SWITCH_MAX_STATE_HANDLERS || index > runtime.state_handler_index) {
return NULL;
}
return runtime.state_handlers[index];
}
SWITCH_DECLARE(char *) switch_core_get_variable(const char *varname)
{
char *val;
switch_mutex_lock(runtime.throttle_mutex);
val = (char *) switch_core_hash_find(runtime.global_vars, varname);
switch_mutex_unlock(runtime.throttle_mutex);
return val;
}
SWITCH_DECLARE(void) switch_core_set_variable(const char *varname, const char *value)
{
char *val;
if (varname) {
switch_mutex_lock(runtime.throttle_mutex);
val = (char *) switch_core_hash_find(runtime.global_vars, varname);
if (val) {
free(val);
}
if (value) {
switch_core_hash_insert(runtime.global_vars, varname, strdup(value));
} else {
switch_core_hash_delete(runtime.global_vars, varname);
}
switch_mutex_unlock(runtime.throttle_mutex);
}
}
SWITCH_DECLARE(char *) switch_core_get_uuid(void)
{
return runtime.uuid_str;
}
static void *switch_core_service_thread(switch_thread_t * thread, void *obj)
{
switch_core_thread_session_t *data = obj;
switch_core_session_t *session = data->objs[0];
int *stream_id_p = data->objs[1];
switch_channel_t *channel;
switch_frame_t *read_frame;
int stream_id = *stream_id_p;
assert(thread != NULL);
assert(session != NULL);
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
switch_channel_set_flag(channel, CF_SERVICE);
while (data->running > 0) {
switch (switch_core_session_read_frame(session, &read_frame, -1, stream_id)) {
case SWITCH_STATUS_SUCCESS:
case SWITCH_STATUS_TIMEOUT:
case SWITCH_STATUS_BREAK:
break;
default:
data->running = -1;
continue;
}
}
switch_channel_clear_flag(channel, CF_SERVICE);
data->running = 0;
return NULL;
}
/* Either add a timeout here or make damn sure the thread cannot get hung somehow (my preference) */
SWITCH_DECLARE(void) switch_core_thread_session_end(switch_core_thread_session_t *thread_session)
{
if (thread_session->running > 0) {
thread_session->running = -1;
while (thread_session->running) {
switch_yield(1000);
}
}
}
SWITCH_DECLARE(void) switch_core_service_session(switch_core_session_t *session, switch_core_thread_session_t *thread_session, int stream_id)
{
thread_session->running = 1;
thread_session->objs[0] = session;
thread_session->objs[1] = &stream_id;
switch_core_session_launch_thread(session, switch_core_service_thread, thread_session);
}
/* This function abstracts the thread creation for modules by allowing you to pass a function ptr and
a void object and trust that that the function will be run in a thread with arg This lets
you request and activate a thread without giving up any knowledge about what is in the thread
neither the core nor the calling module know anything about each other.
This thread is expected to never exit until the application exits so the func is responsible
to make sure that is the case.
The typical use for this is so switch_loadable_module.c can start up a thread for each module
passing the table of module methods as a session obj into the core without actually allowing
the core to have any clue and keeping switch_loadable_module.c from needing any thread code.
*/
SWITCH_DECLARE(void) switch_core_launch_thread(switch_thread_start_t func, void *obj, switch_memory_pool_t *pool)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_core_thread_session_t *ts;
int mypool;
mypool = pool ? 0 : 1;
if (!pool && switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not allocate memory pool\n");
return;
}
switch_threadattr_create(&thd_attr, pool);
switch_threadattr_detach_set(thd_attr, 1);
if ((ts = switch_core_alloc(pool, sizeof(*ts))) == 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not allocate memory\n");
} else {
if (mypool) {
ts->pool = pool;
}
ts->objs[0] = obj;
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, func, ts, pool);
}
}
SWITCH_DECLARE(void) switch_core_set_globals(void)
{
char *dir_path;
#define BUFSIZE 1024
#ifdef WIN32
char lpPathBuffer[BUFSIZE];
DWORD dwBufSize = BUFSIZE;
char base_dir[1024];
char *lastbacklash;
GetModuleFileName(NULL, base_dir, BUFSIZE);
lastbacklash = strrchr(base_dir, '\\');
base_dir[(lastbacklash - base_dir)] = '\0';
#else
char base_dir[1024] = SWITCH_PREFIX_DIR;
#endif
if (!SWITCH_GLOBAL_dirs.base_dir && (SWITCH_GLOBAL_dirs.base_dir = (char *) malloc(BUFSIZE))) {
switch_snprintf(SWITCH_GLOBAL_dirs.base_dir, BUFSIZE, "%s", base_dir);
}
if (!SWITCH_GLOBAL_dirs.mod_dir && (SWITCH_GLOBAL_dirs.mod_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_MOD_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.mod_dir, BUFSIZE, "%s", SWITCH_MOD_DIR);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.mod_dir, BUFSIZE, "%s%smod", base_dir, SWITCH_PATH_SEPARATOR);
#endif
}
if (!SWITCH_GLOBAL_dirs.conf_dir && (SWITCH_GLOBAL_dirs.conf_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_CONF_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.conf_dir, BUFSIZE, "%s", SWITCH_CONF_DIR);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.conf_dir, BUFSIZE, "%s%sconf", base_dir, SWITCH_PATH_SEPARATOR);
#endif
}
if (!SWITCH_GLOBAL_dirs.log_dir && (SWITCH_GLOBAL_dirs.log_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_LOG_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.log_dir, BUFSIZE, "%s", SWITCH_LOG_DIR);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.log_dir, BUFSIZE, "%s%slog", base_dir, SWITCH_PATH_SEPARATOR);
#endif
}
if (!SWITCH_GLOBAL_dirs.storage_dir && (SWITCH_GLOBAL_dirs.storage_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_STORAGE_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.storage_dir, BUFSIZE, "%s", SWITCH_STORAGE_DIR);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.storage_dir, BUFSIZE, "%s%sstorage", base_dir, SWITCH_PATH_SEPARATOR);
#endif
}
if (!SWITCH_GLOBAL_dirs.db_dir && (SWITCH_GLOBAL_dirs.db_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_DB_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.db_dir, BUFSIZE, "%s", SWITCH_DB_DIR);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.db_dir, BUFSIZE, "%s%sdb", base_dir, SWITCH_PATH_SEPARATOR);
#endif
}
if (!SWITCH_GLOBAL_dirs.script_dir && (SWITCH_GLOBAL_dirs.script_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_SCRIPT_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.script_dir, BUFSIZE, "%s", SWITCH_SCRIPT_DIR);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.script_dir, BUFSIZE, "%s%sscripts", base_dir, SWITCH_PATH_SEPARATOR);
#endif
}
if (!SWITCH_GLOBAL_dirs.htdocs_dir && (SWITCH_GLOBAL_dirs.htdocs_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_HTDOCS_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.htdocs_dir, BUFSIZE, "%s", SWITCH_HTDOCS_DIR);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.htdocs_dir, BUFSIZE, "%s%shtdocs", base_dir, SWITCH_PATH_SEPARATOR);
#endif
}
if (!SWITCH_GLOBAL_dirs.grammar_dir && (SWITCH_GLOBAL_dirs.grammar_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_GRAMMAR_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.grammar_dir, BUFSIZE, "%s", SWITCH_GRAMMAR_DIR);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.grammar_dir, BUFSIZE, "%s%sgrammar", base_dir, SWITCH_PATH_SEPARATOR);
#endif
}
if (!SWITCH_GLOBAL_dirs.temp_dir && (SWITCH_GLOBAL_dirs.temp_dir = (char *) malloc(BUFSIZE))) {
#ifdef SWITCH_TEMP_DIR
switch_snprintf(SWITCH_GLOBAL_dirs.temp_dir, BUFSIZE, "%s", SWITCH_TEMP_DIR);
#else
#ifdef WIN32
GetTempPath(dwBufSize, lpPathBuffer);
switch_snprintf(SWITCH_GLOBAL_dirs.temp_dir, BUFSIZE, "%s", lpPathBuffer);
#else
switch_snprintf(SWITCH_GLOBAL_dirs.temp_dir, BUFSIZE, "%s", "/tmp/");
#endif
#endif
}
dir_path = switch_mprintf("%s%ssounds", SWITCH_GLOBAL_dirs.base_dir, SWITCH_PATH_SEPARATOR);
switch_dir_make_recursive(dir_path,
SWITCH_FPROT_UREAD | SWITCH_FPROT_UWRITE | SWITCH_FPROT_UEXECUTE | SWITCH_FPROT_GREAD | SWITCH_FPROT_GEXECUTE,
runtime.memory_pool);
switch_safe_free(dir_path);
}
SWITCH_DECLARE(int32_t) set_high_priority(void)
{
#ifdef WIN32
SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
#else
#ifdef USE_SETRLIMIT
struct rlimit lim = { RLIM_INFINITY, RLIM_INFINITY };
#endif
#ifdef USE_SCHED_SETSCHEDULER
/*
* Try to use a round-robin scheduler
* with a fallback if that does not work
*/
struct sched_param sched = { 0 };
sched.sched_priority = 1;
if (sched_setscheduler(0, SCHED_RR, &sched)) {
sched.sched_priority = 0;
if (sched_setscheduler(0, SCHED_OTHER, &sched)) {
return -1;
}
}
#endif
#ifdef HAVE_SETPRIORITY
/*
* setpriority() works on FreeBSD (6.2), nice() doesn't
*/
if (setpriority(PRIO_PROCESS, getpid(), -10) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
}
#else
if (nice(-10) != -10) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not set nice level\n");
}
#endif
#ifdef USE_SETRLIMIT
/*
* The amount of memory which can be mlocked is limited for non-root users.
* FS will segfault (= hitting the limit) soon after mlockall has been called
* and we've switched to a different user.
* So let's try to remove the mlock limit here...
*/
if (setrlimit(RLIMIT_MEMLOCK, &lim) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
"Failed to disable memlock limit, application may crash if run as non-root user!\n");
}
#endif
#ifdef USE_MLOCKALL
/*
* Pin memory pages to RAM to prevent being swapped to disk
*/
mlockall(MCL_CURRENT | MCL_FUTURE);
#endif
#endif
return 0;
}
SWITCH_DECLARE(int32_t) change_user_group(const char *user, const char *group)
{
#ifndef WIN32
uid_t runas_uid = 0;
gid_t runas_gid = 0;
struct passwd *runas_pw = NULL;
if (user) {
/*
* Lookup user information in the system's db
*/
runas_pw = getpwnam( user );
if (!runas_pw) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unknown user \"%s\"\n", user);
return -1;
}
runas_uid = runas_pw->pw_uid;
}
if (group) {
struct group *gr = NULL;
/*
* Lookup group information in the system's db
*/
gr = getgrnam( group );
if (!gr) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unknown group \"%s\"\n", group);
return -1;
}
runas_gid = gr->gr_gid;
}
if (runas_uid) {
#ifdef HAVE_SETGROUPS
/*
* Drop all group memberships prior to changing anything
* or else we're going to inherit the parent's list of groups
* (which is not what we want...)
*/
if (setgroups(0, NULL) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to drop group access list\n");
return -1;
}
#endif
if (runas_gid) {
/*
* A group has been passed, switch to it
* (without loading the user's other groups)
*/
if (setgid(runas_gid) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n");
return -1;
}
} else {
/*
* No group has been passed, use the user's primary group in this case
*/
if (setgid(runas_pw->pw_gid) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change gid!\n");
return -1;
}
#ifdef HAVE_INITGROUPS
/*
* Set all the other groups the user is a member of
* (This can be really useful for fine-grained access control)
*/
if (initgroups(runas_pw->pw_name, runas_pw->pw_gid) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to set group access list for user\n");
return -1;
}
#endif
}
/*
* Finally drop all privileges by switching to the new userid
*/
if (setuid(runas_uid) < 0) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Failed to change uid!\n");
return -1;
}
}
#endif
return 0;
}
SWITCH_DECLARE(void) switch_core_runtime_loop(int bg)
{
#ifdef WIN32
HANDLE shutdown_event;
char path[256] = "";
#endif
if (bg) {
bg = 0;
#ifdef WIN32
snprintf(path, sizeof(path), "Global\\Freeswitch.%d", getpid());
shutdown_event = CreateEvent(NULL, FALSE, FALSE, path);
WaitForSingleObject(shutdown_event, INFINITE);
#else
runtime.running = 1;
while (runtime.running) {
switch_yield(1000000);
}
#endif
} else {
/* wait for console input */
switch_console_loop();
}
}
SWITCH_DECLARE(switch_status_t) switch_core_init(const char *console, switch_core_flag_t flags, const char **err)
{
switch_xml_t xml = NULL, cfg = NULL;
switch_uuid_t uuid;
char guess_ip[256];
memset(&runtime, 0, sizeof(runtime));
switch_set_flag((&runtime), SCF_NO_NEW_SESSIONS);
runtime.hard_log_level = SWITCH_LOG_DEBUG;
runtime.mailer_app = "sendmail";
runtime.mailer_app_args = "-t";
/* INIT APR and Create the pool context */
if (apr_initialize() != SWITCH_STATUS_SUCCESS) {
*err = "FATAL ERROR! Could not initilize APR\n";
return SWITCH_STATUS_MEMERR;
}
if (!(runtime.memory_pool = switch_core_memory_init())) {
*err = "FATAL ERROR! Could noat allocate memory pool\n";
return SWITCH_STATUS_MEMERR;
}
assert(runtime.memory_pool != NULL);
switch_mutex_init(&runtime.throttle_mutex, SWITCH_MUTEX_NESTED, runtime.memory_pool);
switch_core_set_globals();
switch_core_session_init(runtime.memory_pool);
switch_core_hash_init(&runtime.global_vars, runtime.memory_pool);
runtime.flags = flags;
runtime.sps_total = 30;
switch_find_local_ip(guess_ip, sizeof(guess_ip), AF_INET);
switch_core_set_variable("local_ip_v4", guess_ip);
switch_find_local_ip(guess_ip, sizeof(guess_ip), AF_INET6);
switch_core_set_variable("local_ip_v6", guess_ip);
if (switch_xml_init(runtime.memory_pool, err) != SWITCH_STATUS_SUCCESS) {
apr_terminate();
return SWITCH_STATUS_MEMERR;
}
if ((xml = switch_xml_open_cfg("switch.conf", &cfg, NULL))) {
switch_xml_t settings, param;
if ((settings = switch_xml_child(cfg, "settings"))) {
for (param = switch_xml_child(settings, "param"); param; param = param->next) {
const char *var = switch_xml_attr_soft(param, "name");
const char *val = switch_xml_attr_soft(param, "value");
if (!strcasecmp(var, "crash-protection")) {
if (switch_true(val)) {
switch_set_flag((&runtime), SCF_CRASH_PROT);
}
} else if (!strcasecmp(var, "loglevel")) {
int level;
if (*val > 47 && *val < 58) {
level = atoi(val);
} else {
level = switch_log_str2level(val);
}
switch_core_session_ctl(SCSC_LOGLEVEL, &level);
} else if (!strcasecmp(var, "mailer-app")) {
runtime.mailer_app = switch_core_strdup(runtime.memory_pool, val);
} else if (!strcasecmp(var, "mailer-app-args")) {
runtime.mailer_app_args = switch_core_strdup(runtime.memory_pool, val);
} else if (!strcasecmp(var, "sessions-per-second")) {
switch_core_sessions_per_second(atoi(val));
} else if (!strcasecmp(var, "max-sessions")) {
switch_core_session_limit(atoi(val));
}
else if (!strcasecmp(var, "rtp-start-port")) {
switch_rtp_set_start_port((switch_port_t)atoi(val));
}
else if (!strcasecmp(var, "rtp-end-port")) {
switch_rtp_set_end_port((switch_port_t)atoi(val));
}
}
}
if ((settings = switch_xml_child(cfg, "variables"))) {
for (param = switch_xml_child(settings, "variable"); param; param = param->next) {
const char *var = switch_xml_attr_soft(param, "name");
const char *val = switch_xml_attr_soft(param, "value");
char *varr = NULL, *vall = NULL;
varr = switch_core_strdup(runtime.memory_pool, var);
vall = switch_core_strdup(runtime.memory_pool, val);
switch_core_hash_insert(runtime.global_vars, varr, vall);
}
}
switch_xml_free(xml);
}
switch_core_state_machine_init(runtime.memory_pool);
*err = NULL;
if (console) {
if (*console != '/') {
char path[265];
snprintf(path, sizeof(path), "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, console);
console = path;
}
if (switch_core_set_console(console) != SWITCH_STATUS_SUCCESS) {
*err = "FATAL ERROR! Could not open console\n";
apr_terminate();
return SWITCH_STATUS_GENERR;
}
} else {
runtime.console = stdout;
}
assert(runtime.memory_pool != NULL);
switch_log_init(runtime.memory_pool);
switch_event_init(runtime.memory_pool);
if (switch_test_flag((&runtime), SCF_USE_SQL)) {
switch_core_sqldb_start(runtime.memory_pool);
}
switch_rtp_init(runtime.memory_pool);
runtime.running = 1;
switch_scheduler_task_thread_start();
runtime.initiated = switch_time_now();
switch_scheduler_add_task(time(NULL), heartbeat_callback, "heartbeat", "core", 0, NULL, SSHF_NONE | SSHF_NO_DEL);
switch_uuid_get(&uuid);
switch_uuid_format(runtime.uuid_str, &uuid);
return SWITCH_STATUS_SUCCESS;
}
#ifdef SIGPIPE
static void handle_SIGPIPE(int sig)
{
if (sig);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Sig Pipe!\n");
return;
}
#endif
#ifdef SIGPOLL
static void handle_SIGPOLL(int sig)
{
if (sig);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Sig Poll!\n");
return;
}
#endif
#ifdef SIGIO
static void handle_SIGIO(int sig)
{
if (sig);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Sig I/O!\n");
return;
}
#endif
#ifdef TRAP_BUS
static void handle_SIGBUS(int sig)
{
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Sig BUS!\n");
return;
}
#endif
/* no ctl-c mofo */
static void handle_SIGINT(int sig)
{
if (sig);
return;
}
SWITCH_DECLARE(switch_status_t) switch_core_init_and_modload(const char *console, switch_core_flag_t flags, const char **err)
{
switch_event_t *event;
if (switch_core_init(console, flags, err) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_GENERR;
}
/* set signal handlers */
signal(SIGINT, handle_SIGINT);
#ifdef SIGPIPE
signal(SIGPIPE, handle_SIGPIPE);
#endif
#ifdef SIGPOLL
signal(SIGPOLL, handle_SIGPOLL);
#endif
#ifdef SIGIO
signal(SIGIO, handle_SIGIO);
#endif
#ifdef TRAP_BUS
signal(SIGBUS, handle_SIGBUS);
#endif
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Bringing up environment.\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Loading Modules.\n");
if (switch_loadable_module_init() != SWITCH_STATUS_SUCCESS) {
*err = "Cannot load modules";
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Error: %s", *err);
return SWITCH_STATUS_GENERR;
}
if (switch_event_create(&event, SWITCH_EVENT_STARTUP) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Event-Info", "System Ready");
switch_event_fire(&event);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE,
"\nFreeSWITCH Version %s Started.\nCrash Protection [%s]\nMax Sessions[%u]\nSession Rate[%d]\nSQL [%s]\n", SWITCH_VERSION_FULL,
switch_test_flag((&runtime), SCF_CRASH_PROT) ? "Enabled" : "Disabled",
switch_core_session_limit(0),
switch_core_sessions_per_second(0),
switch_test_flag((&runtime), SCF_USE_SQL) ? "Enabled" : "Disabled"
);
switch_clear_flag((&runtime), SCF_NO_NEW_SESSIONS);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(void) switch_core_measure_time(switch_time_t total_ms, switch_core_time_duration_t *duration)
{
switch_time_t temp = total_ms / 1000;
memset(duration, 0, sizeof(*duration));
duration->mms = (uint32_t) (total_ms % 1000);
duration->ms = (uint32_t) (temp % 1000);
temp = temp / 1000;
duration->sec = (uint32_t) (temp % 60);
temp = temp / 60;
duration->min = (uint32_t) (temp % 60);
temp = temp / 60;
duration->hr = (uint32_t) (temp % 24);
temp = temp / 24;
duration->day = (uint32_t) (temp % 365);
duration->yr = (uint32_t) (temp / 365);
}
SWITCH_DECLARE(switch_time_t) switch_core_uptime(void)
{
return switch_time_now() - runtime.initiated;
}
SWITCH_DECLARE(int32_t) switch_core_session_ctl(switch_session_ctl_t cmd, int32_t * val)
{
if (switch_test_flag((&runtime), SCF_SHUTTING_DOWN)) {
return -1;
}
switch (cmd) {
case SCSC_PAUSE_INBOUND:
if (*val) {
switch_set_flag((&runtime), SCF_NO_NEW_SESSIONS);
} else {
switch_clear_flag((&runtime), SCF_NO_NEW_SESSIONS);
}
break;
case SCSC_HUPALL:
switch_core_session_hupall(SWITCH_CAUSE_MANAGER_REQUEST);
break;
case SCSC_SHUTDOWN:
runtime.running = 0;
break;
case SCSC_CHECK_RUNNING:
*val = runtime.running;
break;
case SCSC_LOGLEVEL:
if (*val > -1) {
runtime.hard_log_level = *val;
}
if (runtime.hard_log_level > SWITCH_LOG_DEBUG) {
runtime.hard_log_level = SWITCH_LOG_DEBUG;
}
*val = runtime.hard_log_level;
break;
case SCSC_MAX_SESSIONS:
*val = switch_core_session_limit(*val);
break;
case SCSC_LAST_SPS:
*val = runtime.sps_last;
break;
case SCSC_SPS:
switch_mutex_lock(runtime.throttle_mutex);
if (*val > 0) {
runtime.sps_total = *val;
}
*val = runtime.sps_total;
switch_mutex_unlock(runtime.throttle_mutex);
break;
case SCSC_RECLAIM:
switch_core_memory_reclaim_all();
*val = 0;
break;
}
return 0;
}
SWITCH_DECLARE(switch_core_flag_t) switch_core_flags(void)
{
return runtime.flags;
}
SWITCH_DECLARE(switch_bool_t) switch_core_ready(void)
{
return (switch_test_flag((&runtime), SCF_SHUTTING_DOWN) || switch_test_flag((&runtime), SCF_NO_NEW_SESSIONS)) ? SWITCH_FALSE : SWITCH_TRUE;
}
SWITCH_DECLARE(switch_status_t) switch_core_destroy(void)
{
switch_event_t *event;
if (switch_event_create(&event, SWITCH_EVENT_SHUTDOWN) == SWITCH_STATUS_SUCCESS) {
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Event-Info", "System Shutting Down");
switch_event_fire(&event);
}
switch_set_flag((&runtime), SCF_NO_NEW_SESSIONS);
switch_set_flag((&runtime), SCF_SHUTTING_DOWN);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "End existing sessions\n");
switch_core_session_hupall(SWITCH_CAUSE_SYSTEM_SHUTDOWN);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Clean up modules.\n");
switch_loadable_module_shutdown();
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Closing Event Engine.\n");
switch_event_shutdown();
if (switch_test_flag((&runtime), SCF_USE_SQL)) {
switch_core_sqldb_stop();
}
switch_scheduler_task_thread_stop();
switch_xml_destroy();
switch_core_memory_stop();
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CONSOLE, "Finalizing Shutdown.\n");
switch_log_shutdown();
if (runtime.console != stdout && runtime.console != stderr) {
fclose(runtime.console);
runtime.console = NULL;
}
switch_safe_free(SWITCH_GLOBAL_dirs.base_dir);
switch_safe_free(SWITCH_GLOBAL_dirs.mod_dir);
switch_safe_free(SWITCH_GLOBAL_dirs.conf_dir);
switch_safe_free(SWITCH_GLOBAL_dirs.log_dir);
switch_safe_free(SWITCH_GLOBAL_dirs.db_dir);
switch_safe_free(SWITCH_GLOBAL_dirs.script_dir);
switch_safe_free(SWITCH_GLOBAL_dirs.htdocs_dir);
switch_safe_free(SWITCH_GLOBAL_dirs.grammar_dir);
switch_safe_free(SWITCH_GLOBAL_dirs.temp_dir);
switch_core_hash_destroy(&runtime.global_vars);
if (runtime.memory_pool) {
apr_pool_destroy(runtime.memory_pool);
/* apr_terminate(); */
}
return SWITCH_STATUS_SUCCESS;
}
SWITCH_DECLARE(void) switch_core_memory_reclaim_all(void)
{
switch_core_memory_reclaim_logger();
switch_core_memory_reclaim_events();
switch_core_memory_reclaim();
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/