static void do_unload(void) { switch_hash_index_t *hi = NULL; switch_mutex_lock(MUTEX); while ((hi = switch_core_hash_first( globals.translate_profiles))) { void *val = NULL; const void *key; switch_ssize_t keylen; translate_rule_t *rl, *nrl; switch_core_hash_this(hi, &key, &keylen, &val); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "deleting translate profile [%s]\n", (char *) key); for (nrl = val; rl;) { rl = nrl; nrl = nrl->next; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "deleting rule for [%s]\n", rl->regex); switch_safe_free(rl->regex); switch_safe_free(rl->replace); switch_safe_free(rl); } switch_core_hash_delete_wrlock(globals.translate_profiles, key, globals.profile_hash_rwlock); } switch_thread_rwlock_destroy(globals.profile_hash_rwlock); switch_core_hash_destroy(&globals.translate_profiles); switch_mutex_unlock(MUTEX); }
void limit_remote_destroy(limit_remote_t **r) { if (r && *r) { switch_hash_index_t *hi; (*r)->state = REMOTE_OFF; if ((*r)->thread) { switch_status_t retval; switch_thread_join(&retval, (*r)->thread); } switch_thread_rwlock_wrlock((*r)->rwlock); /* Free hashtable data */ for (hi = switch_hash_first(NULL, (*r)->index); hi; hi = switch_hash_next(hi)) { void *val; const void *key; switch_ssize_t keylen; switch_hash_this(hi, &key, &keylen, &val); free(val); } switch_thread_rwlock_unlock((*r)->rwlock); switch_thread_rwlock_destroy((*r)->rwlock); switch_core_destroy_memory_pool(&((*r)->pool)); *r = NULL; } }
void mod_format_cdr_profile_shutdown(cdr_profile_t *profile) { int err_dir_index = 0; for (err_dir_index = 0; err_dir_index < profile->err_dir_count; err_dir_index++) { switch_safe_free(profile->err_log_dir[err_dir_index]); } switch_safe_free(profile->log_dir); switch_thread_rwlock_destroy(profile->log_path_lock); switch_core_destroy_memory_pool(&profile->pool); }
static inline void free_context(shout_context_t *context) { int ret; if (context) { switch_mutex_lock(context->audio_mutex); context->err++; switch_mutex_unlock(context->audio_mutex); if (context->stream_url) { int sanity = 0; while (context->thread_running) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Waiting for stream to terminate: %s\n", context->stream_url); switch_yield(500000); if (++sanity > 10) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Giving up waiting for stream to terminate: %s\n", context->stream_url); break; } } } switch_thread_rwlock_wrlock(context->rwlock); if (context->mh) { mpg123_close(context->mh); mpg123_delete(context->mh); } if (context->fp) { unsigned char mp3buffer[8192]; int len; int16_t blank[2048] = { 0 }, *r = NULL; if (context->channels == 2) { r = blank; } len = lame_encode_buffer(context->gfp, blank, r, sizeof(blank) / 2, mp3buffer, sizeof(mp3buffer)); if (len) { ret = fwrite(mp3buffer, 1, len, context->fp); } while ((len = lame_encode_flush(context->gfp, mp3buffer, sizeof(mp3buffer))) > 0) { ret = fwrite(mp3buffer, 1, len, context->fp); if (ret < 0) { break; } } lame_mp3_tags_fid(context->gfp, context->fp); fclose(context->fp); context->fp = NULL; } if (context->shout) { shout_close(context->shout); context->shout = NULL; } if (context->gfp) { lame_close(context->gfp); context->gfp = NULL; } if (context->audio_buffer) { switch_buffer_destroy(&context->audio_buffer); } switch_mutex_destroy(context->audio_mutex); switch_thread_rwlock_unlock(context->rwlock); switch_thread_rwlock_destroy(context->rwlock); } }
static switch_status_t my_on_reporting(switch_core_session_t *session) { cJSON *json_cdr = NULL; char *json_text = NULL; char *path = NULL; char *curl_json_text = NULL; const char *logdir = NULL; char *json_text_escaped = NULL; int fd = -1, err_dir_index; uint32_t cur_try; long httpRes; CURL *curl_handle = NULL; switch_curl_slist_t *headers = NULL; switch_curl_slist_t *slist = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); switch_status_t status = SWITCH_STATUS_FALSE; int is_b; const char *a_prefix = ""; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } is_b = channel && switch_channel_get_originator_caller_profile(channel); if (!globals.log_b && is_b) { const char *force_cdr = switch_channel_get_variable(channel, SWITCH_FORCE_PROCESS_CDR_VARIABLE); if (!switch_true(force_cdr)) { return SWITCH_STATUS_SUCCESS; } } if (!is_b && globals.prefix_a) a_prefix = "a_"; if (switch_ivr_generate_json_cdr(session, &json_cdr, globals.encode_values == ENCODING_DEFAULT) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Generating Data!\n"); return SWITCH_STATUS_FALSE; } json_text = cJSON_PrintUnformatted(json_cdr); if (!json_text) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); goto error; } switch_thread_rwlock_rdlock(globals.log_path_lock); if (!(logdir = switch_channel_get_variable(channel, "json_cdr_base"))) { logdir = globals.log_dir; } if (!zstr(logdir) && (globals.log_http_and_disk || !globals.url_count)) { path = switch_mprintf("%s%s%s%s.cdr.json", logdir, SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session)); switch_thread_rwlock_unlock(globals.log_path_lock); if (path) { #ifdef _MSC_VER if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { #else if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { #endif int wrote; wrote = write(fd, json_text, (unsigned) strlen(json_text)); close(fd); fd = -1; if(wrote < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s]\n",path); } } else { char ebuf[512] = { 0 }; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s][%s]\n", path, switch_strerror_r(errno, ebuf, sizeof(ebuf))); } switch_safe_free(path); } } else { switch_thread_rwlock_unlock(globals.log_path_lock); } /* try to post it to the web server */ if (globals.url_count) { char *destUrl = NULL; curl_handle = switch_curl_easy_init(); if (globals.encode) { switch_size_t need_bytes = strlen(json_text) * 3; json_text_escaped = malloc(need_bytes); switch_assert(json_text_escaped); memset(json_text_escaped, 0, need_bytes); if (globals.encode == ENCODING_DEFAULT) { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); switch_url_encode(json_text, json_text_escaped, need_bytes); } else { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded"); switch_b64_encode((unsigned char *) json_text, need_bytes / 3, (unsigned char *) json_text_escaped, need_bytes); } switch_safe_free(json_text); json_text = json_text_escaped; if (!(curl_json_text = switch_mprintf("cdr=%s", json_text))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); goto error; } } else { headers = switch_curl_slist_append(headers, "Content-Type: application/json"); curl_json_text = (char *)json_text; } if (!zstr(globals.cred)) { switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, globals.auth_scheme); switch_curl_easy_setopt(curl_handle, CURLOPT_USERPWD, globals.cred); } switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); switch_curl_easy_setopt(curl_handle, CURLOPT_POST, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_POSTFIELDS, curl_json_text); switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-json/1.0"); switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, httpCallBack); if (globals.disable100continue) { slist = switch_curl_slist_append(slist, "Expect:"); switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist); } if (globals.ssl_cert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, globals.ssl_cert_file); } if (globals.ssl_key_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, globals.ssl_key_file); } if (globals.ssl_key_password) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEYPASSWD, globals.ssl_key_password); } if (globals.ssl_version) { if (!strcasecmp(globals.ssl_version, "SSLv3")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); } else if (!strcasecmp(globals.ssl_version, "TLSv1")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); } } if (globals.ssl_cacert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, globals.ssl_cacert_file); } /* these were used for testing, optionally they may be enabled if someone desires switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, 120); // tcp timeout switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); // 302 recursion level */ for (cur_try = 0; cur_try < globals.retries; cur_try++) { if (cur_try > 0) { switch_yield(globals.delay * 1000000); } destUrl = switch_mprintf("%s?uuid=%s", globals.urls[globals.url_index], switch_core_session_get_uuid(session)); switch_curl_easy_setopt(curl_handle, CURLOPT_URL, destUrl); if (!strncasecmp(destUrl, "https", 5)) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0); switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0); } if (globals.enable_cacert_check) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, TRUE); } if (globals.enable_ssl_verifyhost) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 2); } switch_curl_easy_perform(curl_handle); switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes); switch_safe_free(destUrl); if (httpRes >= 200 && httpRes < 300) { goto success; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Got error [%ld] posting to web server [%s]\n", httpRes, globals.urls[globals.url_index]); globals.url_index++; switch_assert(globals.url_count <= MAX_URLS); if (globals.url_index >= globals.url_count) { globals.url_index = 0; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retry will be with url [%s]\n", globals.urls[globals.url_index]); } } switch_curl_easy_cleanup(curl_handle); switch_curl_slist_free_all(headers); switch_curl_slist_free_all(slist); slist = NULL; headers = NULL; curl_handle = NULL; /* if we are here the web post failed for some reason */ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to post to web server, writing to file\n"); for (err_dir_index = 0; err_dir_index < globals.err_dir_count; err_dir_index++) { switch_thread_rwlock_rdlock(globals.log_path_lock); path = switch_mprintf("%s%s%s%s.cdr.json", globals.err_log_dir[err_dir_index], SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session)); switch_thread_rwlock_unlock(globals.log_path_lock); if (path) { #ifdef _MSC_VER if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { #else if ((fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) > -1) { #endif int wrote; wrote = write(fd, json_text, (unsigned) strlen(json_text)); close(fd); fd = -1; if(wrote < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error writing [%s]\n",path); } break; } else { char ebuf[512] = { 0 }; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open %s! [%s]\n", path, switch_strerror_r(errno, ebuf, sizeof(ebuf))); } switch_safe_free(path); } } } success: status = SWITCH_STATUS_SUCCESS; error: if (curl_handle) { switch_curl_easy_cleanup(curl_handle); } if (headers) { switch_curl_slist_free_all(headers); } if (slist) { switch_curl_slist_free_all(slist); } if (curl_json_text != json_text) { switch_safe_free(curl_json_text); } cJSON_Delete(json_cdr); switch_safe_free(json_text); return status; } static void event_handler(switch_event_t *event) { const char *sig = switch_event_get_header(event, "Trapped-Signal"); if (sig && !strcmp(sig, "HUP")) { if (globals.rotate) { set_json_cdr_log_dirs(); } } } static switch_state_handler_table_t state_handlers = { /*.on_init */ NULL, /*.on_routing */ NULL, /*.on_execute */ NULL, /*.on_hangup */ NULL, /*.on_exchange_media */ NULL, /*.on_soft_execute */ NULL, /*.on_consume_media */ NULL, /*.on_hibernate */ NULL, /*.on_reset */ NULL, /*.on_park */ NULL, /*.on_reporting */ my_on_reporting }; SWITCH_MODULE_LOAD_FUNCTION(mod_json_cdr_load) { char *cf = "json_cdr.conf"; switch_xml_t cfg, xml, settings, param; switch_status_t status = SWITCH_STATUS_SUCCESS; /* test global state handlers */ switch_core_add_state_handler(&state_handlers); *module_interface = switch_loadable_module_create_module_interface(pool, modname); memset(&globals, 0, sizeof(globals)); if (switch_event_bind_removable(modname, SWITCH_EVENT_TRAP, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL, &globals.node) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n"); return SWITCH_STATUS_GENERR; } globals.log_http_and_disk = 0; globals.log_b = 1; globals.disable100continue = 0; globals.pool = pool; globals.auth_scheme = CURLAUTH_BASIC; globals.encode_values = ENCODING_DEFAULT; switch_thread_rwlock_create(&globals.log_path_lock, pool); /* parse the config */ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", cf); return SWITCH_STATUS_TERM; } if ((settings = switch_xml_child(cfg, "settings"))) { for (param = switch_xml_child(settings, "param"); param; param = param->next) { char *var = (char *) switch_xml_attr_soft(param, "name"); char *val = (char *) switch_xml_attr_soft(param, "value"); if (!strcasecmp(var, "cred") && !zstr(val)) { globals.cred = switch_core_strdup(globals.pool, val); } else if (!strcasecmp(var, "url") && !zstr(val)) { if (globals.url_count >= MAX_URLS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "maximum urls configured!\n"); } else { globals.urls[globals.url_count++] = switch_core_strdup(globals.pool, val); } } else if (!strcasecmp(var, "log-http-and-disk")) { globals.log_http_and_disk = switch_true(val); } else if (!strcasecmp(var, "delay") && !zstr(val)) { globals.delay = (uint32_t) atoi(val); } else if (!strcasecmp(var, "log-b-leg")) { globals.log_b = switch_true(val); } else if (!strcasecmp(var, "prefix-a-leg")) { globals.prefix_a = switch_true(val); } else if (!strcasecmp(var, "disable-100-continue") && switch_true(val)) { globals.disable100continue = 1; } else if (!strcasecmp(var, "encode") && !zstr(val)) { if (!strcasecmp(val, "base64")) { globals.encode = ENCODING_BASE64; } else { globals.encode = switch_true(val) ? ENCODING_DEFAULT : ENCODING_NONE; } } else if (!strcasecmp(var, "retries") && !zstr(val)) { globals.retries = (uint32_t) atoi(val); } else if (!strcasecmp(var, "rotate") && !zstr(val)) { globals.rotate = switch_true(val); } else if (!strcasecmp(var, "log-dir")) { if (zstr(val)) { globals.base_log_dir = switch_core_sprintf(globals.pool, "%s%sjson_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); } else { if (switch_is_file_path(val)) { globals.base_log_dir = switch_core_strdup(globals.pool, val); } else { globals.base_log_dir = switch_core_sprintf(globals.pool, "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, val); } } } else if (!strcasecmp(var, "err-log-dir")) { if (globals.err_dir_count >= MAX_ERR_DIRS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "maximum error directories configured!\n"); } else { if (zstr(val)) { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_sprintf(globals.pool, "%s%sjson_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); } else { if (switch_is_file_path(val)) { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_strdup(globals.pool, val); } else { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_sprintf(globals.pool, "%s%s%s", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, val); } } } } else if (!strcasecmp(var, "enable-cacert-check") && switch_true(val)) { globals.enable_cacert_check = 1; } else if (!strcasecmp(var, "ssl-cert-path")) { globals.ssl_cert_file = switch_core_strdup(globals.pool, val); } else if (!strcasecmp(var, "ssl-key-path")) { globals.ssl_key_file = switch_core_strdup(globals.pool, val); } else if (!strcasecmp(var, "ssl-key-password")) { globals.ssl_key_password = switch_core_strdup(globals.pool, val); } else if (!strcasecmp(var, "ssl-version")) { globals.ssl_version = switch_core_strdup(globals.pool, val); } else if (!strcasecmp(var, "ssl-cacert-file")) { globals.ssl_cacert_file = switch_core_strdup(globals.pool, val); } else if (!strcasecmp(var, "enable-ssl-verifyhost") && switch_true(val)) { globals.enable_ssl_verifyhost = 1; } else if (!strcasecmp(var, "auth-scheme")) { if (*val == '=') { globals.auth_scheme = 0; val++; } if (!strcasecmp(val, "basic")) { globals.auth_scheme |= CURLAUTH_BASIC; } else if (!strcasecmp(val, "digest")) { globals.auth_scheme |= CURLAUTH_DIGEST; } else if (!strcasecmp(val, "NTLM")) { globals.auth_scheme |= CURLAUTH_NTLM; } else if (!strcasecmp(val, "GSS-NEGOTIATE")) { globals.auth_scheme |= CURLAUTH_GSSNEGOTIATE; } else if (!strcasecmp(val, "any")) { globals.auth_scheme = CURLAUTH_ANY; } } else if (!strcasecmp(var, "encode-values") && !zstr(val)) { globals.encode_values = switch_true(val) ? ENCODING_DEFAULT : ENCODING_NONE; } } if (!globals.err_dir_count) { if (!zstr(globals.base_log_dir)) { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_strdup(globals.pool, globals.base_log_dir); } else { globals.base_err_log_dir[globals.err_dir_count++] = switch_core_sprintf(globals.pool, "%s%sjson_cdr", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR); } } } if (globals.retries && !globals.delay) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retries set but delay 0 setting to 5 seconds\n"); globals.delay = 5; } globals.retries++; set_json_cdr_log_dirs(); switch_xml_free(xml); return status; } SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_json_cdr_shutdown) { int err_dir_index = 0; globals.shutdown = 1; switch_safe_free(globals.log_dir); for (;err_dir_index < globals.err_dir_count; err_dir_index++) { switch_safe_free(globals.err_log_dir[err_dir_index]); } switch_event_unbind(&globals.node); switch_core_remove_state_handler(&state_handlers); switch_thread_rwlock_destroy(globals.log_path_lock); return SWITCH_STATUS_SUCCESS; }
static switch_status_t unbind_fetch_agent(switch_xml_binding_t **binding) { ei_xml_agent_t *agent; ei_xml_client_t *client; /* get a pointer to our user_data */ agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(*binding); /* unbind from the switch */ switch_xml_unbind_search_function(binding); /* LOCK ALL THE THINGS */ switch_thread_rwlock_wrlock(agent->lock); switch_mutex_lock(agent->current_client_mutex); switch_mutex_lock(agent->replies_mutex); /* cleanly destroy each client */ client = agent->clients; while(client != NULL) { ei_xml_client_t *tmp_client = client; fetch_handler_t *fetch_handler; fetch_handler = client->fetch_handlers; while(fetch_handler != NULL) { fetch_handler_t *tmp_fetch_handler = fetch_handler; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed %s XML handler %s <%d.%d.%d>\n" ,xml_section_to_string(agent->section) ,fetch_handler->pid.node ,fetch_handler->pid.creation ,fetch_handler->pid.num ,fetch_handler->pid.serial); fetch_handler = fetch_handler->next; switch_safe_free(tmp_fetch_handler); } client = client->next; switch_safe_free(tmp_client); } /* keep the pointers clean, even if its just for a moment */ agent->clients = NULL; agent->current_client = NULL; /* release the locks! */ switch_thread_rwlock_unlock(agent->lock); switch_mutex_unlock(agent->current_client_mutex); switch_mutex_unlock(agent->replies_mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unbound from %s XML requests\n" ,xml_section_to_string(agent->section)); /* cleanly destroy the bindings */ switch_thread_rwlock_destroy(agent->lock); switch_mutex_destroy(agent->current_client_mutex); switch_mutex_destroy(agent->replies_mutex); switch_thread_cond_destroy(agent->new_reply); switch_core_destroy_memory_pool(&agent->pool); return SWITCH_STATUS_SUCCESS; }