From 9d1e2e9167bb3f77d41963127c3d775b2f505abd Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Sat, 6 Jan 2007 17:06:18 +0000 Subject: [PATCH] don't call us we'll call you git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@3917 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- scripts/socket/FreeSWITCH/Client.pm | 238 +++++++++++---- scripts/socket/sock.pl | 45 +++ src/include/switch_ivr.h | 8 + .../mod_event_socket/mod_event_socket.c | 289 +++++++++++++++--- src/switch_ivr.c | 89 +++--- 5 files changed, 526 insertions(+), 143 deletions(-) create mode 100755 scripts/socket/sock.pl diff --git a/scripts/socket/FreeSWITCH/Client.pm b/scripts/socket/FreeSWITCH/Client.pm index 8ef812f8a9..41bfbad238 100644 --- a/scripts/socket/FreeSWITCH/Client.pm +++ b/scripts/socket/FreeSWITCH/Client.pm @@ -13,8 +13,11 @@ sub init($;$) { $self->{_host} = $args->{-host} || "localhost"; $self->{_port} = $args->{-port} || 8021; $self->{_password} = $args->{-password} || undef; - + $self->{events} = []; my $me = bless $self,$class; + if (!$self->{_password}) { + return $me; + } if ($me->connect()) { return $me; } else { @@ -22,61 +25,62 @@ sub init($;$) { } } -sub input($;$) { +sub readhash($;$) { my ($self,$to) = @_; - my $i; - my @r; - my $s = $self->{_sock}; - my $x = 0; - my $done = 0; - my $start = time; + my ($can_read) = IO::Select::select($self->{_sel}, undef, undef, $to ? to : undef); + my $s = shift @{$can_read}; + my @r = (); + my $crc = 0; + my $h; - 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"); + if ($s) { + for (;;) { + my $line; + for (;;) { + my $i = 0; + recv $s, $i, 1, 0; + if ($i eq "") { + $h->{socketerror} = "yes"; + return $h; + last; + } elsif ($i eq "\n") { + $crc++; + last; + } else { + $crc = 0; } + $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($$) { - my $self = shift; - my $arg = shift; + return $h; - 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($$) { @@ -92,31 +96,147 @@ sub output($$) { print $s $data ; } -sub cmd($$$) { +sub get_events($) { 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 $e; - $self->output($cmd->{command}); - foreach(keys %{$cmd}) { - next if ($_ eq "command"); - $self->output($cmd->{$_}); + for(;;) { + $e = $self->readhash(.1); + if ($e && !$e->{socketerror}) { + #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($) { my $self = shift; - $self->{_sock}->shutdown(2); - $self->{_sock}->close(); + if ($self->{_sock}) { + $self->{_sock}->shutdown(2); + $self->{_sock}->close(); + } undef $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($) { my $self = shift; @@ -134,7 +254,7 @@ sub connect($) { if ($h->{"content-type"} eq "auth/request") { my $pass = $self->{"_password"}; - $h = $self->cmd({command => "auth $pass"}); + $h = $self->sendmsg({command => "auth $pass"}); } if ($h->{'reply-text'} =~ "OK") { diff --git a/scripts/socket/sock.pl b/scripts/socket/sock.pl new file mode 100755 index 0000000000..946adab02f --- /dev/null +++ b/scripts/socket/sock.pl @@ -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"; + + diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index f75c42883c..b91c15b0ea 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -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 \param session the session to wait for. 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 index 02b661103f..6eec275ab1 100644 --- a/src/mod/event_handlers/mod_event_socket/mod_event_socket.c +++ b/src/mod/event_handlers/mod_event_socket/mod_event_socket.c @@ -39,7 +39,11 @@ typedef enum { LFLAG_AUTHED = (1 << 0), LFLAG_RUNNING = (1 << 1), 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; typedef enum { @@ -60,6 +64,7 @@ struct listener { uint8_t event_list[SWITCH_EVENT_ALL+1]; switch_hash_t *event_hash; switch_thread_rwlock_t *rwlock; + switch_core_session_t *session; 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_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) { listener_t *l; @@ -122,7 +130,7 @@ static void event_handler(switch_event_t *event) continue; } - if (l->event_list[(uint8_t)SWITCH_EVENT_ALL]) { + if (l->event_list[(uint8_t)SWITCH_EVENT_ALL]) { send = 1; } 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))) { @@ -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 (switch_event_dup(&clone, event) == SWITCH_STATUS_SUCCESS) { 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); } +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 */ "[:]", + /*.next */ NULL +}; + + static switch_loadable_module_interface_t event_socket_module_interface = { /*.module_name */ modname, @@ -149,7 +263,7 @@ static switch_loadable_module_interface_t event_socket_module_interface = { /*.timer_interface */ NULL, /*.dialplan_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; } + if (listener->session && !switch_channel_ready(switch_core_session_get_channel(listener->session))) { + status = SWITCH_STATUS_FALSE; + break; + } + if (mlen) { bytes += mlen; do_sleep = 0; @@ -313,7 +432,7 @@ static switch_status_t read_packet(listener_t *listener, switch_event_t **event, break; } } - + if (timeout) { elapsed = (uint32_t)(time(NULL) - start); 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)) { char *ename; 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_event_t *event; char reply[512] = ""; + switch_core_session_t *session = NULL; + switch_channel_t *channel = 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_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); - switch_socket_send(listener->sock, buf, &len); - + if (session && switch_test_flag(listener, LFLAG_AUTHED)) { + switch_event_t *event = NULL, *call_event; + char *event_str; + - 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); - 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; - } + len = strlen(buf); + switch_socket_send(listener->sock, buf, &len); + 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) { switch_event_t *event; @@ -855,7 +1071,6 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) break; } - if (!switch_strlen_zero(reply)) { snprintf(buf, sizeof(buf), "Content-Type: command/reply\nReply-Text: %s\n\n", reply); len = strlen(buf); @@ -869,25 +1084,23 @@ static void *SWITCH_THREAD_FUNC listener_run(switch_thread_t *thread, void *obj) 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, "Thread done, waiting for children\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Session complete, waiting for children\n"); switch_thread_rwlock_wrlock(listener->rwlock); switch_thread_rwlock_unlock(listener->rwlock); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connection Closed\n"); - - - if (listener->pool) { + if (session) { + switch_channel_clear_flag(switch_core_session_get_channel(session), CF_CONTROLLED); + switch_clear_flag_locked(listener, LFLAG_SESSION); + switch_core_session_rwunlock(session); + } else if (listener->pool) { switch_memory_pool_t *pool = listener->pool; switch_core_destroy_memory_pool(&pool); } + return NULL; } diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 5524bdb2a4..fdef13906b 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -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); 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); 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); cmd_hash = apr_hashfunc_default(cmd, &hlen); switch_channel_set_flag(channel, CF_EVENT_PARSE); - if (!switch_strlen_zero(cmd)) { - if (cmd_hash == CMD_EXECUTE) { - const switch_application_interface_t *application_interface; - char *app_name = switch_event_get_header(event, "execute-app-name"); - char *app_arg = switch_event_get_header(event, "execute-app-arg"); + + if (cmd_hash == CMD_EXECUTE) { + const switch_application_interface_t *application_interface; + char *app_name = switch_event_get_header(event, "execute-app-name"); + char *app_arg = switch_event_get_header(event, "execute-app-arg"); - if (app_name && app_arg) { - if ((application_interface = switch_loadable_module_get_application_interface(app_name))) { - if (application_interface->application_function) { - application_interface->application_function(session, app_arg); - } - } - } - } else if (cmd_hash == CMD_HANGUP) { - char *cause_name = switch_event_get_header(event, "hangup-cause"); - switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; + if (app_name && app_arg) { + if ((application_interface = switch_loadable_module_get_application_interface(app_name))) { + if (application_interface->application_function) { + application_interface->application_function(session, app_arg); + } + } + } + } else if (cmd_hash == CMD_HANGUP) { + char *cause_name = switch_event_get_header(event, "hangup-cause"); + switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; - if (cause_name) { - cause = switch_channel_str2cause(cause_name); - } + if (cause_name) { + cause = switch_channel_str2cause(cause_name); + } - switch_channel_hangup(channel, cause); - } else if (cmd_hash == CMD_NOMEDIA) { - char *uuid = switch_event_get_header(event, "nomedia-uuid"); - switch_ivr_nomedia(uuid, SMF_REBRIDGE); - } - } + switch_channel_hangup(channel, cause); + } else if (cmd_hash == CMD_NOMEDIA) { + char *uuid = switch_event_get_header(event, "nomedia-uuid"); + switch_ivr_nomedia(uuid, SMF_REBRIDGE); + } + 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); - 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 (!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) { switch_ivr_parse_event(session, 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; break; } 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")) { switch_say_interface_t *si; if ((si = switch_loadable_module_get_say_interface(lang))) {