freeswitch/src/mod/event_handlers/mod_kazoo/kazoo_fetch_agent.c

790 lines
25 KiB
C

/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005-2012, Anthony Minessale II <anthm@freeswitch.org>
*
* Version: MPL 1.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
*
* The Initial Developer of the Original Code is
* Anthony Minessale II <anthm@freeswitch.org>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Karl Anderson <karl@2600hz.com>
* Darren Schreiber <darren@2600hz.com>
*
*
* kazoo_fetch.c -- XML fetch request handler
*
*/
#include "mod_kazoo.h"
static const char *fetch_uuid_sources[] = {
"Fetch-Call-UUID",
"refer-from-channel-id",
"sip_call_id",
NULL
};
static char *xml_section_to_string(switch_xml_section_t section) {
switch(section) {
case SWITCH_XML_SECTION_CONFIG:
return "configuration";
case SWITCH_XML_SECTION_DIRECTORY:
return "directory";
case SWITCH_XML_SECTION_DIALPLAN:
return "dialplan";
case SWITCH_XML_SECTION_CHATPLAN:
return "chatplan";
case SWITCH_XML_SECTION_CHANNELS:
return "channels";
case SWITCH_XML_SECTION_LANGUAGES:
return "languages";
default:
return "unknown";
}
}
static char *expand_vars(char *xml_str) {
char *var, *val;
char *rp = xml_str; /* read pointer */
char *ep, *wp, *buff; /* end pointer, write pointer, write buffer */
if (!(strstr(xml_str, "$${"))) {
return xml_str;
}
switch_zmalloc(buff, strlen(xml_str) * 2);
wp = buff;
ep = buff + (strlen(xml_str) * 2) - 1;
while (*rp && wp < ep) {
if (*rp == '$' && *(rp + 1) == '$' && *(rp + 2) == '{') {
char *e = switch_find_end_paren(rp + 2, '{', '}');
if (e) {
rp += 3;
var = rp;
*e++ = '\0';
rp = e;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "trying to expand %s \n", var);
if ((val = switch_core_get_variable_dup(var))) {
char *p;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "expanded %s to %s\n", var, val);
for (p = val; p && *p && wp <= ep; p++) {
*wp++ = *p;
}
switch_safe_free(val);
}
continue;
}
}
*wp++ = *rp++;
}
*wp++ = '\0';
switch_safe_free(xml_str);
return buff;
}
static switch_xml_t fetch_handler(const char *section, const char *tag_name, const char *key_name, const char *key_value, switch_event_t *params, void *user_data) {
switch_xml_t xml = NULL;
switch_uuid_t uuid;
switch_time_t now = 0;
ei_xml_agent_t *agent = (ei_xml_agent_t *) user_data;
ei_xml_client_t *client;
fetch_handler_t *fetch_handler;
xml_fetch_reply_t reply, *pending, *prev = NULL;
switch_event_t *event = params;
kazoo_fetch_profile_ptr profile = agent->profile;
const char *fetch_call_id;
ei_send_msg_t *send_msg = NULL;
int sent = 0;
now = switch_micro_time_now();
if (!switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) {
return xml;
}
/* read-lock the agent */
switch_thread_rwlock_rdlock(agent->lock);
/* serialize access to current, used to round-robin requests */
/* TODO: check kazoo_globals for round-robin boolean or loop all clients */
switch_mutex_lock(agent->current_client_mutex);
if (!agent->current_client) {
client = agent->clients;
} else {
client = agent->current_client;
}
if (client) {
agent->current_client = client->next;
}
switch_mutex_unlock(agent->current_client_mutex);
/* no client, no work required */
if (!client || !client->fetch_handlers) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "No %s XML erlang handler currently available\n"
,section);
switch_thread_rwlock_unlock(agent->lock);
return xml;
}
if(event == NULL) {
if (switch_event_create(&event, SWITCH_EVENT_GENERAL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error creating event for fetch handler\n");
return xml;
}
}
/* prepare the reply collector */
switch_uuid_get(&uuid);
switch_uuid_format(reply.uuid_str, &uuid);
reply.next = NULL;
reply.xml_str = NULL;
if(switch_event_get_header(event, "Unique-ID") == NULL) {
int i;
for(i = 0; fetch_uuid_sources[i] != NULL; i++) {
if((fetch_call_id = switch_event_get_header(event, fetch_uuid_sources[i])) != NULL) {
switch_core_session_t *session = NULL;
if((session = switch_core_session_force_locate(fetch_call_id)) != NULL) {
switch_channel_t *channel = switch_core_session_get_channel(session);
uint32_t verbose = switch_channel_test_flag(channel, CF_VERBOSE_EVENTS);
switch_channel_set_flag(channel, CF_VERBOSE_EVENTS);
switch_channel_event_set_data(channel, event);
switch_channel_set_flag_value(channel, CF_VERBOSE_EVENTS, verbose);
switch_core_session_rwunlock(session);
break;
}
}
}
}
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-UUID", reply.uuid_str);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-Section", section);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-Tag", tag_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-Key-Name", key_name);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-Key-Value", key_value);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Fetch-Timeout", "%u", profile->fetch_timeout);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Fetch-Timestamp-Micro", "%" SWITCH_UINT64_T_FMT, (uint64_t)now);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Kazoo-Version", VERSION);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Kazoo-Bundle", BUNDLE);
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Kazoo-Release", RELEASE);
kz_event_decode(event);
switch_malloc(send_msg, sizeof(*send_msg));
if(client->ei_node->legacy) {
ei_x_new_with_version(&send_msg->buf);
ei_x_encode_tuple_header(&send_msg->buf, 7);
ei_x_encode_atom(&send_msg->buf, "fetch");
ei_x_encode_atom(&send_msg->buf, section);
_ei_x_encode_string(&send_msg->buf, tag_name ? tag_name : "undefined");
_ei_x_encode_string(&send_msg->buf, key_name ? key_name : "undefined");
_ei_x_encode_string(&send_msg->buf, key_value ? key_value : "undefined");
_ei_x_encode_string(&send_msg->buf, reply.uuid_str);
ei_encode_switch_event_headers(&send_msg->buf, event);
} else {
kazoo_message_ptr msg = kazoo_message_create_fetch(event, profile);
ei_x_new_with_version(&send_msg->buf);
ei_x_encode_tuple_header(&send_msg->buf, 2);
ei_x_encode_atom(&send_msg->buf, "fetch");
ei_encode_json(&send_msg->buf, msg->JObj);
kazoo_message_destroy(&msg);
}
/* add our reply placeholder to the replies list */
switch_mutex_lock(agent->replies_mutex);
if (!agent->replies) {
agent->replies = &reply;
} else {
reply.next = agent->replies;
agent->replies = &reply;
}
switch_mutex_unlock(agent->replies_mutex);
fetch_handler = client->fetch_handlers;
while (fetch_handler != NULL && sent == 0) {
memcpy(&send_msg->pid, &fetch_handler->pid, sizeof(erlang_pid));
if (switch_queue_trypush(client->ei_node->send_msgs, send_msg) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send %s XML request to %s <%d.%d.%d>\n"
,section
,fetch_handler->pid.node
,fetch_handler->pid.creation
,fetch_handler->pid.num
,fetch_handler->pid.serial);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending %s XML request (%s) to %s <%d.%d.%d>\n"
,section
,reply.uuid_str
,fetch_handler->pid.node
,fetch_handler->pid.creation
,fetch_handler->pid.num
,fetch_handler->pid.serial);
sent = 1;
}
fetch_handler = fetch_handler->next;
}
if(!sent) {
ei_x_free(&send_msg->buf);
switch_safe_free(send_msg);
}
if(params == NULL)
switch_event_destroy(&event);
/* wait for a reply (if there isnt already one...amazingly improbable but lets not take shortcuts */
switch_mutex_lock(agent->replies_mutex);
switch_thread_rwlock_unlock(agent->lock);
if (!reply.xml_str) {
switch_time_t timeout;
timeout = switch_micro_time_now() + 3000000;
while (switch_micro_time_now() < timeout) {
/* unlock the replies list and go to sleep, calculate a three second timeout before we started the loop
* plus 100ms to add a little hysteresis between the timeout and the while loop */
switch_thread_cond_timedwait(agent->new_reply, agent->replies_mutex, (timeout - switch_micro_time_now() + 100000));
/* if we woke up (and therefore have locked replies again) check if we got our reply
* otherwise we either timed-out (the while condition will fail) or one of
* our sibling processes got a reply and we should go back to sleep */
if (reply.xml_str) {
break;
}
}
}
/* find our reply placeholder in the linked list and remove it */
pending = agent->replies;
while (pending != NULL) {
if (pending->uuid_str == reply.uuid_str) {
break;
}
prev = pending;
pending = pending->next;
}
if (pending) {
if (!prev) {
agent->replies = reply.next;
} else {
prev->next = reply.next;
}
}
/* we are done with the replies link-list */
switch_mutex_unlock(agent->replies_mutex);
/* after all that did we get what we were after?! */
if (reply.xml_str) {
/* HELL YA WE DID */
if (kazoo_globals.expand_headers_on_fetch) {
reply.xml_str = expand_vars(reply.xml_str);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Received %s XML (%s) after %dms: %s\n"
,section
,reply.uuid_str
,(unsigned int) (switch_micro_time_now() - now) / 1000
,reply.xml_str);
xml = switch_xml_parse_str_dynamic(reply.xml_str, SWITCH_FALSE);
} else {
/* facepalm */
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Request for %s XML (%s) timed-out after %dms\n"
,section
,reply.uuid_str
,(unsigned int) (switch_micro_time_now() - now) / 1000);
}
return xml;
}
void bind_fetch_profile(ei_xml_agent_t *agent, kazoo_config_ptr fetch_handlers)
{
switch_hash_index_t *hi;
kazoo_fetch_profile_ptr val = NULL, ptr = NULL;
for (hi = switch_core_hash_first(fetch_handlers->hash); hi; hi = switch_core_hash_next(&hi)) {
switch_core_hash_this(hi, NULL, NULL, (void**) &val);
if (val && val->section == agent->section) {
ptr = val;
break;
}
}
agent->profile = ptr;
}
void rebind_fetch_profiles(kazoo_config_ptr fetch_handlers)
{
if(kazoo_globals.config_fetch_binding != NULL)
bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.config_fetch_binding), fetch_handlers);
if(kazoo_globals.directory_fetch_binding != NULL)
bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.directory_fetch_binding), fetch_handlers);
if(kazoo_globals.dialplan_fetch_binding != NULL)
bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.dialplan_fetch_binding), fetch_handlers);
if(kazoo_globals.channels_fetch_binding != NULL)
bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.channels_fetch_binding), fetch_handlers);
if(kazoo_globals.languages_fetch_binding != NULL)
bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.languages_fetch_binding), fetch_handlers);
if(kazoo_globals.chatplan_fetch_binding != NULL)
bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.chatplan_fetch_binding), fetch_handlers);
}
static switch_status_t bind_fetch_agent(switch_xml_section_t section, switch_xml_binding_t **binding) {
switch_memory_pool_t *pool = NULL;
ei_xml_agent_t *agent;
/* create memory pool for this xml search binging (lives for duration of mod_kazoo runtime) */
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Out of memory: They're not people; they're hippies!\n");
return SWITCH_STATUS_MEMERR;
}
/* allocate some memory to store the fetch bindings for this section */
if (!(agent = switch_core_alloc(pool, sizeof (*agent)))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Out of memory: Oh, Jesus tap-dancing Christ!\n");
return SWITCH_STATUS_MEMERR;
}
/* try to bind to the switch */
if (switch_xml_bind_search_function_ret(fetch_handler, section, agent, binding) != SWITCH_STATUS_SUCCESS) {
switch_core_destroy_memory_pool(&pool);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not bind to FreeSWITCH %s XML requests\n"
,xml_section_to_string(section));
return SWITCH_STATUS_GENERR;
}
agent->pool = pool;
agent->section = section;
switch_thread_rwlock_create(&agent->lock, pool);
agent->clients = NULL;
switch_mutex_init(&agent->current_client_mutex, SWITCH_MUTEX_DEFAULT, pool);
agent->current_client = NULL;
switch_mutex_init(&agent->replies_mutex, SWITCH_MUTEX_DEFAULT, pool);
switch_thread_cond_create(&agent->new_reply, pool);
agent->replies = NULL;
bind_fetch_profile(agent, kazoo_globals.fetch_handlers);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Bound to %s XML requests\n"
,xml_section_to_string(section));
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t unbind_fetch_agent(switch_xml_binding_t **binding) {
ei_xml_agent_t *agent;
ei_xml_client_t *client;
if(*binding == NULL)
return SWITCH_STATUS_GENERR;
/* get a pointer to our user_data */
agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(*binding);
/* unbind from the switch */
switch_xml_unbind_search_function(binding);
/* LOCK ALL THE THINGS */
switch_thread_rwlock_wrlock(agent->lock);
switch_mutex_lock(agent->current_client_mutex);
switch_mutex_lock(agent->replies_mutex);
/* cleanly destroy each client */
client = agent->clients;
while(client != NULL) {
ei_xml_client_t *tmp_client = client;
fetch_handler_t *fetch_handler;
fetch_handler = client->fetch_handlers;
while(fetch_handler != NULL) {
fetch_handler_t *tmp_fetch_handler = fetch_handler;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed %s XML handler %s <%d.%d.%d>\n"
,xml_section_to_string(agent->section)
,fetch_handler->pid.node
,fetch_handler->pid.creation
,fetch_handler->pid.num
,fetch_handler->pid.serial);
fetch_handler = fetch_handler->next;
switch_safe_free(tmp_fetch_handler);
}
client = client->next;
switch_safe_free(tmp_client);
}
/* keep the pointers clean, even if its just for a moment */
agent->clients = NULL;
agent->current_client = NULL;
/* release the locks! */
switch_thread_rwlock_unlock(agent->lock);
switch_mutex_unlock(agent->current_client_mutex);
switch_mutex_unlock(agent->replies_mutex);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unbound from %s XML requests\n"
,xml_section_to_string(agent->section));
/* cleanly destroy the bindings */
switch_thread_rwlock_destroy(agent->lock);
switch_mutex_destroy(agent->current_client_mutex);
switch_mutex_destroy(agent->replies_mutex);
switch_thread_cond_destroy(agent->new_reply);
switch_core_destroy_memory_pool(&agent->pool);
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t remove_xml_client(ei_node_t *ei_node, switch_xml_binding_t *binding) {
ei_xml_agent_t *agent;
ei_xml_client_t *client, *prev = NULL;
int found = 0;
if(binding == NULL)
return SWITCH_STATUS_GENERR;
agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(binding);
/* write-lock the agent */
switch_thread_rwlock_wrlock(agent->lock);
client = agent->clients;
while (client != NULL) {
if (client->ei_node == ei_node) {
found = 1;
break;
}
prev = client;
client = client->next;
}
if (found) {
fetch_handler_t *fetch_handler;
if (!prev) {
agent->clients = client->next;
} else {
prev->next = client->next;
}
/* the mutex lock is not required since we have the write lock
* but hey its fun and safe so do it anyway */
switch_mutex_lock(agent->current_client_mutex);
if (agent->current_client == client) {
agent->current_client = agent->clients;
}
switch_mutex_unlock(agent->current_client_mutex);
fetch_handler = client->fetch_handlers;
while(fetch_handler != NULL) {
fetch_handler_t *tmp_fetch_handler = fetch_handler;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed %s XML handler %s <%d.%d.%d>\n"
,xml_section_to_string(agent->section)
,fetch_handler->pid.node
,fetch_handler->pid.creation
,fetch_handler->pid.num
,fetch_handler->pid.serial);
fetch_handler = fetch_handler->next;
switch_safe_free(tmp_fetch_handler);
}
switch_safe_free(client);
}
switch_thread_rwlock_unlock(agent->lock);
return SWITCH_STATUS_SUCCESS;
}
static ei_xml_client_t *add_xml_client(ei_node_t *ei_node, ei_xml_agent_t *agent) {
ei_xml_client_t *client;
switch_malloc(client, sizeof(*client));
client->ei_node = ei_node;
client->fetch_handlers = NULL;
client->next = NULL;
if (agent->clients) {
client->next = agent->clients;
}
agent->clients = client;
return client;
}
static ei_xml_client_t *find_xml_client(ei_node_t *ei_node, ei_xml_agent_t *agent) {
ei_xml_client_t *client;
client = agent->clients;
while (client != NULL) {
if (client->ei_node == ei_node) {
return client;
}
client = client->next;
}
return NULL;
}
static switch_status_t remove_fetch_handler(ei_node_t *ei_node, erlang_pid *from, switch_xml_binding_t *binding) {
ei_xml_agent_t *agent;
ei_xml_client_t *client;
fetch_handler_t *fetch_handler, *prev = NULL;
int found = 0;
agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(binding);
/* write-lock the agent */
switch_thread_rwlock_wrlock(agent->lock);
if (!(client = find_xml_client(ei_node, agent))) {
switch_thread_rwlock_unlock(agent->lock);
return SWITCH_STATUS_SUCCESS;
}
fetch_handler = client->fetch_handlers;
while (fetch_handler != NULL) {
if (ei_compare_pids(&fetch_handler->pid, from) == SWITCH_STATUS_SUCCESS) {
found = 1;
break;
}
prev = fetch_handler;
fetch_handler = fetch_handler->next;
}
if (found) {
if (!prev) {
client->fetch_handlers = fetch_handler->next;
} else {
prev->next = fetch_handler->next;
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Removed %s XML handler %s <%d.%d.%d>\n"
,xml_section_to_string(agent->section)
,fetch_handler->pid.node
,fetch_handler->pid.creation
,fetch_handler->pid.num
,fetch_handler->pid.serial);
switch_safe_free(fetch_handler);
}
switch_thread_rwlock_unlock(agent->lock);
return SWITCH_STATUS_SUCCESS;
}
static switch_status_t handle_api_command_stream(ei_node_t *ei_node, switch_stream_handle_t *stream, switch_xml_binding_t *binding) {
ei_xml_agent_t *agent;
ei_xml_client_t *client;
if (!binding) {
return SWITCH_STATUS_GENERR;
}
agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(binding);
/* read-lock the agent */
switch_thread_rwlock_rdlock(agent->lock);
client = agent->clients;
while (client != NULL) {
if (client->ei_node == ei_node) {
fetch_handler_t *fetch_handler;
fetch_handler = client->fetch_handlers;
while (fetch_handler != NULL) {
stream->write_function(stream, "XML %s handler <%d.%d.%d>\n"
,xml_section_to_string(agent->section)
,fetch_handler->pid.creation
,fetch_handler->pid.num
,fetch_handler->pid.serial);
fetch_handler = fetch_handler->next;
}
break;
}
client = client->next;
}
switch_thread_rwlock_unlock(agent->lock);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t bind_fetch_agents() {
bind_fetch_agent(SWITCH_XML_SECTION_CONFIG, &kazoo_globals.config_fetch_binding);
bind_fetch_agent(SWITCH_XML_SECTION_DIRECTORY, &kazoo_globals.directory_fetch_binding);
bind_fetch_agent(SWITCH_XML_SECTION_DIALPLAN, &kazoo_globals.dialplan_fetch_binding);
bind_fetch_agent(SWITCH_XML_SECTION_CHANNELS, &kazoo_globals.channels_fetch_binding);
bind_fetch_agent(SWITCH_XML_SECTION_LANGUAGES, &kazoo_globals.languages_fetch_binding);
bind_fetch_agent(SWITCH_XML_SECTION_CHATPLAN, &kazoo_globals.chatplan_fetch_binding);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t unbind_fetch_agents() {
unbind_fetch_agent(&kazoo_globals.config_fetch_binding);
unbind_fetch_agent(&kazoo_globals.directory_fetch_binding);
unbind_fetch_agent(&kazoo_globals.dialplan_fetch_binding);
unbind_fetch_agent(&kazoo_globals.channels_fetch_binding);
unbind_fetch_agent(&kazoo_globals.languages_fetch_binding);
unbind_fetch_agent(&kazoo_globals.chatplan_fetch_binding);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t remove_xml_clients(ei_node_t *ei_node) {
remove_xml_client(ei_node, kazoo_globals.config_fetch_binding);
remove_xml_client(ei_node, kazoo_globals.directory_fetch_binding);
remove_xml_client(ei_node, kazoo_globals.dialplan_fetch_binding);
remove_xml_client(ei_node, kazoo_globals.channels_fetch_binding);
remove_xml_client(ei_node, kazoo_globals.languages_fetch_binding);
remove_xml_client(ei_node, kazoo_globals.chatplan_fetch_binding);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t add_fetch_handler(ei_node_t *ei_node, erlang_pid *from, switch_xml_binding_t *binding) {
ei_xml_agent_t *agent;
ei_xml_client_t *client;
fetch_handler_t *fetch_handler;
if(binding == NULL)
return SWITCH_STATUS_GENERR;
agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(binding);
/* write-lock the agent */
switch_thread_rwlock_wrlock(agent->lock);
if (!(client = find_xml_client(ei_node, agent))) {
client = add_xml_client(ei_node, agent);
}
fetch_handler = client->fetch_handlers;
while (fetch_handler != NULL) {
if (ei_compare_pids(&fetch_handler->pid, from) == SWITCH_STATUS_SUCCESS) {
switch_thread_rwlock_unlock(agent->lock);
return SWITCH_STATUS_SUCCESS;
}
fetch_handler = fetch_handler->next;
}
switch_malloc(fetch_handler, sizeof(*fetch_handler));
memcpy(&fetch_handler->pid, from, sizeof(erlang_pid));;
fetch_handler->next = NULL;
if (client->fetch_handlers) {
fetch_handler->next = client->fetch_handlers;
}
client->fetch_handlers = fetch_handler;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Added %s XML handler %s <%d.%d.%d>\n"
,xml_section_to_string(agent->section)
,fetch_handler->pid.node
,fetch_handler->pid.creation
,fetch_handler->pid.num
,fetch_handler->pid.serial);
switch_thread_rwlock_unlock(agent->lock);
ei_link(ei_node, ei_self(&kazoo_globals.ei_cnode), from);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t remove_fetch_handlers(ei_node_t *ei_node, erlang_pid *from) {
remove_fetch_handler(ei_node, from, kazoo_globals.config_fetch_binding);
remove_fetch_handler(ei_node, from, kazoo_globals.directory_fetch_binding);
remove_fetch_handler(ei_node, from, kazoo_globals.dialplan_fetch_binding);
remove_fetch_handler(ei_node, from, kazoo_globals.channels_fetch_binding);
remove_fetch_handler(ei_node, from, kazoo_globals.languages_fetch_binding);
remove_fetch_handler(ei_node, from, kazoo_globals.chatplan_fetch_binding);
return SWITCH_STATUS_SUCCESS;
}
switch_status_t fetch_reply(char *uuid_str, char *xml_str, switch_xml_binding_t *binding) {
ei_xml_agent_t *agent;
xml_fetch_reply_t *reply;
switch_status_t status = SWITCH_STATUS_NOTFOUND;
agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(binding);
switch_mutex_lock(agent->replies_mutex);
reply = agent->replies;
while (reply != NULL) {
if (!strncmp(reply->uuid_str, uuid_str, SWITCH_UUID_FORMATTED_LENGTH)) {
if (!reply->xml_str) {
reply->xml_str = xml_str;
switch_thread_cond_broadcast(agent->new_reply);
status = SWITCH_STATUS_SUCCESS;
}
break;
}
reply = reply->next;
}
switch_mutex_unlock(agent->replies_mutex);
return status;
}
switch_status_t handle_api_command_streams(ei_node_t *ei_node, switch_stream_handle_t *stream) {
handle_api_command_stream(ei_node, stream, kazoo_globals.config_fetch_binding);
handle_api_command_stream(ei_node, stream, kazoo_globals.directory_fetch_binding);
handle_api_command_stream(ei_node, stream, kazoo_globals.dialplan_fetch_binding);
handle_api_command_stream(ei_node, stream, kazoo_globals.channels_fetch_binding);
handle_api_command_stream(ei_node, stream, kazoo_globals.languages_fetch_binding);
handle_api_command_stream(ei_node, stream, kazoo_globals.chatplan_fetch_binding);
return SWITCH_STATUS_SUCCESS;
}
/* For Emacs:
* Local Variables:
* mode:c
* indent-tabs-mode:t
* tab-width:4
* c-basic-offset:4
* End:
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4:
*/