static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_status_t status = SWITCH_STATUS_SUCCESS; const char *template_str = NULL; char *expanded_vars = NULL, *sql = NULL; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } if (!((globals.legs & CDR_LEG_A) && (globals.legs & CDR_LEG_B))) { if ((globals.legs & CDR_LEG_A)) { if (switch_channel_get_originator_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } else { if (switch_channel_get_originatee_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } } if (globals.debug) { switch_event_t *event; if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { char *buf; switch_channel_event_set_data(channel, event); switch_event_serialize(event, &buf, SWITCH_FALSE); switch_assert(buf); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf); switch_event_destroy(&event); switch_safe_free(buf); } } template_str = (const char *) switch_core_hash_find(globals.template_hash, globals.default_template); if (!template_str) { template_str = default_template; } expanded_vars = switch_channel_expand_variables(channel, template_str); if (!expanded_vars) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error expanding CDR variables.\n"); return SWITCH_STATUS_FALSE; } sql = switch_mprintf("INSERT INTO %s VALUES (%s)", globals.db_table, expanded_vars); assert(sql); write_cdr(sql); switch_safe_free(sql); if (expanded_vars != template_str) { switch_safe_free(expanded_vars); } return status; }
static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_status_t status = SWITCH_STATUS_SUCCESS; const char *log_dir = NULL, *accountcode = NULL, *a_template_str = NULL, *g_template_str = NULL; char *log_line, *path = NULL; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } if (!((globals.legs & CDR_LEG_A) && (globals.legs & CDR_LEG_B))) { if ((globals.legs & CDR_LEG_A)) { if (switch_channel_get_originator_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } else { if (switch_channel_get_originatee_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } } if (!(log_dir = switch_channel_get_variable(channel, "cdr_csv_base"))) { log_dir = globals.log_dir; } if (switch_dir_make_recursive(log_dir, SWITCH_DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", log_dir); return SWITCH_STATUS_FALSE; } if (globals.debug) { switch_event_t *event; if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { char *buf; switch_channel_event_set_data(channel, event); switch_event_serialize(event, &buf, SWITCH_FALSE); switch_assert(buf); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf); switch_event_destroy(&event); free(buf); } } g_template_str = (const char *) switch_core_hash_find(globals.template_hash, globals.default_template); if ((accountcode = switch_channel_get_variable(channel, "ACCOUNTCODE"))) { a_template_str = (const char *) switch_core_hash_find(globals.template_hash, accountcode); } if (!g_template_str) { g_template_str = "\"${accountcode}\",\"${caller_id_number}\",\"${destination_number}\",\"${context}\",\"${caller_id}\",\"${channel_name}\",\"${bridge_channel}\",\"${last_app}\",\"${last_arg}\",\"${start_stamp}\",\"${answer_stamp}\",\"${end_stamp}\",\"${duration}\",\"${billsec}\",\"${hangup_cause}\",\"${amaflags}\",\"${uuid}\",\"${userfield}\";"; } if (!a_template_str) { a_template_str = g_template_str; } log_line = switch_channel_expand_variables(channel, a_template_str); if ((accountcode) && (!globals.masterfileonly)) { path = switch_mprintf("%s%s%s.csv", log_dir, SWITCH_PATH_SEPARATOR, accountcode); assert(path); write_cdr(path, log_line); free(path); } if (g_template_str != a_template_str) { if (log_line != a_template_str) { switch_safe_free(log_line); } log_line = switch_channel_expand_variables(channel, g_template_str); } if (!log_line) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating cdr\n"); return SWITCH_STATUS_FALSE; } path = switch_mprintf("%s%sMaster.csv", log_dir, SWITCH_PATH_SEPARATOR); assert(path); write_cdr(path, log_line); free(path); if (log_line != g_template_str) { free(log_line); } return status; }
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 my_on_reporting(switch_core_session_t *session) { switch_status_t status = SWITCH_STATUS_SUCCESS; switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_header_t *hi; switch_caller_profile_t *caller_profile; switch_app_log_t *app_log; bson cdr; int is_b; char *tmp; 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; } } bson_init(&cdr); /* Channel data */ bson_append_start_object(&cdr, "channel_data"); bson_append_string(&cdr, "state", switch_channel_state_name(switch_channel_get_state(channel))); bson_append_string(&cdr, "direction", switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? "outbound" : "inbound"); bson_append_int(&cdr, "state_number", switch_channel_get_state(channel)); if ((tmp = switch_channel_get_flag_string(channel))) { bson_append_string(&cdr, "flags", tmp); free(tmp); } if ((tmp = switch_channel_get_cap_string(channel))) { bson_append_string(&cdr, "caps", tmp); free(tmp); } bson_append_finish_object(&cdr); /* channel_data */ /* Channel variables */ bson_append_start_object(&cdr, "variables"); if ((hi = switch_channel_variable_first(channel))) { for (; hi; hi = hi->next) { if (!zstr(hi->name) && !zstr(hi->value)) { bson_append_string(&cdr, hi->name, hi->value); } } switch_channel_variable_last(channel); } bson_append_finish_object(&cdr); /* variables */ /* App log */ if ((app_log = switch_core_session_get_app_log(session))) { switch_app_log_t *ap; bson_append_start_object(&cdr, "app_log"); for (ap = app_log; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); bson_append_string(&cdr, "app_name", ap->app); bson_append_string(&cdr, "app_data", ap->arg); bson_append_long(&cdr, "app_stamp", ap->stamp); bson_append_finish_object(&cdr); /* application */ } bson_append_finish_object(&cdr); /* app_log */ } /* Callflow */ caller_profile = switch_channel_get_caller_profile(channel); while (caller_profile) { bson_append_start_object(&cdr, "callflow"); if (!zstr(caller_profile->dialplan)) { bson_append_string(&cdr, "dialplan", caller_profile->dialplan); } if (!zstr(caller_profile->profile_index)) { bson_append_string(&cdr, "profile_index", caller_profile->profile_index); } if (caller_profile->caller_extension) { switch_caller_application_t *ap; bson_append_start_object(&cdr, "extension"); bson_append_string(&cdr, "name", caller_profile->caller_extension->extension_name); bson_append_string(&cdr, "number", caller_profile->caller_extension->extension_number); if (caller_profile->caller_extension->current_application) { bson_append_string(&cdr, "current_app", caller_profile->caller_extension->current_application->application_name); } for (ap = caller_profile->caller_extension->applications; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); if (ap == caller_profile->caller_extension->current_application) { bson_append_bool(&cdr, "last_executed", 1); } bson_append_string(&cdr, "app_name", ap->application_name); bson_append_string(&cdr, "app_data", ap->application_data); bson_append_finish_object(&cdr); } if (caller_profile->caller_extension->children) { switch_caller_profile_t *cp = NULL; for (cp = caller_profile->caller_extension->children; cp; cp = cp->next) { if (!cp->caller_extension) { continue; } bson_append_start_object(&cdr, "sub_extensions"); bson_append_start_object(&cdr, "extension"); bson_append_string(&cdr, "name", cp->caller_extension->extension_name); bson_append_string(&cdr, "number", cp->caller_extension->extension_number); bson_append_string(&cdr, "dialplan", cp->dialplan); if (cp->caller_extension->current_application) { bson_append_string(&cdr, "current_app", cp->caller_extension->current_application->application_name); } for (ap = cp->caller_extension->applications; ap; ap = ap->next) { bson_append_start_object(&cdr, "application"); if (ap == cp->caller_extension->current_application) { bson_append_bool(&cdr, "last_executed", 1); } bson_append_string(&cdr, "app_name", ap->application_name); bson_append_string(&cdr, "app_data", ap->application_data); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* extension */ bson_append_finish_object(&cdr); /* sub_extensions */ } } bson_append_finish_object(&cdr); /* extension */ } bson_append_start_object(&cdr, "caller_profile"); set_bson_profile_data(&cdr, caller_profile); if (caller_profile->origination_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "origination"); for (cp = caller_profile->origination_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "origination_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* origination */ } if (caller_profile->originator_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "originator"); for (cp = caller_profile->originator_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "originator_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* originator */ } if (caller_profile->originatee_caller_profile) { switch_caller_profile_t *cp = NULL; bson_append_start_object(&cdr, "originatee"); for (cp = caller_profile->originatee_caller_profile; cp; cp = cp->next) { bson_append_start_object(&cdr, "originatee_caller_profile"); set_bson_profile_data(&cdr, cp); bson_append_finish_object(&cdr); } bson_append_finish_object(&cdr); /* originatee */ } bson_append_finish_object(&cdr); /* caller_profile */ /* Timestamps */ if (caller_profile->times) { bson_append_start_object(&cdr, "times"); /* Insert timestamps as long ints (microseconds) to preserve accuracy */ bson_append_long(&cdr, "created_time", caller_profile->times->created); bson_append_long(&cdr, "profile_created_time", caller_profile->times->profile_created); bson_append_long(&cdr, "progress_time", caller_profile->times->progress); bson_append_long(&cdr, "progress_media_time", caller_profile->times->progress_media); bson_append_long(&cdr, "answered_time", caller_profile->times->answered); bson_append_long(&cdr, "bridged_time", caller_profile->times->bridged); bson_append_long(&cdr, "last_hold_time", caller_profile->times->last_hold); bson_append_long(&cdr, "hold_accum_time", caller_profile->times->hold_accum); bson_append_long(&cdr, "hangup_time", caller_profile->times->hungup); bson_append_long(&cdr, "resurrect_time", caller_profile->times->resurrected); bson_append_long(&cdr, "transfer_time", caller_profile->times->transferred); bson_append_finish_object(&cdr); /* times */ } bson_append_finish_object(&cdr); /* callflow */ caller_profile = caller_profile->next; } bson_finish(&cdr); switch_mutex_lock(globals.mongo_mutex); if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) { if (globals.mongo_conn->err == MONGO_IO_ERROR) { mongo_error_t db_status; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "MongoDB connection failed; attempting reconnect...\n"); db_status = mongo_reconnect(globals.mongo_conn); if (db_status != MONGO_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MongoDB reconnect failed with error code %d\n", db_status); status = SWITCH_STATUS_FALSE; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "MongoDB connection re-established.\n"); if (mongo_insert(globals.mongo_conn, globals.mongo_namespace, &cdr) != MONGO_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err); status = SWITCH_STATUS_FALSE; } } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "mongo_insert: error code %d\n", globals.mongo_conn->err); status = SWITCH_STATUS_FALSE; } } switch_mutex_unlock(globals.mongo_mutex); bson_destroy(&cdr); return status; }
SWITCH_DECLARE(void) switch_core_session_reporting_state(switch_core_session_t *session) { switch_channel_state_t state = switch_channel_get_state(session->channel), midstate = state; const switch_endpoint_interface_t *endpoint_interface; const switch_state_handler_table_t *driver_state_handler = NULL; const switch_state_handler_table_t *application_state_handler = NULL; int proceed = 1; int global_proceed = 1; int do_extra_handlers = 1; int silly = 0; int index = 0; const char *var = switch_channel_get_variable(session->channel, SWITCH_PROCESS_CDR_VARIABLE); const char *skip_var = switch_channel_get_variable(session->channel, SWITCH_SKIP_CDR_CAUSES_VARIABLE); const char *hook_var; int use_session = 0; switch_event_t *event; switch_call_cause_t cause = switch_channel_get_cause(session->channel); if (switch_channel_test_flag(session->channel, CF_REPORTING)) { return; } switch_channel_set_flag(session->channel, CF_REPORTING); switch_assert(session != NULL); endpoint_interface = session->endpoint_interface; switch_assert(endpoint_interface != NULL); driver_state_handler = endpoint_interface->state_handler; switch_assert(driver_state_handler != NULL); if (!zstr(var)) { if (!strcasecmp(var, "a_only")) { if (switch_channel_get_originator_caller_profile(session->channel)) { do_extra_handlers = 0; } } else if (!strcasecmp(var, "b_only")) { if (switch_channel_get_originatee_caller_profile(session->channel)) { do_extra_handlers = 0; } } else if (!switch_true(var)) { do_extra_handlers = 0; } } if (!zstr(skip_var)) { int x, ttl = 0; char *list[128] = { 0 }; char *dup = switch_core_session_strdup(session, skip_var); ttl = switch_split(dup, '|', list); for(x = 0; x < ttl; x++) { if (switch_channel_str2cause(list[x]) == cause) { do_extra_handlers = 0; break; } } } if (switch_channel_test_flag(session->channel, CF_NO_CDR)) { do_extra_handlers = 0; } STATE_MACRO(reporting, "REPORTING"); if ((hook_var = switch_channel_get_variable(session->channel, SWITCH_API_REPORTING_HOOK_VARIABLE))) { if (switch_true(switch_channel_get_variable(session->channel, SWITCH_SESSION_IN_HANGUP_HOOK_VARIABLE))) { use_session = 1; } api_hook(session, hook_var, use_session); } if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Hangup-Cause", switch_channel_cause2str(cause)); switch_channel_event_set_data(session->channel, event); if (switch_true(switch_channel_get_variable(session->channel, "hangup_complete_with_xml"))) { switch_xml_t cdr = NULL; char *xml_cdr_text; if (switch_ivr_generate_xml_cdr(session, &cdr) == SWITCH_STATUS_SUCCESS) { xml_cdr_text = switch_xml_toxml(cdr, SWITCH_FALSE); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "CDR-Attached", "xml"); switch_event_add_body(event, "%s", xml_cdr_text); switch_xml_free(cdr); switch_safe_free(xml_cdr_text); } } switch_event_fire(&event); } return; }
static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_status_t status = SWITCH_STATUS_SUCCESS; char *values = NULL, *tmp = NULL, *pq_var = NULL; const char *var = NULL; cdr_field_t *cdr_field = NULL; switch_size_t len, offset; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } if (!((globals.legs & CDR_LEG_A) && (globals.legs & CDR_LEG_B))) { if ((globals.legs & CDR_LEG_A)) { if (switch_channel_get_originator_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } else { if (switch_channel_get_originatee_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } } if (switch_dir_make_recursive(globals.spool_dir, SWITCH_DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", globals.spool_dir); return SWITCH_STATUS_FALSE; } if (globals.debug) { switch_event_t *event; if (switch_event_create(&event, SWITCH_EVENT_COMMAND) == SWITCH_STATUS_SUCCESS) { char *buf; switch_channel_event_set_data(channel, event); switch_event_serialize(event, &buf, SWITCH_FALSE); switch_assert(buf); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf); switch_event_destroy(&event); switch_safe_free(buf); } } switch_zmalloc(values, 1); offset = 0; for (cdr_field = globals.db_schema->fields; cdr_field->var_name; cdr_field++) { if ((var = switch_channel_get_variable(channel, cdr_field->var_name))) { /* Allocate sufficient buffer for PQescapeString */ len = strlen(var); tmp = switch_core_session_alloc(session, len * 2 + 1); PQescapeString(tmp, var, len); var = tmp; } if (cdr_field->quote) { if ((cdr_field->not_null == SWITCH_FALSE) && zstr(var)) { pq_var = switch_mprintf("null,", var); } else { pq_var = switch_mprintf("'%s',", var); } } else { pq_var = switch_mprintf("%s,", var); } /* Resize values buffer to accomodate next var */ len = strlen(pq_var); tmp = realloc(values, offset + len); values = tmp; memcpy(values + offset, pq_var, len); switch_safe_free(pq_var); offset += len; } *(values + --offset) = '\0'; insert_cdr(values); switch_safe_free(values); return status; }
static switch_status_t my_on_reporting_cb(switch_core_session_t *session, cdr_profile_t *profile) { switch_xml_t xml_cdr = NULL; cJSON *json_cdr = NULL; char *cdr_text = NULL; char *dpath = NULL; char *path = NULL; char *curl_cdr_text = NULL; const char *logdir = NULL; char *cdr_text_escaped = NULL; int fd = -1; uint32_t cur_try; long httpRes; switch_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 (!profile->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 && profile->prefix_a) a_prefix = "a_"; if ( ! strcasecmp(profile->format, "json") ) { if (switch_ivr_generate_json_cdr(session, &json_cdr, profile->encode_values == ENCODING_DEFAULT) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Generating JSON Data!\n"); return SWITCH_STATUS_FALSE; } /* build the JSON */ cdr_text = cJSON_PrintUnformatted(json_cdr); if (!cdr_text) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error generating JSON!\n"); goto error; } } else if ( ! strcasecmp(profile->format, "xml") ) { if (switch_ivr_generate_xml_cdr(session, &xml_cdr) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Generating XML Data!\n"); return SWITCH_STATUS_FALSE; } /* build the XML */ cdr_text = switch_xml_toxml(xml_cdr, SWITCH_TRUE); if (!cdr_text) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error generating XML!\n"); goto error; } } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Unhandled format for mod_format_cdr!\n"); goto error; } switch_thread_rwlock_rdlock(profile->log_path_lock); if (!(logdir = switch_channel_get_variable(channel, "format_cdr_base"))) { logdir = profile->log_dir; } if (!zstr(logdir) && (profile->log_http_and_disk || !profile->url_count)) { dpath = switch_mprintf("%s%s%s", logdir, SWITCH_PATH_SEPARATOR, a_prefix); path = switch_mprintf("%s%s%s%s.cdr.%s", logdir, SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session), profile->format); switch_thread_rwlock_unlock(profile->log_path_lock); if (path) { if (switch_directory_exists(dpath, profile->pool) != SWITCH_STATUS_SUCCESS) { switch_dir_make_recursive(dpath, SWITCH_FPROT_OS_DEFAULT, profile->pool); } #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, cdr_text, (unsigned) strlen(cdr_text)); wrote++; close(fd); fd = -1; } 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); switch_safe_free(dpath); } } else { switch_thread_rwlock_unlock(profile->log_path_lock); } /* try to post it to the web server */ if (profile->url_count) { char *destUrl = NULL; curl_handle = switch_curl_easy_init(); if (profile->encode == ENCODING_TEXTXML) { headers = switch_curl_slist_append(headers, "Content-Type: text/xml"); } else if (profile->encode == ENCODING_APPLJSON) { headers = switch_curl_slist_append(headers, "Content-Type: application/json"); } else if (profile->encode) { switch_size_t need_bytes = strlen(cdr_text) * 3 + 1; cdr_text_escaped = malloc(need_bytes); switch_assert(cdr_text_escaped); memset(cdr_text_escaped, 0, need_bytes); if (profile->encode == ENCODING_DEFAULT) { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded"); switch_url_encode(cdr_text, cdr_text_escaped, need_bytes); } else { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded"); switch_b64_encode((unsigned char *) cdr_text, need_bytes / 3, (unsigned char *) cdr_text_escaped, need_bytes); } switch_safe_free(cdr_text); cdr_text = cdr_text_escaped; } else { headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-plaintext"); } if (profile->encode == ENCODING_TEXTXML) { curl_cdr_text = cdr_text; } else if (profile->encode == ENCODING_APPLJSON) { curl_cdr_text = cdr_text; } else if (!(curl_cdr_text = switch_mprintf("cdr=%s", cdr_text))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); goto error; } if (!zstr(profile->cred)) { switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPAUTH, profile->auth_scheme); switch_curl_easy_setopt(curl_handle, CURLOPT_USERPWD, profile->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_cdr_text); switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-format-cdr/1.0"); switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, httpCallBack); if (profile->disable100continue) { slist = switch_curl_slist_append(slist, "Expect:"); switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, slist); } if (profile->ssl_cert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLCERT, profile->ssl_cert_file); } if (profile->ssl_key_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEY, profile->ssl_key_file); } if (profile->ssl_key_password) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLKEYPASSWD, profile->ssl_key_password); } if (profile->ssl_version) { if (!strcasecmp(profile->ssl_version, "SSLv3")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_SSLv3); } else if (!strcasecmp(profile->ssl_version, "TLSv1")) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1); } } if (profile->ssl_cacert_file) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, profile->ssl_cacert_file); } switch_curl_easy_setopt(curl_handle, CURLOPT_TIMEOUT, profile->timeout); /* these were used for testing, optionally they may be enabled if someone desires switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); // 302 recursion level */ for (cur_try = 0; cur_try < profile->retries; cur_try++) { if (cur_try > 0) { switch_yield(profile->delay * 1000000); } destUrl = switch_mprintf("%s?uuid=%s%s", profile->urls[profile->url_index], a_prefix, 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 (profile->enable_cacert_check) { switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, TRUE); } if (profile->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 <= 299) { goto success; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Got error [%ld] posting to web server [%s]\n", httpRes, profile->urls[profile->url_index]); profile->url_index++; switch_assert(profile->url_count <= MAX_URLS); if (profile->url_index >= profile->url_count) { profile->url_index = 0; } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Retry will be with url [%s]\n", profile->urls[profile->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"); switch_thread_rwlock_rdlock(profile->log_path_lock); dpath = switch_mprintf("%s%s%s", profile->err_log_dir, SWITCH_PATH_SEPARATOR, a_prefix); path = switch_mprintf("%s%s%s%s.cdr.%s", profile->err_log_dir, SWITCH_PATH_SEPARATOR, a_prefix, switch_core_session_get_uuid(session), profile->format); switch_thread_rwlock_unlock(profile->log_path_lock); if (path) { if (switch_directory_exists(dpath, profile->pool) != SWITCH_STATUS_SUCCESS) { switch_dir_make_recursive(dpath, SWITCH_FPROT_OS_DEFAULT, profile->pool); } #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, cdr_text, (unsigned) strlen(cdr_text)); wrote++; close(fd); fd = -1; } else { char ebuf[512] = { 0 }; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error![%s]\n", switch_strerror_r(errno, ebuf, sizeof(ebuf))); } switch_safe_free(path); switch_safe_free(dpath); } } 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_cdr_text != cdr_text) { switch_safe_free(curl_cdr_text); } switch_safe_free(cdr_text); switch_safe_free(path); switch_safe_free(dpath); if ( xml_cdr ) { switch_xml_free(xml_cdr); } if ( json_cdr ) { cJSON_Delete(json_cdr); } return status; } static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_hash_index_t *hi; void *val; switch_status_t status, tmpstatus; status = SWITCH_STATUS_SUCCESS; for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { cdr_profile_t *profile; switch_hash_this(hi, NULL, NULL, &val); profile = (cdr_profile_t *) val; tmpstatus = my_on_reporting_cb(session, profile); if ( tmpstatus != SWITCH_STATUS_SUCCESS ) { status = tmpstatus; } } return status; }
SWITCH_DECLARE(void) switch_core_session_reporting_state(switch_core_session_t *session) { switch_channel_state_t state = switch_channel_get_state(session->channel), midstate = state; const switch_endpoint_interface_t *endpoint_interface; const switch_state_handler_table_t *driver_state_handler = NULL; const switch_state_handler_table_t *application_state_handler = NULL; int proceed = 1; int global_proceed = 1; int do_extra_handlers = 1; int silly = 0; int index = 0; const char *var = switch_channel_get_variable(session->channel, SWITCH_PROCESS_CDR_VARIABLE); const char *hook_var; int use_session = 0; switch_event_t *event; switch_call_cause_t cause = switch_channel_get_cause(session->channel); if (switch_channel_test_flag(session->channel, CF_REPORTING)) { return; } switch_channel_set_flag(session->channel, CF_REPORTING); switch_assert(session != NULL); endpoint_interface = session->endpoint_interface; switch_assert(endpoint_interface != NULL); driver_state_handler = endpoint_interface->state_handler; switch_assert(driver_state_handler != NULL); if (!zstr(var)) { if (!strcasecmp(var, "a_only")) { if (switch_channel_get_originator_caller_profile(session->channel)) { do_extra_handlers = 0; } } else if (!strcasecmp(var, "b_only")) { if (switch_channel_get_originatee_caller_profile(session->channel)) { do_extra_handlers = 0; } } else if (!switch_true(var)) { do_extra_handlers = 0; } } STATE_MACRO(reporting, "REPORTING"); if ((hook_var = switch_channel_get_variable(session->channel, SWITCH_API_REPORTING_HOOK_VARIABLE))) { if (switch_true(switch_channel_get_variable(session->channel, SWITCH_SESSION_IN_HANGUP_HOOK_VARIABLE))) { use_session = 1; } api_hook(session, hook_var, use_session); } if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_HANGUP_COMPLETE) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Hangup-Cause", switch_channel_cause2str(cause)); switch_channel_event_set_data(session->channel, event); switch_event_fire(&event); } return; }
static switch_status_t my_on_reporting(switch_core_session_t *session) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_status_t status = SWITCH_STATUS_SUCCESS; const char *log_dir = NULL, *accountcode = NULL, *a_template_str = NULL, *g_template_str = NULL; char *log_line, *path = NULL,*file = NULL; const char *start_stamp = NULL; char *lbuf = NULL; char *argv[4] = { 0 }; int argc = 0; char *start_day=NULL; char *dargv[8] = {0}; int dargc = 0; char *Y,*M,*D; if (globals.shutdown) { return SWITCH_STATUS_SUCCESS; } if (!((globals.legs & CDR_LEG_A) && (globals.legs & CDR_LEG_B))) { if ((globals.legs & CDR_LEG_A)) { if (switch_channel_get_originator_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } else { if (switch_channel_get_originatee_caller_profile(channel)) { return SWITCH_STATUS_SUCCESS; } } } get_var(start_stamp); if(!start_stamp){ return SWITCH_STATUS_SUCCESS; } fire_cdr_event(channel); if(!(lbuf = strdup(start_stamp))){ return SWITCH_STATUS_SUCCESS; } argc = switch_separate_string(lbuf,' ',argv,(sizeof(argv)/sizeof(argv[0]))); if(argc < 1){ goto done; } if(!(start_day = strdup(argv[0]))){ goto done; } dargc = switch_separate_string(start_day,'-',dargv,(sizeof(dargv)/sizeof(dargv[0]))); if(dargc < 3){ goto done; } Y = dargv[0]; M = dargv[1]; D = dargv[2]; if (!(log_dir = switch_channel_get_variable(channel, "cdr_csv_base"))) { log_dir = globals.log_dir; } if (switch_dir_make_recursive(log_dir, SWITCH_DEFAULT_DIR_PERMS, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", log_dir); //return SWITCH_STATUS_FALSE; goto done; } /*if (globals.debug) { switch_event_t *event; if (switch_event_create_plain(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { char *buf; switch_channel_event_set_data(channel, event); switch_event_serialize(event, &buf, SWITCH_FALSE); switch_assert(buf); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "CHANNEL_DATA:\n%s\n", buf); switch_event_destroy(&event); free(buf); } }*/ g_template_str = (const char *) switch_core_hash_find(globals.template_hash, globals.default_template); if (!(accountcode = switch_channel_get_variable(channel, "ACCOUNTCODE"))) { accountcode = switch_channel_get_variable(channel,"dialed_extension"); } if(accountcode){ a_template_str = (const char *) switch_core_hash_find(globals.template_hash, accountcode); } if (!g_template_str) { g_template_str = "\"${accountcode}\",\"${caller_id_number}\",\"${destination_number}\",\"${context}\",\"${caller_id}\",\"${channel_name}\",\"${bridge_channel}\",\"${last_app}\",\"${last_arg}\",\"${start_stamp}\",\"${answer_stamp}\",\"${end_stamp}\",\"${duration}\",\"${billsec}\",\"${hangup_cause}\",\"${amaflags}\",\"${uuid}\",\"${userfield}\";"; } if (!a_template_str) { a_template_str = g_template_str; } if ((accountcode) && (!globals.masterfileonly)) { log_line = switch_channel_expand_variables(channel, a_template_str); if (!log_line) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating cdr\n"); //return SWITCH_STATUS_FALSE; goto done; } path = switch_mprintf("%s%s%s%s%s-%s",log_dir,SWITCH_PATH_SEPARATOR,accountcode,SWITCH_PATH_SEPARATOR,Y,M); assert(path); if (switch_dir_make_recursive(path, SWITCH_DEFAULT_DIR_PERMS| SWITCH_FPROT_WREAD | SWITCH_FPROT_WEXECUTE, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating %s\n", path); //return SWITCH_STATUS_FALSE; free(path); goto done; } //free(path); file = switch_mprintf("%s%s%s.csv", path, SWITCH_PATH_SEPARATOR, D); assert(file); write_cdr(file, log_line); free(file); free(path); if (log_line != a_template_str) { free(log_line); } } else{ log_line = switch_channel_expand_variables(channel, g_template_str); if (!log_line) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error creating cdr\n"); //return SWITCH_STATUS_FALSE; goto done; } path = switch_mprintf("%s%sMaster.csv", log_dir, SWITCH_PATH_SEPARATOR); assert(path); write_cdr(path, log_line); free(path); if (log_line != g_template_str) { free(log_line); } } done: switch_safe_free(start_day); switch_safe_free(lbuf); return status; }