From 9c79c2a3fb1ac5958f804db8af8338ae10a952aa Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 22 Jul 2006 21:49:52 +0000 Subject: [PATCH] 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] *) noevents *) log // same as the console.conf values *) nolog *) api *) exit there is a perl client in scripts/socket called fs.pl with the module up and loaded: cd scripts/socket perl fs.pl 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 --- conf/freeswitch.xml | 13 +- modules.conf.in | 1 + scripts/socket/FreeSWITCH/Client.pm | 134 ++++ scripts/socket/fs.pl | 55 ++ src/include/switch_event.h | 8 + .../mod_event_socket/mod_event_socket.c | 672 ++++++++++++++++++ .../mod_event_socket/mod_event_socket.vcproj | 209 ++++++ src/switch_channel.c | 11 +- src/switch_event.c | 37 +- 9 files changed, 1130 insertions(+), 10 deletions(-) create mode 100644 scripts/socket/FreeSWITCH/Client.pm create mode 100644 scripts/socket/fs.pl create mode 100644 src/mod/event_handlers/mod_event_socket/mod_event_socket.c create mode 100644 src/mod/event_handlers/mod_event_socket/mod_event_socket.vcproj diff --git a/conf/freeswitch.xml b/conf/freeswitch.xml index c33f136727..8e9162c13f 100644 --- a/conf/freeswitch.xml +++ b/conf/freeswitch.xml @@ -21,7 +21,8 @@ - + + @@ -72,7 +73,15 @@ - + + + + + + + + + diff --git a/modules.conf.in b/modules.conf.in index fb96edc301..7dd8b80965 100644 --- a/modules.conf.in +++ b/modules.conf.in @@ -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 diff --git a/scripts/socket/FreeSWITCH/Client.pm b/scripts/socket/FreeSWITCH/Client.pm new file mode 100644 index 0000000000..e70ff78668 --- /dev/null +++ b/scripts/socket/FreeSWITCH/Client.pm @@ -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; diff --git a/scripts/socket/fs.pl b/scripts/socket/fs.pl new file mode 100644 index 0000000000..202cc7df63 --- /dev/null +++ b/scripts/socket/fs.pl @@ -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/; +} + diff --git a/src/include/switch_event.h b/src/include/switch_event.h index 15ff554206..cd9678418f 100644 --- a/src/include/switch_event.h +++ b/src/include/switch_event.h @@ -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 diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c new file mode 100644 index 0000000000..445e847f52 --- /dev/null +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -0,0 +1,672 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005/2006, Anthony Minessale II + * + * 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 + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * + * + * mod_event_socket.c -- Framework Demo Module + * + */ +#include +#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; +} + + + diff --git a/src/mod/event_handlers/mod_event_socket/mod_event_socket.vcproj b/src/mod/event_handlers/mod_event_socket/mod_event_socket.vcproj new file mode 100644 index 0000000000..3e23ba9374 --- /dev/null +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.vcproj @@ -0,0 +1,209 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/switch_channel.c b/src/switch_channel.c index d6ad600b17..fda2965e60 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -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); } } diff --git a/src/switch_event.c b/src/switch_event.c index f6a2734bc5..f55165eff7 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -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;