don't call us we'll call you
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3917 d0543943-73ff-0310-b7d9-9358b9ac24b2
This commit is contained in:
parent
aa2d884df7
commit
9d1e2e9167
|
@ -13,8 +13,11 @@ sub init($;$) {
|
||||||
$self->{_host} = $args->{-host} || "localhost";
|
$self->{_host} = $args->{-host} || "localhost";
|
||||||
$self->{_port} = $args->{-port} || 8021;
|
$self->{_port} = $args->{-port} || 8021;
|
||||||
$self->{_password} = $args->{-password} || undef;
|
$self->{_password} = $args->{-password} || undef;
|
||||||
|
$self->{events} = [];
|
||||||
my $me = bless $self,$class;
|
my $me = bless $self,$class;
|
||||||
|
if (!$self->{_password}) {
|
||||||
|
return $me;
|
||||||
|
}
|
||||||
if ($me->connect()) {
|
if ($me->connect()) {
|
||||||
return $me;
|
return $me;
|
||||||
} else {
|
} else {
|
||||||
|
@ -22,61 +25,62 @@ sub init($;$) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub input($;$) {
|
sub readhash($;$) {
|
||||||
my ($self,$to) = @_;
|
my ($self,$to) = @_;
|
||||||
my $i;
|
my ($can_read) = IO::Select::select($self->{_sel}, undef, undef, $to ? to : undef);
|
||||||
my @r;
|
my $s = shift @{$can_read};
|
||||||
my $s = $self->{_sock};
|
my @r = ();
|
||||||
my $x = 0;
|
my $crc = 0;
|
||||||
my $done = 0;
|
my $h;
|
||||||
my $start = time;
|
|
||||||
|
|
||||||
while(!$done) {
|
if ($s) {
|
||||||
if ($to and time - $start > $to) {
|
for (;;) {
|
||||||
last;
|
my $line;
|
||||||
}
|
for (;;) {
|
||||||
@ready = $self->{_sel}->can_read($to);
|
my $i = 0;
|
||||||
if (@ready) {
|
recv $s, $i, 1, 0;
|
||||||
$x=0;
|
if ($i eq "") {
|
||||||
foreach my $s (@ready) {
|
$h->{socketerror} = "yes";
|
||||||
while ($i = <$s>) {
|
return $h;
|
||||||
$x++;
|
last;
|
||||||
return @r if($i eq "\n");
|
} elsif ($i eq "\n") {
|
||||||
$i =~ s/[\n]+$//g;
|
$crc++;
|
||||||
push @r,$i;
|
last;
|
||||||
|
} else {
|
||||||
}
|
$crc = 0;
|
||||||
unless($x) {
|
|
||||||
return ("SocketError: yes");
|
|
||||||
}
|
}
|
||||||
|
$line .= $i;
|
||||||
}
|
}
|
||||||
|
if (!$line) {
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
push @r, $line;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!@r) {
|
||||||
|
return undef;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach(@r) {
|
||||||
|
my ($var, $val) = /^([^:]+):[\s\t]*(.*)$/;
|
||||||
|
$h->{lc $var} = $val;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($h->{'content-length'}) {
|
||||||
|
recv $s, $h->{body}, $h->{'content-length'}, 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($h->{'content-type'} eq "text/event-plain") {
|
||||||
|
my $e = $self->extract_event($h);
|
||||||
|
$h->{has_event} = 1;
|
||||||
|
$h->{event} = $e;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return @r;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
sub readhash($$) {
|
return $h;
|
||||||
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($$) {
|
sub error($$) {
|
||||||
|
@ -92,31 +96,147 @@ sub output($$) {
|
||||||
print $s $data ;
|
print $s $data ;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub cmd($$$) {
|
sub get_events($) {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
my $cmd = shift;
|
my $e = $self->{events};
|
||||||
|
$self->{events} = [];
|
||||||
|
return $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub sendmsg($$$) {
|
||||||
|
my $self = shift;
|
||||||
|
my $sendmsg = shift;
|
||||||
my $to = shift;
|
my $to = shift;
|
||||||
|
my $e;
|
||||||
|
|
||||||
$self->output($cmd->{command});
|
for(;;) {
|
||||||
foreach(keys %{$cmd}) {
|
$e = $self->readhash(.1);
|
||||||
next if ($_ eq "command");
|
if ($e && !$e->{socketerror}) {
|
||||||
$self->output($cmd->{$_});
|
#print Dumper $e;
|
||||||
|
push @{$self->{events}}, $e;
|
||||||
|
} else {
|
||||||
|
last;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
$self->output("\n\n");
|
|
||||||
|
|
||||||
my $h = $self->readhash($to);
|
$self->output($sendmsg->{command} . "\n");
|
||||||
|
foreach(keys %{$sendmsg}) {
|
||||||
|
next if ($_ eq "command");
|
||||||
|
$self->output("$_" . ": " . $sendmsg->{$_} . "\n");
|
||||||
|
}
|
||||||
|
$self->output("\n");
|
||||||
|
|
||||||
$h;
|
return $self->readhash($to);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub command($$) {
|
||||||
|
my $self = shift;
|
||||||
|
my $reply;
|
||||||
|
|
||||||
|
my $r = $self->sendmsg({ 'command' => "api " . shift });
|
||||||
|
|
||||||
|
if ($r->{body}) {
|
||||||
|
$reply = $r->{body};
|
||||||
|
} else {
|
||||||
|
$reply = "socketerror";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $reply;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub disconnect($) {
|
sub disconnect($) {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
$self->{_sock}->shutdown(2);
|
if ($self->{_sock}) {
|
||||||
$self->{_sock}->close();
|
$self->{_sock}->shutdown(2);
|
||||||
|
$self->{_sock}->close();
|
||||||
|
}
|
||||||
undef $self->{_sock};
|
undef $self->{_sock};
|
||||||
delete $self->{_sock};
|
delete $self->{_sock};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub raw_command($) {
|
||||||
|
my $self = shift;
|
||||||
|
return $self->sendmsg({ 'command' => shift });
|
||||||
|
}
|
||||||
|
|
||||||
|
sub htdecode($;$) {
|
||||||
|
my $urlin = shift;
|
||||||
|
my $url = (ref $urlin) ? \$$urlin : \$urlin;
|
||||||
|
$$url =~ s/%([0-9A-Z]{2})/chr hex $1/ieg;
|
||||||
|
$$url;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub extract_event($$) {
|
||||||
|
my $self = shift;
|
||||||
|
my $r = shift;
|
||||||
|
|
||||||
|
|
||||||
|
my %h = $r->{body} =~ /^([^:]+)\s*:\s*([^\n]*)/mg;
|
||||||
|
|
||||||
|
foreach (keys %h) {
|
||||||
|
my $new = lc $_;
|
||||||
|
$h{$new} = $h{$_};
|
||||||
|
delete $h{$_};
|
||||||
|
}
|
||||||
|
foreach(keys %h) {
|
||||||
|
htdecode(\$h{$_});
|
||||||
|
}
|
||||||
|
return \%h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub call_command($$$) {
|
||||||
|
my $self = shift;
|
||||||
|
my $app = shift;
|
||||||
|
my $arg = shift;
|
||||||
|
|
||||||
|
my $hash = {
|
||||||
|
'command' => "sendmsg",
|
||||||
|
'call-command' => "execute",
|
||||||
|
'execute-app-name' => $app,
|
||||||
|
'execute-app-arg' => $arg
|
||||||
|
};
|
||||||
|
|
||||||
|
return $self->sendmsg($hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub call_data($) {
|
||||||
|
my $self = shift;
|
||||||
|
|
||||||
|
return $self->{call_data};
|
||||||
|
}
|
||||||
|
|
||||||
|
sub accept($;$$) {
|
||||||
|
my $self = shift;
|
||||||
|
my $ip = shift;
|
||||||
|
my $port = shift || 8084;
|
||||||
|
|
||||||
|
if (!$self->{_lsock}) {
|
||||||
|
$self->{_lsock} = IO::Socket::INET->new(Listen => 10000,
|
||||||
|
LocalAddr => $ip,
|
||||||
|
LocalPort => $port,
|
||||||
|
Reuse => 1,
|
||||||
|
Proto => "tcp") or return $self->error("Cannot listen");
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{_sock} = $self->{_lsock}->accept();
|
||||||
|
$self->{_sock}->autoflush(1);
|
||||||
|
$self->{_sel} = new IO::Select( $self->{_sock} );
|
||||||
|
|
||||||
|
$self->{call_data} = $self->sendmsg({ 'command' => "connect"});
|
||||||
|
foreach(keys %{$self->{call_data}}) {
|
||||||
|
htdecode(\$self->{call_data}->{$_});
|
||||||
|
}
|
||||||
|
if ($self->{call_data} =~ /socketerror/) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
sub connect($) {
|
sub connect($) {
|
||||||
my $self = shift;
|
my $self = shift;
|
||||||
|
|
||||||
|
@ -134,7 +254,7 @@ sub connect($) {
|
||||||
|
|
||||||
if ($h->{"content-type"} eq "auth/request") {
|
if ($h->{"content-type"} eq "auth/request") {
|
||||||
my $pass = $self->{"_password"};
|
my $pass = $self->{"_password"};
|
||||||
$h = $self->cmd({command => "auth $pass"});
|
$h = $self->sendmsg({command => "auth $pass"});
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($h->{'reply-text'} =~ "OK") {
|
if ($h->{'reply-text'} =~ "OK") {
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
use FreeSWITCH::Client;
|
||||||
|
use Data::Dumper;
|
||||||
|
|
||||||
|
my $fs = init FreeSWITCH::Client {} or die "Error $@";
|
||||||
|
my $pid;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
$fs->accept();
|
||||||
|
|
||||||
|
if (!($pid = fork)) {
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $data = $fs->call_data();
|
||||||
|
|
||||||
|
#print Dumper $data
|
||||||
|
print "Call: $data->{'caller-channel-name'} $data->{'unique-id'}\n";
|
||||||
|
|
||||||
|
|
||||||
|
$o = $fs->call_command("answer");
|
||||||
|
#to turn on events when in async mode
|
||||||
|
#$o = $fs->raw_command("myevents");
|
||||||
|
$o = $fs->call_command("playback", "/ram/swimp.raw");
|
||||||
|
$o = $fs->call_command("hangup");
|
||||||
|
|
||||||
|
#comment exit in async mode
|
||||||
|
exit;
|
||||||
|
|
||||||
|
while(my $r = $fs->readhash(undef)) {
|
||||||
|
if ($r->{socketerror}) {
|
||||||
|
last;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($r->{has_event}) {
|
||||||
|
print Dumper $r->{event};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$fs->disconnect();
|
||||||
|
print "done\n";
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,14 @@ SWITCH_BEGIN_EXTERN_C
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Parse command from an event
|
||||||
|
\param session the session to send the message to
|
||||||
|
\param event the event to send
|
||||||
|
\return SWITCH_STATUS_SUCCESS if successful
|
||||||
|
*/
|
||||||
|
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *session, switch_event_t *event);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Wait for time to pass for a specified number of milliseconds
|
\brief Wait for time to pass for a specified number of milliseconds
|
||||||
\param session the session to wait for.
|
\param session the session to wait for.
|
||||||
|
|
|
@ -39,7 +39,11 @@ typedef enum {
|
||||||
LFLAG_AUTHED = (1 << 0),
|
LFLAG_AUTHED = (1 << 0),
|
||||||
LFLAG_RUNNING = (1 << 1),
|
LFLAG_RUNNING = (1 << 1),
|
||||||
LFLAG_EVENTS = (1 << 2),
|
LFLAG_EVENTS = (1 << 2),
|
||||||
LFLAG_LOG = (1 << 3)
|
LFLAG_LOG = (1 << 3),
|
||||||
|
LFLAG_FULL = (1 << 4),
|
||||||
|
LFLAG_MYEVENTS = (1 << 5),
|
||||||
|
LFLAG_SESSION = (1 << 6),
|
||||||
|
LFLAG_ASYNC = (1 << 7)
|
||||||
} event_flag_t;
|
} event_flag_t;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
@ -60,6 +64,7 @@ struct listener {
|
||||||
uint8_t event_list[SWITCH_EVENT_ALL+1];
|
uint8_t event_list[SWITCH_EVENT_ALL+1];
|
||||||
switch_hash_t *event_hash;
|
switch_hash_t *event_hash;
|
||||||
switch_thread_rwlock_t *rwlock;
|
switch_thread_rwlock_t *rwlock;
|
||||||
|
switch_core_session_t *session;
|
||||||
struct listener *next;
|
struct listener *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -83,6 +88,9 @@ static struct {
|
||||||
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_ip, prefs.ip)
|
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_ip, prefs.ip)
|
||||||
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_pass, prefs.password)
|
SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_pass, prefs.password)
|
||||||
|
|
||||||
|
static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj);
|
||||||
|
static void launch_listener_thread(listener_t *listener);
|
||||||
|
|
||||||
static switch_status_t socket_logger(const switch_log_node_t *node, switch_log_level_t level)
|
static switch_status_t socket_logger(const switch_log_node_t *node, switch_log_level_t level)
|
||||||
{
|
{
|
||||||
listener_t *l;
|
listener_t *l;
|
||||||
|
@ -122,7 +130,7 @@ static void event_handler(switch_event_t *event)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (l->event_list[(uint8_t)SWITCH_EVENT_ALL]) {
|
if (l->event_list[(uint8_t)SWITCH_EVENT_ALL]) {
|
||||||
send = 1;
|
send = 1;
|
||||||
} else if ((l->event_list[(uint8_t)event->event_id])) {
|
} else if ((l->event_list[(uint8_t)event->event_id])) {
|
||||||
if (event->event_id != SWITCH_EVENT_CUSTOM || (event->subclass && switch_core_hash_find(l->event_hash, event->subclass->name))) {
|
if (event->event_id != SWITCH_EVENT_CUSTOM || (event->subclass && switch_core_hash_find(l->event_hash, event->subclass->name))) {
|
||||||
|
@ -130,6 +138,13 @@ static void event_handler(switch_event_t *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (send && switch_test_flag(l, LFLAG_MYEVENTS)) {
|
||||||
|
char *uuid = switch_event_get_header(event, "unique-id");
|
||||||
|
if (!uuid || strcmp(uuid, switch_core_session_get_uuid(l->session))) {
|
||||||
|
send = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (send) {
|
if (send) {
|
||||||
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
|
if (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) {
|
||||||
switch_queue_push(l->event_queue, clone);
|
switch_queue_push(l->event_queue, clone);
|
||||||
|
@ -142,6 +157,105 @@ static void event_handler(switch_event_t *event)
|
||||||
switch_mutex_unlock(listen_list.mutex);
|
switch_mutex_unlock(listen_list.mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void socket_function(switch_core_session_t *session, char *data)
|
||||||
|
{
|
||||||
|
char *host, *port_name;
|
||||||
|
switch_socket_t *new_sock;
|
||||||
|
switch_sockaddr_t *sa;
|
||||||
|
int port = 8084;
|
||||||
|
listener_t *listener;
|
||||||
|
int argc = 0, x = 0;
|
||||||
|
char *argv[80] = {0};
|
||||||
|
char *mydata;
|
||||||
|
|
||||||
|
if (data && (mydata = switch_core_session_strdup(session, data))) {
|
||||||
|
argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0])));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (argc < 1) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Parse Error!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
host = argv[0];
|
||||||
|
|
||||||
|
if (switch_strlen_zero(host)) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Host!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((port_name = strchr(host, ':'))) {
|
||||||
|
*port_name++ = '\0';
|
||||||
|
port = atoi(port_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_sockaddr_info_get(&sa, host, AF_INET, port, 0, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_socket_create(&new_sock, AF_INET, SOCK_STREAM, APR_PROTO_TCP, switch_core_session_get_pool(session)) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_socket_opt_set(new_sock, SWITCH_SO_KEEPALIVE, 1);
|
||||||
|
|
||||||
|
if (switch_socket_connect(new_sock, sa) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Socket Error!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!(listener = switch_core_session_alloc(session, sizeof(*listener)))) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_thread_rwlock_create(&listener->rwlock, switch_core_session_get_pool(session));
|
||||||
|
switch_queue_create(&listener->event_queue, SWITCH_CORE_QUEUE_LEN, switch_core_session_get_pool(session));
|
||||||
|
switch_queue_create(&listener->log_queue, SWITCH_CORE_QUEUE_LEN, switch_core_session_get_pool(session));
|
||||||
|
|
||||||
|
listener->sock = new_sock;
|
||||||
|
listener->pool = switch_core_session_get_pool(session);
|
||||||
|
listener->format = EVENT_FORMAT_PLAIN;
|
||||||
|
listener->session = session;
|
||||||
|
|
||||||
|
switch_mutex_init(&listener->flag_mutex, SWITCH_MUTEX_NESTED, listener->pool);
|
||||||
|
switch_core_hash_init(&listener->event_hash, listener->pool);
|
||||||
|
switch_set_flag(listener, LFLAG_AUTHED);
|
||||||
|
for(x = 1; x < argc; x++) {
|
||||||
|
if (argv[x] && !strcasecmp(argv[x], "full")) {
|
||||||
|
switch_set_flag(listener, LFLAG_FULL);
|
||||||
|
} else if (argv[x] && !strcasecmp(argv[x], "async")) {
|
||||||
|
switch_set_flag(listener, LFLAG_ASYNC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_test_flag(listener, LFLAG_ASYNC)) {
|
||||||
|
launch_listener_thread(listener);
|
||||||
|
switch_ivr_park(session);
|
||||||
|
} else {
|
||||||
|
listener_run(NULL, (void*) listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
while(switch_test_flag(listener, LFLAG_SESSION)) {
|
||||||
|
switch_yield(100000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static const switch_application_interface_t socket_application_interface = {
|
||||||
|
/*.interface_name */ "socket",
|
||||||
|
/*.application_function */ socket_function,
|
||||||
|
/* long_desc */ "Connect to a socket",
|
||||||
|
/* short_desc */ "Connect to a socket",
|
||||||
|
/* syntax */ "<ip>[:<port>]",
|
||||||
|
/*.next */ NULL
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static switch_loadable_module_interface_t event_socket_module_interface = {
|
static switch_loadable_module_interface_t event_socket_module_interface = {
|
||||||
/*.module_name */ modname,
|
/*.module_name */ modname,
|
||||||
|
@ -149,7 +263,7 @@ static switch_loadable_module_interface_t event_socket_module_interface = {
|
||||||
/*.timer_interface */ NULL,
|
/*.timer_interface */ NULL,
|
||||||
/*.dialplan_interface */ NULL,
|
/*.dialplan_interface */ NULL,
|
||||||
/*.codec_interface */ NULL,
|
/*.codec_interface */ NULL,
|
||||||
/*.application_interface */ NULL
|
/*.application_interface */ &socket_application_interface
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -255,6 +369,11 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event,
|
||||||
return SWITCH_STATUS_FALSE;
|
return SWITCH_STATUS_FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (listener->session && !switch_channel_ready(switch_core_session_get_channel(listener->session))) {
|
||||||
|
status = SWITCH_STATUS_FALSE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (mlen) {
|
if (mlen) {
|
||||||
bytes += mlen;
|
bytes += mlen;
|
||||||
do_sleep = 0;
|
do_sleep = 0;
|
||||||
|
@ -313,7 +432,7 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
elapsed = (uint32_t)(time(NULL) - start);
|
elapsed = (uint32_t)(time(NULL) - start);
|
||||||
if (elapsed >= timeout) {
|
if (elapsed >= timeout) {
|
||||||
|
@ -493,6 +612,53 @@ static switch_status_t parse_command(listener_t *listener, switch_event_t *event
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (listener->session) {
|
||||||
|
if (!strncasecmp(cmd, "connect", 7)) {
|
||||||
|
snprintf(reply, reply_len, "+OK");
|
||||||
|
goto done;
|
||||||
|
} else if (!strncasecmp(cmd, "sendmsg", 4)) {
|
||||||
|
if (switch_test_flag(listener, LFLAG_ASYNC)) {
|
||||||
|
if ((status = switch_core_session_queue_private_event(listener->session, &event)) == SWITCH_STATUS_SUCCESS) {
|
||||||
|
snprintf(reply, reply_len, "+OK");
|
||||||
|
} else {
|
||||||
|
snprintf(reply, reply_len, "-ERR memory error");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch_ivr_parse_event(listener->session, event);
|
||||||
|
snprintf(reply, reply_len, "+OK");
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
} else if (!strncasecmp(cmd, "myevents", 8)) {
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_CREATE] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_DESTROY] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_STATE] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_ANSWER] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_HANGUP] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_EXECUTE] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_BRIDGE] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_UNBRIDGE] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_PROGRESS] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_OUTGOING] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_PARK] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_CHANNEL_UNPARK] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_TALK] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_DTMF] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_NOTALK] = 1;
|
||||||
|
listener->event_list[SWITCH_EVENT_DETECTED_SPEECH] = 1;
|
||||||
|
switch_set_flag_locked(listener, LFLAG_MYEVENTS);
|
||||||
|
switch_set_flag_locked(listener, LFLAG_EVENTS);
|
||||||
|
if (strstr(cmd, "xml") || strstr(cmd, "XML")) {
|
||||||
|
listener->format = EVENT_FORMAT_XML;
|
||||||
|
}
|
||||||
|
snprintf(reply, reply_len, "+OK Events Enabled");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!switch_test_flag(listener, LFLAG_FULL)) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!strncasecmp(cmd, "sendevent", 9)) {
|
if (!strncasecmp(cmd, "sendevent", 9)) {
|
||||||
char *ename;
|
char *ename;
|
||||||
strip_cr(cmd);
|
strip_cr(cmd);
|
||||||
|
@ -798,42 +964,92 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
|
||||||
switch_status_t status;
|
switch_status_t status;
|
||||||
switch_event_t *event;
|
switch_event_t *event;
|
||||||
char reply[512] = "";
|
char reply[512] = "";
|
||||||
|
switch_core_session_t *session = NULL;
|
||||||
|
switch_channel_t *channel = NULL;
|
||||||
|
|
||||||
|
|
||||||
assert(listener != NULL);
|
assert(listener != NULL);
|
||||||
|
|
||||||
|
if ((session = listener->session)) {
|
||||||
|
channel = switch_core_session_get_channel(session);
|
||||||
|
switch_core_session_read_lock(session);
|
||||||
|
}
|
||||||
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Open\n");
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Open\n");
|
||||||
|
|
||||||
switch_socket_opt_set(listener->sock, APR_SO_NONBLOCK, TRUE);
|
switch_socket_opt_set(listener->sock, APR_SO_NONBLOCK, TRUE);
|
||||||
switch_set_flag_locked(listener, LFLAG_RUNNING);
|
switch_set_flag_locked(listener, LFLAG_RUNNING);
|
||||||
add_listener(listener);
|
add_listener(listener);
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "Content-Type: auth/request\n\n");
|
if (session && switch_test_flag(listener, LFLAG_AUTHED)) {
|
||||||
|
switch_event_t *event = NULL, *call_event;
|
||||||
len = strlen(buf);
|
char *event_str;
|
||||||
switch_socket_send(listener->sock, buf, &len);
|
|
||||||
|
|
||||||
|
|
||||||
while (!switch_test_flag(listener, LFLAG_AUTHED)) {
|
switch_set_flag_locked(listener, LFLAG_SESSION);
|
||||||
|
status = read_packet(listener, &event, 25);
|
||||||
|
|
||||||
|
if (status != SWITCH_STATUS_SUCCESS || !event) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Socket Error!\n");
|
||||||
|
switch_clear_flag_locked(listener, LFLAG_RUNNING);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_event_create(&call_event, SWITCH_EVENT_MESSAGE) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||||
|
switch_clear_flag_locked(listener, LFLAG_RUNNING);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parse_command(listener, event, reply, sizeof(reply)) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_clear_flag_locked(listener, LFLAG_RUNNING);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch_caller_profile_event_set_data(switch_channel_get_caller_profile(channel), "Channel", call_event);
|
||||||
|
switch_channel_event_set_data(channel, call_event);
|
||||||
|
switch_event_add_header(call_event, SWITCH_STACK_BOTTOM, "Content-Type", "command/reply");
|
||||||
|
|
||||||
|
switch_event_add_header(call_event, SWITCH_STACK_BOTTOM, "Socket-Mode", switch_test_flag(listener, LFLAG_ASYNC) ? "async" : "static");
|
||||||
|
switch_event_add_header(call_event, SWITCH_STACK_BOTTOM, "Control", switch_test_flag(listener, LFLAG_FULL) ? "full" : "single-channel");
|
||||||
|
|
||||||
|
switch_event_serialize(call_event, &event_str);
|
||||||
|
if (!event_str) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
|
||||||
|
switch_clear_flag_locked(listener, LFLAG_RUNNING);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
len = strlen(event_str);
|
||||||
|
switch_socket_send(listener->sock, event_str, &len);
|
||||||
|
|
||||||
|
switch_safe_free(event_str);
|
||||||
|
} else {
|
||||||
|
snprintf(buf, sizeof(buf), "Content-Type: auth/request\n\n");
|
||||||
|
|
||||||
status = read_packet(listener, &event, 25);
|
len = strlen(buf);
|
||||||
if (status != SWITCH_STATUS_SUCCESS) {
|
switch_socket_send(listener->sock, buf, &len);
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!event) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (parse_command(listener, event, reply, sizeof(reply)) != SWITCH_STATUS_SUCCESS) {
|
|
||||||
switch_clear_flag_locked(listener, LFLAG_RUNNING);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!switch_strlen_zero(reply)) {
|
|
||||||
snprintf(buf, sizeof(buf), "Content-Type: command/reply\nReply-Text: %s\n\n", reply);
|
|
||||||
len = strlen(buf);
|
|
||||||
switch_socket_send(listener->sock, buf, &len);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
while (!switch_test_flag(listener, LFLAG_AUTHED)) {
|
||||||
|
status = read_packet(listener, &event, 25);
|
||||||
|
if (status != SWITCH_STATUS_SUCCESS) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (!event) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parse_command(listener, event, reply, sizeof(reply)) != SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_clear_flag_locked(listener, LFLAG_RUNNING);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (!switch_strlen_zero(reply)) {
|
||||||
|
snprintf(buf, sizeof(buf), "Content-Type: command/reply\nReply-Text: %s\n\n", reply);
|
||||||
|
len = strlen(buf);
|
||||||
|
switch_socket_send(listener->sock, buf, &len);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while(switch_test_flag(listener, LFLAG_RUNNING) && listen_list.ready) {
|
while(switch_test_flag(listener, LFLAG_RUNNING) && listen_list.ready) {
|
||||||
switch_event_t *event;
|
switch_event_t *event;
|
||||||
|
@ -855,7 +1071,6 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (!switch_strlen_zero(reply)) {
|
if (!switch_strlen_zero(reply)) {
|
||||||
snprintf(buf, sizeof(buf), "Content-Type: command/reply\nReply-Text: %s\n\n", reply);
|
snprintf(buf, sizeof(buf), "Content-Type: command/reply\nReply-Text: %s\n\n", reply);
|
||||||
len = strlen(buf);
|
len = strlen(buf);
|
||||||
|
@ -869,25 +1084,23 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj)
|
||||||
remove_listener(listener);
|
remove_listener(listener);
|
||||||
close_socket(&listener->sock);
|
close_socket(&listener->sock);
|
||||||
|
|
||||||
if (switch_test_flag(listener, LFLAG_EVENTS)) {
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session complete, waiting for children\n");
|
||||||
remove_listener(listener);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Thread done, waiting for children\n");
|
|
||||||
|
|
||||||
switch_thread_rwlock_wrlock(listener->rwlock);
|
switch_thread_rwlock_wrlock(listener->rwlock);
|
||||||
switch_thread_rwlock_unlock(listener->rwlock);
|
switch_thread_rwlock_unlock(listener->rwlock);
|
||||||
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Closed\n");
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Closed\n");
|
||||||
|
|
||||||
|
if (session) {
|
||||||
|
switch_channel_clear_flag(switch_core_session_get_channel(session), CF_CONTROLLED);
|
||||||
if (listener->pool) {
|
switch_clear_flag_locked(listener, LFLAG_SESSION);
|
||||||
|
switch_core_session_rwunlock(session);
|
||||||
|
} else if (listener->pool) {
|
||||||
switch_memory_pool_t *pool = listener->pool;
|
switch_memory_pool_t *pool = listener->pool;
|
||||||
switch_core_destroy_memory_pool(&pool);
|
switch_core_destroy_memory_pool(&pool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_sleep(switch_core_session_t *session,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void switch_ivr_parse_event(switch_core_session_t *session, switch_event_t *event)
|
SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *session, switch_event_t *event)
|
||||||
{
|
{
|
||||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||||
char *cmd = switch_event_get_header(event, "call-command");
|
char *cmd = switch_event_get_header(event, "call-command");
|
||||||
|
@ -97,40 +97,47 @@ static void switch_ivr_parse_event(switch_core_session_t *session, switch_event_
|
||||||
unsigned long CMD_NOMEDIA = apr_hashfunc_default("nomedia", &hlen);
|
unsigned long CMD_NOMEDIA = apr_hashfunc_default("nomedia", &hlen);
|
||||||
|
|
||||||
assert(channel != NULL);
|
assert(channel != NULL);
|
||||||
|
|
||||||
|
if (switch_strlen_zero(cmd)) {
|
||||||
|
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Command!\n");
|
||||||
|
return SWITCH_STATUS_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
hlen = (switch_size_t) strlen(cmd);
|
hlen = (switch_size_t) strlen(cmd);
|
||||||
cmd_hash = apr_hashfunc_default(cmd, &hlen);
|
cmd_hash = apr_hashfunc_default(cmd, &hlen);
|
||||||
|
|
||||||
switch_channel_set_flag(channel, CF_EVENT_PARSE);
|
switch_channel_set_flag(channel, CF_EVENT_PARSE);
|
||||||
|
|
||||||
if (!switch_strlen_zero(cmd)) {
|
|
||||||
if (cmd_hash == CMD_EXECUTE) {
|
if (cmd_hash == CMD_EXECUTE) {
|
||||||
const switch_application_interface_t *application_interface;
|
const switch_application_interface_t *application_interface;
|
||||||
char *app_name = switch_event_get_header(event, "execute-app-name");
|
char *app_name = switch_event_get_header(event, "execute-app-name");
|
||||||
char *app_arg = switch_event_get_header(event, "execute-app-arg");
|
char *app_arg = switch_event_get_header(event, "execute-app-arg");
|
||||||
|
|
||||||
if (app_name && app_arg) {
|
if (app_name && app_arg) {
|
||||||
if ((application_interface = switch_loadable_module_get_application_interface(app_name))) {
|
if ((application_interface = switch_loadable_module_get_application_interface(app_name))) {
|
||||||
if (application_interface->application_function) {
|
if (application_interface->application_function) {
|
||||||
application_interface->application_function(session, app_arg);
|
application_interface->application_function(session, app_arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (cmd_hash == CMD_HANGUP) {
|
} else if (cmd_hash == CMD_HANGUP) {
|
||||||
char *cause_name = switch_event_get_header(event, "hangup-cause");
|
char *cause_name = switch_event_get_header(event, "hangup-cause");
|
||||||
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
|
switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING;
|
||||||
|
|
||||||
if (cause_name) {
|
if (cause_name) {
|
||||||
cause = switch_channel_str2cause(cause_name);
|
cause = switch_channel_str2cause(cause_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_channel_hangup(channel, cause);
|
switch_channel_hangup(channel, cause);
|
||||||
} else if (cmd_hash == CMD_NOMEDIA) {
|
} else if (cmd_hash == CMD_NOMEDIA) {
|
||||||
char *uuid = switch_event_get_header(event, "nomedia-uuid");
|
char *uuid = switch_event_get_header(event, "nomedia-uuid");
|
||||||
switch_ivr_nomedia(uuid, SMF_REBRIDGE);
|
switch_ivr_nomedia(uuid, SMF_REBRIDGE);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
switch_channel_clear_flag(channel, CF_EVENT_PARSE);
|
switch_channel_clear_flag(channel, CF_EVENT_PARSE);
|
||||||
|
return SWITCH_STATUS_SUCCESS;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +160,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch_channel_set_flag(channel, CF_CONTROLLED);
|
switch_channel_set_flag(channel, CF_CONTROLLED);
|
||||||
while (switch_channel_ready(channel)) {
|
while (switch_channel_ready(channel) && switch_channel_test_flag(channel, CF_CONTROLLED)) {
|
||||||
|
|
||||||
if ((status = switch_core_session_read_frame(session, &frame, -1, stream_id)) == SWITCH_STATUS_SUCCESS) {
|
if ((status = switch_core_session_read_frame(session, &frame, -1, stream_id)) == SWITCH_STATUS_SUCCESS) {
|
||||||
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
if (!SWITCH_READ_ACCEPTABLE(status)) {
|
||||||
|
@ -163,6 +170,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_park(switch_core_session_t *session)
|
||||||
if (switch_core_session_dequeue_private_event(session, &event) == SWITCH_STATUS_SUCCESS) {
|
if (switch_core_session_dequeue_private_event(session, &event) == SWITCH_STATUS_SUCCESS) {
|
||||||
switch_ivr_parse_event(session, event);
|
switch_ivr_parse_event(session, event);
|
||||||
switch_event_destroy(&event);
|
switch_event_destroy(&event);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_channel_has_dtmf(channel)) {
|
||||||
|
char dtmf[128];
|
||||||
|
switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (switch_core_session_dequeue_event(session, &event) == SWITCH_STATUS_SUCCESS) {
|
||||||
|
switch_channel_event_set_data(channel, event);
|
||||||
|
switch_event_fire(&event);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4597,27 +4614,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_phrase_macro(switch_core_session_t *s
|
||||||
done = 1;
|
done = 1;
|
||||||
break;
|
break;
|
||||||
} else if (!strcasecmp(func, "execute")) {
|
} else if (!strcasecmp(func, "execute")) {
|
||||||
const switch_application_interface_t *application_interface;
|
|
||||||
char *app_name = NULL;
|
|
||||||
char *app_arg = NULL;
|
|
||||||
|
|
||||||
if ((app_name = strdup(odata))) {
|
|
||||||
char *e = NULL;
|
|
||||||
if ((app_arg = strchr(app_name, '('))) {
|
|
||||||
*app_arg++ = '\0';
|
|
||||||
if ((e = strchr(app_arg, ')'))) {
|
|
||||||
*e = '\0';
|
|
||||||
}
|
|
||||||
if (app_name && app_arg && e && (application_interface = switch_loadable_module_get_application_interface(app_name))) {
|
|
||||||
if (application_interface->application_function) {
|
|
||||||
application_interface->application_function(session, app_arg);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Application!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
switch_safe_free(app_name);
|
|
||||||
}
|
|
||||||
} else if (!strcasecmp(func, "say")) {
|
} else if (!strcasecmp(func, "say")) {
|
||||||
switch_say_interface_t *si;
|
switch_say_interface_t *si;
|
||||||
if ((si = switch_loadable_module_get_say_interface(lang))) {
|
if ((si = switch_loadable_module_get_say_interface(lang))) {
|
||||||
|
|
Loading…
Reference in New Issue