SWITCH_DECLARE(void) EventConsumer::cleanup() { uint32_t i; void *pop; if (!ready) { return; } ready = 0; for (i = 0; i < node_index; i++) { switch_event_unbind(&enodes[i]); } node_index = 0; if (events) { switch_queue_interrupt_all(events); } while(switch_queue_trypop(events, &pop) == SWITCH_STATUS_SUCCESS) { switch_event_t *event = (switch_event_t *) pop; switch_event_destroy(&event); } switch_core_destroy_memory_pool(&pool); }
SWITCH_DECLARE_CONSTRUCTOR EventConsumer::~EventConsumer() { if (node) { switch_event_unbind(&node); } if (events) { switch_queue_interrupt_all(events); } switch_core_destroy_memory_pool(&pool); }
SWITCH_DECLARE_CONSTRUCTOR EventConsumer::~EventConsumer() { uint32_t i; for (i = 0; i < node_index; i++) { switch_event_unbind(&enodes[i]); } if (events) { switch_queue_interrupt_all(events); } switch_core_destroy_memory_pool(&pool); }
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; }
abyss_bool websocket_hook(TSession *r) { wsh_t *wsh; int ret; int i; ws_opcode_t opcode; uint8_t *data; switch_event_node_t *nodes[MAX_EVENT_BIND_SLOTS]; int node_count = 0; char *p; char *key = NULL; char *version = NULL; char *proto = NULL; char *upgrade = NULL; for (i = 0; i < r->requestHeaderFields.size; i++) { TTableItem * const item = &r->requestHeaderFields.item[i]; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "headers %s: %s\n", item->name, item->value); } key = RequestHeaderValue(r, "sec-websocket-key"); version = RequestHeaderValue(r, "sec-websocket-version"); proto = RequestHeaderValue(r, "sec-websocket-protocol"); upgrade = RequestHeaderValue(r, "upgrade"); if (!key || !version || !proto || !upgrade) return FALSE; if (strncasecmp(upgrade, "websocket", 9) || strncasecmp(proto, "websocket", 9)) return FALSE; wsh = ws_init(r); if (!wsh) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "websocket error %d\n", ret); return FALSE; } ret = ws_handshake_kvp(wsh, key, version, proto); if (ret < 0) wsh->down = 1; if (ret != 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "handshake error %d\n", ret); return FALSE; } if (switch_event_bind_removable("websocket", SWITCH_EVENT_CUSTOM, "websocket::stophook", stop_hook_event_handler, wsh, &nodes[node_count++]) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't bind!\n"); node_count--; } while (!wsh->down) { int bytes = ws_read_frame(wsh, &opcode, &data); if (bytes < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%d %s\n", opcode, (char *)data); switch_yield(100000); continue; } switch (opcode) { case WSOC_CLOSE: ws_close(wsh, 1000); break; case WSOC_CONTINUATION: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "continue\n"); continue; case WSOC_TEXT: p = data; if (!p) continue; if (!strncasecmp(data, "event ", 6)) { switch_event_types_t type; char *subclass; if (node_count == MAX_EVENT_BIND_SLOTS - 1) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "cannot subscribe more than %d events\n", node_count); continue; } p += 6; if (p = strchr(p, ' ')) p++; if (!strncasecmp(p, "json ", 5)) { p += 5; } else if (!strncasecmp(p, "xml ", 4)) { p += 4; } else if (!strncasecmp(p, "plain ", 6)) { p += 6; } if (!*p) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "missing event type in [%s]\n", data); break; } else { } if (subclass = strchr(p, ' ')) { *subclass++ = '\0'; if (!*subclass) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing subclass\n"); continue; } } else { subclass = SWITCH_EVENT_SUBCLASS_ANY; } if (switch_name_event(p, &type) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unknown event %s\n", p); continue; } if (switch_event_bind_removable("websocket", type, subclass, event_handler, wsh, &nodes[node_count++]) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't bind!\n"); node_count--; continue; } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Bind %s\n", data); } } break; default: break; } } switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "wsh->down = %d, node_count = %d\n", wsh->down, node_count); switch_yield(2000); while (--node_count >= 0) switch_event_unbind(&nodes[node_count]); switch_safe_free(wsh); return FALSE; }
void eventpipe_events_unload() { if (&globals.node) { switch_event_unbind(&globals.node); } }