Add mod_event_socket remote client module and sample client.

To Test:

uncomment or add from modules.conf
make installall again to compile it
uncomment the load line from freeswitch.xml

the default values are to bind to 127.0.0.1 port 8021

telnet to port 8021
enter "auth ClueCon" to authenticate

from here you can do the following:
*) events [xml|plain] <list of events to log or all for all>
*) noevents 
*) log <level> // same as the console.conf values
*) nolog
*) api <command> <arg>
*) exit

there is a perl client in scripts/socket called fs.pl

with the module up and loaded:
cd scripts/socket
perl fs.pl <optional log level>

you can enter a few api commands like "show or status"




git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2047 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
Anthony Minessale 2006-07-22 21:49:52 +00:00
parent 7a5bc3b711
commit 9c79c2a3fb
9 changed files with 1130 additions and 10 deletions

View File

@ -21,7 +21,8 @@
<!-- <load module="mod_event_test"/> -->
<!-- <load module="mod_zeroconf"/> -->
<!-- <load module="mod_xmpp_event"/> -->
<!-- <load module="mod_event_socket"/> -->
<!-- Directory Interfaces -->
<!-- <load module="mod_ldap"/> -->
@ -72,7 +73,15 @@
</modules>
</configuration>
<configuration name="event_socket.conf" description="Socket Client">
<settings>
<param name="listen-ip" value="127.0.0.1"/>
<param name="listen-port" value="8021"/>
<param name="password" value="ClueCon"/>
</settings>
</configuration>
<configuration name="iax.conf" description="IAX Configuration">
<settings>
<param name="debug" value="0"/>

View File

@ -29,6 +29,7 @@ endpoints/mod_woomera
#event_handlers/mod_event_test
event_handlers/mod_xmpp_event
#event_handlers/mod_zeroconf
#event_handlers/mod_event_socket
formats/mod_sndfile
#languages/mod_perl
#languages/mod_spidermonkey

View File

@ -0,0 +1,134 @@
package FreeSWITCH::Client;
$|=1;
use IO::Socket::INET;
use IO::Select;
use Data::Dumper;
sub init($;$) {
my $proto = shift;
my $args = shift;
my $class = ref($proto) || $proto;
$self->{_host} = $args->{-host} || "localhost";
$self->{_port} = $args->{-port} || 8021;
$self->{_password} = $args->{-password} || undef;
my $me = bless $self,$class;
if ($me->connect()) {
return $me;
} else {
return undef;
}
}
sub input($;$) {
my ($self,$to) = @_;
my $i;
my @r;
my $s = $self->{_sock};
my $x = 0;
my $done = 0;
my $start = time;
while(!$done) {
if ($to and time - $start > $to) {
last;
}
@ready = $self->{_sel}->can_read($to);
if (@ready) {
$x=0;
foreach my $s (@ready) {
while ($i = <$s>) {
$x++;
return @r if($i eq "\n");
$i =~ s/[\n]+$//g;
push @r,$i;
}
unless($x) {
return ("SocketError: yes");
}
}
}
}
return @r;
}
sub readhash($$) {
my $self = shift;
my $arg = shift;
my @r = $self->input($arg);
my $data = join "\n", @r;
my %h = $data =~ /^([^:]+)\s*:\s*([^\n]*)/mg;
foreach (keys %h) {
my $new = lc $_;
$h{$new} = $h{$_};
delete $h{$_};
}
if ($h{'content-length'}) {
my $s = $self->{_sock};
read $s, $h{body}, $h{'content-length'};
}
return \%h;
}
sub error($$) {
my($self,$error) = @_;
die $error;
}
sub output($$) {
my ($self,$data) = @_;
my $s = $self->{_sock};
print $s $data;
}
sub cmd($$$) {
my $self = shift;
my $cmd = shift;
my $to = shift;
$self->output($cmd);
my $h = $self->readhash($to);
$h;
}
sub connect($) {
my $self = shift;
$self->{_sock} = new IO::Socket::INET( Proto => 'tcp',
PeerAddr => $self->{_host},
PeerPort => $self->{_port}
) or return $self->error("Connection refused $self->{_host} port $self->{_port}");
$self->{_sock}->autoflush(1);
#$self->{_sock}->blocking(0);
$self->{_sel} = new IO::Select( $self->{_sock} );
my $h = $self->readhash(undef);
if ($h->{"content-type"} eq "auth/request") {
my $pass = $self->{"_password"};
$self->output("auth $pass");
$h = $self->readhash(undef);
}
if ($h->{'reply-text'} =~ "OK") {
return 1;
}
return 0;
}
1;

55
scripts/socket/fs.pl Normal file
View File

@ -0,0 +1,55 @@
use FreeSWITCH::Client;
use Data::Dumper;
use Term::ReadLine;
my $password = "ClueCon";
my $fs = init FreeSWITCH::Client {-password => $password} or die "Error $@";
my $term = new Term::ReadLine ?FreeSWITCH CLI?;
my $prompt = "FS>";
my $OUT = $term->OUT .. \*STDOUT;
my $log = shift;
if ($log) {
$pid = fork;
if (!$pid) {
my $fs2 = init FreeSWITCH::Client {-password => $password} or die "Error $@";
$fs2->cmd("log $log");
while (1) {
my $reply = $fs2->readhash(undef);
if ($reply->{body}) {
print $reply->{body} . "\n";
} elsif ($reply->{'reply-text'}) {
print $reply->{'reply-text'} . "\n";
}
}
}
}
while ( defined ($_ = $term->readline($prompt)) ) {
my $reply;
if ($_) {
if ($_ =~ /^alog|^anolog/) {
$reply = $fs2->cmd($_);
} else {
$reply = $fs->cmd("api $_");
}
if ($reply->{body}) {
print $reply->{body};
} elsif ($reply->{'reply-text'}) {
print $reply->{'reply-text'};
}
print "\n";
if ($_ =~ /exit/) {
last;
}
}
$term->addhistory($_) if /\S/;
}

View File

@ -208,6 +208,14 @@ SWITCH_DECLARE(switch_status_t) switch_event_bind(char *id, switch_event_types_t
*/
SWITCH_DECLARE(char *) switch_event_name(switch_event_types_t event);
/*!
\brief return the event id that matches a given event name
\param name the name of the event
\param type the event id to return
\return SWITCH_STATUS_SUCCESS if there was a match
*/
SWITCH_DECLARE(switch_status_t) switch_name_event(char *name, switch_event_types_t *type);
/*!
\brief Reserve a subclass name for private use with a custom event
\param owner the owner of the event name

View File

@ -0,0 +1,672 @@
/*
* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
* Copyright (C) 2005/2006, Anthony Minessale II <anthmct@yahoo.com>
*
* 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 <anthmct@yahoo.com>
* Portions created by the Initial Developer are Copyright (C)
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Anthony Minessale II <anthmct@yahoo.com>
*
*
* mod_event_socket.c -- Framework Demo Module
*
*/
#include <switch.h>
#define CMD_BUFLEN 1024 * 1000
static const char modname[] = "mod_event_socket";
static char *MARKER = "1";
typedef enum {
LFLAG_AUTHED = (1 << 0),
LFLAG_RUNNING = (1 << 1),
LFLAG_EVENTS = (1 << 2),
LFLAG_LOG = (1 << 3)
} event_flag_t;
typedef enum {
EVENT_FORMAT_PLAIN,
EVENT_FORMAT_XML
} event_format_t;
struct listener {
switch_socket_t *sock;
switch_queue_t *event_queue;
switch_queue_t *log_queue;
switch_memory_pool_t *pool;
event_format_t format;
switch_mutex_t *flag_mutex;
uint32_t flags;
switch_log_level_t level;
char *retbuf;
uint8_t event_list[SWITCH_EVENT_ALL];
switch_hash_t *event_hash;
struct listener *next;
};
typedef struct listener listener_t;
static struct {
switch_socket_t *sock;
switch_mutex_t *mutex;
listener_t *listeners;
uint8_t ready;
} listen_list;
static struct {
char *ip;
uint16_t port;
char *password;
} prefs;
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_ip, prefs.ip)
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_pass, prefs.password)
static switch_status_t socket_logger(const switch_log_node_t *node, switch_log_level_t level)
{
listener_t *l;
switch_mutex_lock(listen_list.mutex);
for (l = listen_list.listeners; l; l = l->next) {
if (switch_test_flag(l, LFLAG_LOG) && l->level >= node->level) {
char *data = strdup(node->data);
if (data) {
switch_queue_push(l->log_queue, data);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
}
}
}
switch_mutex_unlock(listen_list.mutex);
return SWITCH_STATUS_SUCCESS;
}
static void event_handler(switch_event_t *event)
{
switch_event_t *clone = NULL;
listener_t *l;
assert(event != NULL);
if (!listen_list.ready) {
return;
}
switch_mutex_lock(listen_list.mutex);
for (l = listen_list.listeners; l; l = l->next) {
if (switch_test_flag(l, LFLAG_EVENTS) && (l->event_list[(uint8_t)event->event_id] || l->event_list[(uint8_t)SWITCH_EVENT_ALL])) {
if (event->event_id != SWITCH_EVENT_CUSTOM || switch_core_hash_find(l->event_hash, switch_event_name(event->event_id))) {
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
switch_queue_push(l->event_queue, clone);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
}
}
}
}
switch_mutex_unlock(listen_list.mutex);
}
static switch_loadable_module_interface_t event_socket_module_interface = {
/*.module_name */ modname,
/*.endpoint_interface */ NULL,
/*.timer_interface */ NULL,
/*.dialplan_interface */ NULL,
/*.codec_interface */ NULL,
/*.application_interface */ NULL
};
static void close_socket(switch_socket_t **sock) {
if (*sock) {
apr_socket_shutdown(*sock, APR_SHUTDOWN_READWRITE);
switch_socket_close(*sock);
*sock = NULL;
}
}
SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void)
{
close_socket(&listen_list.sock);
return SWITCH_STATUS_SUCCESS;
}
SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
{
/* connect my internal structure to the blank pointer passed to me */
*module_interface = &event_socket_module_interface;
/* indicate that the module should continue to be loaded */
return SWITCH_STATUS_SUCCESS;
}
static void add_listener(listener_t *listener)
{
/* add me to the listeners so I get events */
switch_mutex_lock(listen_list.mutex);
listener->next = listen_list.listeners;
listen_list.listeners = listener;
switch_mutex_unlock(listen_list.mutex);
}
static void remove_listener(listener_t *listener)
{
listener_t *l, *last = NULL;
switch_mutex_lock(listen_list.mutex);
for (l = listen_list.listeners; l; l = l->next) {
if (l == listener) {
if (last) {
last->next = l->next;
} else {
listen_list.listeners = l->next;
}
}
last = l;
}
switch_mutex_unlock(listen_list.mutex);
}
static void strip_cr(char *s)
{
char *p;
if ((p = strchr(s, '\r')) || (p = strchr(s, '\n'))) {
*p = '\0';
}
}
static void parse_command(listener_t *listener, char *cmd, char *reply, uint32_t reply_len)
{
*reply = '\0';
if (!strncasecmp(cmd, "exit", 4)) {
switch_clear_flag_locked(listener, LFLAG_RUNNING);
snprintf(reply, reply_len, "+OK bye");
goto done;
}
if (!switch_test_flag(listener, LFLAG_AUTHED)) {
if (!strncasecmp(cmd, "auth ", 5)) {
strip_cr(cmd);
char *pass = cmd + 5;
if (!strcmp(prefs.password, pass)) {
switch_set_flag_locked(listener, LFLAG_AUTHED);
snprintf(reply, reply_len, "+OK accepted");
} else {
snprintf(reply, reply_len, "-ERR invalid");
switch_clear_flag_locked(listener, LFLAG_RUNNING);
}
goto done;
}
goto done;
}
if (!strncasecmp(cmd, "api ", 4)) {
char *api_cmd = cmd + 4;
switch_stream_handle_t stream = {0};
char *arg;
if (!listener->retbuf) {
listener->retbuf = switch_core_alloc(listener->pool, CMD_BUFLEN);
}
stream.data = listener->retbuf;
stream.end = stream.data;
stream.data_size = CMD_BUFLEN;
stream.write_function = switch_console_stream_write;
strip_cr(api_cmd);
if ((arg = strchr(api_cmd, ' '))) {
*arg++ = '\0';
}
if (switch_api_execute(api_cmd, arg, &stream) == SWITCH_STATUS_SUCCESS) {
switch_size_t len;
char buf[1024];
len = strlen(listener->retbuf) + 1;
snprintf(buf, sizeof(buf), "Content-Type: api/response\nContent-Length: %"APR_SSIZE_T_FMT"\n\n", len);
len = strlen(buf) + 1;
switch_socket_send(listener->sock, buf, &len);
len = strlen(listener->retbuf) + 1;
switch_socket_send(listener->sock, listener->retbuf, &len);
return;
}
} else if (!strncasecmp(cmd, "log", 3)) {
char *level_s;
strip_cr(cmd);
level_s = cmd + 4;
if (switch_strlen_zero(level_s)) {
level_s = "debug";
}
if ((listener->level = switch_log_str2level(level_s))) {
switch_set_flag(listener, LFLAG_LOG);
snprintf(reply, reply_len, "+OK log level %s [%d]", level_s, listener->level);
} else {
snprintf(reply, reply_len, "-ERR invalid log level");
}
} else if (!strncasecmp(cmd, "nolog", 5)) {
if (switch_test_flag(listener, LFLAG_LOG)) {
switch_clear_flag_locked(listener, LFLAG_LOG);
snprintf(reply, reply_len, "+OK no longer logging");
} else {
snprintf(reply, reply_len, "-ERR not loging");
}
} else if (!strncasecmp(cmd, "event", 5)) {
char *next, *cur;
uint32_t count = 0, key_count = 0;
uint8_t custom = 0;
strip_cr(cmd);
cur = cmd + 5;
if (cur && (cur = strchr(cur, ' '))) {
for(cur++; cur; count++) {
switch_event_types_t type;
if ((next = strchr(cur, ' '))) {
*next++ = '\0';
}
if (!count) {
if (!strcasecmp(cur, "xml")) {
listener->format = EVENT_FORMAT_XML;
goto end;
} else if (!strcasecmp(cur, "plain")) {
listener->format = EVENT_FORMAT_PLAIN;
goto end;
}
}
if (custom) {
switch_core_hash_insert_dup(listener->event_hash, cur, MARKER);
} else if (switch_name_event(cur, &type) == SWITCH_STATUS_SUCCESS) {
key_count++;
listener->event_list[(uint8_t)type] = 1;
if (type == SWITCH_EVENT_CUSTOM) {
custom++;
}
}
end:
cur = next;
}
}
if (!key_count) {
snprintf(reply, reply_len, "-ERR no keywords supplied");
goto done;
}
if (!switch_test_flag(listener, LFLAG_EVENTS)) {
switch_set_flag_locked(listener, LFLAG_EVENTS);
}
snprintf(reply, reply_len, "+OK event listener enabled %s", listener->format == EVENT_FORMAT_XML ? "xml" : "plain");
} else if (!strncasecmp(cmd, "noevents", 8)) {
if (switch_test_flag(listener, LFLAG_EVENTS)) {
uint8_t x = 0;
switch_clear_flag_locked(listener, LFLAG_EVENTS);
for (x = 0; x <= SWITCH_EVENT_ALL; x++) {
listener->event_list[x] = 0;
}
/* wipe the hash */
switch_core_hash_init(&listener->event_hash, listener->pool);
snprintf(reply, reply_len, "+OK no longer listening for events");
} else {
snprintf(reply, reply_len, "-ERR not listening for events");
}
}
done:
if (switch_strlen_zero(reply)) {
snprintf(reply, reply_len, "-ERR command not found");
}
}
static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
{
listener_t *listener = (listener_t *) obj;
char buf[1024];
switch_size_t len;
switch_status_t status;
void *pop;
uint32_t elapsed;
time_t start = 0;
char reply[512] = "";
assert(listener != NULL);
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Open\n");
switch_socket_opt_set(listener->sock, APR_SO_NONBLOCK, TRUE);
switch_set_flag_locked(listener, LFLAG_RUNNING);
add_listener(listener);
snprintf(buf, sizeof(buf), "Content-Type: auth/request\n\n");
len = strlen(buf) + 1;
switch_socket_send(listener->sock, buf, &len);
start = time(NULL);
while(!switch_test_flag(listener, LFLAG_AUTHED)) {
len = sizeof(buf);
memset(buf, 0, len);
status = switch_socket_recv(listener->sock, buf, &len);
if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
break;
}
if (len) {
parse_command(listener, buf, reply, sizeof(reply));
if (!switch_strlen_zero(reply)) {
snprintf(buf, sizeof(buf), "Content-Type: command/reply\nReply-Text: %s\n\n", reply);
len = strlen(buf) + 1;
switch_socket_send(listener->sock, buf, &len);
}
goto done;
}
if (status == SWITCH_STATUS_BREAK) {
elapsed = time(NULL) - start;
if (elapsed >= 15) {
switch_clear_flag_locked(listener, LFLAG_RUNNING);
break;
}
//switch_yield(1000);
continue;
}
}
done:
while(switch_test_flag(listener, LFLAG_RUNNING) && listen_list.ready) {
len = sizeof(buf);
memset(buf, 0, len);
status = switch_socket_recv(listener->sock, buf, &len);
uint8_t do_sleep = 1;
if (!len && status != SWITCH_STATUS_BREAK) {
break;
}
if (len) {
parse_command(listener, buf, reply, sizeof(reply));
if (!switch_strlen_zero(reply)) {
snprintf(buf, sizeof(buf), "Content-Type: command/reply\nReply-Text: %s\n\n", reply);
len = strlen(buf) + 1;
switch_socket_send(listener->sock, buf, &len);
}
continue;
}
if (switch_test_flag(listener, LFLAG_LOG)) {
if (switch_queue_trypop(listener->log_queue, &pop) == SWITCH_STATUS_SUCCESS) {
char *data = (char *) pop;
if (data) {
snprintf(buf, sizeof(buf), "Content-Type: log/data\nContent-Length: %"APR_SSIZE_T_FMT"\n\n", strlen(data));
len = strlen(buf) + 1;
switch_socket_send(listener->sock, buf, &len);
len = strlen(data) + 1;
switch_socket_send(listener->sock, data, &len);
free(data);
}
do_sleep = 0;
}
}
if (switch_test_flag(listener, LFLAG_EVENTS)) {
if (switch_queue_trypop(listener->event_queue, &pop) == SWITCH_STATUS_SUCCESS) {
char hbuf[512];
switch_event_t *event = (switch_event_t *) pop;
char *etype, *packet, *xmlstr = NULL;
do_sleep = 0;
if (listener->format == EVENT_FORMAT_PLAIN) {
etype = "plain";
switch_event_serialize(event, buf, sizeof(buf), NULL);
packet = buf;
} else {
switch_xml_t xml;
etype = "xml";
if ((xml = switch_event_xmlize(event, NULL))) {
xmlstr = switch_xml_toxml(xml);
packet = xmlstr;
switch_xml_free(xml);
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "XML ERROR!\n");
continue;
}
}
len = strlen(packet) + 1;
snprintf(hbuf, sizeof(hbuf), "Content-Length: %"APR_SSIZE_T_FMT"\n"
"Content-Type: text/event-%s\n"
"\n", len, etype);
len = strlen(hbuf) + 1;
switch_socket_send(listener->sock, hbuf, &len);
len = strlen(packet) + 1;
switch_socket_send(listener->sock, packet, &len);
switch_event_destroy(&event);
if (xmlstr) {
free(xmlstr);
}
}
}
if (do_sleep) {
switch_yield(1000);
}
}
remove_listener(listener);
close_socket(&listener->sock);
if (switch_test_flag(listener, LFLAG_EVENTS)) {
remove_listener(listener);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Closed\n");
if (listener->pool) {
switch_memory_pool_t *pool = listener->pool;
switch_core_destroy_memory_pool(&pool);
}
return NULL;
}
/* Create a thread for the conference and launch it */
static void launch_listener_thread(listener_t *listener)
{
switch_thread_t *thread;
switch_threadattr_t *thd_attr = NULL;
switch_threadattr_create(&thd_attr, listener->pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, listener_run, listener, listener->pool);
}
static int config(void)
{
char *cf = "event_socket.conf";
switch_xml_t cfg, xml, settings, param;
memset(&prefs, 0, sizeof(prefs));
if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
} else {
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 (!strcmp(var, "listen-ip")) {
set_pref_ip(val);
} else if (!strcmp(var, "listen-port")) {
prefs.port = atoi(val);
} else if (!strcmp(var, "password")) {
set_pref_pass(val);
}
}
}
switch_xml_free(xml);
}
if (switch_strlen_zero(prefs.ip)) {
set_pref_ip("127.0.0.1");
}
if (switch_strlen_zero(prefs.password)) {
set_pref_pass("ClueCon");
}
if (!prefs.port) {
prefs.port = 8021;
}
return 0;
}
SWITCH_MOD_DECLARE(switch_status_t) switch_module_runtime(void)
{
switch_memory_pool_t *pool = NULL, *listener_pool = NULL;
switch_status_t rv;
switch_sockaddr_t *sa;
switch_socket_t *inbound_socket = NULL;
listener_t *listener;
uint32_t count;
memset(&listen_list, 0, sizeof(listen_list));
config();
if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
return SWITCH_STATUS_TERM;
}
switch_mutex_init(&listen_list.mutex, SWITCH_MUTEX_NESTED, pool);
for(;;) {
count++;
rv = switch_sockaddr_info_get(&sa, prefs.ip, APR_INET, prefs.port, 0, pool);
if (rv) goto fail;
rv = switch_socket_create(&listen_list.sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, pool);
if (rv) goto sock_fail;
rv = switch_socket_bind(listen_list.sock, sa);
if (rv) goto sock_fail;
rv = switch_socket_listen(listen_list.sock, 5);
if (rv) goto sock_fail;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Socket up listening on %s:%u\n", prefs.ip, prefs.port);
break;
sock_fail:
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error!\n");
switch_yield(1000000);
}
listen_list.ready = 1;
if (switch_event_bind((char *) modname, SWITCH_EVENT_ALL, SWITCH_EVENT_SUBCLASS_ANY, event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
return SWITCH_STATUS_GENERR;
}
switch_log_bind_logger(socket_logger, SWITCH_LOG_DEBUG);
for (;;) {
if (switch_core_new_memory_pool(&listener_pool) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OH OH no pool\n");
goto fail;
}
if ((rv = switch_socket_accept(&inbound_socket, listen_list.sock, listener_pool))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error\n");
break;
}
if (!(listener = switch_core_alloc(listener_pool, sizeof(*listener)))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n");
break;
}
switch_queue_create(&listener->event_queue, SWITCH_CORE_QUEUE_LEN, listener_pool);
switch_queue_create(&listener->log_queue, SWITCH_CORE_QUEUE_LEN, listener_pool);
listener->sock = inbound_socket;
listener->pool = listener_pool;
listener->format = EVENT_FORMAT_PLAIN;
switch_mutex_init(&listener->flag_mutex, SWITCH_MUTEX_NESTED, listener_pool);
switch_core_hash_init(&listener->event_hash, listener_pool);
launch_listener_thread(listener);
}
close_socket(&listen_list.sock);
if (pool) {
switch_core_destroy_memory_pool(&pool);
}
if (listener_pool) {
switch_core_destroy_memory_pool(&listener_pool);
}
fail:
return SWITCH_STATUS_TERM;
}

View File

@ -0,0 +1,209 @@
<?xml version="1.0" encoding="Windows-1252"?>
<VisualStudioProject
ProjectType="Visual C++"
Version="8.00"
Name="mod_event_test"
ProjectGUID="{3A2A7795-C216-4FFF-B8EF-4D17A84BACCC}"
RootNamespace="mod_event_test"
Keyword="Win32Proj"
>
<Platforms>
<Platform
Name="Win32"
/>
</Platforms>
<ToolFiles>
</ToolFiles>
<Configurations>
<Configuration
Name="Debug|Win32"
OutputDirectory="Debug"
IntermediateDirectory="Debug"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
Optimization="0"
AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;"
PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
MinimalRebuild="true"
BasicRuntimeChecks="3"
RuntimeLibrary="1"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="4"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\..\..\w32\vsnet\$(OutDir)/mod/mod_event_test.dll"
LinkIncremental="2"
AdditionalLibraryDirectories="..\..\..\..\w32\vsnet\$(OutDir)"
GenerateDebugInformation="true"
ProgramDatabaseFile="$(OutDir)/mod_event_test.pdb"
SubSystem="2"
ImportLibrary="$(OutDir)/mod_event_test.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
<Configuration
Name="Release|Win32"
OutputDirectory="Release"
IntermediateDirectory="Release"
ConfigurationType="2"
InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops"
CharacterSet="2"
>
<Tool
Name="VCPreBuildEventTool"
/>
<Tool
Name="VCCustomBuildTool"
/>
<Tool
Name="VCXMLDataGeneratorTool"
/>
<Tool
Name="VCWebServiceProxyGeneratorTool"
/>
<Tool
Name="VCMIDLTool"
/>
<Tool
Name="VCCLCompilerTool"
AdditionalIncludeDirectories="&quot;$(InputDir)..\..\..\include&quot;;&quot;$(InputDir)include&quot;;&quot;$(InputDir)..\..\..\..\libs\include&quot;"
PreprocessorDefinitions="WIN32;NDEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS"
RuntimeLibrary="0"
UsePrecompiledHeader="0"
WarningLevel="4"
WarnAsError="true"
Detect64BitPortabilityProblems="true"
DebugInformationFormat="3"
/>
<Tool
Name="VCManagedResourceCompilerTool"
/>
<Tool
Name="VCResourceCompilerTool"
/>
<Tool
Name="VCPreLinkEventTool"
/>
<Tool
Name="VCLinkerTool"
OutputFile="..\..\..\..\w32\vsnet\$(OutDir)/mod/mod_event_test.dll"
LinkIncremental="1"
AdditionalLibraryDirectories="..\..\..\..\w32\vsnet\$(OutDir)"
GenerateDebugInformation="true"
SubSystem="2"
OptimizeReferences="2"
EnableCOMDATFolding="2"
ImportLibrary="$(OutDir)/mod_event_test.lib"
TargetMachine="1"
/>
<Tool
Name="VCALinkTool"
/>
<Tool
Name="VCManifestTool"
/>
<Tool
Name="VCXDCMakeTool"
/>
<Tool
Name="VCBscMakeTool"
/>
<Tool
Name="VCFxCopTool"
/>
<Tool
Name="VCAppVerifierTool"
/>
<Tool
Name="VCWebDeploymentTool"
/>
<Tool
Name="VCPostBuildEventTool"
/>
</Configuration>
</Configurations>
<References>
</References>
<Files>
<Filter
Name="Source Files"
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
<File
RelativePath=".\mod_event_test.c"
>
</File>
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
</Filter>
<Filter
Name="Resource Files"
Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx"
UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
>
</Filter>
</Files>
<Globals>
</Globals>
</VisualStudioProject>

View File

@ -566,7 +566,16 @@ SWITCH_DECLARE(switch_channel_state_t) switch_channel_perform_set_state(switch_c
if (state < CS_HANGUP) {
switch_event_t *event;
if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_STATE) == SWITCH_STATUS_SUCCESS) {
switch_channel_event_set_data(channel, event);
if (state == CS_RING) {
switch_channel_event_set_data(channel, event);
} else {
char state_num[25];
snprintf(state_num, sizeof(state_num), "%d", channel->state);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-State", (char *) switch_channel_state_name(channel->state));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-State-Number", (char *) state_num);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Channel-Name", switch_channel_get_name(channel));
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Unique-ID", switch_core_session_get_uuid(channel->session));
}
switch_event_fire(&event);
}
}

View File

@ -248,6 +248,23 @@ SWITCH_DECLARE(char *) switch_event_name(switch_event_types_t event)
return EVENT_NAMES[event];
}
SWITCH_DECLARE(switch_status_t) switch_name_event(char *name, switch_event_types_t *type)
{
switch_event_types_t x;
assert(BLOCK != NULL);
assert(RUNTIME_POOL != NULL);
for (x = 0; x <= SWITCH_EVENT_ALL; x++) {
if (!strcasecmp(name, EVENT_NAMES[x])) {
*type = x;
return SWITCH_STATUS_SUCCESS;
}
}
return SWITCH_STATUS_FALSE;
}
SWITCH_DECLARE(switch_status_t) switch_event_reserve_subclass_detailed(char *owner, char *subclass_name)
{
@ -454,9 +471,9 @@ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event)
SWITCH_DECLARE(switch_status_t) switch_event_dup(switch_event_t **event, switch_event_t *todup)
{
switch_event_header_t *header, *hp, *hp2;
switch_event_header_t *header, *hp, *hp2, *last = NULL;
if (switch_event_create_subclass(event, todup->event_id, todup->subclass->name) != SWITCH_STATUS_SUCCESS) {
if (switch_event_create_subclass(event, todup->event_id, todup->subclass ? todup->subclass->name : NULL) != SWITCH_STATUS_SUCCESS) {
return SWITCH_STATUS_GENERR;
}
@ -464,7 +481,9 @@ SWITCH_DECLARE(switch_status_t) switch_event_dup(switch_event_t **event, switch_
(*event)->event_user_data = todup->event_user_data;
(*event)->bind_user_data = todup->bind_user_data;
for (hp = todup->headers; hp && hp->next;) {
hp2 = (*event)->headers;
for (hp = todup->headers; hp; hp = hp->next) {
if ((header = ALLOC(sizeof(*header))) == 0) {
return SWITCH_STATUS_MEMERR;
}
@ -474,13 +493,17 @@ SWITCH_DECLARE(switch_status_t) switch_event_dup(switch_event_t **event, switch_
header->name = DUP(hp->name);
header->value = DUP(hp->value);
for (hp2 = todup->headers; hp2 && hp2->next; hp2 = hp2->next);
if (hp2) {
hp2->next = header;
if (last) {
last->next = header;
} else {
(*event)->headers = header;
}
last = header;
}
if (todup->body) {
(*event)->body = DUP(todup->body);
}
return SWITCH_STATUS_SUCCESS;