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;