static void event_handler(switch_event_t *event) { const char *sig = switch_event_get_header(event, "Trapped-Signal"); switch_hash_index_t *hi; void *val; const void *var; logfile_profile_t *profile; if (sig && !strcmp(sig, "HUP")) { if (globals.rotate) { for (hi = switch_hash_first(NULL, profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, &var, NULL, &val); profile = val; mod_logfile_rotate(profile); } } else { switch_mutex_lock(globals.mutex); for (hi = switch_hash_first(NULL, profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, &var, NULL, &val); profile = val; switch_file_close(profile->log_afd); if (mod_logfile_openlogfile(profile, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Re-opening Log!\n"); } } switch_mutex_unlock(globals.mutex); } } }
static void check_timeouts(void) { switch_hash_index_t *hi; const void *var; void *val; time_t now; valet_lot_t *lot; switch_console_callback_match_t *matches = NULL; switch_console_callback_match_node_t *m; switch_hash_index_t *i_hi; const void *i_var; void *i_val; char *i_ext; valet_token_t *token; now = switch_epoch_time_now(NULL); switch_mutex_lock(globals.mutex); if (now - globals.last_timeout_check < TOKEN_FREQ) { switch_mutex_unlock(globals.mutex); return; } globals.last_timeout_check = now; for (hi = switch_hash_first(NULL, globals.hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, &var, NULL, &val); switch_console_push_match(&matches, (const char *) var); } switch_mutex_unlock(globals.mutex); if (matches) { for (m = matches->head; m; m = m->next) { lot = valet_find_lot(m->val, SWITCH_FALSE); switch_mutex_lock(lot->mutex); top: for (i_hi = switch_hash_first(NULL, lot->hash); i_hi; i_hi = switch_hash_next(i_hi)) { switch_hash_this(i_hi, &i_var, NULL, &i_val); i_ext = (char *) i_var; token = (valet_token_t *) i_val; if (token->timeout > 0 && (token->timeout < now || token->timeout == 1)) { switch_core_hash_delete(lot->hash, i_ext); switch_safe_free(token); goto top; } } switch_mutex_unlock(lot->mutex); } switch_console_free_matches(&matches); } }
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; } }
static switch_status_t skinny_api_list_profiles(const char *line, const char *cursor, switch_console_callback_match_t **matches) { switch_console_callback_match_t *my_matches = NULL; switch_status_t status = SWITCH_STATUS_FALSE; switch_hash_index_t *hi; void *val; skinny_profile_t *profile; /* walk profiles */ switch_mutex_lock(globals.mutex); for (hi = switch_hash_first(NULL, globals.profile_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); profile = (skinny_profile_t *) val; switch_console_push_match(&my_matches, profile->name); } switch_mutex_unlock(globals.mutex); if (my_matches) { *matches = my_matches; status = SWITCH_STATUS_SUCCESS; } return status; }
static void event_handler(switch_event_t *event) { const char *sig = switch_event_get_header(event, "Trapped-Signal"); switch_hash_index_t *hi; void *val; cdr_fd_t *fd; if (globals.shutdown) { return; } if (sig && !strcmp(sig, "HUP")) { for (hi = switch_hash_first(NULL, globals.fd_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); fd = (cdr_fd_t *) val; switch_mutex_lock(fd->mutex); do_rotate(fd); switch_mutex_unlock(fd->mutex); } if (globals.db_online) { PQfinish(globals.db_connection); globals.db_online = 0; } } }
SWITCH_DECLARE(switch_status_t) switch_core_hash_delete_multi(switch_hash_t *hash, switch_hash_delete_callback_t callback, void *pData) { switch_hash_index_t *hi = NULL; switch_event_t *event = NULL; switch_event_header_t *header = NULL; switch_status_t status = SWITCH_STATUS_GENERR; switch_event_create_subclass(&event, SWITCH_EVENT_CLONE, NULL); switch_assert(event); /* iterate through the hash, call callback, if callback returns NULL or true, put the key on the list (event) When done, iterate through the list deleting hash entries */ for (hi = switch_hash_first(NULL, hash); hi; hi = switch_hash_next(hi)) { const void *key; void *val; switch_hash_this(hi, &key, NULL, &val); if (!callback || callback(key, val, pData)) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "delete", (const char *) key); } } /* now delete them */ for (header = event->headers; header; header = header->next) { if (switch_core_hash_delete(hash, header->value) == SWITCH_STATUS_SUCCESS) { status = SWITCH_STATUS_SUCCESS; } } switch_event_destroy(&event); return status; }
static int find_longest(valet_lot_t *lot, int min, int max) { switch_hash_index_t *i_hi; const void *i_var; void *i_val; valet_token_t *token; int longest = 0, cur = 0, longest_ext = 0; time_t now = switch_epoch_time_now(NULL); switch_mutex_lock(lot->mutex); for (i_hi = switch_hash_first(NULL, lot->hash); i_hi; i_hi = switch_hash_next(i_hi)) { int i; switch_hash_this(i_hi, &i_var, NULL, &i_val); token = (valet_token_t *) i_val; cur = (now - token->start_time); i = atoi(token->ext); if (cur > longest && i >= min && i <= max) { longest = cur; longest_ext = i; } } switch_mutex_unlock(lot->mutex); return longest_ext; }
/* Compute the usage sum of a resource on remote boxes */ static limit_hash_item_t get_remote_usage(const char *key) { limit_hash_item_t usage = { 0 }; switch_hash_index_t *hi; switch_thread_rwlock_rdlock(globals.remote_hash_rwlock); for (hi = switch_hash_first(NULL, globals.remote_hash); hi; hi = switch_hash_next(hi)) { void *val; const void *hashkey; switch_ssize_t keylen; limit_remote_t *remote; limit_hash_item_t *item; switch_hash_this(hi, &hashkey, &keylen, &val); remote = (limit_remote_t *)val; if (remote->state != REMOTE_UP) { continue; } switch_thread_rwlock_rdlock(remote->rwlock); if ((item = switch_core_hash_find(remote->index, key))) { usage.total_usage += item->total_usage; usage.rate_usage += item->rate_usage; if (!usage.last_check) { usage.last_check = item->last_check; } } switch_thread_rwlock_unlock(remote->rwlock); } switch_thread_rwlock_unlock(globals.remote_hash_rwlock); return usage; }
static void do_rotate_all() { switch_hash_index_t *hi; void *val; cdr_fd_t *fd; if (globals.shutdown) { return; } for (hi = switch_hash_first(NULL, globals.fd_hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, NULL, NULL, &val); fd = (cdr_fd_t *) val; switch_mutex_lock(fd->mutex); do_rotate(fd); switch_mutex_unlock(fd->mutex); } }
static void event_handler(switch_event_t *event) { switch_hash_index_t *hi; void *val; const char *sig = switch_event_get_header(event, "Trapped-Signal"); if (sig && !strcmp(sig, "HUP")) { 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; if (profile->rotate) { set_format_cdr_log_dirs(profile); } } } }
/** * Search for best voice based on attributes * @param cur_node the desired voice attributes * @param map the map to search * @param type "say" or "tts" * @param lang_required if true, language must match * @return the voice or NULL */ static struct voice *find_voice(struct ssml_node *cur_node, switch_hash_t *map, char *type, int lang_required) { switch_hash_index_t *hi = NULL; struct voice *voice = (struct voice *)switch_core_hash_find(map, cur_node->name); char *lang_name_gender = NULL; int best_score = 0; /* check cache */ lang_name_gender = switch_mprintf("%s-%s-%s-%s", type, cur_node->language, cur_node->name, cur_node->gender); voice = (struct voice *)switch_core_hash_find(globals.voice_cache, lang_name_gender); if (voice) { /* that was easy! */ goto done; } /* find best language, name, gender match */ for (hi = switch_hash_first(NULL, map); hi; hi = switch_hash_next(hi)) { const void *key; void *val; struct voice *candidate; int candidate_score = 0; switch_hash_this(hi, &key, NULL, &val); candidate = (struct voice *)val; candidate_score = score_voice(candidate, cur_node, lang_required); if (candidate_score > 0 && candidate_score > best_score) { voice = candidate; best_score = candidate_score; } } /* remember for next time */ if (voice) { switch_core_hash_insert(globals.voice_cache, lang_name_gender, voice); } done: switch_safe_free(lang_name_gender); return voice; }
static switch_status_t process_node(const switch_log_node_t *node, switch_log_level_t level) { switch_hash_index_t *hi; void *val; const void *var; logfile_profile_t *profile; for (hi = switch_hash_first(NULL, profile_hash); hi; hi = switch_hash_next(hi)) { size_t mask = 0; size_t ok = 0; switch_hash_this(hi, &var, NULL, &val); profile = val; ok = switch_log_check_mask(profile->all_level, level); if (!ok) { mask = (size_t) switch_core_hash_find(profile->log_hash, node->file); ok = switch_log_check_mask(mask, level); } if (!ok) { mask = (size_t) switch_core_hash_find(profile->log_hash, node->func); ok = switch_log_check_mask(mask, level); } if (ok) { if (profile->log_uuid && !zstr(node->userdata)) { char buf[2048]; switch_snprintf(buf, sizeof(buf), "%s %s", node->userdata, node->data); mod_logfile_raw_write(profile, buf); } else { mod_logfile_raw_write(profile, node->data); } } } return SWITCH_STATUS_SUCCESS; }
static int valet_lot_count(valet_lot_t *lot) { switch_hash_index_t *i_hi; const void *i_var; void *i_val; valet_token_t *token; int count = 0; time_t now; now = switch_epoch_time_now(NULL); switch_mutex_lock(lot->mutex); for (i_hi = switch_hash_first(NULL, lot->hash); i_hi; i_hi = switch_hash_next(i_hi)) { switch_hash_this(i_hi, &i_var, NULL, &i_val); token = (valet_token_t *) i_val; if (token->timeout > 0 && (token->timeout < now || token->timeout == 1)) { continue; } count++; } switch_mutex_unlock(lot->mutex); return count; }
static switch_status_t handle_ref_tuple(listener_t *listener, erlang_msg * msg, ei_x_buff * buf, ei_x_buff * rbuf) { erlang_ref ref; erlang_pid pid; char hash[100]; int arity; const void *key; void *val; session_elem_t *se; switch_hash_index_t *iter; int found = 0; ei_decode_tuple_header(buf->buff, &buf->index, &arity); if (ei_decode_ref(buf->buff, &buf->index, &ref)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid reference\n"); return SWITCH_STATUS_FALSE; } if (ei_decode_pid(buf->buff, &buf->index, &pid)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid pid in a reference/pid tuple\n"); return SWITCH_STATUS_FALSE; } ei_hash_ref(&ref, hash); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Hashed ref to %s\n", hash); switch_thread_rwlock_rdlock(listener->session_rwlock); for (iter = switch_hash_first(NULL, listener->sessions); iter; iter = switch_hash_next(iter)) { switch_hash_this(iter, &key, NULL, &val); se = (session_elem_t*)val; if (se->spawn_reply && !strncmp(se->spawn_reply->hash, hash, 100)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "found matching session for %s : %s\n", hash, se->uuid_str); switch_mutex_lock(se->spawn_reply->mutex); se->spawn_reply->pid = switch_core_alloc(se->pool, sizeof(erlang_pid)); switch_assert(se->spawn_reply->pid != NULL); memcpy(se->spawn_reply->pid, &pid, sizeof(erlang_pid)); switch_thread_cond_signal(se->spawn_reply->ready_or_found); switch_mutex_unlock(se->spawn_reply->mutex); found++; break; } } switch_thread_rwlock_unlock(listener->session_rwlock); if (found) { ei_x_encode_atom(rbuf, "ok"); } else { ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "notfound"); } return SWITCH_STATUS_SUCCESS; }
static void pres_event_handler(switch_event_t *event) { char *to = switch_event_get_header(event, "to"); char *dup_to = NULL, *lot_name, *dup_lot_name = NULL, *domain_name; valet_lot_t *lot; int found = 0; if (!to || strncasecmp(to, "park+", 5) || !strchr(to, '@')) { return; } if (!(dup_to = strdup(to))) { return; } lot_name = dup_to + 5; if ((domain_name = strchr(lot_name, '@'))) { *domain_name++ = '\0'; } dup_lot_name = switch_mprintf("%q@%q", lot_name, domain_name); if ((lot = valet_find_lot(lot_name, SWITCH_FALSE)) || (dup_lot_name && (lot = valet_find_lot(dup_lot_name, SWITCH_FALSE)))) { int count = valet_lot_count(lot); if (count) { if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", lot_name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "force-status", "Active (%d caller%s)", count, count == 1 ? "" : "s"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "active"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "confirmed"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound"); switch_event_fire(&event); } found++; } } else { if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Empty"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound"); switch_event_fire(&event); } } } else { switch_console_callback_match_t *matches = NULL; switch_console_callback_match_node_t *m; switch_hash_index_t *hi; const void *var; void *val; const char *nvar; switch_mutex_lock(globals.mutex); for (hi = switch_hash_first(NULL, globals.hash); hi; hi = switch_hash_next(hi)) { switch_hash_this(hi, &var, NULL, &val); nvar = (const char *) var; if (!strchr(nvar, '@') || switch_stristr(domain_name, nvar)) { switch_console_push_match(&matches, nvar); } } switch_mutex_unlock(globals.mutex); if (matches) { valet_token_t *token; for (m = matches->head; !found && m; m = m->next) { lot = valet_find_lot(m->val, SWITCH_FALSE); switch_mutex_lock(lot->mutex); if ((token = (valet_token_t *) switch_core_hash_find(lot->hash, lot_name)) && !token->timeout) { found++; if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", lot_name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", token->bridged == 0 ? "Holding" : "Active"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_ROUTING"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", token->bridged == 0 ? "early" : "confirmed"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", token->bridged == 0 ? "outbound" : "inbound"); switch_event_fire(&event); } } switch_mutex_unlock(lot->mutex); } } } if (!found && switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "proto", VALET_PROTO); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "login", lot_name); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", lot_name, domain_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "force-status", "Empty"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "rpid", "unknown"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event_type", "presence"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "alt_event_type", "dialog"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_count", "%d", EC++); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "unique-id", lot_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "channel-state", "CS_HANGUP"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "answer-state", "terminated"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "call-direction", "inbound"); switch_event_fire(&event); } switch_safe_free(dup_to); switch_safe_free(dup_lot_name); }
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; }
static switch_status_t handle_ref_tuple(listener_t *listener, erlang_msg * msg, ei_x_buff * buf, ei_x_buff * rbuf) { erlang_ref ref; erlang_pid *pid; char hash[100]; int arity; const void *key; void *val; session_elem_t *se; switch_hash_index_t *iter; ei_decode_tuple_header(buf->buff, &buf->index, &arity); if (ei_decode_ref(buf->buff, &buf->index, &ref)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid reference\n"); return SWITCH_STATUS_FALSE; } if (!(pid = malloc(sizeof(erlang_pid)))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n"); ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "badmem"); return SWITCH_STATUS_SUCCESS; } if (ei_decode_pid(buf->buff, &buf->index, pid)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid pid in a reference/pid tuple\n"); return SWITCH_STATUS_FALSE; } ei_hash_ref(&ref, hash); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Hashed ref to %s\n", hash); switch_thread_rwlock_rdlock(listener->session_rwlock); for (iter = switch_hash_first(NULL, listener->sessions); iter; iter = switch_hash_next(iter)) { switch_hash_this(iter, &key, NULL, &val); se = (session_elem_t*)val; if (se->spawn_reply && !strncmp(se->spawn_reply->hash, hash, 100)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "found matching session for %s : %s\n", hash, se->uuid_str); switch_mutex_lock(se->spawn_reply->mutex); if (se->spawn_reply->state == reply_not_ready) { switch_thread_cond_wait(se->spawn_reply->ready_or_found, se->spawn_reply->mutex); } if (se->spawn_reply->state == reply_waiting) { se->spawn_reply->pid = pid; switch_thread_cond_broadcast(se->spawn_reply->ready_or_found); ei_x_encode_atom(rbuf, "ok"); switch_thread_rwlock_unlock(listener->session_rwlock); switch_mutex_unlock(se->spawn_reply->mutex); return SWITCH_STATUS_SUCCESS; } switch_mutex_unlock(se->spawn_reply->mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "get_pid came in too late for %s; %s\n", hash, se->uuid_str); break; } } switch_thread_rwlock_unlock(listener->session_rwlock); ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "error"); ei_x_encode_atom(rbuf, "notfound"); switch_safe_free(pid); /* don't need it */ return SWITCH_STATUS_SUCCESS; }
static void event_handler(switch_event_t *event) { uint8_t send = 0; if (globals.running != 1) { return; } if (event->subclass_name && (!strcmp(event->subclass_name, MULTICAST_EVENT) || !strcmp(event->subclass_name, MULTICAST_PEERUP) || !strcmp(event->subclass_name, MULTICAST_PEERDOWN))) { char *event_name, *sender; if ((event_name = switch_event_get_header(event, "orig-event-name")) && !strcasecmp(event_name, "HEARTBEAT") && (sender = switch_event_get_header(event, "orig-multicast-sender"))) { struct peer_status *p; time_t now = switch_epoch_time_now(NULL); if (!(p = switch_core_hash_find(globals.peer_hash, sender))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Host %s not already in hash\n", sender); p = switch_core_alloc(module_pool, sizeof(struct peer_status)); p->active = SWITCH_FALSE; p->lastseen = 0; /*} else { */ /*switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Host %s last seen %d seconds ago\n", sender, now - p->lastseen); */ } if (!p->active) { switch_event_t *local_event; if (switch_event_create_subclass(&local_event, SWITCH_EVENT_CUSTOM, MULTICAST_PEERUP) == SWITCH_STATUS_SUCCESS) { char lastseen[21]; switch_event_add_header_string(local_event, SWITCH_STACK_BOTTOM, "Peer", sender); if (p->lastseen) { switch_snprintf(lastseen, sizeof(lastseen), "%d", (int) p->lastseen); } else { switch_snprintf(lastseen, sizeof(lastseen), "%s", "Never"); } switch_event_add_header_string(local_event, SWITCH_STACK_BOTTOM, "Lastseen", lastseen); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Peer %s has come up; last seen: %s\n", sender, lastseen); switch_event_fire(&local_event); } } p->active = SWITCH_TRUE; p->lastseen = now; switch_core_hash_insert(globals.peer_hash, sender, p); } /* ignore our own events to avoid ping pong */ return; } if (event->event_id == SWITCH_EVENT_RELOADXML) { switch_mutex_lock(globals.mutex); switch_core_hash_destroy(&globals.event_hash); globals.event_hash = NULL; if (globals.psk) { switch_safe_free(globals.psk); globals.psk = NULL; } switch_core_hash_init(&globals.event_hash, module_pool); memset(globals.event_list, 0, SWITCH_EVENT_ALL + 1); if (load_config() != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to reload config file\n"); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Event Multicast Reloaded\n"); } switch_mutex_unlock(globals.mutex); } if (event->event_id == SWITCH_EVENT_HEARTBEAT) { switch_hash_index_t *cur; switch_ssize_t keylen; const void *key; void *value; time_t now = switch_epoch_time_now(NULL); struct peer_status *last; char *host; for (cur = switch_hash_first(NULL, globals.peer_hash); cur; cur = switch_hash_next(cur)) { switch_hash_this(cur, &key, &keylen, &value); host = (char *) key; last = (struct peer_status *) value; if (last->active && (now - (last->lastseen)) > 60) { switch_event_t *local_event; last->active = SWITCH_FALSE; if (switch_event_create_subclass(&local_event, SWITCH_EVENT_CUSTOM, MULTICAST_PEERDOWN) == SWITCH_STATUS_SUCCESS) { char lastseen[21]; switch_event_add_header_string(local_event, SWITCH_STACK_BOTTOM, "Peer", host); switch_snprintf(lastseen, sizeof(lastseen), "%d", (int) last->lastseen); switch_event_add_header_string(local_event, SWITCH_STACK_BOTTOM, "Lastseen", lastseen); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Peer %s has gone down; last seen: %s\n", host, lastseen); switch_event_fire(&local_event); } } } } switch_mutex_lock(globals.mutex); if (globals.event_list[(uint8_t) SWITCH_EVENT_ALL]) { send = 1; } else if ((globals.event_list[(uint8_t) event->event_id])) { if (event->event_id != SWITCH_EVENT_CUSTOM || (event->subclass_name && switch_core_hash_find(globals.event_hash, event->subclass_name))) { send = 1; } } switch_mutex_unlock(globals.mutex); if (send) { char *packet; switch (event->event_id) { case SWITCH_EVENT_LOG: return; default: switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Multicast-Sender", switch_core_get_switchname()); if (switch_event_serialize(event, &packet, SWITCH_TRUE) == SWITCH_STATUS_SUCCESS) { size_t len; char *buf; #ifdef HAVE_OPENSSL int outlen, tmplen; EVP_CIPHER_CTX ctx; char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; switch_uuid_t uuid; switch_uuid_get(&uuid); switch_uuid_format(uuid_str, &uuid); len = strlen(packet) + SWITCH_UUID_FORMATTED_LENGTH + EVP_MAX_IV_LENGTH + strlen((char *) MAGIC); #else len = strlen(packet) + strlen((char *) MAGIC); #endif buf = malloc(len + 1); memset(buf, 0, len + 1); switch_assert(buf); #ifdef HAVE_OPENSSL if (globals.psk) { switch_copy_string(buf, uuid_str, SWITCH_UUID_FORMATTED_LENGTH); EVP_CIPHER_CTX_init(&ctx); EVP_EncryptInit(&ctx, EVP_bf_cbc(), NULL, NULL); EVP_CIPHER_CTX_set_key_length(&ctx, strlen(globals.psk)); EVP_EncryptInit(&ctx, NULL, (unsigned char *) globals.psk, (unsigned char *) uuid_str); EVP_EncryptUpdate(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH, &outlen, (unsigned char *) packet, (int) strlen(packet)); EVP_EncryptUpdate(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH + outlen, &tmplen, (unsigned char *) MAGIC, (int) strlen((char *) MAGIC)); outlen += tmplen; EVP_EncryptFinal(&ctx, (unsigned char *) buf + SWITCH_UUID_FORMATTED_LENGTH + outlen, &tmplen); outlen += tmplen; len = (size_t) outlen + SWITCH_UUID_FORMATTED_LENGTH; *(buf + SWITCH_UUID_FORMATTED_LENGTH + outlen) = '\0'; } else { #endif switch_copy_string(buf, packet, len); switch_copy_string(buf + strlen(packet), (char *) MAGIC, strlen((char *) MAGIC) + 1); #ifdef HAVE_OPENSSL } #endif switch_socket_sendto(globals.udp_socket, globals.addr, 0, buf, &len); switch_safe_free(packet); switch_safe_free(buf); } break; } } return; }