[Freeswitch-svn] [commit] r2047 - in freeswitch/trunk: . conf scripts/socket scripts/socket/FreeSWITCH src src/include src/mod/event_handlers/mod_event_socket

Freeswitch SVN anthm at freeswitch.org
Sat Jul 22 17:49:52 EDT 2006


Author: anthm
Date: Sat Jul 22 17:49:52 2006
New Revision: 2047

Added:
   freeswitch/trunk/scripts/socket/
   freeswitch/trunk/scripts/socket/FreeSWITCH/
   freeswitch/trunk/scripts/socket/FreeSWITCH/Client.pm
   freeswitch/trunk/scripts/socket/fs.pl
   freeswitch/trunk/src/mod/event_handlers/mod_event_socket/
   freeswitch/trunk/src/mod/event_handlers/mod_event_socket/mod_event_socket.c
   freeswitch/trunk/src/mod/event_handlers/mod_event_socket/mod_event_socket.vcproj
Modified:
   freeswitch/trunk/conf/freeswitch.xml
   freeswitch/trunk/modules.conf.in
   freeswitch/trunk/src/include/switch_event.h
   freeswitch/trunk/src/switch_channel.c
   freeswitch/trunk/src/switch_event.c

Log:
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"




Modified: freeswitch/trunk/conf/freeswitch.xml
==============================================================================
--- freeswitch/trunk/conf/freeswitch.xml	(original)
+++ freeswitch/trunk/conf/freeswitch.xml	Sat Jul 22 17:49:52 2006
@@ -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"/>

Modified: freeswitch/trunk/modules.conf.in
==============================================================================
--- freeswitch/trunk/modules.conf.in	(original)
+++ freeswitch/trunk/modules.conf.in	Sat Jul 22 17:49:52 2006
@@ -29,6 +29,7 @@
 #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

Added: freeswitch/trunk/scripts/socket/FreeSWITCH/Client.pm
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/FreeSWITCH/Client.pm	Sat Jul 22 17:49:52 2006
@@ -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;

Added: freeswitch/trunk/scripts/socket/fs.pl
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/socket/fs.pl	Sat Jul 22 17:49:52 2006
@@ -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/;
+}
+  

Modified: freeswitch/trunk/src/include/switch_event.h
==============================================================================
--- freeswitch/trunk/src/include/switch_event.h	(original)
+++ freeswitch/trunk/src/include/switch_event.h	Sat Jul 22 17:49:52 2006
@@ -209,6 +209,14 @@
 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
   \param subclass_name the name to reserve

Added: freeswitch/trunk/src/mod/event_handlers/mod_event_socket/mod_event_socket.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_event_socket/mod_event_socket.c	Sat Jul 22 17:49:52 2006
@@ -0,0 +1,672 @@
+/* 
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct at 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 at yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * 
+ * Anthony Minessale II <anthmct at 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;
+}
+
+
+

Added: freeswitch/trunk/src/mod/event_handlers/mod_event_socket/mod_event_socket.vcproj
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/event_handlers/mod_event_socket/mod_event_socket.vcproj	Sat Jul 22 17:49:52 2006
@@ -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>

Modified: freeswitch/trunk/src/switch_channel.c
==============================================================================
--- freeswitch/trunk/src/switch_channel.c	(original)
+++ freeswitch/trunk/src/switch_channel.c	Sat Jul 22 17:49:52 2006
@@ -566,7 +566,16 @@
 		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);
 			}
 		}

Modified: freeswitch/trunk/src/switch_event.c
==============================================================================
--- freeswitch/trunk/src/switch_event.c	(original)
+++ freeswitch/trunk/src/switch_event.c	Sat Jul 22 17:49:52 2006
@@ -248,6 +248,23 @@
 	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(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 @@
 	(*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 @@
 		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;



More information about the Freeswitch-svn mailing list