2013-06-06 16:03:00 -04:00
/*
* mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
* Copyright ( C ) 2013 , Grasshopper
*
* 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 mod_rayo for FreeSWITCH Modular Media Switching Software Library / Soft - Switch Application
*
* The Initial Developer of the Original Code is Grasshopper
* Portions created by the Initial Developer are Copyright ( C )
* the Initial Developer . All Rights Reserved .
*
* Contributor ( s ) :
* Chris Rienzo < chris . rienzo @ grasshopper . com >
*
* mod_rayo . c - - Rayo server / node implementation . Allows MxN clustering of FreeSWITCH and Rayo Clients ( like Adhearsion )
*
*/
# include <switch.h>
# include <iksemel.h>
# include "mod_rayo.h"
# include "rayo_components.h"
# include "rayo_elements.h"
# include "xmpp_streams.h"
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_rayo_shutdown ) ;
SWITCH_MODULE_LOAD_FUNCTION ( mod_rayo_load ) ;
SWITCH_MODULE_DEFINITION ( mod_rayo , mod_rayo_load , mod_rayo_shutdown , NULL ) ;
# define RAYO_CAUSE_HANGUP SWITCH_CAUSE_NORMAL_CLEARING
# define RAYO_CAUSE_DECLINE SWITCH_CAUSE_CALL_REJECTED
# define RAYO_CAUSE_BUSY SWITCH_CAUSE_USER_BUSY
# define RAYO_CAUSE_ERROR SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE
2013-06-13 11:23:12 -04:00
# define RAYO_END_REASON_HANGUP "hungup"
# define RAYO_END_REASON_HANGUP_LOCAL "hangup-command"
2013-06-06 16:03:00 -04:00
# define RAYO_END_REASON_TIMEOUT "timeout"
2013-06-13 11:23:12 -04:00
# define RAYO_END_REASON_BUSY "busy"
# define RAYO_END_REASON_REJECT "rejected"
# define RAYO_END_REASON_ERROR "error"
2013-06-06 16:03:00 -04:00
2013-09-12 12:13:22 -04:00
# define RAYO_SIP_REQUEST_HEADER "sip_h_"
2013-06-06 16:03:00 -04:00
# define RAYO_SIP_RESPONSE_HEADER "sip_rh_"
# define RAYO_SIP_PROVISIONAL_RESPONSE_HEADER "sip_ph_"
# define RAYO_SIP_BYE_RESPONSE_HEADER "sip_bye_h_"
# define RAYO_CONFIG_FILE "rayo.conf"
2013-08-09 09:42:10 -04:00
# define JOINED_CALL 1
# define JOINED_MIXER 2
2013-06-06 16:03:00 -04:00
struct rayo_actor ;
struct rayo_client ;
struct rayo_call ;
# define rayo_call_get_uuid(call) RAYO_ID(call)
/**
* Function pointer wrapper for the handlers hash
*/
struct rayo_xmpp_handler {
2013-06-24 14:51:54 -04:00
const char * from_type ;
2013-06-06 16:03:00 -04:00
const char * from_subtype ;
2013-06-24 14:51:54 -04:00
const char * to_type ;
2013-06-06 16:03:00 -04:00
const char * to_subtype ;
rayo_actor_xmpp_handler fn ;
} ;
/**
* Client availability
*/
enum presence_status {
PS_UNKNOWN = - 1 ,
PS_OFFLINE = 0 ,
PS_ONLINE = 1
} ;
/**
* A xmpp peer server that routes messages to / from clients
*/
struct rayo_peer_server {
/** base class */
struct rayo_actor base ;
/** clients connected via this server */
switch_hash_t * clients ;
} ;
# define RAYO_PEER_SERVER(x) ((struct rayo_peer_server *)x)
/**
* A Rayo client that controls calls
*/
struct rayo_client {
/** base class */
struct rayo_actor base ;
/** availability */
enum presence_status availability ;
/** set if reachable via s2s */
struct rayo_peer_server * peer_server ;
/** domain or full JID to route to */
const char * route ;
/** time when last probe was sent */
switch_time_t last_probe ;
} ;
# define RAYO_CLIENT(x) ((struct rayo_client *)x)
/**
* A call controlled by a Rayo client
*/
struct rayo_call {
/** actor base class */
struct rayo_actor base ;
/** Definitive controlling party JID */
char * dcp_jid ;
/** Potential controlling parties */
switch_hash_t * pcps ;
/** current idle start time */
switch_time_t idle_start_time ;
2013-11-06 17:00:13 -05:00
/** true if fax is in progress */
int faxing ;
2013-08-09 09:42:10 -04:00
/** 1 if joined to call, 2 if joined to mixer */
2013-06-06 16:03:00 -04:00
int joined ;
2013-10-09 17:39:33 -04:00
/** pending join */
iks * pending_join_request ;
2013-08-09 09:42:10 -04:00
/** ID of joined party TODO this will be many mixers / calls */
const char * joined_id ;
2013-06-06 16:03:00 -04:00
/** set if response needs to be sent to IQ request */
const char * dial_id ;
/** channel destroy event */
switch_event_t * end_event ;
2013-08-06 16:21:22 -04:00
/** True if ringing event sent to client */
int ringing_sent ;
2013-06-06 16:03:00 -04:00
} ;
/**
* A conference
*/
struct rayo_mixer {
/** actor base class */
struct rayo_actor base ;
/** member JIDs */
switch_hash_t * members ;
/** subscriber JIDs */
switch_hash_t * subscribers ;
} ;
/**
* A member of a mixer
*/
struct rayo_mixer_member {
/** JID of member */
const char * jid ;
/** Controlling party JID */
const char * dcp_jid ;
} ;
/**
* A subscriber to mixer events
*/
struct rayo_mixer_subscriber {
/** JID of subscriber */
const char * jid ;
/** Number of controlled parties in mixer */
int ref_count ;
} ;
/**
* Module state
*/
static struct {
/** module memory pool */
switch_memory_pool_t * pool ;
/** Rayo <iq> set commands mapped to functions */
switch_hash_t * command_handlers ;
/** Rayo <presence> events mapped to functions */
switch_hash_t * event_handlers ;
/** Active Rayo actors mapped by JID */
switch_hash_t * actors ;
/** Rayo actors pending destruction */
switch_hash_t * destroy_actors ;
/** Active Rayo actors mapped by internal ID */
switch_hash_t * actors_by_id ;
/** synchronizes access to actors */
switch_mutex_t * actors_mutex ;
/** map of DCP JID to client */
switch_hash_t * clients_roster ;
/** synchronizes access to available clients */
switch_mutex_t * clients_mutex ;
/** server for calls/mixers/etc */
struct rayo_actor * server ;
/** Maximum idle time before call is considered abandoned */
int max_idle_ms ;
/** Conference profile to use for mixers */
char * mixer_conf_profile ;
/** to URI prefixes mapped to gateways */
switch_hash_t * dial_gateways ;
/** console command aliases */
switch_hash_t * cmd_aliases ;
/** global console */
struct rayo_client * console ;
/** XMPP context */
struct xmpp_stream_context * xmpp_context ;
2013-06-24 20:50:37 -04:00
/** number of message threads */
int num_message_threads ;
/** message delivery queue */
switch_queue_t * msg_queue ;
/** shutdown flag */
int shutdown ;
/** prevents context shutdown until all threads are finished */
switch_thread_rwlock_t * shutdown_rwlock ;
2013-08-10 09:30:33 -04:00
/** if true, URI is put in from/to of offer if available */
int offer_uri ;
2013-06-06 16:03:00 -04:00
} globals ;
/**
* An outbound dial gateway
*/
struct dial_gateway {
/** URI prefix to match */
const char * uri_prefix ;
/** dial prefix to match */
const char * dial_prefix ;
/** number of digits to strip from dialstring */
int strip ;
} ;
2013-06-24 20:50:37 -04:00
static void rayo_call_send ( struct rayo_actor * call , struct rayo_message * msg ) ;
static void rayo_server_send ( struct rayo_actor * server , struct rayo_message * msg ) ;
static void rayo_mixer_send ( struct rayo_actor * mixer , struct rayo_message * msg ) ;
static void rayo_component_send ( struct rayo_actor * component , struct rayo_message * msg ) ;
static void rayo_client_send ( struct rayo_actor * client , struct rayo_message * msg ) ;
static void rayo_console_client_send ( struct rayo_actor * client , struct rayo_message * msg ) ;
2013-06-06 16:03:00 -04:00
static void on_client_presence ( struct rayo_client * rclient , iks * node ) ;
2013-08-14 18:00:30 -04:00
typedef switch_bool_t ( * rayo_actor_match_fn ) ( struct rayo_actor * ) ;
static switch_bool_t is_call_actor ( struct rayo_actor * actor ) ;
2013-06-25 11:30:10 -04:00
/**
* @ param msg to check
* @ return true if message was sent by admin client ( console )
*/
static int is_admin_client_message ( struct rayo_message * msg )
{
return ! zstr ( msg - > from_jid ) & & ! strcmp ( RAYO_JID ( globals . console ) , msg - > from_jid ) ;
}
2013-06-06 16:03:00 -04:00
2013-06-24 14:51:54 -04:00
/**
2013-06-25 11:30:10 -04:00
* @ param msg to check
* @ return true if from / to bare JIDs match
2013-06-24 14:51:54 -04:00
*/
2013-06-25 11:30:10 -04:00
static int is_internal_message ( struct rayo_message * msg )
2013-06-24 14:51:54 -04:00
{
2013-06-25 11:30:10 -04:00
return msg - > from & & msg - > to & & ( iks_id_cmp ( msg - > from , msg - > to , IKS_ID_PARTIAL ) = = 0 ) ;
2013-06-24 14:51:54 -04:00
}
2013-06-06 16:03:00 -04:00
/**
* Presence status
* @ param status the presence status
* @ return the string value of status
*/
static const char * presence_status_to_string ( enum presence_status status )
{
switch ( status ) {
case PS_OFFLINE : return " OFFLINE " ;
case PS_ONLINE : return " ONLINE " ;
case PS_UNKNOWN :
default : return " UNKNOWN " ;
}
return " UNKNOWN " ;
}
/**
* Get rayo cause code from FS hangup cause
* @ param cause FS hangup cause
* @ return rayo end cause
*/
static const char * switch_cause_to_rayo_cause ( switch_call_cause_t cause )
{
switch ( cause ) {
case SWITCH_CAUSE_NONE :
case SWITCH_CAUSE_NORMAL_CLEARING :
return RAYO_END_REASON_HANGUP ;
case SWITCH_CAUSE_UNALLOCATED_NUMBER :
case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET :
case SWITCH_CAUSE_NO_ROUTE_DESTINATION :
case SWITCH_CAUSE_CHANNEL_UNACCEPTABLE :
return RAYO_END_REASON_ERROR ;
case SWITCH_CAUSE_CALL_AWARDED_DELIVERED :
return RAYO_END_REASON_HANGUP ;
case SWITCH_CAUSE_USER_BUSY :
return RAYO_END_REASON_BUSY ;
case SWITCH_CAUSE_NO_USER_RESPONSE :
case SWITCH_CAUSE_NO_ANSWER :
return RAYO_END_REASON_TIMEOUT ;
case SWITCH_CAUSE_SUBSCRIBER_ABSENT :
return RAYO_END_REASON_ERROR ;
case SWITCH_CAUSE_CALL_REJECTED :
return RAYO_END_REASON_REJECT ;
case SWITCH_CAUSE_NUMBER_CHANGED :
case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION :
case SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR :
case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER :
case SWITCH_CAUSE_INVALID_NUMBER_FORMAT :
return RAYO_END_REASON_ERROR ;
case SWITCH_CAUSE_FACILITY_REJECTED :
return RAYO_END_REASON_REJECT ;
case SWITCH_CAUSE_RESPONSE_TO_STATUS_ENQUIRY :
case SWITCH_CAUSE_NORMAL_UNSPECIFIED :
return RAYO_END_REASON_HANGUP ;
case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION :
case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER :
case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE :
case SWITCH_CAUSE_SWITCH_CONGESTION :
case SWITCH_CAUSE_ACCESS_INFO_DISCARDED :
case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL :
case SWITCH_CAUSE_PRE_EMPTED :
case SWITCH_CAUSE_FACILITY_NOT_SUBSCRIBED :
case SWITCH_CAUSE_OUTGOING_CALL_BARRED :
case SWITCH_CAUSE_INCOMING_CALL_BARRED :
case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH :
case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL :
case SWITCH_CAUSE_SERVICE_UNAVAILABLE :
case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL :
case SWITCH_CAUSE_CHAN_NOT_IMPLEMENTED :
case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED :
case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED :
case SWITCH_CAUSE_INVALID_CALL_REFERENCE :
case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION :
case SWITCH_CAUSE_INVALID_MSG_UNSPECIFIED :
case SWITCH_CAUSE_MANDATORY_IE_MISSING :
return RAYO_END_REASON_ERROR ;
case SWITCH_CAUSE_MESSAGE_TYPE_NONEXIST :
case SWITCH_CAUSE_WRONG_MESSAGE :
case SWITCH_CAUSE_IE_NONEXIST :
case SWITCH_CAUSE_INVALID_IE_CONTENTS :
case SWITCH_CAUSE_WRONG_CALL_STATE :
case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE :
case SWITCH_CAUSE_MANDATORY_IE_LENGTH_ERROR :
case SWITCH_CAUSE_PROTOCOL_ERROR :
return RAYO_END_REASON_ERROR ;
case SWITCH_CAUSE_INTERWORKING :
case SWITCH_CAUSE_SUCCESS :
case SWITCH_CAUSE_ORIGINATOR_CANCEL :
return RAYO_END_REASON_HANGUP ;
case SWITCH_CAUSE_CRASH :
case SWITCH_CAUSE_SYSTEM_SHUTDOWN :
case SWITCH_CAUSE_LOSE_RACE :
case SWITCH_CAUSE_MANAGER_REQUEST :
case SWITCH_CAUSE_BLIND_TRANSFER :
case SWITCH_CAUSE_ATTENDED_TRANSFER :
case SWITCH_CAUSE_ALLOTTED_TIMEOUT :
case SWITCH_CAUSE_USER_CHALLENGE :
case SWITCH_CAUSE_MEDIA_TIMEOUT :
case SWITCH_CAUSE_PICKED_OFF :
case SWITCH_CAUSE_USER_NOT_REGISTERED :
case SWITCH_CAUSE_PROGRESS_TIMEOUT :
case SWITCH_CAUSE_INVALID_GATEWAY :
case SWITCH_CAUSE_GATEWAY_DOWN :
case SWITCH_CAUSE_INVALID_URL :
case SWITCH_CAUSE_INVALID_PROFILE :
case SWITCH_CAUSE_NO_PICKUP :
return RAYO_END_REASON_ERROR ;
}
return RAYO_END_REASON_HANGUP ;
}
/**
* Add < header > to node
* @ param node to add < header > to
* @ param name of header
* @ param value of header
*/
static void add_header ( iks * node , const char * name , const char * value )
{
if ( ! zstr ( name ) & & ! zstr ( value ) ) {
iks * header = iks_insert ( node , " header " ) ;
iks_insert_attrib ( header , " name " , name ) ;
iks_insert_attrib ( header , " value " , value ) ;
}
}
/**
* Add an outbound dialing gateway
* @ param uri_prefix to match
* @ param dial_prefix to use
* @ param strip number of digits to strip from dialstring
*/
static void dial_gateway_add ( const char * uri_prefix , const char * dial_prefix , int strip )
{
struct dial_gateway * gateway = switch_core_alloc ( globals . pool , sizeof ( * gateway ) ) ;
gateway - > uri_prefix = uri_prefix ? switch_core_strdup ( globals . pool , uri_prefix ) : " " ;
gateway - > dial_prefix = dial_prefix ? switch_core_strdup ( globals . pool , dial_prefix ) : " " ;
gateway - > strip = strip > 0 ? strip : 0 ;
switch_core_hash_insert ( globals . dial_gateways , uri_prefix , gateway ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " dial-gateway uriprefix = %s, dialprefix = %s, strip = %i \n " , uri_prefix , dial_prefix , strip ) ;
}
/**
* Find outbound dial gateway for the specified dialstring
*/
static struct dial_gateway * dial_gateway_find ( const char * uri )
{
switch_hash_index_t * hi = NULL ;
int match_len = 0 ;
struct dial_gateway * gateway = ( struct dial_gateway * ) switch_core_hash_find ( globals . dial_gateways , " default " ) ;
/* find longest prefix match */
for ( hi = switch_core_hash_first ( globals . dial_gateways ) ; hi ; hi = switch_core_hash_next ( hi ) ) {
struct dial_gateway * candidate = NULL ;
const void * prefix ;
int prefix_len = 0 ;
void * val ;
switch_core_hash_this ( hi , & prefix , NULL , & val ) ;
candidate = ( struct dial_gateway * ) val ;
switch_assert ( candidate ) ;
prefix_len = strlen ( prefix ) ;
if ( ! zstr ( prefix ) & & ! strncmp ( prefix , uri , prefix_len ) & & prefix_len > match_len ) {
match_len = prefix_len ;
gateway = candidate ;
}
}
return gateway ;
}
/**
* Add command handler function
* @ param name the command name
* @ param handler the command handler function
*/
static void rayo_command_handler_add ( const char * name , struct rayo_xmpp_handler * handler )
{
char full_name [ 1024 ] ;
full_name [ 1023 ] = ' \0 ' ;
2013-06-24 14:51:54 -04:00
snprintf ( full_name , sizeof ( full_name ) - 1 , " %s:%s:%s " , handler - > to_type , handler - > to_subtype , name ) ;
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Adding command: %s \n " , full_name ) ;
switch_core_hash_insert ( globals . command_handlers , full_name , handler ) ;
}
/**
* Add command handler function
* @ param type the actor type
* @ param subtype the actor subtype
* @ param name the command name
* @ param fn the command callback function
*/
2013-06-24 14:51:54 -04:00
void rayo_actor_command_handler_add ( const char * type , const char * subtype , const char * name , rayo_actor_xmpp_handler fn )
2013-06-06 16:03:00 -04:00
{
struct rayo_xmpp_handler * handler = switch_core_alloc ( globals . pool , sizeof ( * handler ) ) ;
2013-06-24 14:51:54 -04:00
handler - > to_type = zstr ( type ) ? " " : switch_core_strdup ( globals . pool , type ) ;
2013-06-06 16:03:00 -04:00
handler - > to_subtype = zstr ( subtype ) ? " " : switch_core_strdup ( globals . pool , subtype ) ;
handler - > fn = fn ;
rayo_command_handler_add ( name , handler ) ;
}
/**
* Get command handler function from hash
* @ param hash the hash to search
2013-06-24 14:51:54 -04:00
* @ param msg the command
2013-06-06 16:03:00 -04:00
* @ return the command handler function or NULL
*/
2013-06-24 14:51:54 -04:00
rayo_actor_xmpp_handler rayo_actor_command_handler_find ( struct rayo_actor * actor , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * iq = msg - > payload ;
2013-06-06 16:03:00 -04:00
const char * iq_type = iks_find_attrib_soft ( iq , " type " ) ;
iks * command = iks_first_tag ( iq ) ;
const char * name = " " ;
const char * namespace = " " ;
struct rayo_xmpp_handler * handler = NULL ;
char full_name [ 1024 ] ;
full_name [ 1023 ] = ' \0 ' ;
if ( command ) {
name = iks_name ( command ) ;
namespace = iks_find_attrib_soft ( command , " xmlns " ) ;
if ( zstr ( name ) ) {
name = " " ;
}
}
2013-06-24 14:51:54 -04:00
snprintf ( full_name , sizeof ( full_name ) - 1 , " %s:%s:%s:%s:%s " , actor - > type , actor - > subtype , iq_type , namespace , name ) ;
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, looking for %s command \n " , RAYO_JID ( actor ) , full_name ) ;
handler = ( struct rayo_xmpp_handler * ) switch_core_hash_find ( globals . command_handlers , full_name ) ;
if ( handler ) {
return handler - > fn ;
}
return NULL ;
}
/**
* Add event handler function
* @ param name the event name
* @ param handler the event handler function
*/
static void rayo_event_handler_add ( const char * name , struct rayo_xmpp_handler * handler )
{
char full_name [ 1024 ] ;
full_name [ 1023 ] = ' \0 ' ;
2013-06-24 14:51:54 -04:00
snprintf ( full_name , sizeof ( full_name ) - 1 , " %s:%s:%s:%s:%s " , handler - > from_type , handler - > from_subtype , handler - > to_type , handler - > to_subtype , name ) ;
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Adding event: %s \n " , full_name ) ;
switch_core_hash_insert ( globals . event_handlers , full_name , handler ) ;
}
/**
* Add event handler function
* @ param from_type the source actor type
* @ param from_subtype the source actor subtype
* @ param to_type the destination actor type
* @ param to_subtype the destination actor subtype
* @ param name the event name
* @ param fn the event callback function
*/
2013-06-24 14:51:54 -04:00
void rayo_actor_event_handler_add ( const char * from_type , const char * from_subtype , const char * to_type , const char * to_subtype , const char * name , rayo_actor_xmpp_handler fn )
2013-06-06 16:03:00 -04:00
{
struct rayo_xmpp_handler * handler = switch_core_alloc ( globals . pool , sizeof ( * handler ) ) ;
2013-06-24 14:51:54 -04:00
handler - > from_type = zstr ( from_type ) ? " " : switch_core_strdup ( globals . pool , from_type ) ;
2013-06-06 16:03:00 -04:00
handler - > from_subtype = zstr ( from_subtype ) ? " " : switch_core_strdup ( globals . pool , from_subtype ) ;
2013-06-24 14:51:54 -04:00
handler - > to_type = zstr ( to_type ) ? " " : switch_core_strdup ( globals . pool , to_type ) ;
2013-06-06 16:03:00 -04:00
handler - > to_subtype = zstr ( to_subtype ) ? " " : switch_core_strdup ( globals . pool , to_subtype ) ;
handler - > fn = fn ;
rayo_event_handler_add ( name , handler ) ;
}
/**
* Get event handler function from hash
* @ param actor the event destination
2013-06-24 14:51:54 -04:00
* @ param msg the event
2013-06-06 16:03:00 -04:00
* @ return the event handler function or NULL
*/
2013-06-24 14:51:54 -04:00
rayo_actor_xmpp_handler rayo_actor_event_handler_find ( struct rayo_actor * actor , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * presence = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * event = iks_first_tag ( presence ) ;
if ( event ) {
struct rayo_xmpp_handler * handler = NULL ;
const char * presence_type = iks_find_attrib_soft ( presence , " type " ) ;
const char * event_name = iks_name ( event ) ;
const char * event_namespace = iks_find_attrib_soft ( event , " xmlns " ) ;
char full_name [ 1024 ] ;
full_name [ 1023 ] = ' \0 ' ;
if ( zstr ( event_name ) ) {
return NULL ;
}
2013-06-24 14:51:54 -04:00
snprintf ( full_name , sizeof ( full_name ) - 1 , " %s:%s:%s:%s:%s:%s:%s " , msg - > from_type , msg - > from_subtype , actor - > type , actor - > subtype , presence_type , event_namespace , event_name ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s => %s, looking for %s event handler \n " , msg - > from_jid , RAYO_JID ( actor ) , full_name ) ;
2013-06-06 16:03:00 -04:00
handler = ( struct rayo_xmpp_handler * ) switch_core_hash_find ( globals . event_handlers , full_name ) ;
if ( handler ) {
return handler - > fn ;
}
} else {
2013-06-24 14:51:54 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " %s => %s, event missing child element \n " , msg - > from_jid , RAYO_JID ( actor ) ) ;
2013-06-06 16:03:00 -04:00
}
return NULL ;
}
/**
* Clean up a message
* @ param msg to destroy
*/
void rayo_message_destroy ( struct rayo_message * msg )
{
if ( msg ) {
if ( msg - > payload ) {
iks_delete ( msg - > payload ) ;
}
2013-06-24 20:50:37 -04:00
switch_safe_free ( msg - > to_jid ) ;
2013-06-24 14:51:54 -04:00
switch_safe_free ( msg - > from_jid ) ;
switch_safe_free ( msg - > from_type ) ;
switch_safe_free ( msg - > from_subtype ) ;
2013-06-24 20:50:37 -04:00
switch_safe_free ( msg - > file ) ;
2013-06-06 16:03:00 -04:00
free ( msg ) ;
}
}
/**
* Remove payload from message
*/
iks * rayo_message_remove_payload ( struct rayo_message * msg )
{
iks * payload = msg - > payload ;
msg - > payload = NULL ;
2013-06-25 11:30:10 -04:00
msg - > from = NULL ;
msg - > to = NULL ;
2013-06-06 16:03:00 -04:00
return payload ;
}
/**
2013-06-24 20:50:37 -04:00
* Thread that delivers internal XMPP messages
* @ param thread this thread
* @ param obj unused
* @ return NULL
2013-06-06 16:03:00 -04:00
*/
2013-06-24 20:50:37 -04:00
static void * SWITCH_THREAD_FUNC deliver_message_thread ( switch_thread_t * thread , void * obj )
{
struct rayo_message * msg = NULL ;
switch_thread_rwlock_rdlock ( globals . shutdown_rwlock ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " New message delivery thread \n " ) ;
while ( ! globals . shutdown ) {
if ( switch_queue_pop ( globals . msg_queue , ( void * ) & msg ) = = SWITCH_STATUS_SUCCESS ) {
struct rayo_actor * actor = RAYO_LOCATE ( msg - > to_jid ) ;
if ( actor ) {
2013-06-24 21:14:27 -04:00
/* deliver to actor */
2013-06-24 20:50:37 -04:00
switch_mutex_lock ( actor - > mutex ) ;
2013-06-25 11:30:10 -04:00
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , msg - > file , " " , msg - > line , " " , SWITCH_LOG_DEBUG , " Deliver %s => %s %s \n " , msg - > from_jid , msg - > to_jid , iks_string ( iks_stack ( msg - > payload ) , msg - > payload ) ) ;
2013-06-24 20:50:37 -04:00
actor - > send_fn ( actor , msg ) ;
switch_mutex_unlock ( actor - > mutex ) ;
RAYO_UNLOCK ( actor ) ;
2013-06-25 07:42:34 -04:00
} else if ( ! msg - > is_reply ) {
2013-06-24 21:14:27 -04:00
/* unknown actor */
RAYO_SEND_REPLY ( globals . server , msg - > from_jid , iks_new_error ( msg - > payload , STANZA_ERROR_ITEM_NOT_FOUND ) ) ;
2013-06-24 20:50:37 -04:00
}
2013-06-24 21:14:27 -04:00
rayo_message_destroy ( msg ) ;
2013-06-24 20:50:37 -04:00
}
}
2013-06-06 16:03:00 -04:00
2013-06-24 20:50:37 -04:00
/* clean up remaining messages */
while ( switch_queue_trypop ( globals . msg_queue , ( void * ) & msg ) = = SWITCH_STATUS_SUCCESS ) {
rayo_message_destroy ( msg ) ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Message delivery thread finished \n " ) ;
switch_thread_rwlock_unlock ( globals . shutdown_rwlock ) ;
return NULL ;
}
/**
* Create a new message thread
* @ param pool to use
*/
static void start_deliver_message_thread ( switch_memory_pool_t * pool )
{
switch_thread_t * thread ;
switch_threadattr_t * thd_attr = NULL ;
switch_threadattr_create ( & thd_attr , pool ) ;
switch_threadattr_detach_set ( thd_attr , 1 ) ;
switch_threadattr_stacksize_set ( thd_attr , SWITCH_THREAD_STACKSIZE ) ;
switch_thread_create ( & thread , thd_attr , deliver_message_thread , NULL , pool ) ;
}
2013-06-06 16:03:00 -04:00
2013-06-24 20:50:37 -04:00
/**
* Stop all message threads
*/
static void stop_deliver_message_threads ( void )
{
globals . shutdown = 1 ;
switch_queue_interrupt_all ( globals . msg_queue ) ;
switch_thread_rwlock_wrlock ( globals . shutdown_rwlock ) ;
2013-06-06 16:03:00 -04:00
}
/**
* Send message to actor addressed by JID
2013-06-24 20:50:37 -04:00
* @ param from actor sending the message
* @ param to destination JID
* @ param payload the message payload to deliver
* @ param dup true if payload is to be copied
* @ param reply true if a reply
* @ param file file name
* @ param line line number
2013-06-06 16:03:00 -04:00
*/
2013-06-24 20:50:37 -04:00
void rayo_message_send ( struct rayo_actor * from , const char * to , iks * payload , int dup , int reply , const char * file , int line )
2013-06-06 16:03:00 -04:00
{
2013-06-24 20:50:37 -04:00
struct rayo_message * msg = malloc ( sizeof ( * msg ) ) ;
if ( dup ) {
msg - > payload = iks_copy ( payload ) ;
2013-06-06 16:03:00 -04:00
} else {
2013-06-24 20:50:37 -04:00
msg - > payload = payload ;
}
msg - > is_reply = reply ;
msg - > to_jid = strdup ( zstr ( to ) ? " " : to ) ;
2013-06-25 11:30:10 -04:00
if ( ! zstr ( msg - > to_jid ) ) {
2013-06-25 11:40:38 -04:00
msg - > to = iks_id_new ( iks_stack ( msg - > payload ) , msg - > to_jid ) ;
2013-06-25 11:30:10 -04:00
}
2013-06-24 20:50:37 -04:00
msg - > from_jid = strdup ( RAYO_JID ( from ) ) ;
2013-06-25 11:30:10 -04:00
if ( ! zstr ( msg - > from_jid ) ) {
2013-06-25 11:40:38 -04:00
msg - > from = iks_id_new ( iks_stack ( msg - > payload ) , msg - > from_jid ) ;
2013-06-25 11:30:10 -04:00
}
2013-06-24 20:50:37 -04:00
msg - > from_type = strdup ( zstr ( from - > type ) ? " " : from - > type ) ;
msg - > from_subtype = strdup ( zstr ( from - > subtype ) ? " " : from - > subtype ) ;
msg - > file = strdup ( file ) ;
msg - > line = line ;
if ( switch_queue_trypush ( globals . msg_queue , msg ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CRIT , " failed to queue message! \n " ) ;
2013-06-06 16:03:00 -04:00
rayo_message_destroy ( msg ) ;
}
}
/**
* Get access to Rayo actor with JID .
* @ param jid the JID
* @ return the actor or NULL . Call RAYO_UNLOCK ( ) when done with pointer .
*/
struct rayo_actor * rayo_actor_locate ( const char * jid , const char * file , int line )
{
struct rayo_actor * actor = NULL ;
switch_mutex_lock ( globals . actors_mutex ) ;
2013-08-20 17:26:07 -04:00
if ( ! strncmp ( " xmpp: " , jid , 5 ) ) {
jid = jid + 5 ;
}
2013-06-06 16:03:00 -04:00
actor = ( struct rayo_actor * ) switch_core_hash_find ( globals . actors , jid ) ;
if ( actor ) {
if ( ! actor - > destroy ) {
actor - > ref_count + + ;
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , file , " " , line , " " , SWITCH_LOG_DEBUG , " Locate %s: ref count = %i \n " , RAYO_JID ( actor ) , actor - > ref_count ) ;
} else {
actor = NULL ;
}
}
switch_mutex_unlock ( globals . actors_mutex ) ;
return actor ;
}
/**
* Get exclusive access to Rayo actor with internal ID
* @ param id the internal ID
* @ return the actor or NULL . Call RAYO_UNLOCK ( ) when done with pointer .
*/
struct rayo_actor * rayo_actor_locate_by_id ( const char * id , const char * file , int line )
{
struct rayo_actor * actor = NULL ;
if ( ! zstr ( id ) ) {
switch_mutex_lock ( globals . actors_mutex ) ;
actor = ( struct rayo_actor * ) switch_core_hash_find ( globals . actors_by_id , id ) ;
if ( actor ) {
if ( ! actor - > destroy ) {
actor - > ref_count + + ;
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , file , " " , line , " " , SWITCH_LOG_DEBUG , " Locate %s: ref count = %i \n " , RAYO_JID ( actor ) , actor - > ref_count ) ;
} else {
actor = NULL ;
}
}
switch_mutex_unlock ( globals . actors_mutex ) ;
}
return actor ;
}
/**
* Destroy a rayo actor
*/
void rayo_actor_destroy ( struct rayo_actor * actor , const char * file , int line )
{
switch_memory_pool_t * pool = actor - > pool ;
switch_mutex_lock ( globals . actors_mutex ) ;
if ( ! actor - > destroy ) {
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , file , " " , line , " " , SWITCH_LOG_DEBUG , " Destroy %s requested: ref_count = %i \n " , RAYO_JID ( actor ) , actor - > ref_count ) ;
switch_core_hash_delete ( globals . actors , RAYO_JID ( actor ) ) ;
if ( ! zstr ( actor - > id ) ) {
switch_core_hash_delete ( globals . actors_by_id , actor - > id ) ;
}
}
actor - > destroy = 1 ;
if ( actor - > ref_count < = 0 ) {
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , file , " " , line , " " , SWITCH_LOG_DEBUG , " Destroying %s \n " , RAYO_JID ( actor ) ) ;
if ( actor - > cleanup_fn ) {
actor - > cleanup_fn ( actor ) ;
}
switch_core_hash_delete ( globals . destroy_actors , RAYO_JID ( actor ) ) ;
switch_core_destroy_memory_pool ( & pool ) ;
} else {
switch_core_hash_insert ( globals . destroy_actors , RAYO_JID ( actor ) , actor ) ;
}
switch_mutex_unlock ( globals . actors_mutex ) ;
}
/**
* Increment actor ref count - locks from destruction .
*/
void rayo_actor_rdlock ( struct rayo_actor * actor , const char * file , int line )
{
if ( actor ) {
switch_mutex_lock ( globals . actors_mutex ) ;
actor - > ref_count + + ;
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , file , " " , line , " " , SWITCH_LOG_DEBUG , " Lock %s: ref count = %i \n " , RAYO_JID ( actor ) , actor - > ref_count ) ;
switch_mutex_unlock ( globals . actors_mutex ) ;
}
}
/**
* Unlock rayo actor
*/
void rayo_actor_unlock ( struct rayo_actor * actor , const char * file , int line )
{
if ( actor ) {
switch_mutex_lock ( globals . actors_mutex ) ;
actor - > ref_count - - ;
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , file , " " , line , " " , SWITCH_LOG_DEBUG , " Unlock %s: ref count = %i \n " , RAYO_JID ( actor ) , actor - > ref_count ) ;
if ( actor - > ref_count < = 0 & & actor - > destroy ) {
rayo_actor_destroy ( actor , file , line ) ;
}
switch_mutex_unlock ( globals . actors_mutex ) ;
}
}
/**
* Get next number in sequence
*/
int rayo_actor_seq_next ( struct rayo_actor * actor )
{
int seq ;
switch_mutex_lock ( actor - > mutex ) ;
seq = actor - > seq + + ;
switch_mutex_unlock ( actor - > mutex ) ;
return seq ;
}
2013-08-20 17:26:07 -04:00
# define RAYO_CALL_LOCATE(call_uri) rayo_call_locate(call_uri, __FILE__, __LINE__)
/**
* Get access to Rayo call data . Use to access call data outside channel thread .
* @ param call_uri the Rayo XMPP URI
* @ return the call or NULL .
*/
static struct rayo_call * rayo_call_locate ( const char * call_uri , const char * file , int line )
{
struct rayo_actor * actor = rayo_actor_locate ( call_uri , file , line ) ;
if ( actor & & is_call_actor ( actor ) ) {
return RAYO_CALL ( actor ) ;
} else if ( actor ) {
RAYO_UNLOCK ( actor ) ;
}
return NULL ;
}
# define RAYO_CALL_LOCATE_BY_ID(call_uuid) rayo_call_locate_by_id(call_uuid, __FILE__, __LINE__)
2013-06-06 16:03:00 -04:00
/**
2013-08-20 17:26:07 -04:00
* Get access to Rayo call data . Use to access call data outside channel thread .
2013-06-06 16:03:00 -04:00
* @ param call_uuid the FreeSWITCH call UUID
* @ return the call or NULL .
*/
2013-08-20 17:26:07 -04:00
static struct rayo_call * rayo_call_locate_by_id ( const char * call_uuid , const char * file , int line )
2013-06-06 16:03:00 -04:00
{
struct rayo_actor * actor = rayo_actor_locate_by_id ( call_uuid , file , line ) ;
2013-08-14 18:00:30 -04:00
if ( actor & & is_call_actor ( actor ) ) {
2013-06-06 16:03:00 -04:00
return RAYO_CALL ( actor ) ;
} else if ( actor ) {
RAYO_UNLOCK ( actor ) ;
}
return NULL ;
}
/**
* Fire < end > event when call is cleaned up completely
*/
static void rayo_call_cleanup ( struct rayo_actor * actor )
{
struct rayo_call * call = RAYO_CALL ( actor ) ;
switch_event_t * event = call - > end_event ;
int no_offered_clients = 1 ;
switch_hash_index_t * hi = NULL ;
iks * revent ;
iks * end ;
if ( ! event ) {
/* destroyed before FS session was created (in originate, for example) */
return ;
}
revent = iks_new_presence ( " end " , RAYO_NS ,
RAYO_JID ( call ) ,
rayo_call_get_dcp_jid ( call ) ) ;
iks_insert_attrib ( revent , " type " , " unavailable " ) ;
end = iks_find ( revent , " end " ) ;
2013-06-13 11:23:12 -04:00
if ( switch_true ( switch_event_get_header ( event , " variable_rayo_local_hangup " ) ) ) {
iks_insert ( end , RAYO_END_REASON_HANGUP_LOCAL ) ;
} else {
/* remote hangup... translate to specific rayo reason */
switch_call_cause_t cause = SWITCH_CAUSE_NONE ;
char * cause_str = switch_event_get_header ( event , " variable_hangup_cause " ) ;
if ( cause_str ) {
cause = switch_channel_str2cause ( cause_str ) ;
}
iks_insert ( end , switch_cause_to_rayo_cause ( cause ) ) ;
2013-06-06 16:03:00 -04:00
}
#if 0
{
char * event_str ;
if ( switch_event_serialize ( event , & event_str , SWITCH_FALSE ) = = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_DEBUG , " %s \n " , event_str ) ;
switch_safe_free ( event_str ) ;
}
}
# endif
/* add signaling headers */
{
switch_event_header_t * header ;
2013-09-12 12:13:22 -04:00
/* get all variables prefixed with sip_h_ */
2013-06-06 16:03:00 -04:00
for ( header = event - > headers ; header ; header = header - > next ) {
2013-09-12 12:13:22 -04:00
if ( ! strncmp ( " variable_sip_h_ " , header - > name , 15 ) ) {
2013-06-06 16:03:00 -04:00
add_header ( end , header - > name + 15 , header - > value ) ;
}
}
}
/* send <end> to all offered clients */
for ( hi = switch_hash_first ( NULL , call - > pcps ) ; hi ; hi = switch_hash_next ( hi ) ) {
const void * key ;
void * val ;
const char * client_jid = NULL ;
switch_hash_this ( hi , & key , NULL , & val ) ;
client_jid = ( const char * ) key ;
switch_assert ( client_jid ) ;
iks_insert_attrib ( revent , " to " , client_jid ) ;
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_DEBUG , " Sending <end> to offered client %s \n " , client_jid ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE_DUP ( actor , client_jid , revent ) ;
2013-06-06 16:03:00 -04:00
no_offered_clients = 0 ;
}
if ( no_offered_clients ) {
/* send to DCP only */
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_DEBUG , " Sending <end> to DCP %s \n " , rayo_call_get_dcp_jid ( call ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE_DUP ( actor , rayo_call_get_dcp_jid ( call ) , revent ) ;
2013-06-06 16:03:00 -04:00
}
2013-10-09 17:39:33 -04:00
/* lost the race: pending join failed... send IQ result to client now. */
if ( call - > pending_join_request ) {
2013-10-15 14:17:33 -04:00
iks * request = call - > pending_join_request ;
iks * result = iks_new_error_detailed ( request , STANZA_ERROR_ITEM_NOT_FOUND , " call ended " ) ;
2013-10-09 17:39:33 -04:00
call - > pending_join_request = NULL ;
2013-10-15 14:17:33 -04:00
RAYO_SEND_REPLY ( call , iks_find_attrib_soft ( request , " from " ) , result ) ;
iks_delete ( call - > pending_join_request ) ;
2013-10-09 17:39:33 -04:00
}
2013-06-06 16:03:00 -04:00
iks_delete ( revent ) ;
switch_event_destroy ( & event ) ;
2013-11-07 20:31:58 -05:00
switch_core_hash_destroy ( & call - > pcps ) ;
2013-06-06 16:03:00 -04:00
}
/**
* @ param call the Rayo call
* @ return the Rayo call DCP JID
*/
const char * rayo_call_get_dcp_jid ( struct rayo_call * call )
{
return call - > dcp_jid ;
}
/**
* @ param call the Rayo call
2013-11-06 17:00:13 -05:00
* @ return true if joined ( or a join is in progress )
2013-06-06 16:03:00 -04:00
*/
2013-11-06 17:00:13 -05:00
int rayo_call_is_joined ( struct rayo_call * call )
2013-06-06 16:03:00 -04:00
{
2013-11-06 17:00:13 -05:00
return call - > joined | | call - > pending_join_request ;
}
/**
* @ param call to check if faxing
* @ return true if faxing is in progress
*/
int rayo_call_is_faxing ( struct rayo_call * call )
{
return call - > faxing ;
}
/**
* Set faxing flag if faxing is not in progress
* @ param call the call to flag
* @ param faxing true if faxing is in progress
* @ return true if set , false if can ' t set because faxing is already in progress . Reset always succeeds .
*/
int rayo_call_set_faxing ( struct rayo_call * call , int faxing )
{
if ( ! faxing | | ( faxing & & ! call - > faxing ) ) {
call - > faxing = faxing ;
return 1 ;
}
return 0 ;
2013-06-06 16:03:00 -04:00
}
# define RAYO_MIXER_LOCATE(mixer_name) rayo_mixer_locate(mixer_name, __FILE__, __LINE__)
/**
* Get access to Rayo mixer data .
* @ param mixer_name the mixer name
* @ return the mixer or NULL . Call RAYO_UNLOCK ( ) when done with mixer pointer .
*/
static struct rayo_mixer * rayo_mixer_locate ( const char * mixer_name , const char * file , int line )
{
struct rayo_actor * actor = rayo_actor_locate_by_id ( mixer_name , file , line ) ;
2013-06-24 14:51:54 -04:00
if ( actor & & ! strcmp ( RAT_MIXER , actor - > type ) ) {
2013-06-06 16:03:00 -04:00
return RAYO_MIXER ( actor ) ;
} else if ( actor ) {
RAYO_UNLOCK ( actor ) ;
}
return NULL ;
}
/**
* Default message handler - drops messages
*/
2013-06-24 20:50:37 -04:00
void rayo_actor_send_ignore ( struct rayo_actor * to , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
2013-06-24 20:50:37 -04:00
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , msg - > file , " " , msg - > line , " " , SWITCH_LOG_WARNING , " %s, dropping unexpected message to %s. \n " , msg - > from_jid , RAYO_JID ( to ) ) ;
2013-06-06 16:03:00 -04:00
}
# define RAYO_ACTOR_INIT(actor, pool, type, subtype, id, jid, cleanup, send) rayo_actor_init(actor, pool, type, subtype, id, jid, cleanup, send, __FILE__, __LINE__)
/**
* Initialize a rayo actor
* @ param pool to use
* @ param type of actor ( MIXER , CALL , SERVER , COMPONENT )
* @ param subtype of actor ( input / output / prompt )
* @ param id internal ID
* @ param jid external ID
* @ param cleanup function
2013-06-24 14:51:54 -04:00
* @ param send sent message handler
2013-06-06 16:03:00 -04:00
* @ param file that called this function
* @ param line that called this function
* @ return the actor
*/
2013-06-24 14:51:54 -04:00
static struct rayo_actor * rayo_actor_init ( struct rayo_actor * actor , switch_memory_pool_t * pool , const char * type , const char * subtype , const char * id , const char * jid , rayo_actor_cleanup_fn cleanup , rayo_actor_send_fn send , const char * file , int line )
2013-06-06 16:03:00 -04:00
{
char * domain ;
2013-06-24 14:51:54 -04:00
actor - > type = switch_core_strdup ( pool , type ) ;
2013-06-06 16:03:00 -04:00
actor - > subtype = switch_core_strdup ( pool , subtype ) ;
actor - > pool = pool ;
if ( ! zstr ( id ) ) {
actor - > id = switch_core_strdup ( pool , id ) ;
}
/* TODO validate JID with regex */
if ( ! zstr ( jid ) ) {
RAYO_JID ( actor ) = switch_core_strdup ( pool , jid ) ;
if ( ! ( domain = strrchr ( RAYO_JID ( actor ) , ' @ ' ) ) ) {
RAYO_DOMAIN ( actor ) = RAYO_JID ( actor ) ;
} else if ( ! zstr ( + + domain ) ) {
RAYO_DOMAIN ( actor ) = switch_core_strdup ( pool , domain ) ;
/* strip resource from domain if it exists */
domain = strrchr ( RAYO_DOMAIN ( actor ) , ' / ' ) ;
if ( domain ) {
* domain = ' \0 ' ;
}
}
}
actor - > seq = 1 ;
actor - > ref_count = 1 ;
actor - > destroy = 0 ;
switch_mutex_init ( & actor - > mutex , SWITCH_MUTEX_NESTED , pool ) ;
actor - > cleanup_fn = cleanup ;
if ( send = = NULL ) {
actor - > send_fn = rayo_actor_send_ignore ;
} else {
actor - > send_fn = send ;
}
/* add to hash of actors, so commands can route to call */
switch_mutex_lock ( globals . actors_mutex ) ;
if ( ! zstr ( id ) ) {
switch_core_hash_insert ( globals . actors_by_id , actor - > id , actor ) ;
}
if ( ! zstr ( jid ) ) {
switch_core_hash_insert ( globals . actors , RAYO_JID ( actor ) , actor ) ;
}
switch_mutex_unlock ( globals . actors_mutex ) ;
switch_log_printf ( SWITCH_CHANNEL_ID_LOG , file , " " , line , " " , SWITCH_LOG_DEBUG , " Init %s \n " , RAYO_JID ( actor ) ) ;
return actor ;
}
/**
* Initialize rayo call
*/
static struct rayo_call * rayo_call_init ( struct rayo_call * call , switch_memory_pool_t * pool , const char * uuid , const char * file , int line )
{
char * call_jid ;
char uuid_id_buf [ SWITCH_UUID_FORMATTED_LENGTH + 1 ] ;
if ( zstr ( uuid ) ) {
switch_uuid_str ( uuid_id_buf , sizeof ( uuid_id_buf ) ) ;
uuid = uuid_id_buf ;
}
call_jid = switch_mprintf ( " %s@%s " , uuid , RAYO_JID ( globals . server ) ) ;
rayo_actor_init ( RAYO_ACTOR ( call ) , pool , RAT_CALL , " " , uuid , call_jid , rayo_call_cleanup , rayo_call_send , file , line ) ;
call - > dcp_jid = " " ;
call - > idle_start_time = switch_micro_time_now ( ) ;
call - > joined = 0 ;
2013-08-09 09:42:10 -04:00
call - > joined_id = NULL ;
2013-08-06 16:21:22 -04:00
call - > ringing_sent = 0 ;
2013-10-09 17:39:33 -04:00
call - > pending_join_request = NULL ;
2013-06-06 16:03:00 -04:00
switch_core_hash_init ( & call - > pcps , pool ) ;
switch_safe_free ( call_jid ) ;
return call ;
}
# define rayo_call_create(uuid) _rayo_call_create(uuid, __FILE__, __LINE__)
/**
* Create Rayo call
* @ param uuid uuid to assign call , if NULL one is picked
* @ param file file that called this function
* @ param line number of file that called this function
* @ return the call
*/
static struct rayo_call * _rayo_call_create ( const char * uuid , const char * file , int line )
{
switch_memory_pool_t * pool ;
struct rayo_call * call ;
switch_core_new_memory_pool ( & pool ) ;
call = switch_core_alloc ( pool , sizeof ( * call ) ) ;
return rayo_call_init ( call , pool , uuid , file , line ) ;
}
2013-11-07 20:31:58 -05:00
/**
* Mixer destructor
*/
static void rayo_mixer_cleanup ( struct rayo_actor * actor )
{
struct rayo_mixer * mixer = RAYO_MIXER ( actor ) ;
switch_core_hash_destroy ( & mixer - > members ) ;
switch_core_hash_destroy ( & mixer - > subscribers ) ;
}
2013-06-06 16:03:00 -04:00
/**
* Initialize mixer
*/
static struct rayo_mixer * rayo_mixer_init ( struct rayo_mixer * mixer , switch_memory_pool_t * pool , const char * name , const char * file , int line )
{
char * mixer_jid = switch_mprintf ( " %s@%s " , name , RAYO_JID ( globals . server ) ) ;
2013-11-07 20:31:58 -05:00
rayo_actor_init ( RAYO_ACTOR ( mixer ) , pool , RAT_MIXER , " " , name , mixer_jid , rayo_mixer_cleanup , rayo_mixer_send , file , line ) ;
2013-06-06 16:03:00 -04:00
switch_core_hash_init ( & mixer - > members , pool ) ;
switch_core_hash_init ( & mixer - > subscribers , pool ) ;
switch_safe_free ( mixer_jid ) ;
return mixer ;
}
# define rayo_mixer_create(name) _rayo_mixer_create(name, __FILE__, __LINE__)
/**
* Create Rayo mixer
* @ param name of this mixer
* @ return the mixer
*/
static struct rayo_mixer * _rayo_mixer_create ( const char * name , const char * file , int line )
{
switch_memory_pool_t * pool ;
struct rayo_mixer * mixer = NULL ;
switch_core_new_memory_pool ( & pool ) ;
mixer = switch_core_alloc ( pool , sizeof ( * mixer ) ) ;
return rayo_mixer_init ( mixer , pool , name , file , line ) ;
}
/**
* Clean up component before destruction
*/
static void rayo_component_cleanup ( struct rayo_actor * actor )
{
/* parent can now be destroyed */
RAYO_UNLOCK ( RAYO_COMPONENT ( actor ) - > parent ) ;
}
/**
* Initialize Rayo component
* @ param type of this component
2013-06-24 14:51:54 -04:00
* @ param subtype of this component
2013-06-06 16:03:00 -04:00
* @ param id internal ID of this component
* @ param parent the parent that owns this component
* @ param client_jid the client that created this component
* @ return the component
*/
2013-06-24 14:51:54 -04:00
struct rayo_component * _rayo_component_init ( struct rayo_component * component , switch_memory_pool_t * pool , const char * type , const char * subtype , const char * id , struct rayo_actor * parent , const char * client_jid , const char * file , int line )
2013-06-06 16:03:00 -04:00
{
2013-06-25 08:08:56 -04:00
char * ref = switch_mprintf ( " %s-%d " , subtype , rayo_actor_seq_next ( parent ) ) ;
2013-06-06 16:03:00 -04:00
char * jid = switch_mprintf ( " %s/%s " , RAYO_JID ( parent ) , ref ) ;
if ( zstr ( id ) ) {
id = jid ;
}
2013-06-24 14:51:54 -04:00
rayo_actor_init ( RAYO_ACTOR ( component ) , pool , type , subtype , id , jid , rayo_component_cleanup , rayo_component_send , file , line ) ;
2013-06-06 16:03:00 -04:00
RAYO_RDLOCK ( parent ) ;
component - > client_jid = switch_core_strdup ( pool , client_jid ) ;
component - > ref = switch_core_strdup ( pool , ref ) ;
component - > parent = parent ;
switch_safe_free ( ref ) ;
switch_safe_free ( jid ) ;
return component ;
}
/**
* Send XMPP message to client
*/
2013-06-24 20:50:37 -04:00
void rayo_client_send ( struct rayo_actor * client , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
xmpp_stream_context_send ( globals . xmpp_context , RAYO_CLIENT ( client ) - > route , msg - > payload ) ;
}
/**
* Cleanup rayo client
*/
static void rayo_client_cleanup ( struct rayo_actor * actor )
{
/* remove session from map */
switch_mutex_lock ( globals . clients_mutex ) ;
if ( ! zstr ( RAYO_JID ( actor ) ) ) {
switch_core_hash_delete ( globals . clients_roster , RAYO_JID ( actor ) ) ;
if ( RAYO_CLIENT ( actor ) - > peer_server ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Removing %s from peer server %s \n " , RAYO_JID ( actor ) , RAYO_JID ( RAYO_CLIENT ( actor ) - > peer_server ) ) ;
switch_core_hash_delete ( RAYO_CLIENT ( actor ) - > peer_server - > clients , RAYO_JID ( actor ) ) ;
}
}
switch_mutex_unlock ( globals . clients_mutex ) ;
}
/**
* Initialize rayo client
* @ param pool the memory pool for this client
* @ param jid for this client
* @ param route to this client
* @ param availability of client
* @ param send message transmission function
* @ param peer_server NULL if locally connected client
* @ return the new client
*/
2013-06-24 14:51:54 -04:00
static struct rayo_client * rayo_client_init ( struct rayo_client * client , switch_memory_pool_t * pool , const char * jid , const char * route , enum presence_status availability , rayo_actor_send_fn send , struct rayo_peer_server * peer_server )
2013-06-06 16:03:00 -04:00
{
RAYO_ACTOR_INIT ( RAYO_ACTOR ( client ) , pool , RAT_CLIENT , " " , jid , jid , rayo_client_cleanup , send ) ;
client - > availability = availability ;
client - > peer_server = peer_server ;
client - > last_probe = 0 ;
if ( route ) {
client - > route = switch_core_strdup ( pool , route ) ;
}
/* make client available for offers */
switch_mutex_lock ( globals . clients_mutex ) ;
switch_core_hash_insert ( globals . clients_roster , RAYO_JID ( client ) , client ) ;
if ( peer_server ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Adding %s to peer server %s \n " , RAYO_JID ( client ) , RAYO_JID ( peer_server ) ) ;
switch_core_hash_insert ( peer_server - > clients , RAYO_JID ( client ) , client ) ;
}
switch_mutex_unlock ( globals . clients_mutex ) ;
return client ;
}
/**
* Create a new Rayo client
* @ param jid for this client
* @ param route to this client
* @ param availability of client
* @ param send message transmission function
* @ param peer_server NULL if locally connected client
* @ return the new client or NULL
*/
2013-06-24 14:51:54 -04:00
static struct rayo_client * rayo_client_create ( const char * jid , const char * route , enum presence_status availability , rayo_actor_send_fn send , struct rayo_peer_server * peer_server )
2013-06-06 16:03:00 -04:00
{
switch_memory_pool_t * pool ;
struct rayo_client * rclient = NULL ;
switch_core_new_memory_pool ( & pool ) ;
if ( ! ( rclient = switch_core_alloc ( pool , sizeof ( * rclient ) ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Memory Error \n " ) ;
return NULL ;
}
2013-06-24 14:51:54 -04:00
return rayo_client_init ( rclient , pool , jid , route , availability , send , peer_server ) ;
2013-06-06 16:03:00 -04:00
}
/**
* Send XMPP message to peer server
*/
2013-06-24 20:50:37 -04:00
void rayo_peer_server_send ( struct rayo_actor * server , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
xmpp_stream_context_send ( globals . xmpp_context , RAYO_JID ( server ) , msg - > payload ) ;
}
/**
* Destroy peer server and its associated clients
*/
static void rayo_peer_server_cleanup ( struct rayo_actor * actor )
{
switch_hash_index_t * hi ;
struct rayo_peer_server * rserver = RAYO_PEER_SERVER ( actor ) ;
/* a little messy... client will remove itself from the peer server when it is destroyed,
* however , there is no guarantee the client will actually be destroyed now so
* the server must remove the client .
*/
switch_mutex_lock ( globals . clients_mutex ) ;
while ( ( hi = switch_core_hash_first ( rserver - > clients ) ) ) {
const void * key ;
void * client ;
switch_core_hash_this ( hi , & key , NULL , & client ) ;
switch_assert ( client ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Removing %s from peer server %s \n " , RAYO_JID ( client ) , RAYO_JID ( rserver ) ) ;
switch_core_hash_delete ( rserver - > clients , key ) ;
RAYO_CLIENT ( client ) - > peer_server = NULL ;
RAYO_UNLOCK ( client ) ;
RAYO_DESTROY ( client ) ;
}
2013-11-07 20:31:58 -05:00
switch_core_hash_destroy ( & rserver - > clients ) ;
2013-06-06 16:03:00 -04:00
switch_mutex_unlock ( globals . clients_mutex ) ;
}
/**
* Create a new Rayo peer server
* @ param jid of this server
* @ return the peer server
*/
static struct rayo_peer_server * rayo_peer_server_create ( const char * jid )
{
switch_memory_pool_t * pool ;
struct rayo_peer_server * rserver = NULL ;
switch_core_new_memory_pool ( & pool ) ;
if ( ! ( rserver = switch_core_alloc ( pool , sizeof ( * rserver ) ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Memory Error \n " ) ;
return NULL ;
}
RAYO_ACTOR_INIT ( RAYO_ACTOR ( rserver ) , pool , RAT_PEER_SERVER , " " , jid , jid , rayo_peer_server_cleanup , rayo_peer_server_send ) ;
switch_core_hash_init ( & rserver - > clients , pool ) ;
return rserver ;
}
2013-10-09 17:39:33 -04:00
/**
* Check if message sender has control of offered call .
* @ param call the Rayo call
* @ param msg the message
* @ return 1 if sender has call control , 0 if sender does not have control
*/
static int has_call_control ( struct rayo_call * call , struct rayo_message * msg )
{
return ( ! strcmp ( rayo_call_get_dcp_jid ( call ) , msg - > from_jid ) | | is_internal_message ( msg ) | | is_admin_client_message ( msg ) ) ;
}
2013-06-06 16:03:00 -04:00
/**
2013-06-25 11:30:10 -04:00
* Check if message sender has control of offered call . Take control if nobody else does .
2013-06-06 16:03:00 -04:00
* @ param call the Rayo call
* @ param session the session
2013-06-25 11:30:10 -04:00
* @ param msg the message
* @ return 1 if sender has call control
2013-06-06 16:03:00 -04:00
*/
2013-10-09 17:39:33 -04:00
static int take_call_control ( struct rayo_call * call , switch_core_session_t * session , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
int control = 0 ;
/* nobody in charge */
if ( zstr ( call - > dcp_jid ) ) {
/* was offered to this session? */
2013-06-25 11:30:10 -04:00
if ( ! zstr ( msg - > from_jid ) & & switch_core_hash_find ( call - > pcps , msg - > from_jid ) ) {
2013-06-06 16:03:00 -04:00
/* take charge */
2013-06-25 11:30:10 -04:00
call - > dcp_jid = switch_core_strdup ( RAYO_POOL ( call ) , msg - > from_jid ) ;
2013-06-06 16:03:00 -04:00
switch_channel_set_variable ( switch_core_session_get_channel ( session ) , " rayo_dcp_jid " , rayo_call_get_dcp_jid ( call ) ) ;
control = 1 ;
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_INFO , " %s has control of call \n " , rayo_call_get_dcp_jid ( call ) ) ;
}
2013-10-09 17:39:33 -04:00
} else if ( has_call_control ( call , msg ) ) {
2013-06-06 16:03:00 -04:00
control = 1 ;
}
if ( ! control ) {
2013-06-25 11:30:10 -04:00
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_INFO , " %s does not have control of call \n " , msg - > from_jid ) ;
2013-06-06 16:03:00 -04:00
}
return control ;
}
/**
* Check Rayo server command for errors .
2013-06-24 14:51:54 -04:00
* @ param server the server
* @ param msg the command
2013-06-06 16:03:00 -04:00
* @ return 1 if OK
*/
2013-06-24 14:51:54 -04:00
static iks * rayo_server_command_ok ( struct rayo_actor * server , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * response = NULL ;
int bad = zstr ( iks_find_attrib ( node , " id " ) ) ;
if ( bad ) {
response = iks_new_error ( node , STANZA_ERROR_BAD_REQUEST ) ;
}
return response ;
}
/**
* Check Rayo call command for errors .
* @ param call the Rayo call
* @ param session the session
2013-06-24 14:51:54 -04:00
* @ param msg the command
2013-06-06 16:03:00 -04:00
* @ return 1 if OK
*/
2013-06-24 14:51:54 -04:00
static iks * rayo_call_command_ok ( struct rayo_call * call , switch_core_session_t * session , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * response = NULL ;
int bad = zstr ( iks_find_attrib ( node , " id " ) ) ;
if ( bad ) {
response = iks_new_error ( node , STANZA_ERROR_BAD_REQUEST ) ;
2013-10-09 17:39:33 -04:00
} else if ( ! take_call_control ( call , session , msg ) ) {
2013-06-06 16:03:00 -04:00
response = iks_new_error ( node , STANZA_ERROR_CONFLICT ) ;
2013-06-24 14:51:54 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, %s conflict \n " , msg - > from_jid , RAYO_JID ( call ) ) ;
2013-06-06 16:03:00 -04:00
}
return response ;
}
/**
* Check Rayo component command for errors .
* @ param component the component
2013-06-24 14:51:54 -04:00
* @ param msg the command
2013-06-06 16:03:00 -04:00
* @ return 0 if error
*/
2013-06-24 14:51:54 -04:00
static iks * rayo_component_command_ok ( struct rayo_component * component , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * response = NULL ;
char * from = iks_find_attrib ( node , " from " ) ;
int bad = zstr ( iks_find_attrib ( node , " id " ) ) ;
if ( bad ) {
response = iks_new_error ( node , STANZA_ERROR_BAD_REQUEST ) ;
2013-06-24 14:51:54 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, %s bad request \n " , msg - > from_jid , RAYO_JID ( component ) ) ;
2013-06-25 11:30:10 -04:00
} else if ( strcmp ( component - > client_jid , from ) & & ! is_admin_client_message ( msg ) & & ! is_internal_message ( msg ) ) {
2013-06-06 16:03:00 -04:00
/* does not have control of this component */
response = iks_new_error ( node , STANZA_ERROR_CONFLICT ) ;
2013-06-24 14:51:54 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, %s conflict \n " , msg - > from_jid , RAYO_JID ( component ) ) ;
2013-06-06 16:03:00 -04:00
}
return response ;
}
/**
* Handle server message
*/
2013-06-24 20:50:37 -04:00
void rayo_server_send ( struct rayo_actor * server , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
2013-06-24 10:02:09 -04:00
iks * response = NULL ;
2013-06-06 16:03:00 -04:00
rayo_actor_xmpp_handler handler = NULL ;
iks * iq = msg - > payload ;
if ( ! strcmp ( " presence " , iks_name ( iq ) ) ) {
2013-06-24 14:51:54 -04:00
/* this is a hack - message from internal console */
struct rayo_actor * client = RAYO_LOCATE ( msg - > from_jid ) ;
if ( client ) {
if ( ! strcmp ( RAT_CLIENT , client - > type ) ) {
on_client_presence ( RAYO_CLIENT ( client ) , iq ) ;
}
RAYO_UNLOCK ( client ) ;
}
2013-06-24 10:02:09 -04:00
return ;
2013-06-06 16:03:00 -04:00
}
/* is this a command a server supports? */
2013-06-24 14:51:54 -04:00
handler = rayo_actor_command_handler_find ( server , msg ) ;
2013-06-06 16:03:00 -04:00
if ( ! handler ) {
2013-06-24 14:51:54 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, no handler function for command to %s \n " , msg - > from_jid , RAYO_JID ( server ) ) ;
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( server , msg - > from_jid , iks_new_error ( iq , STANZA_ERROR_FEATURE_NOT_IMPLEMENTED ) ) ;
}
2013-06-24 10:02:09 -04:00
return ;
2013-06-06 16:03:00 -04:00
}
/* is the command valid? */
2013-06-24 14:51:54 -04:00
if ( ! ( response = rayo_server_command_ok ( server , msg ) ) ) {
response = handler ( server , msg , NULL ) ;
2013-06-06 16:03:00 -04:00
}
if ( response ) {
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( server , msg - > from_jid , response ) ;
} else {
iks_delete ( response ) ;
}
2013-06-06 16:03:00 -04:00
}
}
/**
* Handle call message
*/
2013-06-24 20:50:37 -04:00
void rayo_call_send ( struct rayo_actor * call , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
rayo_actor_xmpp_handler handler = NULL ;
iks * iq = msg - > payload ;
switch_core_session_t * session ;
iks * response = NULL ;
/* is this a command a call supports? */
2013-06-24 14:51:54 -04:00
handler = rayo_actor_command_handler_find ( call , msg ) ;
2013-06-06 16:03:00 -04:00
if ( ! handler ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, no handler function for command \n " , RAYO_JID ( call ) ) ;
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( call , msg - > from_jid , iks_new_error ( iq , STANZA_ERROR_FEATURE_NOT_IMPLEMENTED ) ) ;
}
2013-06-24 10:02:09 -04:00
return ;
2013-06-06 16:03:00 -04:00
}
/* is the session still available? */
session = switch_core_session_locate ( rayo_call_get_uuid ( RAYO_CALL ( call ) ) ) ;
if ( ! session ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, session not found \n " , RAYO_JID ( call ) ) ;
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
2013-08-06 11:03:01 -03:00
RAYO_SEND_REPLY ( call , msg - > from_jid , iks_new_error ( iq , STANZA_ERROR_ITEM_NOT_FOUND ) ) ;
2013-06-25 11:30:10 -04:00
}
2013-06-24 10:02:09 -04:00
return ;
2013-06-06 16:03:00 -04:00
}
/* is the command valid? */
2013-06-24 14:51:54 -04:00
if ( ! ( response = rayo_call_command_ok ( RAYO_CALL ( call ) , session , msg ) ) ) {
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, executing command \n " , RAYO_JID ( call ) ) ;
2013-06-24 14:51:54 -04:00
response = handler ( call , msg , session ) ;
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, done executing command \n " , RAYO_JID ( call ) ) ;
RAYO_CALL ( call ) - > idle_start_time = switch_micro_time_now ( ) ;
}
switch_core_session_rwunlock ( session ) ;
if ( response ) {
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( call , msg - > from_jid , response ) ;
} else {
iks_delete ( response ) ;
}
2013-06-06 16:03:00 -04:00
}
}
/**
* Handle mixer message
*/
2013-06-24 20:50:37 -04:00
void rayo_mixer_send ( struct rayo_actor * mixer , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
rayo_actor_xmpp_handler handler = NULL ;
iks * iq = msg - > payload ;
iks * response = NULL ;
/* is this a command a mixer supports? */
2013-06-24 14:51:54 -04:00
handler = rayo_actor_command_handler_find ( mixer , msg ) ;
2013-06-06 16:03:00 -04:00
if ( ! handler ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, no handler function for command \n " , RAYO_JID ( mixer ) ) ;
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( mixer , msg - > from_jid , iks_new_error ( iq , STANZA_ERROR_FEATURE_NOT_IMPLEMENTED ) ) ;
}
2013-06-24 10:02:09 -04:00
return ;
2013-06-06 16:03:00 -04:00
}
/* execute the command */
2013-06-24 14:51:54 -04:00
response = handler ( mixer , msg , NULL ) ;
2013-06-06 16:03:00 -04:00
if ( response ) {
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( mixer , msg - > from_jid , response ) ;
} else {
iks_delete ( response ) ;
}
2013-06-06 16:03:00 -04:00
}
}
/**
* Handle mixer message
*/
2013-06-24 20:50:37 -04:00
void rayo_component_send ( struct rayo_actor * component , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
rayo_actor_xmpp_handler handler = NULL ;
iks * xml_msg = msg - > payload ;
iks * response = NULL ;
if ( ! strcmp ( " iq " , iks_name ( xml_msg ) ) ) {
/* is this a command a component supports? */
2013-06-24 14:51:54 -04:00
handler = rayo_actor_command_handler_find ( component , msg ) ;
2013-06-06 16:03:00 -04:00
if ( ! handler ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, no component handler function for command \n " , RAYO_JID ( component ) ) ;
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( component , msg - > from_jid , iks_new_error ( xml_msg , STANZA_ERROR_FEATURE_NOT_IMPLEMENTED ) ) ;
}
2013-06-24 10:02:09 -04:00
return ;
2013-06-06 16:03:00 -04:00
}
/* is the command valid? */
2013-06-24 14:51:54 -04:00
if ( ! ( response = rayo_component_command_ok ( RAYO_COMPONENT ( component ) , msg ) ) ) {
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, executing command \n " , RAYO_JID ( component ) ) ;
2013-06-24 14:51:54 -04:00
response = handler ( component , msg , NULL ) ;
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, done executing command \n " , RAYO_JID ( component ) ) ;
}
if ( response ) {
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( component , msg - > from_jid , response ) ;
} else {
iks_delete ( response ) ;
}
2013-06-24 10:02:09 -04:00
return ;
2013-06-06 16:03:00 -04:00
}
} else if ( ! strcmp ( " presence " , iks_name ( xml_msg ) ) ) {
/* is this an event the component wants? */
2013-06-24 14:51:54 -04:00
handler = rayo_actor_event_handler_find ( component , msg ) ;
2013-06-06 16:03:00 -04:00
if ( ! handler ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, no component handler function for event \n " , RAYO_JID ( component ) ) ;
2013-06-24 10:02:09 -04:00
return ;
2013-06-06 16:03:00 -04:00
}
/* forward the event */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, forwarding event \n " , RAYO_JID ( component ) ) ;
2013-06-24 14:51:54 -04:00
response = handler ( component , msg , NULL ) ;
if ( response ) {
2013-06-25 11:30:10 -04:00
if ( ! msg - > is_reply ) {
RAYO_SEND_REPLY ( component , msg - > from_jid , response ) ;
} else {
iks_delete ( response ) ;
}
2013-06-24 14:51:54 -04:00
}
2013-06-06 16:03:00 -04:00
}
}
/**
* Add signaling headers to channel - - only works on SIP
* @ param session the channel
* @ param iq_cmd the request containing < header >
* @ param type header type
*/
static void add_signaling_headers ( switch_core_session_t * session , iks * iq_cmd , const char * type )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
iks * header = NULL ;
for ( header = iks_find ( iq_cmd , " header " ) ; header ; header = iks_next_tag ( header ) ) {
if ( ! strcmp ( " header " , iks_name ( header ) ) ) {
const char * name = iks_find_attrib_soft ( header , " name " ) ;
const char * value = iks_find_attrib_soft ( header , " value " ) ;
if ( ! zstr ( name ) & & ! zstr ( value ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Adding header: %s: %s \n " , name , value ) ;
switch_channel_set_variable_name_printf ( channel , value , " %s%s " , type , name ) ;
}
}
}
}
/**
* Handle < iq > < accept > request
* @ param call the Rayo call
* @ param session the session
* @ param node the < iq > node
*/
2013-06-24 14:51:54 -04:00
static iks * on_rayo_accept ( struct rayo_actor * call , struct rayo_message * msg , void * session_data )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
switch_core_session_t * session = ( switch_core_session_t * ) session_data ;
iks * response = NULL ;
/* send ringing */
add_signaling_headers ( session , iks_find ( node , " accept " ) , RAYO_SIP_RESPONSE_HEADER ) ;
switch_channel_pre_answer ( switch_core_session_get_channel ( session ) ) ;
response = iks_new_iq_result ( node ) ;
return response ;
}
/**
* Handle < iq > < answer > request
* @ param call the Rayo call
* @ param session the session
* @ param node the < iq > node
*/
2013-06-24 14:51:54 -04:00
static iks * on_rayo_answer ( struct rayo_actor * call , struct rayo_message * msg , void * session_data )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
switch_core_session_t * session = ( switch_core_session_t * ) session_data ;
iks * response = NULL ;
/* send answer to call */
add_signaling_headers ( session , iks_find ( node , " answer " ) , RAYO_SIP_RESPONSE_HEADER ) ;
switch_channel_answer ( switch_core_session_get_channel ( session ) ) ;
response = iks_new_iq_result ( node ) ;
return response ;
}
/**
* Handle < iq > < redirect > request
* @ param call the Rayo call
* @ param session the session
* @ param node the < iq > node
*/
2013-06-24 14:51:54 -04:00
static iks * on_rayo_redirect ( struct rayo_actor * call , struct rayo_message * msg , void * session_data )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
switch_core_session_t * session = ( switch_core_session_t * ) session_data ;
iks * response = NULL ;
iks * redirect = iks_find ( node , " redirect " ) ;
char * redirect_to = iks_find_attrib ( redirect , " to " ) ;
if ( zstr ( redirect_to ) ) {
response = iks_new_error_detailed ( node , STANZA_ERROR_BAD_REQUEST , " Missing redirect to attrib " ) ;
} else {
switch_core_session_message_t msg = { 0 } ;
add_signaling_headers ( session , redirect , RAYO_SIP_RESPONSE_HEADER ) ;
/* Tell the channel to deflect the call */
msg . from = __FILE__ ;
msg . string_arg = switch_core_session_strdup ( session , redirect_to ) ;
msg . message_id = SWITCH_MESSAGE_INDICATE_DEFLECT ;
switch_core_session_receive_message ( session , & msg ) ;
response = iks_new_iq_result ( node ) ;
}
return response ;
}
/**
* Handle < iq > < hangup > or < iq > < reject > request
* @ param call the Rayo call
* @ param session the session
* @ param node the < iq > node
*/
2013-06-24 14:51:54 -04:00
static iks * on_rayo_hangup ( struct rayo_actor * call , struct rayo_message * msg , void * session_data )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
switch_core_session_t * session = ( switch_core_session_t * ) session_data ;
iks * response = NULL ;
iks * hangup = iks_first_tag ( node ) ;
iks * reason = iks_first_tag ( hangup ) ;
int hangup_cause = RAYO_CAUSE_HANGUP ;
/* get hangup cause */
if ( ! reason & & ! strcmp ( " hangup " , iks_name ( hangup ) ) ) {
/* no reason in <hangup> */
hangup_cause = RAYO_CAUSE_HANGUP ;
} else if ( reason & & ! strcmp ( " reject " , iks_name ( hangup ) ) ) {
char * reason_name = iks_name ( reason ) ;
/* reason required for <reject> */
if ( ! strcmp ( " busy " , reason_name ) ) {
hangup_cause = RAYO_CAUSE_BUSY ;
} else if ( ! strcmp ( " decline " , reason_name ) ) {
hangup_cause = RAYO_CAUSE_DECLINE ;
} else if ( ! strcmp ( " error " , reason_name ) ) {
hangup_cause = RAYO_CAUSE_ERROR ;
} else {
response = iks_new_error_detailed ( node , STANZA_ERROR_BAD_REQUEST , " invalid reject reason " ) ;
}
} else {
response = iks_new_error ( node , STANZA_ERROR_BAD_REQUEST ) ;
}
/* do hangup */
if ( ! response ) {
2013-06-13 11:23:12 -04:00
switch_channel_set_variable ( switch_core_session_get_channel ( session ) , " rayo_local_hangup " , " true " ) ;
2013-06-06 16:03:00 -04:00
add_signaling_headers ( session , hangup , RAYO_SIP_REQUEST_HEADER ) ;
add_signaling_headers ( session , hangup , RAYO_SIP_RESPONSE_HEADER ) ;
switch_ivr_kill_uuid ( rayo_call_get_uuid ( call ) , hangup_cause ) ;
response = iks_new_iq_result ( node ) ;
}
return response ;
}
/**
* Join calls together
* @ param call the call that joins
* @ param session the session
2013-10-09 17:39:33 -04:00
* @ param msg the rayo join message
2013-08-20 17:26:07 -04:00
* @ param call_uri to join
2013-06-06 16:03:00 -04:00
* @ param media mode ( direct / bridge )
* @ return the response
*/
2013-10-09 17:39:33 -04:00
static iks * join_call ( struct rayo_call * call , switch_core_session_t * session , struct rayo_message * msg , const char * call_uri , const char * media )
2013-06-06 16:03:00 -04:00
{
2013-10-09 17:39:33 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * response = NULL ;
/* take call out of media path if media = "direct" */
const char * bypass = ! strcmp ( " direct " , media ) ? " true " : " false " ;
/* check if joining to rayo call */
2013-08-20 17:26:07 -04:00
struct rayo_call * b_call = RAYO_CALL_LOCATE ( call_uri ) ;
2013-06-06 16:03:00 -04:00
if ( ! b_call ) {
/* not a rayo call */
response = iks_new_error_detailed ( node , STANZA_ERROR_SERVICE_UNAVAILABLE , " b-leg is not a rayo call " ) ;
2013-10-09 17:39:33 -04:00
} else if ( ! has_call_control ( b_call , msg ) ) {
/* not allowed to join to this call */
response = iks_new_error ( node , STANZA_ERROR_NOT_ALLOWED ) ;
2013-06-06 16:03:00 -04:00
} else if ( b_call - > joined ) {
/* don't support multiple joined calls */
response = iks_new_error_detailed ( node , STANZA_ERROR_CONFLICT , " multiple joined calls not supported " ) ;
RAYO_UNLOCK ( b_call ) ;
} else {
2013-06-13 11:23:12 -04:00
/* bridge this call to call-uri */
2013-06-06 16:03:00 -04:00
switch_channel_set_variable ( switch_core_session_get_channel ( session ) , " bypass_media " , bypass ) ;
if ( switch_false ( bypass ) ) {
switch_channel_pre_answer ( switch_core_session_get_channel ( session ) ) ;
}
2013-10-09 17:39:33 -04:00
call - > pending_join_request = iks_copy ( node ) ;
if ( switch_ivr_uuid_bridge ( rayo_call_get_uuid ( call ) , rayo_call_get_uuid ( b_call ) ) ! = SWITCH_STATUS_SUCCESS ) {
2013-10-15 14:17:33 -04:00
iks * request = call - > pending_join_request ;
iks * result = iks_new_error_detailed ( request , STANZA_ERROR_ITEM_NOT_FOUND , " failed to bridge call " ) ;
2013-10-09 17:39:33 -04:00
call - > pending_join_request = NULL ;
2013-10-15 14:17:33 -04:00
RAYO_SEND_REPLY ( call , iks_find_attrib_soft ( request , " from " ) , result ) ;
iks_delete ( call - > pending_join_request ) ;
2013-06-06 16:03:00 -04:00
}
2013-08-20 17:26:07 -04:00
RAYO_UNLOCK ( b_call ) ;
2013-06-06 16:03:00 -04:00
}
return response ;
}
2013-08-09 09:42:10 -04:00
/**
* Execute command on session ' s conference
2013-10-15 14:17:33 -04:00
* @ param session to execute conference API on
* @ param conf_name of conference
* @ param command to send to conference
* @ param node IQ request
* @ return response on failure
2013-08-09 09:42:10 -04:00
*/
2013-10-15 14:17:33 -04:00
static iks * exec_conference_api ( switch_core_session_t * session , const char * conf_name , const char * command , iks * node )
2013-08-09 09:42:10 -04:00
{
2013-10-15 14:17:33 -04:00
iks * response = NULL ;
2013-08-09 09:42:10 -04:00
switch_stream_handle_t stream = { 0 } ;
const char * conf_member_id = switch_channel_get_variable ( switch_core_session_get_channel ( session ) , " conference_member_id " ) ;
SWITCH_STANDARD_STREAM ( stream ) ;
switch_api_execute ( " conference " , switch_core_session_sprintf ( session , " %s %s %s " , conf_name , command , conf_member_id ) , NULL , & stream ) ;
2013-10-15 14:17:33 -04:00
if ( ! zstr ( stream . data ) & & strncmp ( " OK " , stream . data , 2 ) ) {
2013-10-17 09:42:52 -04:00
response = iks_new_error_detailed_printf ( node , STANZA_ERROR_SERVICE_UNAVAILABLE , " %s " , stream . data ) ;
2013-10-15 14:17:33 -04:00
}
2013-08-09 09:42:10 -04:00
switch_safe_free ( stream . data ) ;
2013-10-15 14:17:33 -04:00
return response ;
}
/**
* Execute conference app on session
* @ param session to execute conference API on
* @ param command to send to conference ( conference name , member flags , etc )
* @ param node IQ request
* @ return response on failure
*/
static iks * exec_conference_app ( switch_core_session_t * session , const char * command , iks * node )
{
iks * response = NULL ;
switch_event_t * execute_event = NULL ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
/* conference requires local media on channel */
if ( ! switch_channel_media_ready ( channel ) & & switch_channel_pre_answer ( channel ) ! = SWITCH_STATUS_SUCCESS ) {
/* shit */
response = iks_new_error_detailed ( node , STANZA_ERROR_INTERNAL_SERVER_ERROR , " failed to start media " ) ;
return response ;
}
/* send execute conference event to session */
if ( switch_event_create ( & execute_event , SWITCH_EVENT_COMMAND ) = = SWITCH_STATUS_SUCCESS ) {
switch_event_add_header_string ( execute_event , SWITCH_STACK_BOTTOM , " call-command " , " execute " ) ;
switch_event_add_header_string ( execute_event , SWITCH_STACK_BOTTOM , " execute-app-name " , " conference " ) ;
switch_event_add_header_string ( execute_event , SWITCH_STACK_BOTTOM , " execute-app-arg " , command ) ;
//switch_event_add_header_string(execute_event, SWITCH_STACK_BOTTOM, "event_uuid", uuid);
switch_event_add_header_string ( execute_event , SWITCH_STACK_BOTTOM , " event-lock " , " true " ) ;
if ( ! switch_channel_test_flag ( channel , CF_PROXY_MODE ) ) {
switch_channel_set_flag ( channel , CF_BLOCK_BROADCAST_UNTIL_MEDIA ) ;
}
if ( switch_core_session_queue_private_event ( session , & execute_event , SWITCH_FALSE ) ! = SWITCH_STATUS_SUCCESS ) {
response = iks_new_error_detailed ( node , STANZA_ERROR_INTERNAL_SERVER_ERROR , " failed to join mixer (queue event failed) " ) ;
if ( execute_event ) {
switch_event_destroy ( & execute_event ) ;
}
return response ;
}
}
return response ;
2013-08-09 09:42:10 -04:00
}
2013-06-06 16:03:00 -04:00
/**
* Join call to a mixer
* @ param call the call that joins
* @ param session the session
2013-10-09 17:39:33 -04:00
* @ param msg the join request
2013-08-09 09:42:10 -04:00
* @ param mixer_name the mixer to join
* @ param direction the media direction
2013-06-06 16:03:00 -04:00
* @ return the response
*/
2013-10-09 17:39:33 -04:00
static iks * join_mixer ( struct rayo_call * call , switch_core_session_t * session , struct rayo_message * msg , const char * mixer_name , const char * direction )
2013-06-06 16:03:00 -04:00
{
2013-10-09 17:39:33 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * response = NULL ;
2013-08-09 09:42:10 -04:00
if ( call - > joined_id ) {
/* adjust join conference params */
if ( ! strcmp ( " duplex " , direction ) ) {
2013-10-15 14:17:33 -04:00
if ( ( response = exec_conference_api ( session , mixer_name , " unmute " , node ) ) | |
( response = exec_conference_api ( session , mixer_name , " undeaf " , node ) ) ) {
return response ;
}
2013-08-09 09:42:10 -04:00
} else if ( ! strcmp ( " recv " , direction ) ) {
2013-10-15 14:17:33 -04:00
if ( ( response = exec_conference_api ( session , mixer_name , " mute " , node ) ) | |
( response = exec_conference_api ( session , mixer_name , " undeaf " , node ) ) ) {
return response ;
}
2013-08-09 09:42:10 -04:00
} else {
2013-10-15 14:17:33 -04:00
if ( ( response = exec_conference_api ( session , mixer_name , " unmute " , node ) ) | |
( response = exec_conference_api ( session , mixer_name , " deaf " , node ) ) ) {
return response ;
}
2013-08-09 09:42:10 -04:00
}
2013-06-06 16:03:00 -04:00
response = iks_new_iq_result ( node ) ;
} else {
2013-08-09 09:42:10 -04:00
/* join new conference */
const char * conf_args = switch_core_session_sprintf ( session , " %s@%s " , mixer_name , globals . mixer_conf_profile ) ;
if ( ! strcmp ( " send " , direction ) ) {
conf_args = switch_core_session_sprintf ( session , " %s+flags{deaf} " , conf_args ) ;
2013-08-09 09:54:45 -04:00
} else if ( ! strcmp ( " recv " , direction ) ) {
conf_args = switch_core_session_sprintf ( session , " %s+flags{mute} " , conf_args ) ;
2013-08-09 09:42:10 -04:00
}
2013-10-15 14:17:33 -04:00
call - > pending_join_request = iks_copy ( node ) ;
response = exec_conference_app ( session , conf_args , node ) ;
if ( response ) {
iks_delete ( call - > pending_join_request ) ;
call - > pending_join_request = NULL ;
2013-08-09 09:42:10 -04:00
}
2013-06-06 16:03:00 -04:00
}
return response ;
}
/**
* Handle < iq > < join > request
* @ param call the Rayo call
* @ param session the session
2013-10-09 17:39:33 -04:00
* @ param msg the rayo join message
2013-06-06 16:03:00 -04:00
*/
2013-06-24 14:51:54 -04:00
static iks * on_rayo_join ( struct rayo_actor * call , struct rayo_message * msg , void * session_data )
2013-06-06 16:03:00 -04:00
{
switch_core_session_t * session = ( switch_core_session_t * ) session_data ;
iks * response = NULL ;
2013-10-09 17:39:33 -04:00
iks * join = iks_find ( msg - > payload , " join " ) ;
2013-08-09 09:42:10 -04:00
const char * join_id ;
2013-06-06 16:03:00 -04:00
const char * mixer_name ;
2013-08-20 17:26:07 -04:00
const char * call_uri ;
2013-06-06 16:03:00 -04:00
/* validate input attributes */
if ( ! VALIDATE_RAYO_JOIN ( join ) ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Bad join attrib \n " ) ;
2013-10-09 17:39:33 -04:00
response = iks_new_error ( msg - > payload , STANZA_ERROR_BAD_REQUEST ) ;
2013-06-06 16:03:00 -04:00
goto done ;
}
mixer_name = iks_find_attrib ( join , " mixer-name " ) ;
2013-08-20 17:26:07 -04:00
call_uri = iks_find_attrib ( join , " call-uri " ) ;
2013-06-06 16:03:00 -04:00
2013-08-09 09:42:10 -04:00
if ( ! zstr ( mixer_name ) ) {
join_id = mixer_name ;
} else {
2013-08-20 17:26:07 -04:00
join_id = call_uri ;
2013-08-09 09:42:10 -04:00
}
2013-06-06 16:03:00 -04:00
/* can't join both mixer and call */
2013-08-20 17:26:07 -04:00
if ( ! zstr ( mixer_name ) & & ! zstr ( call_uri ) ) {
2013-10-09 17:39:33 -04:00
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_BAD_REQUEST , " mixer-name and call-uri are mutually exclusive " ) ;
2013-06-06 16:03:00 -04:00
goto done ;
}
/* need to join *something* */
2013-08-20 17:26:07 -04:00
if ( zstr ( mixer_name ) & & zstr ( call_uri ) ) {
2013-10-09 17:39:33 -04:00
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_BAD_REQUEST , " mixer-name or call-uri is required " ) ;
2013-06-06 16:03:00 -04:00
goto done ;
}
2013-08-09 09:42:10 -04:00
if ( ( RAYO_CALL ( call ) - > joined = = JOINED_CALL ) | |
( RAYO_CALL ( call ) - > joined = = JOINED_MIXER & & strcmp ( RAYO_CALL ( call ) - > joined_id , join_id ) ) ) {
2013-06-06 16:03:00 -04:00
/* already joined */
2013-10-09 17:39:33 -04:00
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_CONFLICT , " call is already joined " ) ;
goto done ;
}
2013-11-06 17:00:13 -05:00
if ( rayo_call_is_faxing ( RAYO_CALL ( call ) ) ) {
/* can't join a call while it's faxing */
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_UNEXPECTED_REQUEST , " fax is in progress " ) ;
goto done ;
}
2013-10-09 17:39:33 -04:00
if ( RAYO_CALL ( call ) - > pending_join_request ) {
/* don't allow concurrent join requests */
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_UNEXPECTED_REQUEST , " (un)join request is pending " ) ;
2013-06-06 16:03:00 -04:00
goto done ;
}
if ( ! zstr ( mixer_name ) ) {
/* join conference */
2013-10-09 17:39:33 -04:00
response = join_mixer ( RAYO_CALL ( call ) , session , msg , mixer_name , iks_find_attrib ( join , " direction " ) ) ;
2013-06-06 16:03:00 -04:00
} else {
/* bridge calls */
2013-10-09 17:39:33 -04:00
response = join_call ( RAYO_CALL ( call ) , session , msg , call_uri , iks_find_attrib ( join , " media " ) ) ;
2013-06-06 16:03:00 -04:00
}
done :
return response ;
}
/**
* unjoin call to a bridge
* @ param call the call that unjoined
* @ param session the session
2013-10-09 17:39:33 -04:00
* @ param msg the unjoin request
2013-08-20 17:26:07 -04:00
* @ param call_uri the b - leg xmpp URI
2013-06-06 16:03:00 -04:00
* @ return the response
*/
2013-10-09 17:39:33 -04:00
static iks * unjoin_call ( struct rayo_call * call , switch_core_session_t * session , struct rayo_message * msg , const char * call_uri )
2013-06-06 16:03:00 -04:00
{
2013-10-09 17:39:33 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * response = NULL ;
2013-10-18 15:14:50 -04:00
if ( ! strcmp ( call_uri , call - > joined_id ) ) {
2013-06-06 16:03:00 -04:00
/* unbridge call */
2013-10-09 17:39:33 -04:00
call - > pending_join_request = iks_copy ( node ) ;
2013-06-06 16:03:00 -04:00
switch_ivr_park_session ( session ) ;
} else {
2013-08-20 17:26:07 -04:00
/* not bridged or wrong b-leg URI */
2013-06-06 16:03:00 -04:00
response = iks_new_error ( node , STANZA_ERROR_SERVICE_UNAVAILABLE ) ;
}
return response ;
}
/**
* unjoin call to a mixer
* @ param call the call that unjoined
* @ param session the session
2013-10-09 17:39:33 -04:00
* @ param msg the unjoin request
2013-06-06 16:03:00 -04:00
* @ param mixer_name the mixer name
* @ return the response
*/
2013-10-09 17:39:33 -04:00
static iks * unjoin_mixer ( struct rayo_call * call , switch_core_session_t * session , struct rayo_message * msg , const char * mixer_name )
2013-06-06 16:03:00 -04:00
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
const char * conf_member_id = switch_channel_get_variable ( channel , " conference_member_id " ) ;
const char * conf_name = switch_channel_get_variable ( channel , " conference_name " ) ;
2013-10-09 17:39:33 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * response = NULL ;
/* not conferenced, or wrong conference */
if ( zstr ( conf_name ) | | strcmp ( mixer_name , conf_name ) ) {
response = iks_new_error_detailed_printf ( node , STANZA_ERROR_SERVICE_UNAVAILABLE , " not joined to %s " , mixer_name ) ;
goto done ;
} else if ( zstr ( conf_member_id ) ) {
/* shouldn't happen */
response = iks_new_error_detailed ( node , STANZA_ERROR_SERVICE_UNAVAILABLE , " channel doesn't have conference member ID " ) ;
goto done ;
}
/* kick the member */
2013-10-15 14:17:33 -04:00
response = exec_conference_api ( session , mixer_name , " hup " , node ) ;
if ( ! response ) {
/* ack command */
response = iks_new_iq_result ( node ) ;
}
2013-06-06 16:03:00 -04:00
done :
return response ;
}
/**
* Handle < iq > < unjoin > request
* @ param call the Rayo call
* @ param session the session
* @ param node the < iq > node
*/
2013-06-24 14:51:54 -04:00
static iks * on_rayo_unjoin ( struct rayo_actor * call , struct rayo_message * msg , void * session_data )
2013-06-06 16:03:00 -04:00
{
switch_core_session_t * session = ( switch_core_session_t * ) session_data ;
iks * response = NULL ;
2013-10-09 17:39:33 -04:00
iks * unjoin = iks_find ( msg - > payload , " unjoin " ) ;
2013-08-20 17:26:07 -04:00
const char * call_uri = iks_find_attrib ( unjoin , " call-uri " ) ;
2013-06-06 16:03:00 -04:00
const char * mixer_name = iks_find_attrib ( unjoin , " mixer-name " ) ;
2013-08-20 17:26:07 -04:00
if ( ! zstr ( call_uri ) & & ! zstr ( mixer_name ) ) {
2013-10-09 17:39:33 -04:00
response = iks_new_error ( msg - > payload , STANZA_ERROR_BAD_REQUEST ) ;
} else if ( RAYO_CALL ( call ) - > pending_join_request ) {
/* need to let pending request finish first */
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_UNEXPECTED_REQUEST , " (un)join request is pending " ) ;
2013-06-06 16:03:00 -04:00
} else if ( ! RAYO_CALL ( call ) - > joined ) {
/* not joined to anything */
2013-10-17 09:42:52 -04:00
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_SERVICE_UNAVAILABLE , " not joined to anything " ) ;
} else if ( RAYO_CALL ( call ) - > joined = = JOINED_MIXER & & ! zstr ( call_uri ) ) {
/* joined to mixer, not call */
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_SERVICE_UNAVAILABLE , " not joined to call " ) ;
} else if ( RAYO_CALL ( call ) - > joined = = JOINED_CALL & & ! zstr ( mixer_name ) ) {
/* joined to call, not mixer */
response = iks_new_error_detailed ( msg - > payload , STANZA_ERROR_SERVICE_UNAVAILABLE , " not joined to mixer " ) ;
2013-08-20 17:26:07 -04:00
} else if ( ! zstr ( call_uri ) ) {
2013-10-09 17:39:33 -04:00
response = unjoin_call ( RAYO_CALL ( call ) , session , msg , call_uri ) ;
2013-06-06 16:03:00 -04:00
} else if ( ! zstr ( mixer_name ) ) {
2013-10-09 17:39:33 -04:00
response = unjoin_mixer ( RAYO_CALL ( call ) , session , msg , mixer_name ) ;
2013-06-06 16:03:00 -04:00
} else {
2013-08-09 09:42:10 -04:00
/* unjoin everything */
if ( RAYO_CALL ( call ) - > joined = = JOINED_MIXER ) {
2013-10-09 17:39:33 -04:00
response = unjoin_mixer ( RAYO_CALL ( call ) , session , msg , RAYO_CALL ( call ) - > joined_id ) ;
2013-08-09 09:42:10 -04:00
} else if ( RAYO_CALL ( call ) - > joined = = JOINED_CALL ) {
2013-10-09 17:39:33 -04:00
response = unjoin_call ( RAYO_CALL ( call ) , session , msg , RAYO_CALL ( call ) - > joined_id ) ;
2013-08-09 09:42:10 -04:00
} else {
/* shouldn't happen */
2013-10-09 17:39:33 -04:00
response = iks_new_error ( msg - > payload , STANZA_ERROR_INTERNAL_SERVER_ERROR ) ;
2013-08-09 09:42:10 -04:00
}
2013-06-06 16:03:00 -04:00
}
return response ;
}
2013-06-24 14:51:54 -04:00
struct dial_thread_data {
switch_memory_pool_t * pool ;
iks * node ;
} ;
2013-06-06 16:03:00 -04:00
/**
* Thread that handles originating new calls
* @ param thread this thread
* @ param obj the Rayo client
* @ return NULL
*/
2013-06-24 14:51:54 -04:00
static void * SWITCH_THREAD_FUNC rayo_dial_thread ( switch_thread_t * thread , void * user )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
struct dial_thread_data * dtdata = ( struct dial_thread_data * ) user ;
iks * iq = dtdata - > node ;
2013-06-06 16:03:00 -04:00
iks * dial = iks_find ( iq , " dial " ) ;
iks * response = NULL ;
const char * dcp_jid = iks_find_attrib ( iq , " from " ) ;
const char * dial_to = iks_find_attrib ( dial , " to " ) ;
2013-06-19 08:53:17 -04:00
char * dial_to_dup = NULL ;
2013-06-06 16:03:00 -04:00
const char * dial_from = iks_find_attrib ( dial , " from " ) ;
const char * dial_timeout_ms = iks_find_attrib ( dial , " timeout " ) ;
2013-08-06 14:52:56 -04:00
const char * uuid = NULL ;
2013-06-06 16:03:00 -04:00
struct dial_gateway * gateway = NULL ;
struct rayo_call * call = NULL ;
switch_stream_handle_t stream = { 0 } ;
SWITCH_STANDARD_STREAM ( stream ) ;
/* create call and link to DCP */
call = rayo_call_create ( NULL ) ;
call - > dcp_jid = switch_core_strdup ( RAYO_POOL ( call ) , dcp_jid ) ;
call - > dial_id = iks_find_attrib ( iq , " id " ) ;
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_INFO , " %s has control of call \n " , dcp_jid ) ;
2013-08-06 14:52:56 -04:00
uuid = switch_core_strdup ( dtdata - > pool , rayo_call_get_uuid ( call ) ) ;
2013-06-06 16:03:00 -04:00
/* set rayo channel variables so channel originate event can be identified as coming from Rayo */
stream . write_function ( & stream , " {origination_uuid=%s,rayo_dcp_jid=%s,rayo_call_jid=%s " ,
rayo_call_get_uuid ( call ) , dcp_jid , RAYO_JID ( call ) ) ;
2013-06-19 08:53:17 -04:00
/* parse optional params from dialstring and append to */
if ( * dial_to = = ' { ' ) {
switch_event_t * params = NULL ;
dial_to_dup = strdup ( dial_to ) ;
switch_event_create_brackets ( dial_to_dup , ' { ' , ' } ' , ' , ' , & params , ( char * * ) & dial_to , SWITCH_FALSE ) ;
if ( params ) {
switch_event_header_t * param ;
for ( param = params - > headers ; param ; param = param - > next ) {
if ( strchr ( param - > value , ' , ' ) ) {
stream . write_function ( & stream , " ,%s= \\ '%s \\ ' " , param - > name , param - > value ) ;
} else {
stream . write_function ( & stream , " ,%s=%s " , param - > name , param - > value ) ;
}
}
switch_event_destroy ( & params ) ;
}
}
2013-06-06 16:03:00 -04:00
/* set originate channel variables */
if ( ! zstr ( dial_from ) ) {
/* caller ID */
/* TODO parse caller ID name and number from URI */
stream . write_function ( & stream , " ,origination_caller_id_number=%s,origination_caller_id_name=%s " , dial_from , dial_from ) ;
}
if ( ! zstr ( dial_timeout_ms ) & & switch_is_number ( dial_timeout_ms ) ) {
/* timeout */
int dial_timeout_sec = round ( ( double ) atoi ( dial_timeout_ms ) / 1000.0 ) ;
stream . write_function ( & stream , " ,originate_timeout=%i " , dial_timeout_sec ) ;
}
/* set outbound signaling headers - only works on SIP */
{
iks * header = NULL ;
for ( header = iks_find ( dial , " header " ) ; header ; header = iks_next_tag ( header ) ) {
if ( ! strcmp ( " header " , iks_name ( header ) ) ) {
const char * name = iks_find_attrib_soft ( header , " name " ) ;
const char * value = iks_find_attrib_soft ( header , " value " ) ;
if ( ! zstr ( name ) & & ! zstr ( value ) ) {
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_DEBUG , " Adding header: %s: %s \n " , name , value ) ;
stream . write_function ( & stream , " ,%s%s=%s " , RAYO_SIP_REQUEST_HEADER , name , value ) ;
}
}
}
}
stream . write_function ( & stream , " } " ) ;
/* build dialstring and dial call */
gateway = dial_gateway_find ( dial_to ) ;
if ( gateway ) {
iks * join = iks_find ( dial , " join " ) ;
const char * dial_to_stripped = dial_to + gateway - > strip ;
switch_stream_handle_t api_stream = { 0 } ;
SWITCH_STANDARD_STREAM ( api_stream ) ;
if ( join ) {
/* check join args */
2013-08-20 17:26:07 -04:00
const char * call_uri = iks_find_attrib ( join , " call-uri " ) ;
2013-06-06 16:03:00 -04:00
const char * mixer_name = iks_find_attrib ( join , " mixer-name " ) ;
2013-08-20 17:26:07 -04:00
if ( ! zstr ( call_uri ) & & ! zstr ( mixer_name ) ) {
2013-06-06 16:03:00 -04:00
/* can't join both */
response = iks_new_error ( iq , STANZA_ERROR_BAD_REQUEST ) ;
goto done ;
2013-08-20 17:26:07 -04:00
} else if ( zstr ( call_uri ) & & zstr ( mixer_name ) ) {
2013-06-06 16:03:00 -04:00
/* nobody to join to? */
response = iks_new_error ( iq , STANZA_ERROR_BAD_REQUEST ) ;
goto done ;
2013-08-20 17:26:07 -04:00
} else if ( ! zstr ( call_uri ) ) {
2013-06-06 16:03:00 -04:00
/* bridge */
2013-08-20 17:26:07 -04:00
struct rayo_call * b_call = RAYO_CALL_LOCATE ( call_uri ) ;
2013-06-06 16:03:00 -04:00
/* is b-leg available? */
if ( ! b_call ) {
response = iks_new_error_detailed ( iq , STANZA_ERROR_SERVICE_UNAVAILABLE , " b-leg not found " ) ;
goto done ;
} else if ( b_call - > joined ) {
response = iks_new_error_detailed ( iq , STANZA_ERROR_SERVICE_UNAVAILABLE , " b-leg already joined to another call " ) ;
RAYO_UNLOCK ( b_call ) ;
goto done ;
}
2013-08-20 17:26:07 -04:00
stream . write_function ( & stream , " %s%s &rayo(bridge %s) " , gateway - > dial_prefix , dial_to_stripped , rayo_call_get_uuid ( b_call ) ) ;
2013-06-06 16:03:00 -04:00
RAYO_UNLOCK ( b_call ) ;
} else {
/* conference */
stream . write_function ( & stream , " %s%s &rayo(conference %s@%s) " , gateway - > dial_prefix , dial_to_stripped , mixer_name , globals . mixer_conf_profile ) ;
}
} else {
stream . write_function ( & stream , " %s%s &rayo " , gateway - > dial_prefix , dial_to_stripped ) ;
}
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_DEBUG , " Using dialstring: %s \n " , ( char * ) stream . data ) ;
/* <iq><ref> response will be sent when originate event is received- otherwise error is returned */
if ( switch_api_execute ( " originate " , stream . data , NULL , & api_stream ) = = SWITCH_STATUS_SUCCESS ) {
2013-08-06 14:52:56 -04:00
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( uuid ) , SWITCH_LOG_DEBUG , " Got originate result: %s \n " , ( char * ) api_stream . data ) ;
2013-06-06 16:03:00 -04:00
/* check for failure */
if ( strncmp ( " +OK " , api_stream . data , strlen ( " +OK " ) ) ) {
2013-08-06 14:52:56 -04:00
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( uuid ) , SWITCH_LOG_INFO , " Failed to originate call \n " ) ;
2013-06-06 16:03:00 -04:00
if ( call - > dial_id ) {
/* map failure reason to iq error */
if ( ! strncmp ( " -ERR DESTINATION_OUT_OF_ORDER " , api_stream . data , strlen ( " -ERR DESTINATION_OUT_OF_ORDER " ) ) ) {
/* this -ERR is received when out of sessions */
response = iks_new_error ( iq , STANZA_ERROR_RESOURCE_CONSTRAINT ) ;
}
}
}
} else if ( call - > dial_id ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Failed to exec originate API \n " ) ;
response = iks_new_error_detailed ( iq , STANZA_ERROR_INTERNAL_SERVER_ERROR , " Failed to execute originate API " ) ;
}
switch_safe_free ( api_stream . data ) ;
} else {
/* will only happen if misconfigured */
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_CRIT , " No dial gateway found for %s! \n " , dial_to ) ;
response = iks_new_error_detailed_printf ( iq , STANZA_ERROR_INTERNAL_SERVER_ERROR , " No dial gateway found for %s! \n " , dial_to ) ;
goto done ;
}
done :
/* response when error */
if ( response ) {
/* send response to client */
2013-06-24 20:50:37 -04:00
RAYO_SEND_REPLY ( call , iks_find_attrib ( response , " to " ) , response ) ;
2013-06-06 16:03:00 -04:00
/* destroy call */
if ( call ) {
RAYO_DESTROY ( call ) ;
RAYO_UNLOCK ( call ) ;
}
}
iks_delete ( dial ) ;
switch_safe_free ( stream . data ) ;
2013-06-19 08:53:17 -04:00
switch_safe_free ( dial_to_dup ) ;
2013-06-06 16:03:00 -04:00
2013-06-24 14:51:54 -04:00
{
switch_memory_pool_t * pool = dtdata - > pool ;
switch_core_destroy_memory_pool ( & pool ) ;
}
2013-06-06 16:03:00 -04:00
return NULL ;
}
2013-06-24 14:51:54 -04:00
2013-06-06 16:03:00 -04:00
/**
* Dial a new call
* @ param rclient requesting the call
* @ param server handling the call
* @ param node the request
*/
2013-06-24 14:51:54 -04:00
static iks * on_rayo_dial ( struct rayo_actor * server , struct rayo_message * msg , void * data )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
switch_thread_t * thread ;
switch_threadattr_t * thd_attr = NULL ;
iks * dial = iks_find ( node , " dial " ) ;
iks * response = NULL ;
2013-06-19 08:53:17 -04:00
const char * dial_to = iks_find_attrib ( dial , " to " ) ;
2013-06-06 16:03:00 -04:00
2013-06-19 08:53:17 -04:00
if ( zstr ( dial_to ) ) {
response = iks_new_error_detailed ( node , STANZA_ERROR_BAD_REQUEST , " missing dial to attribute " ) ;
} else if ( strchr ( dial_to , ' ' ) ) {
response = iks_new_error_detailed ( node , STANZA_ERROR_BAD_REQUEST , " malformed dial string " ) ;
} else {
2013-06-24 14:51:54 -04:00
switch_memory_pool_t * pool ;
struct dial_thread_data * dtdata = NULL ;
switch_core_new_memory_pool ( & pool ) ;
dtdata = switch_core_alloc ( pool , sizeof ( * dtdata ) ) ;
2013-06-24 20:50:37 -04:00
dtdata - > pool = pool ;
2013-06-24 14:51:54 -04:00
dtdata - > node = iks_copy ( node ) ;
iks_insert_attrib ( dtdata - > node , " from " , msg - > from_jid ) ; /* save DCP jid in case it isn't specified */
2013-06-06 16:03:00 -04:00
/* start dial thread */
2013-06-24 14:51:54 -04:00
switch_threadattr_create ( & thd_attr , pool ) ;
2013-06-06 16:03:00 -04:00
switch_threadattr_detach_set ( thd_attr , 1 ) ;
switch_threadattr_stacksize_set ( thd_attr , SWITCH_THREAD_STACKSIZE ) ;
2013-06-24 14:51:54 -04:00
switch_thread_create ( & thread , thd_attr , rayo_dial_thread , dtdata , pool ) ;
2013-06-06 16:03:00 -04:00
}
return response ;
}
/**
* Handle < iq > < ping > request
* @ param rclient the Rayo client
* @ param server the Rayo server
* @ param node the < iq > node
* @ return NULL
*/
2013-06-24 14:51:54 -04:00
static iks * on_iq_xmpp_ping ( struct rayo_actor * server , struct rayo_message * msg , void * data )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * pong = iks_new ( " iq " ) ;
char * from = iks_find_attrib ( node , " from " ) ;
char * to = iks_find_attrib ( node , " to " ) ;
if ( zstr ( from ) ) {
2013-06-24 14:51:54 -04:00
from = msg - > from_jid ;
2013-06-06 16:03:00 -04:00
}
if ( zstr ( to ) ) {
to = RAYO_JID ( server ) ;
}
iks_insert_attrib ( pong , " type " , " result " ) ;
iks_insert_attrib ( pong , " from " , to ) ;
iks_insert_attrib ( pong , " to " , from ) ;
iks_insert_attrib ( pong , " id " , iks_find_attrib ( node , " id " ) ) ;
return pong ;
}
/**
* Handle service discovery request
* @ param rclient the Rayo client
* @ param server the Rayo server
* @ param node the < iq > node
* @ return NULL
*/
2013-06-24 14:51:54 -04:00
static iks * on_iq_get_xmpp_disco ( struct rayo_actor * server , struct rayo_message * msg , void * data )
2013-06-06 16:03:00 -04:00
{
2013-06-24 14:51:54 -04:00
iks * node = msg - > payload ;
2013-06-06 16:03:00 -04:00
iks * response = NULL ;
iks * x ;
2013-11-07 16:14:03 -05:00
iks * feature ;
2013-06-06 16:03:00 -04:00
response = iks_new_iq_result ( node ) ;
x = iks_insert ( response , " query " ) ;
iks_insert_attrib ( x , " xmlns " , IKS_NS_XMPP_DISCO ) ;
2013-11-07 16:14:03 -05:00
feature = iks_insert ( x , " feature " ) ;
iks_insert_attrib ( feature , " var " , RAYO_NS ) ;
feature = iks_insert ( x , " feature " ) ;
iks_insert_attrib ( feature , " var " , RAYO_FAX_NS ) ;
2013-06-06 16:03:00 -04:00
/* TODO The response MUST also include features for the application formats and transport methods supported by
* the responding entity , as described in the relevant specifications .
*/
return response ;
}
/**
* Handle message from client
* @ param rclient that sent the command
* @ param message the message
*/
static void on_client_message ( struct rayo_client * rclient , iks * message )
{
const char * to = iks_find_attrib ( message , " to " ) ;
/* must be directed to a client */
if ( zstr ( to ) ) {
return ;
}
/* assume client source */
if ( zstr ( iks_find_attrib ( message , " from " ) ) ) {
iks_insert_attrib ( message , " from " , RAYO_JID ( rclient ) ) ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, recv message, availability = %s \n " , RAYO_JID ( rclient ) , presence_status_to_string ( rclient - > availability ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE_DUP ( rclient , to , message ) ;
2013-06-06 16:03:00 -04:00
}
/**
* Handle < presence > message from a client
* @ param rclient the client
* @ param node the presence message
*/
static void on_client_presence ( struct rayo_client * rclient , iks * node )
{
char * type = iks_find_attrib ( node , " type " ) ;
enum presence_status status = PS_UNKNOWN ;
/*
From RFC - 6121 :
Entity is available when < presence / > received .
Entity is unavailable when < presence type = ' unavailable ' / > is received .
From Rayo - XEP :
Entity is available when < presence to = ' foo ' from = ' bar ' > < show > chat < / show > < / presence > is received .
Entity is unavailable when < presence to = ' foo ' from = ' bar ' > < show > dnd < / show > < / presence > is received .
*/
/* figure out if online/offline */
if ( zstr ( type ) ) {
/* <presence><show>chat</show></presence> */
char * status_str = iks_find_cdata ( node , " show " ) ;
if ( ! zstr ( status_str ) ) {
if ( ! strcmp ( " chat " , status_str ) ) {
status = PS_ONLINE ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s got chat presence \n " , RAYO_JID ( rclient ) ) ;
} else if ( ! strcmp ( " dnd " , status_str ) ) {
status = PS_OFFLINE ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s got dnd presence \n " , RAYO_JID ( rclient ) ) ;
}
} else {
/* <presence/> */
status = PS_ONLINE ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s got empty presence \n " , RAYO_JID ( rclient ) ) ;
}
} else if ( ! strcmp ( " unavailable " , type ) ) {
status = PS_OFFLINE ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s got unavailable presence \n " , RAYO_JID ( rclient ) ) ;
} else if ( ! strcmp ( " error " , type ) ) {
/* TODO presence error */
} else if ( ! strcmp ( " probe " , type ) ) {
/* TODO presence probe */
} else if ( ! strcmp ( " subscribe " , type ) ) {
/* TODO presence subscribe */
} else if ( ! strcmp ( " subscribed " , type ) ) {
/* TODO presence subscribed */
} else if ( ! strcmp ( " unsubscribe " , type ) ) {
/* TODO presence unsubscribe */
} else if ( ! strcmp ( " unsubscribed " , type ) ) {
/* TODO presence unsubscribed */
}
if ( status = = PS_ONLINE & & rclient - > availability ! = PS_ONLINE ) {
rclient - > availability = PS_ONLINE ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s is ONLINE \n " , RAYO_JID ( rclient ) ) ;
} else if ( status = = PS_OFFLINE & & rclient - > availability ! = PS_OFFLINE ) {
rclient - > availability = PS_OFFLINE ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s is OFFLINE \n " , RAYO_JID ( rclient ) ) ;
}
/* destroy if not a local client (connected via peer_server) and is OFFLINE */
2013-06-24 14:51:54 -04:00
if ( rclient - > peer_server & & rclient - > availability = = PS_OFFLINE ) {
RAYO_DESTROY ( rclient ) ;
RAYO_UNLOCK ( rclient ) ;
}
2013-06-06 16:03:00 -04:00
}
/**
* Handle command from client
* @ param rclient that sent the command
* @ param iq the command
*/
static void rayo_client_command_recv ( struct rayo_client * rclient , iks * iq )
{
iks * command = iks_first_tag ( iq ) ;
const char * to = iks_find_attrib ( iq , " to " ) ;
/* assume server destination */
if ( zstr ( to ) ) {
to = RAYO_JID ( globals . server ) ;
iks_insert_attrib ( iq , " to " , to ) ;
}
/* assume client source */
if ( zstr ( iks_find_attrib ( iq , " from " ) ) ) {
iks_insert_attrib ( iq , " from " , RAYO_JID ( rclient ) ) ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, recv iq, availability = %s \n " , RAYO_JID ( rclient ) , presence_status_to_string ( rclient - > availability ) ) ;
if ( command ) {
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE_DUP ( rclient , to , iq ) ;
2013-06-06 16:03:00 -04:00
} else {
2013-06-25 11:30:10 -04:00
const char * type = iks_find_attrib_soft ( iq , " type " ) ;
if ( strcmp ( " error " , type ) & & strcmp ( " result " , type ) ) {
RAYO_SEND_REPLY ( globals . server , RAYO_JID ( rclient ) , iks_new_error_detailed ( iq , STANZA_ERROR_BAD_REQUEST , " empty IQ request " ) ) ;
}
2013-06-06 16:03:00 -04:00
}
}
/**
* Send event to mixer subscribers
* @ param mixer the mixer
* @ param rayo_event the event to send
*/
static void broadcast_mixer_event ( struct rayo_mixer * mixer , iks * rayo_event )
{
switch_hash_index_t * hi = NULL ;
for ( hi = switch_core_hash_first ( mixer - > subscribers ) ; hi ; hi = switch_core_hash_next ( hi ) ) {
const void * key ;
void * val ;
struct rayo_mixer_subscriber * subscriber ;
switch_core_hash_this ( hi , & key , NULL , & val ) ;
subscriber = ( struct rayo_mixer_subscriber * ) val ;
switch_assert ( subscriber ) ;
iks_insert_attrib ( rayo_event , " to " , subscriber - > jid ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE_DUP ( mixer , subscriber - > jid , rayo_event ) ;
2013-06-06 16:03:00 -04:00
}
}
/**
* Handle mixer delete member event
*/
static void on_mixer_delete_member_event ( struct rayo_mixer * mixer , switch_event_t * event )
{
iks * delete_member_event , * x ;
const char * uuid = switch_event_get_header ( event , " Unique-ID " ) ;
struct rayo_call * call ;
struct rayo_mixer_member * member ;
struct rayo_mixer_subscriber * subscriber ;
/* not a rayo mixer */
if ( ! mixer ) {
return ;
}
/* remove member from mixer */
member = ( struct rayo_mixer_member * ) switch_core_hash_find ( mixer - > members , uuid ) ;
if ( ! member ) {
/* not a member */
return ;
}
switch_core_hash_delete ( mixer - > members , uuid ) ;
/* flag call as available to join another mixer */
2013-08-20 17:26:07 -04:00
call = RAYO_CALL_LOCATE_BY_ID ( uuid ) ;
2013-06-06 16:03:00 -04:00
if ( call ) {
call - > joined = 0 ;
2013-08-09 09:42:10 -04:00
call - > joined_id = NULL ;
2013-06-06 16:03:00 -04:00
RAYO_UNLOCK ( call ) ;
}
/* send mixer unjoined event to member DCP */
delete_member_event = iks_new_presence ( " unjoined " , RAYO_NS , member - > jid , member - > dcp_jid ) ;
x = iks_find ( delete_member_event , " unjoined " ) ;
iks_insert_attrib ( x , " mixer-name " , rayo_mixer_get_name ( mixer ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( mixer , member - > dcp_jid , delete_member_event ) ;
2013-06-06 16:03:00 -04:00
/* broadcast member unjoined event to subscribers */
delete_member_event = iks_new_presence ( " unjoined " , RAYO_NS , RAYO_JID ( mixer ) , " " ) ;
x = iks_find ( delete_member_event , " unjoined " ) ;
2013-08-20 17:26:07 -04:00
iks_insert_attrib_printf ( x , " call-uri " , " xmpp:%s@%s " , uuid , RAYO_JID ( globals . server ) ) ;
2013-06-06 16:03:00 -04:00
broadcast_mixer_event ( mixer , delete_member_event ) ;
iks_delete ( delete_member_event ) ;
/* remove member DCP as subscriber to mixer */
subscriber = ( struct rayo_mixer_subscriber * ) switch_core_hash_find ( mixer - > subscribers , member - > dcp_jid ) ;
if ( subscriber ) {
subscriber - > ref_count - - ;
if ( subscriber - > ref_count < = 0 ) {
switch_core_hash_delete ( mixer - > subscribers , member - > dcp_jid ) ;
}
}
}
/**
* Handle mixer destroy event
*/
static void on_mixer_destroy_event ( struct rayo_mixer * mixer , switch_event_t * event )
{
if ( mixer ) {
/* remove from hash and destroy */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, destroying mixer: %s \n " , RAYO_JID ( mixer ) , rayo_mixer_get_name ( mixer ) ) ;
RAYO_UNLOCK ( mixer ) ; /* release original lock */
RAYO_DESTROY ( mixer ) ;
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " destroy: NULL mixer \n " ) ;
}
}
/**
* Handle mixer add member event
*/
static void on_mixer_add_member_event ( struct rayo_mixer * mixer , switch_event_t * event )
{
iks * add_member_event = NULL , * x ;
const char * uuid = switch_event_get_header ( event , " Unique-ID " ) ;
2013-08-20 17:26:07 -04:00
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( uuid ) ;
2013-06-06 16:03:00 -04:00
if ( ! mixer ) {
/* new mixer */
const char * mixer_name = switch_event_get_header ( event , " Conference-Name " ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " creating mixer: %s \n " , mixer_name ) ;
mixer = rayo_mixer_create ( mixer_name ) ;
}
if ( call ) {
struct rayo_mixer_member * member = NULL ;
/* add member DCP as subscriber to mixer */
struct rayo_mixer_subscriber * subscriber = ( struct rayo_mixer_subscriber * ) switch_core_hash_find ( mixer - > subscribers , call - > dcp_jid ) ;
if ( ! subscriber ) {
subscriber = switch_core_alloc ( RAYO_POOL ( mixer ) , sizeof ( * subscriber ) ) ;
subscriber - > ref_count = 0 ;
subscriber - > jid = switch_core_strdup ( RAYO_POOL ( mixer ) , call - > dcp_jid ) ;
switch_core_hash_insert ( mixer - > subscribers , call - > dcp_jid , subscriber ) ;
}
subscriber - > ref_count + + ;
/* add call as member of mixer */
member = switch_core_alloc ( RAYO_POOL ( mixer ) , sizeof ( * member ) ) ;
member - > jid = switch_core_strdup ( RAYO_POOL ( mixer ) , RAYO_JID ( call ) ) ;
member - > dcp_jid = subscriber - > jid ;
switch_core_hash_insert ( mixer - > members , uuid , member ) ;
2013-08-09 09:42:10 -04:00
call - > joined = JOINED_MIXER ;
call - > joined_id = switch_core_strdup ( RAYO_POOL ( call ) , rayo_mixer_get_name ( mixer ) ) ;
2013-06-06 16:03:00 -04:00
2013-10-15 14:17:33 -04:00
/* send IQ result to client now. */
if ( call - > pending_join_request ) {
iks * request = call - > pending_join_request ;
iks * result = iks_new_iq_result ( request ) ;
call - > pending_join_request = NULL ;
RAYO_SEND_REPLY ( call , iks_find_attrib_soft ( request , " from " ) , result ) ;
iks_delete ( request ) ;
}
2013-06-06 16:03:00 -04:00
/* send mixer joined event to member DCP */
add_member_event = iks_new_presence ( " joined " , RAYO_NS , RAYO_JID ( call ) , call - > dcp_jid ) ;
x = iks_find ( add_member_event , " joined " ) ;
iks_insert_attrib ( x , " mixer-name " , rayo_mixer_get_name ( mixer ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( call , call - > dcp_jid , add_member_event ) ;
2013-06-06 16:03:00 -04:00
RAYO_UNLOCK ( call ) ;
}
/* broadcast member joined event to subscribers */
add_member_event = iks_new_presence ( " joined " , RAYO_NS , RAYO_JID ( mixer ) , " " ) ;
x = iks_find ( add_member_event , " joined " ) ;
2013-08-20 17:26:07 -04:00
iks_insert_attrib_printf ( x , " call-uri " , " xmpp:%s@%s " , uuid , RAYO_JID ( globals . server ) ) ;
2013-06-06 16:03:00 -04:00
broadcast_mixer_event ( mixer , add_member_event ) ;
iks_delete ( add_member_event ) ;
}
/**
* Receives mixer events from FreeSWITCH core and routes them to the proper Rayo client ( s ) .
* @ param event received from FreeSWITCH core . It will be destroyed by the core after this function returns .
*/
static void route_mixer_event ( switch_event_t * event )
{
const char * action = switch_event_get_header ( event , " Action " ) ;
const char * profile = switch_event_get_header ( event , " Conference-Profile-Name " ) ;
const char * mixer_name = switch_event_get_header ( event , " Conference-Name " ) ;
struct rayo_mixer * mixer = NULL ;
if ( strcmp ( profile , globals . mixer_conf_profile ) ) {
/* don't care about other conferences */
goto done ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " looking for mixer: %s \n " , mixer_name ) ;
mixer = RAYO_MIXER_LOCATE ( mixer_name ) ;
if ( ! strcmp ( " add-member " , action ) ) {
on_mixer_add_member_event ( mixer , event ) ;
} else if ( ! strcmp ( " conference-destroy " , action ) ) {
on_mixer_destroy_event ( mixer , event ) ;
} else if ( ! strcmp ( " del-member " , action ) ) {
on_mixer_delete_member_event ( mixer , event ) ;
}
/* TODO speaking events */
done :
RAYO_UNLOCK ( mixer ) ;
}
/**
* Handle call originate event - create rayo call and send < iq > < ref > to client .
* @ param rclient The Rayo client
* @ param event the originate event
*/
static void on_call_originate_event ( struct rayo_client * rclient , switch_event_t * event )
{
switch_core_session_t * session = NULL ;
const char * uuid = switch_event_get_header ( event , " Unique-ID " ) ;
2013-08-20 17:26:07 -04:00
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( uuid ) ;
2013-06-06 16:03:00 -04:00
if ( call & & ( session = switch_core_session_locate ( uuid ) ) ) {
iks * response , * ref ;
switch_channel_set_private ( switch_core_session_get_channel ( session ) , " rayo_call_private " , call ) ;
switch_core_session_rwunlock ( session ) ;
/* send response to DCP */
response = iks_new ( " iq " ) ;
iks_insert_attrib ( response , " from " , RAYO_JID ( globals . server ) ) ;
iks_insert_attrib ( response , " to " , rayo_call_get_dcp_jid ( call ) ) ;
iks_insert_attrib ( response , " id " , call - > dial_id ) ;
iks_insert_attrib ( response , " type " , " result " ) ;
ref = iks_insert ( response , " ref " ) ;
iks_insert_attrib ( ref , " xmlns " , RAYO_NS ) ;
2013-06-13 11:23:12 -04:00
2013-06-24 14:51:54 -04:00
iks_insert_attrib_printf ( ref , " uri " , " xmpp:%s " , RAYO_JID ( call ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( call , RAYO_JID ( rclient ) , response ) ;
2013-06-06 16:03:00 -04:00
call - > dial_id = NULL ;
}
RAYO_UNLOCK ( call ) ;
}
/**
* Handle call end event
* @ param event the hangup event
*/
static void on_call_end_event ( switch_event_t * event )
{
2013-08-20 17:26:07 -04:00
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( switch_event_get_header ( event , " Unique-ID " ) ) ;
2013-06-06 16:03:00 -04:00
if ( call ) {
#if 0
char * event_str ;
if ( switch_event_serialize ( event , & event_str , SWITCH_FALSE ) = = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( rayo_call_get_uuid ( call ) ) , SWITCH_LOG_DEBUG , " %s \n " , event_str ) ;
switch_safe_free ( event_str ) ;
}
# endif
switch_event_dup ( & call - > end_event , event ) ;
RAYO_UNLOCK ( call ) ; /* decrement ref from creation */
RAYO_DESTROY ( call ) ;
RAYO_UNLOCK ( call ) ; /* decrement this ref */
}
}
/**
* Handle call answer event
* @ param rclient the Rayo client
* @ param event the answer event
*/
static void on_call_answer_event ( struct rayo_client * rclient , switch_event_t * event )
{
2013-08-20 17:26:07 -04:00
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( switch_event_get_header ( event , " Unique-ID " ) ) ;
2013-06-06 16:03:00 -04:00
if ( call ) {
iks * revent = iks_new_presence ( " answered " , RAYO_NS ,
switch_event_get_header ( event , " variable_rayo_call_jid " ) ,
switch_event_get_header ( event , " variable_rayo_dcp_jid " ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( call , RAYO_JID ( rclient ) , revent ) ;
2013-06-06 16:03:00 -04:00
RAYO_UNLOCK ( call ) ;
}
}
/**
* Handle call ringing event
* @ param rclient the Rayo client
* @ param event the ringing event
*/
static void on_call_ringing_event ( struct rayo_client * rclient , switch_event_t * event )
{
2013-08-06 16:21:22 -04:00
const char * call_direction = switch_event_get_header ( event , " Call-Direction " ) ;
if ( call_direction & & ! strcmp ( call_direction , " outbound " ) ) {
2013-08-20 17:26:07 -04:00
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( switch_event_get_header ( event , " Unique-ID " ) ) ;
2013-08-06 16:21:22 -04:00
if ( call ) {
switch_mutex_lock ( RAYO_ACTOR ( call ) - > mutex ) ;
if ( ! call - > ringing_sent ) {
iks * revent = iks_new_presence ( " ringing " , RAYO_NS ,
switch_event_get_header ( event , " variable_rayo_call_jid " ) ,
switch_event_get_header ( event , " variable_rayo_dcp_jid " ) ) ;
call - > ringing_sent = 1 ;
RAYO_SEND_MESSAGE ( call , RAYO_JID ( rclient ) , revent ) ;
RAYO_UNLOCK ( call ) ;
}
switch_mutex_unlock ( RAYO_ACTOR ( call ) - > mutex ) ;
}
2013-06-06 16:03:00 -04:00
}
}
/**
* Handle call bridge event
* @ param rclient the Rayo client
* @ param event the bridge event
*/
static void on_call_bridge_event ( struct rayo_client * rclient , switch_event_t * event )
{
const char * a_uuid = switch_event_get_header ( event , " Unique-ID " ) ;
const char * b_uuid = switch_event_get_header ( event , " Bridge-B-Unique-ID " ) ;
2013-08-20 17:26:07 -04:00
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( a_uuid ) ;
2013-06-06 16:03:00 -04:00
struct rayo_call * b_call ;
if ( call ) {
2013-10-09 17:39:33 -04:00
iks * revent ;
iks * joined ;
call - > joined = JOINED_CALL ;
2013-10-18 15:14:50 -04:00
call - > joined_id = switch_core_sprintf ( RAYO_POOL ( call ) , " xmpp:%s@%s " , b_uuid , RAYO_JID ( globals . server ) ) ;
2013-10-09 17:39:33 -04:00
/* send IQ result to client now. */
if ( call - > pending_join_request ) {
2013-10-15 14:17:33 -04:00
iks * request = call - > pending_join_request ;
iks * result = iks_new_iq_result ( request ) ;
2013-10-09 17:39:33 -04:00
call - > pending_join_request = NULL ;
2013-10-15 14:17:33 -04:00
RAYO_SEND_REPLY ( call , iks_find_attrib_soft ( request , " from " ) , result ) ;
iks_delete ( request ) ;
2013-10-09 17:39:33 -04:00
}
2013-08-20 17:26:07 -04:00
b_call = RAYO_CALL_LOCATE_BY_ID ( b_uuid ) ;
2013-06-06 16:03:00 -04:00
if ( b_call ) {
2013-10-18 15:14:50 -04:00
b_call - > joined = JOINED_CALL ;
b_call - > joined_id = switch_core_sprintf ( RAYO_POOL ( b_call ) , " xmpp:%s@s " , a_uuid , RAYO_JID ( globals . server ) ) ;
/* send IQ result to client now. */
if ( b_call - > pending_join_request ) {
iks * request = b_call - > pending_join_request ;
iks * result = iks_new_iq_result ( request ) ;
b_call - > pending_join_request = NULL ;
RAYO_SEND_REPLY ( call , iks_find_attrib_soft ( request , " from " ) , result ) ;
iks_delete ( request ) ;
}
/* send B-leg event */
2013-06-06 16:03:00 -04:00
revent = iks_new_presence ( " joined " , RAYO_NS , RAYO_JID ( b_call ) , rayo_call_get_dcp_jid ( b_call ) ) ;
joined = iks_find ( revent , " joined " ) ;
2013-08-20 17:26:07 -04:00
iks_insert_attrib_printf ( joined , " call-uri " , " xmpp:%s@%s " , a_uuid , RAYO_JID ( globals . server ) ) ;
2013-06-06 16:03:00 -04:00
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( b_call , rayo_call_get_dcp_jid ( b_call ) , revent ) ;
2013-06-06 16:03:00 -04:00
RAYO_UNLOCK ( b_call ) ;
}
2013-10-18 15:14:50 -04:00
/* send A-leg event */
revent = iks_new_presence ( " joined " , RAYO_NS ,
switch_event_get_header ( event , " variable_rayo_call_jid " ) ,
switch_event_get_header ( event , " variable_rayo_dcp_jid " ) ) ;
joined = iks_find ( revent , " joined " ) ;
iks_insert_attrib_printf ( joined , " call-uri " , " xmpp:%s@%s " , b_uuid , RAYO_JID ( globals . server ) ) ;
RAYO_SEND_MESSAGE ( call , RAYO_JID ( rclient ) , revent ) ;
2013-06-06 16:03:00 -04:00
RAYO_UNLOCK ( call ) ;
}
}
/**
* Handle call unbridge event
* @ param rclient the Rayo client
* @ param event the unbridge event
*/
static void on_call_unbridge_event ( struct rayo_client * rclient , switch_event_t * event )
{
const char * a_uuid = switch_event_get_header ( event , " Unique-ID " ) ;
const char * b_uuid = switch_event_get_header ( event , " Bridge-B-Unique-ID " ) ;
2013-08-20 17:26:07 -04:00
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( a_uuid ) ;
2013-06-06 16:03:00 -04:00
struct rayo_call * b_call ;
if ( call ) {
2013-10-09 17:39:33 -04:00
iks * revent ;
iks * joined ;
call - > joined = 0 ;
call - > joined_id = NULL ;
/* send IQ result to client now. */
if ( call - > pending_join_request ) {
2013-10-15 14:17:33 -04:00
iks * request = call - > pending_join_request ;
iks * result = iks_new_iq_result ( request ) ;
2013-10-09 17:39:33 -04:00
call - > pending_join_request = NULL ;
2013-10-15 14:17:33 -04:00
RAYO_SEND_REPLY ( call , iks_find_attrib_soft ( request , " from " ) , result ) ;
iks_delete ( request ) ;
2013-10-09 17:39:33 -04:00
}
2013-08-20 17:26:07 -04:00
b_call = RAYO_CALL_LOCATE_BY_ID ( b_uuid ) ;
2013-06-06 16:03:00 -04:00
if ( b_call ) {
2013-10-18 15:14:50 -04:00
b_call - > joined = 0 ;
b_call - > joined_id = NULL ;
/* send IQ result to client now. */
if ( b_call - > pending_join_request ) {
iks * request = b_call - > pending_join_request ;
iks * result = iks_new_iq_result ( request ) ;
b_call - > pending_join_request = NULL ;
RAYO_SEND_REPLY ( b_call , iks_find_attrib_soft ( request , " from " ) , result ) ;
iks_delete ( request ) ;
}
/* send B-leg event */
2013-06-06 16:03:00 -04:00
revent = iks_new_presence ( " unjoined " , RAYO_NS , RAYO_JID ( b_call ) , rayo_call_get_dcp_jid ( b_call ) ) ;
joined = iks_find ( revent , " unjoined " ) ;
2013-08-20 17:26:07 -04:00
iks_insert_attrib_printf ( joined , " call-uri " , " xmpp:%s@%s " , a_uuid , RAYO_JID ( globals . server ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( b_call , rayo_call_get_dcp_jid ( b_call ) , revent ) ;
2013-06-06 16:03:00 -04:00
RAYO_UNLOCK ( b_call ) ;
}
2013-10-18 15:14:50 -04:00
/* send A-leg event */
revent = iks_new_presence ( " unjoined " , RAYO_NS ,
switch_event_get_header ( event , " variable_rayo_call_jid " ) ,
switch_event_get_header ( event , " variable_rayo_dcp_jid " ) ) ;
joined = iks_find ( revent , " unjoined " ) ;
iks_insert_attrib_printf ( joined , " call-uri " , " xmpp:%s@%s " , b_uuid , RAYO_JID ( globals . server ) ) ;
RAYO_SEND_MESSAGE ( call , RAYO_JID ( rclient ) , revent ) ;
2013-06-06 16:03:00 -04:00
RAYO_UNLOCK ( call ) ;
}
}
2013-10-15 14:17:33 -04:00
/**
* Handle call execute application event
* @ param rclient the Rayo client
* @ param event the execute event
*/
static void on_call_execute_event ( struct rayo_client * rclient , switch_event_t * event )
{
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( switch_event_get_header ( event , " Unique-ID " ) ) ;
if ( call ) {
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( RAYO_ID ( call ) ) , SWITCH_LOG_DEBUG , " Application %s execute \n " , switch_event_get_header ( event , " Application " ) ) ;
RAYO_UNLOCK ( call ) ;
}
}
/**
* Handle call execute application complete event
* @ param rclient the Rayo client
* @ param event the execute complete event
*/
static void on_call_execute_complete_event ( struct rayo_client * rclient , switch_event_t * event )
{
struct rayo_call * call = RAYO_CALL_LOCATE_BY_ID ( switch_event_get_header ( event , " Unique-ID " ) ) ;
if ( call ) {
const char * app = switch_event_get_header ( event , " Application " ) ;
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( RAYO_ID ( call ) ) , SWITCH_LOG_DEBUG , " Application %s execute complete: %s \n " ,
app ,
switch_event_get_header ( event , " Application-Response " ) ) ;
RAYO_UNLOCK ( call ) ;
}
}
2013-06-06 16:03:00 -04:00
/**
* Handle events to deliver to client connection
* @ param rclient the Rayo client connection to receive the event
* @ param event the event .
*/
static void rayo_client_handle_event ( struct rayo_client * rclient , switch_event_t * event )
{
if ( event ) {
switch ( event - > event_id ) {
case SWITCH_EVENT_CHANNEL_ORIGINATE :
on_call_originate_event ( rclient , event ) ;
break ;
2013-08-06 16:21:22 -04:00
case SWITCH_EVENT_CHANNEL_PROGRESS :
2013-06-06 16:03:00 -04:00
case SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA :
on_call_ringing_event ( rclient , event ) ;
break ;
case SWITCH_EVENT_CHANNEL_ANSWER :
on_call_answer_event ( rclient , event ) ;
break ;
case SWITCH_EVENT_CHANNEL_BRIDGE :
on_call_bridge_event ( rclient , event ) ;
break ;
case SWITCH_EVENT_CHANNEL_UNBRIDGE :
on_call_unbridge_event ( rclient , event ) ;
break ;
2013-10-15 14:17:33 -04:00
case SWITCH_EVENT_CHANNEL_EXECUTE :
on_call_execute_event ( rclient , event ) ;
break ;
case SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE :
on_call_execute_complete_event ( rclient , event ) ;
break ;
2013-06-06 16:03:00 -04:00
default :
/* don't care */
break ;
}
}
}
/**
* Receives events from FreeSWITCH core and routes them to the proper Rayo client .
* @ param event received from FreeSWITCH core . It will be destroyed by the core after this function returns .
*/
static void route_call_event ( switch_event_t * event )
{
char * uuid = switch_event_get_header ( event , " unique-id " ) ;
char * dcp_jid = switch_event_get_header ( event , " variable_rayo_dcp_jid " ) ;
char * event_subclass = switch_event_get_header ( event , " Event-Subclass " ) ;
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( uuid ) , SWITCH_LOG_DEBUG , " got event %s %s \n " , switch_event_name ( event - > event_id ) , zstr ( event_subclass ) ? " " : event_subclass ) ;
/* this event is for a rayo client */
if ( ! zstr ( dcp_jid ) ) {
struct rayo_actor * actor ;
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( uuid ) , SWITCH_LOG_DEBUG , " %s rayo event %s \n " , dcp_jid , switch_event_name ( event - > event_id ) ) ;
actor = RAYO_LOCATE ( dcp_jid ) ;
2013-06-24 14:51:54 -04:00
if ( actor & & ! strcmp ( RAT_CLIENT , actor - > type ) ) {
/* route to client */
rayo_client_handle_event ( RAYO_CLIENT ( actor ) , event ) ;
2013-06-06 16:03:00 -04:00
} else {
/* TODO orphaned call... maybe allow events to queue so they can be delivered on reconnect? */
switch_log_printf ( SWITCH_CHANNEL_UUID_LOG ( uuid ) , SWITCH_LOG_DEBUG , " Orphaned call event %s to %s \n " , switch_event_name ( event - > event_id ) , dcp_jid ) ;
}
RAYO_UNLOCK ( actor ) ;
}
}
/**
* Create server .
* @ param domain the domain name
* @ return the domain
*/
static struct rayo_actor * rayo_server_create ( const char * domain )
{
switch_memory_pool_t * pool ;
struct rayo_actor * new_server = NULL ;
switch_core_new_memory_pool ( & pool ) ;
new_server = switch_core_alloc ( pool , sizeof ( * new_server ) ) ;
RAYO_ACTOR_INIT ( RAYO_ACTOR ( new_server ) , pool , RAT_SERVER , " " , domain , domain , NULL , rayo_server_send ) ;
return new_server ;
}
/**
* Create an offer for a call
* @ param call the call
* @ param session the session
* @ return the offer
*/
static iks * rayo_create_offer ( struct rayo_call * call , switch_core_session_t * session )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
switch_caller_profile_t * profile = switch_channel_get_caller_profile ( channel ) ;
iks * presence = iks_new ( " presence " ) ;
iks * offer = iks_insert ( presence , " offer " ) ;
2013-08-06 15:30:22 -04:00
const char * val ;
2013-06-06 16:03:00 -04:00
iks_insert_attrib ( presence , " from " , RAYO_JID ( call ) ) ;
iks_insert_attrib ( offer , " xmlns " , RAYO_NS ) ;
2013-08-10 09:30:33 -04:00
if ( globals . offer_uri & & ( val = switch_channel_get_variable ( channel , " sip_from_uri " ) ) ) {
2013-08-06 15:30:22 -04:00
/* is a SIP call - pass the URI */
if ( ! strchr ( val , ' : ' ) ) {
iks_insert_attrib_printf ( offer , " from " , " sip:%s " , val ) ;
} else {
iks_insert_attrib ( offer , " from " , val ) ;
}
} else {
/* pass caller ID */
iks_insert_attrib ( offer , " from " , profile - > caller_id_number ) ;
}
2013-08-10 09:30:33 -04:00
if ( globals . offer_uri & & ( val = switch_channel_get_variable ( channel , " sip_to_uri " ) ) ) {
2013-08-06 15:30:22 -04:00
/* is a SIP call - pass the URI */
if ( ! strchr ( val , ' : ' ) ) {
iks_insert_attrib_printf ( offer , " to " , " sip:%s " , val ) ;
} else {
iks_insert_attrib ( offer , " to " , val ) ;
}
} else {
/* pass dialed number */
iks_insert_attrib ( offer , " to " , profile - > destination_number ) ;
}
2013-06-06 16:03:00 -04:00
/* add signaling headers */
{
switch_event_header_t * var ;
add_header ( offer , " from " , switch_channel_get_variable ( channel , " sip_full_from " ) ) ;
add_header ( offer , " to " , switch_channel_get_variable ( channel , " sip_full_to " ) ) ;
add_header ( offer , " via " , switch_channel_get_variable ( channel , " sip_full_via " ) ) ;
2013-09-12 12:13:22 -04:00
/* get all variables prefixed with sip_h_ */
2013-06-06 16:03:00 -04:00
for ( var = switch_channel_variable_first ( channel ) ; var ; var = var - > next ) {
2013-09-12 12:13:22 -04:00
if ( ! strncmp ( " sip_h_ " , var - > name , 6 ) ) {
2013-06-06 16:03:00 -04:00
add_header ( offer , var - > name + 6 , var - > value ) ;
}
}
switch_channel_variable_last ( channel ) ;
}
return presence ;
}
/**
* Monitor rayo call activity - detect idle
*/
static switch_status_t rayo_call_on_read_frame ( switch_core_session_t * session , switch_frame_t * * frame , switch_io_flag_t flags , int i )
{
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
struct rayo_call * call = ( struct rayo_call * ) switch_channel_get_private ( channel , " rayo_call_private " ) ;
if ( call ) {
switch_time_t now = switch_micro_time_now ( ) ;
switch_time_t idle_start = call - > idle_start_time ;
int idle_duration_ms = ( now - idle_start ) / 1000 ;
/* detect idle session (rayo-client has stopped controlling call) and terminate call */
2013-11-06 17:00:13 -05:00
if ( rayo_call_is_joined ( call ) | | rayo_call_is_faxing ( call ) ) {
2013-10-15 14:17:33 -04:00
call - > idle_start_time = now ;
} else if ( idle_duration_ms > globals . max_idle_ms ) {
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_WARNING , " Ending abandoned call. idle_duration_ms = %i ms \n " , idle_duration_ms ) ;
switch_channel_hangup ( channel , RAYO_CAUSE_HANGUP ) ;
}
2013-11-06 17:00:13 -05:00
/* check for break request */
{
const char * break_jid = switch_channel_get_variable ( channel , " rayo_read_frame_interrupt " ) ;
struct rayo_actor * actor ;
if ( break_jid & & ( actor = RAYO_LOCATE ( break_jid ) ) ) {
RAYO_UNLOCK ( actor ) ;
return SWITCH_STATUS_FALSE ;
}
}
2013-06-06 16:03:00 -04:00
}
return SWITCH_STATUS_SUCCESS ;
}
# define RAYO_USAGE "[bridge <uuid>|conference <name>]"
/**
* Offer call and park channel
*/
SWITCH_STANDARD_APP ( rayo_app )
{
int ok = 0 ;
switch_channel_t * channel = switch_core_session_get_channel ( session ) ;
struct rayo_call * call = ( struct rayo_call * ) switch_channel_get_private ( channel , " rayo_call_private " ) ;
const char * app = " " ; /* optional app to execute */
const char * app_args = " " ; /* app args */
/* is outbound call already under control? */
if ( switch_channel_direction ( channel ) = = SWITCH_CALL_DIRECTION_OUTBOUND ) {
/* check origination args */
if ( ! zstr ( data ) ) {
char * argv [ 2 ] = { 0 } ;
char * args = switch_core_session_strdup ( session , data ) ;
int argc = switch_separate_string ( args , ' ' , argv , sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ;
if ( argc ) {
if ( ! strcmp ( " conference " , argv [ 0 ] ) ) {
app = " conference " ;
app_args = argv [ 1 ] ;
} else if ( ! strcmp ( " bridge " , argv [ 0 ] ) ) {
app = " intercept " ;
app_args = argv [ 1 ] ;
} else {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " Invalid rayo args: %s \n " , data ) ;
goto done ;
}
}
}
if ( ! call ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_CRIT , " Missing rayo call!! \n " ) ;
goto done ;
}
ok = 1 ;
} else {
/* inbound call - offer control */
switch_hash_index_t * hi = NULL ;
iks * offer = NULL ;
if ( call ) {
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_INFO , " Call is already under Rayo 3PCC! \n " ) ;
goto done ;
}
call = rayo_call_create ( switch_core_session_get_uuid ( session ) ) ;
switch_channel_set_variable ( switch_core_session_get_channel ( session ) , " rayo_call_jid " , RAYO_JID ( call ) ) ;
switch_channel_set_private ( switch_core_session_get_channel ( session ) , " rayo_call_private " , call ) ;
offer = rayo_create_offer ( call , session ) ;
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_DEBUG , " Offering call for Rayo 3PCC \n " ) ;
/* Offer call to all ONLINE clients */
/* TODO load balance offers so first session doesn't always get offer first? */
switch_mutex_lock ( globals . clients_mutex ) ;
for ( hi = switch_hash_first ( NULL , globals . clients_roster ) ; hi ; hi = switch_hash_next ( hi ) ) {
struct rayo_client * rclient ;
const void * key ;
void * val ;
switch_hash_this ( hi , & key , NULL , & val ) ;
rclient = ( struct rayo_client * ) val ;
switch_assert ( rclient ) ;
/* is session available to take call? */
if ( rclient - > availability = = PS_ONLINE ) {
ok = 1 ;
switch_core_hash_insert ( call - > pcps , RAYO_JID ( rclient ) , " 1 " ) ;
iks_insert_attrib ( offer , " to " , RAYO_JID ( rclient ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE_DUP ( call , RAYO_JID ( rclient ) , offer ) ;
2013-06-06 16:03:00 -04:00
}
}
iks_delete ( offer ) ;
switch_mutex_unlock ( globals . clients_mutex ) ;
/* nobody to offer to */
if ( ! ok ) {
2013-11-08 09:38:10 -05:00
switch_log_printf ( SWITCH_CHANNEL_SESSION_LOG ( session ) , SWITCH_LOG_NOTICE , " Rejecting rayo call - there are no online rayo clients to offer call to \n " ) ;
2013-08-08 11:59:17 -04:00
switch_channel_hangup ( channel , SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE ) ;
2013-06-06 16:03:00 -04:00
}
}
done :
if ( ok ) {
switch_channel_set_variable ( channel , " hangup_after_bridge " , " false " ) ;
2013-10-18 09:47:30 -04:00
switch_channel_set_variable ( channel , " transfer_after_bridge " , " " ) ;
2013-10-18 15:14:50 -04:00
switch_channel_set_variable ( channel , " park_after_bridge " , " true " ) ;
switch_channel_set_variable ( channel , " hold_hangup_xfer_exten " , " foo " ) ; /* Icky hack to prevent unjoin of call on hold from hanging up b-leg. park_after_bridge will take precedence over the transfer_after_bridge variable that gets set by this var */
2013-06-06 16:03:00 -04:00
switch_channel_set_variable ( channel , SWITCH_SEND_SILENCE_WHEN_IDLE_VARIABLE , " -1 " ) ; /* required so that output mixing works */
switch_core_event_hook_add_read_frame ( session , rayo_call_on_read_frame ) ;
if ( switch_channel_direction ( channel ) = = SWITCH_CALL_DIRECTION_OUTBOUND ) {
if ( ! zstr ( app ) ) {
switch_core_session_execute_application ( session , app , app_args ) ;
}
}
switch_ivr_park ( session , NULL ) ;
}
}
/**
* Stream locates client
*/
static struct rayo_actor * xmpp_stream_client_locate ( struct xmpp_stream * stream , const char * jid )
{
struct rayo_actor * actor = NULL ;
if ( xmpp_stream_is_s2s ( stream ) ) {
actor = RAYO_LOCATE ( jid ) ;
if ( ! actor ) {
/* previously unknown client - add it */
struct rayo_peer_server * rserver = RAYO_PEER_SERVER ( xmpp_stream_get_private ( stream ) ) ;
2013-06-24 14:51:54 -04:00
actor = RAYO_ACTOR ( rayo_client_create ( jid , xmpp_stream_get_jid ( stream ) , PS_UNKNOWN , rayo_client_send , rserver ) ) ;
2013-06-06 16:03:00 -04:00
RAYO_RDLOCK ( actor ) ;
2013-07-08 13:09:27 -04:00
} else if ( strcmp ( RAT_CLIENT , actor - > type ) ) {
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s, not a client: %s \n " , xmpp_stream_get_jid ( stream ) , jid ) ;
RAYO_UNLOCK ( actor ) ;
actor = NULL ;
}
} else {
actor = RAYO_ACTOR ( xmpp_stream_get_private ( stream ) ) ;
RAYO_RDLOCK ( actor ) ;
}
return actor ;
}
/**
* Handle new stream creation
* @ param stream the new stream
*/
static void on_xmpp_stream_ready ( struct xmpp_stream * stream )
{
if ( xmpp_stream_is_s2s ( stream ) ) {
if ( xmpp_stream_is_incoming ( stream ) ) {
/* peer server belongs to a s2s inbound stream */
xmpp_stream_set_private ( stream , rayo_peer_server_create ( xmpp_stream_get_jid ( stream ) ) ) ;
} else {
/* send directed presence to domain */
iks * presence = iks_new ( " presence " ) ;
iks * x ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " sending server presence \n " ) ;
iks_insert_attrib ( presence , " from " , RAYO_JID ( globals . server ) ) ;
iks_insert_attrib ( presence , " to " , xmpp_stream_get_jid ( stream ) ) ;
x = iks_insert ( presence , " show " ) ;
iks_insert_cdata ( x , " chat " , 4 ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( globals . server , xmpp_stream_get_jid ( stream ) , presence ) ;
2013-06-06 16:03:00 -04:00
}
} else {
/* client belongs to stream */
2013-06-24 14:51:54 -04:00
xmpp_stream_set_private ( stream , rayo_client_create ( xmpp_stream_get_jid ( stream ) , xmpp_stream_get_jid ( stream ) , PS_OFFLINE , rayo_client_send , NULL ) ) ;
2013-06-06 16:03:00 -04:00
}
}
/**
* Checks client availability . If unknown , client presence is probed .
* @ param rclient to check
*/
static void rayo_client_presence_check ( struct rayo_client * rclient )
{
if ( rclient - > availability = = PS_UNKNOWN ) {
/* for now, set online */
rclient - > availability = PS_ONLINE ;
}
}
/**
* Handle stream stanza
* @ param stream the stream
* @ param stanza the stanza to process
*/
static void on_xmpp_stream_recv ( struct xmpp_stream * stream , iks * stanza )
{
const char * name = iks_name ( stanza ) ;
if ( ! strcmp ( " iq " , name ) ) {
const char * from = iks_find_attrib_soft ( stanza , " from " ) ;
struct rayo_actor * actor = xmpp_stream_client_locate ( stream , from ) ;
if ( actor ) {
rayo_client_presence_check ( RAYO_CLIENT ( actor ) ) ;
rayo_client_command_recv ( RAYO_CLIENT ( actor ) , stanza ) ;
RAYO_UNLOCK ( actor ) ;
}
} else if ( ! strcmp ( " presence " , name ) ) {
const char * from = iks_find_attrib_soft ( stanza , " from " ) ;
struct rayo_actor * actor = xmpp_stream_client_locate ( stream , from ) ;
if ( actor ) {
on_client_presence ( RAYO_CLIENT ( actor ) , stanza ) ;
RAYO_UNLOCK ( actor ) ;
}
} else if ( ! strcmp ( " message " , name ) ) {
const char * from = iks_find_attrib_soft ( stanza , " from " ) ;
struct rayo_actor * actor = xmpp_stream_client_locate ( stream , from ) ;
if ( actor ) {
rayo_client_presence_check ( RAYO_CLIENT ( actor ) ) ;
on_client_message ( RAYO_CLIENT ( actor ) , stanza ) ;
RAYO_UNLOCK ( actor ) ;
}
}
}
/**
* Handle stream destruction
*/
static void on_xmpp_stream_destroy ( struct xmpp_stream * stream )
{
/* destroy peer server / client associated with this stream */
void * actor = xmpp_stream_get_private ( stream ) ;
if ( actor ) {
RAYO_UNLOCK ( actor ) ;
RAYO_DESTROY ( actor ) ;
}
}
2013-08-14 18:00:30 -04:00
/**
* Add an alias to an API command
* @ param alias_name
* @ param alias_target
* @ param alias_cmd
*/
static void rayo_add_cmd_alias ( const char * alias_name , const char * alias_target , const char * alias_cmd )
{
if ( zstr ( alias_target ) ) {
alias_target = " all " ;
}
switch_console_set_complete ( switch_core_sprintf ( globals . pool , " add rayo %s ::rayo::list_%s " , alias_name , alias_target ) ) ;
switch_core_hash_insert ( globals . cmd_aliases , alias_name , alias_cmd ) ;
}
2013-06-06 16:03:00 -04:00
/**
* Process module XML configuration
* @ param pool memory pool to allocate from
* @ param config_file to use
* @ return SWITCH_STATUS_SUCCESS on successful configuration
*/
static switch_status_t do_config ( switch_memory_pool_t * pool , const char * config_file )
{
switch_xml_t cfg , xml ;
switch_status_t status = SWITCH_STATUS_SUCCESS ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Configuring module \n " ) ;
if ( ! ( xml = switch_xml_open_cfg ( config_file , & cfg , NULL ) ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " open of %s failed \n " , config_file ) ;
return SWITCH_STATUS_TERM ;
}
/* set defaults */
globals . max_idle_ms = 30000 ;
globals . mixer_conf_profile = " sla " ;
2013-06-24 20:50:37 -04:00
globals . num_message_threads = 8 ;
2013-08-10 09:30:33 -04:00
globals . offer_uri = 1 ;
2013-06-06 16:03:00 -04:00
/* get params */
{
switch_xml_t settings = switch_xml_child ( cfg , " settings " ) ;
if ( settings ) {
switch_xml_t param ;
for ( param = switch_xml_child ( settings , " param " ) ; param ; param = param - > next ) {
const char * var = switch_xml_attr_soft ( param , " name " ) ;
const char * val = switch_xml_attr_soft ( param , " value " ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " param: %s = %s \n " , var , val ) ;
if ( ! strcasecmp ( var , " max-idle-sec " ) ) {
if ( switch_is_number ( val ) ) {
int max_idle_sec = atoi ( val ) ;
if ( max_idle_sec > 0 ) {
globals . max_idle_ms = max_idle_sec * 1000 ;
}
}
} else if ( ! strcasecmp ( var , " mixer-conf-profile " ) ) {
if ( ! zstr ( val ) ) {
globals . mixer_conf_profile = switch_core_strdup ( pool , val ) ;
}
2013-06-24 20:50:37 -04:00
} else if ( ! strcasecmp ( var , " message-threads " ) ) {
if ( switch_is_number ( val ) ) {
int num_message_threads = atoi ( val ) ;
if ( num_message_threads > 0 ) {
globals . num_message_threads = num_message_threads ;
}
}
2013-08-10 09:30:33 -04:00
} else if ( ! strcasecmp ( var , " offer-uri " ) ) {
if ( switch_false ( val ) ) {
globals . offer_uri = 0 ;
}
2013-06-06 16:03:00 -04:00
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Unsupported param: %s \n " , var ) ;
}
}
}
}
/* configure dial gateways */
{
switch_xml_t dial_gateways = switch_xml_child ( cfg , " dial-gateways " ) ;
/* set defaults */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Setting default dial-gateways \n " ) ;
dial_gateway_add ( " default " , " sofia/gateway/outbound/ " , 0 ) ;
dial_gateway_add ( " tel: " , " sofia/gateway/outbound/ " , 4 ) ;
dial_gateway_add ( " user " , " " , 0 ) ;
dial_gateway_add ( " sofia " , " " , 0 ) ;
if ( dial_gateways ) {
switch_xml_t dg ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Setting configured dial-gateways \n " ) ;
for ( dg = switch_xml_child ( dial_gateways , " dial-gateway " ) ; dg ; dg = dg - > next ) {
const char * uri_prefix = switch_xml_attr_soft ( dg , " uriprefix " ) ;
const char * dial_prefix = switch_xml_attr_soft ( dg , " dialprefix " ) ;
const char * strip_str = switch_xml_attr_soft ( dg , " strip " ) ;
int strip = 0 ;
if ( ! zstr ( strip_str ) & & switch_is_number ( strip_str ) ) {
strip = atoi ( strip_str ) ;
if ( strip < 0 ) {
strip = 0 ;
}
}
if ( ! zstr ( uri_prefix ) ) {
dial_gateway_add ( uri_prefix , dial_prefix , strip ) ;
}
}
}
}
/* configure domain */
{
switch_xml_t domain = switch_xml_child ( cfg , " domain " ) ;
if ( domain ) {
switch_xml_t l ;
const char * shared_secret = switch_xml_attr_soft ( domain , " shared-secret " ) ;
const char * name = switch_xml_attr_soft ( domain , " name " ) ;
2013-07-15 18:52:09 -04:00
const char * cert = switch_xml_attr_soft ( domain , " cert " ) ;
const char * key = switch_xml_attr_soft ( domain , " key " ) ;
2013-06-06 16:03:00 -04:00
if ( zstr ( name ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_ERROR , " Missing <domain name= \" ... failed to configure rayo server \n " ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_NOTICE , " Rayo domain set to %s \n " , name ) ;
if ( zstr ( shared_secret ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_INFO , " Missing shared secret for %s domain. Server dialback will not work \n " , name ) ;
}
globals . xmpp_context = xmpp_stream_context_create ( name , shared_secret , on_xmpp_stream_ready , on_xmpp_stream_recv , on_xmpp_stream_destroy ) ;
globals . server = rayo_server_create ( name ) ;
2013-07-15 18:52:09 -04:00
/* set up TLS */
if ( ! zstr ( cert ) ) {
xmpp_stream_context_add_cert ( globals . xmpp_context , cert ) ;
}
if ( ! zstr ( key ) ) {
xmpp_stream_context_add_key ( globals . xmpp_context , key ) ;
}
2013-06-06 16:03:00 -04:00
/* configure authorized users for this domain */
l = switch_xml_child ( domain , " users " ) ;
if ( l ) {
switch_xml_t u ;
for ( u = switch_xml_child ( l , " user " ) ; u ; u = u - > next ) {
const char * user = switch_xml_attr_soft ( u , " name " ) ;
const char * password = switch_xml_attr_soft ( u , " password " ) ;
xmpp_stream_context_add_user ( globals . xmpp_context , user , password ) ;
}
}
/* get listeners for this domain */
for ( l = switch_xml_child ( domain , " listen " ) ; l ; l = l - > next ) {
const char * address = switch_xml_attr_soft ( l , " address " ) ;
const char * port = switch_xml_attr_soft ( l , " port " ) ;
const char * type = switch_xml_attr_soft ( l , " type " ) ;
const char * acl = switch_xml_attr_soft ( l , " acl " ) ;
int is_s2s = 0 ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " %s listener: %s:%s \n " , type , address , port ) ;
is_s2s = ! strcmp ( " s2s " , type ) ;
if ( ! is_s2s & & strcmp ( " c2s " , type ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Type must be \" c2s \" or \" s2s \" ! \n " ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
if ( zstr ( address ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Missing address! \n " ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
if ( ! zstr ( port ) & & ! switch_is_number ( port ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Port must be an integer! \n " ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
if ( xmpp_stream_context_listen ( globals . xmpp_context , address , atoi ( port ) , is_s2s , acl ) ! = SWITCH_STATUS_SUCCESS ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Failed to create %s listener: %s:%s \n " , type , address , port ) ;
}
}
/* get outbound server connections */
for ( l = switch_xml_child ( domain , " connect " ) ; l ; l = l - > next ) {
const char * domain = switch_xml_attr_soft ( l , " domain " ) ;
const char * address = switch_xml_attr_soft ( l , " address " ) ;
const char * port = switch_xml_attr_soft ( l , " port " ) ;
if ( ! zstr ( port ) & & ! switch_is_number ( port ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Outbound server port must be an integer! \n " ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
if ( zstr ( address ) & & zstr ( domain ) ) {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_WARNING , " Missing outbound server address! \n " ) ;
status = SWITCH_STATUS_FALSE ;
goto done ;
}
xmpp_stream_context_connect ( globals . xmpp_context , domain , address , atoi ( port ) ) ;
}
}
}
2013-08-14 18:00:30 -04:00
/* get aliases */
{
switch_xml_t aliases = switch_xml_child ( cfg , " aliases " ) ;
if ( aliases ) {
switch_xml_t alias ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Setting configured aliases \n " ) ;
for ( alias = switch_xml_child ( aliases , " alias " ) ; alias ; alias = alias - > next ) {
const char * alias_name = switch_xml_attr_soft ( alias , " name " ) ;
const char * alias_target = switch_xml_attr_soft ( alias , " target " ) ;
if ( ! zstr ( alias_name ) & & ! zstr ( alias - > txt ) ) {
2013-09-15 23:22:12 -04:00
rayo_add_cmd_alias ( alias_name , switch_core_strdup ( pool , alias_target ) , switch_core_strdup ( pool , alias - > txt ) ) ;
2013-08-14 18:00:30 -04:00
}
}
}
}
2013-06-06 16:03:00 -04:00
done :
switch_xml_free ( xml ) ;
return status ;
}
/**
* Dump rayo actor stats
*/
static void rayo_actor_dump ( struct rayo_actor * actor , switch_stream_handle_t * stream )
{
2013-06-24 14:51:54 -04:00
if ( ! strcmp ( RAT_CLIENT , actor - > type ) ) {
stream - > write_function ( stream , " TYPE='%s',SUBTYPE='%s',ID='%s',JID='%s',DOMAIN='%s',REFS=%i,STATUS='%s' " , actor - > type , actor - > subtype , actor - > id , RAYO_JID ( actor ) , RAYO_DOMAIN ( actor ) , actor - > ref_count , presence_status_to_string ( RAYO_CLIENT ( actor ) - > availability ) ) ;
2013-06-06 16:03:00 -04:00
} else {
2013-06-24 14:51:54 -04:00
stream - > write_function ( stream , " TYPE='%s',SUBTYPE='%s',ID='%s',JID='%s',DOMAIN='%s',REFS=%i " , actor - > type , actor - > subtype , actor - > id , RAYO_JID ( actor ) , RAYO_DOMAIN ( actor ) , actor - > ref_count ) ;
2013-06-06 16:03:00 -04:00
}
}
/**
* Dump rayo actors
*/
static int dump_api ( const char * cmd , switch_stream_handle_t * stream )
{
switch_hash_index_t * hi ;
if ( ! zstr ( cmd ) ) {
return 0 ;
}
stream - > write_function ( stream , " \n ENTITIES \n " ) ;
switch_mutex_lock ( globals . actors_mutex ) ;
for ( hi = switch_core_hash_first ( globals . actors ) ; hi ; hi = switch_core_hash_next ( hi ) ) {
struct rayo_actor * actor = NULL ;
const void * key ;
void * val ;
switch_core_hash_this ( hi , & key , NULL , & val ) ;
actor = ( struct rayo_actor * ) val ;
switch_assert ( actor ) ;
stream - > write_function ( stream , " " ) ;
rayo_actor_dump ( actor , stream ) ;
stream - > write_function ( stream , " \n " ) ;
}
for ( hi = switch_core_hash_first ( globals . destroy_actors ) ; hi ; hi = switch_core_hash_next ( hi ) ) {
struct rayo_actor * actor = NULL ;
const void * key ;
void * val ;
switch_core_hash_this ( hi , & key , NULL , & val ) ;
actor = ( struct rayo_actor * ) val ;
switch_assert ( actor ) ;
stream - > write_function ( stream , " (DEAD) " ) ;
rayo_actor_dump ( actor , stream ) ;
stream - > write_function ( stream , " \n " ) ;
}
switch_mutex_unlock ( globals . actors_mutex ) ;
xmpp_stream_context_dump ( globals . xmpp_context , stream ) ;
return 1 ;
}
/**
* Process response to console command_api
*/
2013-06-24 20:50:37 -04:00
void rayo_console_client_send ( struct rayo_actor * actor , struct rayo_message * msg )
2013-06-06 16:03:00 -04:00
{
iks * response = msg - > payload ;
if ( response ) {
2013-06-24 14:51:54 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CONSOLE , " \n RECV: from %s, %s \n " , msg - > from_jid , iks_string ( iks_stack ( response ) , response ) ) ;
2013-06-06 16:03:00 -04:00
} else {
2013-06-24 14:51:54 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CONSOLE , " \n RECV: (null) from %s \n " , msg - > from_jid ) ;
2013-06-06 16:03:00 -04:00
}
}
/**
* Create a new Rayo console client
* @ return the new client or NULL
*/
static struct rayo_client * rayo_console_client_create ( void )
{
struct rayo_client * client = NULL ;
char * jid = NULL ;
char id [ SWITCH_UUID_FORMATTED_LENGTH + 1 ] = { 0 } ;
switch_uuid_str ( id , sizeof ( id ) ) ;
jid = switch_mprintf ( " %s@%s/console " , id , RAYO_JID ( globals . server ) ) ;
2013-06-24 14:51:54 -04:00
client = rayo_client_create ( jid , NULL , PS_OFFLINE , rayo_console_client_send , NULL ) ;
2013-06-06 16:03:00 -04:00
free ( jid ) ;
return client ;
}
/**
* Send command from console
*/
static void send_console_command ( struct rayo_client * client , const char * to , const char * command_str )
{
iks * command = NULL ;
iksparser * p = iks_dom_new ( & command ) ;
if ( iks_parse ( p , command_str , 0 , 1 ) = = IKS_OK & & command ) {
char * str ;
iks * iq = NULL ;
/* is command already wrapped in IQ? */
if ( ! strcmp ( iks_name ( command ) , " iq " ) ) {
/* command already IQ */
iq = command ;
} else {
/* create IQ to wrap command */
iq = iks_new_within ( " iq " , iks_stack ( command ) ) ;
iks_insert_node ( iq , command ) ;
}
/* fill in command attribs */
iks_insert_attrib ( iq , " to " , to ) ;
if ( ! iks_find_attrib ( iq , " type " ) ) {
iks_insert_attrib ( iq , " type " , " set " ) ;
}
if ( ! iks_find_attrib ( iq , " id " ) ) {
iks_insert_attrib_printf ( iq , " id " , " console-%i " , RAYO_SEQ_NEXT ( client ) ) ;
}
iks_insert_attrib ( iq , " from " , RAYO_JID ( client ) ) ;
/* send command */
str = iks_string ( iks_stack ( iq ) , iq ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CONSOLE , " \n SEND: to %s, %s \n " , to , str ) ;
rayo_client_command_recv ( client , iq ) ;
2013-06-24 21:55:58 -04:00
iks_delete ( command ) ;
2013-06-06 16:03:00 -04:00
} else {
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CONSOLE , " bad request xml \n " ) ;
}
iks_parser_delete ( p ) ;
}
/**
* Send command to rayo actor
*/
2013-08-14 18:00:30 -04:00
static int command_api ( char * cmd , switch_stream_handle_t * stream )
2013-06-06 16:03:00 -04:00
{
char * argv [ 2 ] = { 0 } ;
2013-08-14 18:00:30 -04:00
if ( ! zstr ( cmd ) ) {
int argc = switch_separate_string ( cmd , ' ' , argv , sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ;
if ( argc ! = 2 ) {
return 0 ;
}
} else {
2013-06-06 16:03:00 -04:00
return 0 ;
}
/* send command */
send_console_command ( globals . console , argv [ 0 ] , argv [ 1 ] ) ;
stream - > write_function ( stream , " +OK \n " ) ;
2013-08-14 18:00:30 -04:00
return 1 ;
}
/**
* Send command to rayo actor
*/
static int alias_api ( const char * cmd , char * jid , switch_stream_handle_t * stream )
{
if ( zstr ( cmd ) | | zstr ( jid ) ) {
return 0 ;
}
/* send command */
send_console_command ( globals . console , jid , cmd ) ;
stream - > write_function ( stream , " +OK \n " ) ;
2013-06-06 16:03:00 -04:00
return 1 ;
}
/**
* Send message from console
*/
static void send_console_message ( struct rayo_client * client , const char * to , const char * message_str )
{
2013-06-24 14:51:54 -04:00
iks * message = NULL , * x ;
message = iks_new ( " message " ) ;
iks_insert_attrib ( message , " to " , to ) ;
iks_insert_attrib ( message , " from " , RAYO_JID ( client ) ) ;
iks_insert_attrib_printf ( message , " id " , " console-%i " , RAYO_SEQ_NEXT ( client ) ) ;
iks_insert_attrib ( message , " type " , " chat " ) ;
x = iks_insert ( message , " body " ) ;
iks_insert_cdata ( x , message_str , strlen ( message_str ) ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CONSOLE , " \n SEND: to %s, %s \n " , to , iks_string ( iks_stack ( message ) , message ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( client , to , message ) ;
2013-06-06 16:03:00 -04:00
}
/**
* Send message to rayo actor
*/
2013-08-14 18:00:30 -04:00
static int message_api ( char * cmd , switch_stream_handle_t * stream )
2013-06-06 16:03:00 -04:00
{
char * argv [ 2 ] = { 0 } ;
2013-08-14 18:00:30 -04:00
if ( ! zstr ( cmd ) ) {
int argc = switch_separate_string ( cmd , ' ' , argv , sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ;
if ( argc ! = 2 ) {
return 0 ;
}
} else {
2013-06-06 16:03:00 -04:00
return 0 ;
}
/* send message */
send_console_message ( globals . console , argv [ 0 ] , argv [ 1 ] ) ;
stream - > write_function ( stream , " +OK \n " ) ;
return 1 ;
}
/**
* Send presence from console
*/
static void send_console_presence ( struct rayo_client * client , const char * to , int is_online )
{
2013-06-24 14:51:54 -04:00
iks * presence = NULL , * x ;
presence = iks_new ( " presence " ) ;
iks_insert_attrib ( presence , " to " , to ) ;
iks_insert_attrib ( presence , " from " , RAYO_JID ( client ) ) ;
iks_insert_attrib_printf ( presence , " id " , " console-%i " , RAYO_SEQ_NEXT ( client ) ) ;
if ( ! is_online ) {
iks_insert_attrib ( presence , " type " , " unavailable " ) ;
2013-06-06 16:03:00 -04:00
}
2013-06-24 14:51:54 -04:00
x = iks_insert ( presence , " show " ) ;
iks_insert_cdata ( x , is_online ? " chat " : " dnd " , 0 ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_CONSOLE , " \n SEND: to %s, %s \n " , to , iks_string ( iks_stack ( presence ) , presence ) ) ;
2013-06-24 20:50:37 -04:00
RAYO_SEND_MESSAGE ( client , to , presence ) ;
2013-06-06 16:03:00 -04:00
}
/**
* Send console presence
*/
2013-08-14 18:00:30 -04:00
static int presence_api ( char * cmd , switch_stream_handle_t * stream )
2013-06-06 16:03:00 -04:00
{
int is_online = 0 ;
2013-08-14 18:00:30 -04:00
char * argv [ 2 ] = { 0 } ;
if ( ! zstr ( cmd ) ) {
int argc = switch_separate_string ( cmd , ' ' , argv , sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ;
if ( argc ! = 2 ) {
return 0 ;
}
} else {
2013-06-06 16:03:00 -04:00
return 0 ;
}
if ( ! strcmp ( " online " , argv [ 1 ] ) ) {
is_online = 1 ;
} else if ( strcmp ( " offline " , argv [ 1 ] ) ) {
return 0 ;
}
/* send presence */
send_console_presence ( globals . console , argv [ 0 ] , is_online ) ;
stream - > write_function ( stream , " +OK \n " ) ;
return 1 ;
}
2013-08-14 18:00:30 -04:00
# define RAYO_API_SYNTAX "status | (<alias> <jid>) | (cmd <jid> <command>) | (msg <jid> <message text>) | (presence <jid> <online|offline>)"
2013-06-06 16:03:00 -04:00
SWITCH_STANDARD_API ( rayo_api )
{
2013-08-14 18:00:30 -04:00
const char * alias ;
char * cmd_dup = strdup ( cmd ) ;
char * argv [ 2 ] = { 0 } ;
2013-06-06 16:03:00 -04:00
int success = 0 ;
2013-08-14 18:00:30 -04:00
switch_separate_string ( cmd_dup , ' ' , argv , sizeof ( argv ) / sizeof ( argv [ 0 ] ) ) ;
/* check if a command alias */
alias = switch_core_hash_find ( globals . cmd_aliases , argv [ 0 ] ) ;
if ( ! zstr ( alias ) ) {
success = alias_api ( alias , argv [ 1 ] , stream ) ;
} else if ( ! strcmp ( " cmd " , argv [ 0 ] ) ) {
success = command_api ( argv [ 1 ] , stream ) ;
} else if ( ! strcmp ( " status " , argv [ 0 ] ) ) {
success = dump_api ( argv [ 1 ] , stream ) ;
} else if ( ! strcmp ( " msg " , argv [ 0 ] ) ) {
success = message_api ( argv [ 1 ] , stream ) ;
} else if ( ! strcmp ( " presence " , argv [ 0 ] ) ) {
success = presence_api ( argv [ 1 ] , stream ) ;
2013-06-06 16:03:00 -04:00
}
if ( ! success ) {
stream - > write_function ( stream , " -ERR: USAGE %s \n " , RAYO_API_SYNTAX ) ;
}
2013-08-14 18:00:30 -04:00
free ( cmd_dup ) ;
2013-06-06 16:03:00 -04:00
return SWITCH_STATUS_SUCCESS ;
}
/**
2013-08-14 18:00:30 -04:00
* Console auto - completion for actors given validation function
2013-06-06 16:03:00 -04:00
*/
2013-08-14 18:00:30 -04:00
static switch_status_t list_actors ( const char * line , const char * cursor , switch_console_callback_match_t * * matches , rayo_actor_match_fn match )
2013-06-06 16:03:00 -04:00
{
switch_hash_index_t * hi ;
void * val ;
const void * vvar ;
switch_console_callback_match_t * my_matches = NULL ;
switch_status_t status = SWITCH_STATUS_FALSE ;
struct rayo_actor * actor ;
switch_mutex_lock ( globals . actors_mutex ) ;
for ( hi = switch_hash_first ( NULL , globals . actors ) ; hi ; hi = switch_hash_next ( hi ) ) {
switch_hash_this ( hi , & vvar , NULL , & val ) ;
actor = ( struct rayo_actor * ) val ;
2013-08-14 18:00:30 -04:00
if ( match ( actor ) ) {
2013-06-06 16:03:00 -04:00
switch_console_push_match ( & my_matches , ( const char * ) vvar ) ;
}
}
switch_mutex_unlock ( globals . actors_mutex ) ;
if ( my_matches ) {
* matches = my_matches ;
status = SWITCH_STATUS_SUCCESS ;
}
return status ;
}
/**
2013-08-14 18:00:30 -04:00
* @ return true if internal actor
2013-06-06 16:03:00 -04:00
*/
2013-08-14 18:00:30 -04:00
static switch_bool_t is_internal_actor ( struct rayo_actor * actor )
2013-06-06 16:03:00 -04:00
{
2013-08-14 18:00:30 -04:00
return strcmp ( RAT_CLIENT , actor - > type ) & & strcmp ( RAT_PEER_SERVER , actor - > type ) ;
}
2013-06-06 16:03:00 -04:00
2013-08-14 18:00:30 -04:00
/**
* Console auto - completion for all internal actors
*/
static switch_status_t list_internal ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
{
return list_actors ( line , cursor , matches , is_internal_actor ) ;
}
2013-06-06 16:03:00 -04:00
2013-08-14 18:00:30 -04:00
/**
* @ return true if external actor
*/
static switch_bool_t is_external_actor ( struct rayo_actor * actor )
{
return ! strcmp ( RAT_CLIENT , actor - > type ) | | ! strcmp ( RAT_PEER_SERVER , actor - > type ) ;
}
2013-06-06 16:03:00 -04:00
2013-08-14 18:00:30 -04:00
/**
* Console auto - completion for all external actors
*/
static switch_status_t list_external ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
{
return list_actors ( line , cursor , matches , is_external_actor ) ;
}
2013-06-06 16:03:00 -04:00
2013-08-14 18:00:30 -04:00
/**
* @ return true
*/
static switch_bool_t is_any_actor ( struct rayo_actor * actor )
{
return SWITCH_TRUE ;
2013-06-06 16:03:00 -04:00
}
/**
* Console auto - completion for all actors
*/
2013-08-14 18:00:30 -04:00
static switch_status_t list_all ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
2013-06-06 16:03:00 -04:00
{
2013-08-14 18:00:30 -04:00
return list_actors ( line , cursor , matches , is_any_actor ) ;
}
2013-06-06 16:03:00 -04:00
2013-08-14 18:00:30 -04:00
/**
* @ return true if a server
*/
static switch_bool_t is_server_actor ( struct rayo_actor * actor )
{
return ! strcmp ( RAT_SERVER , actor - > type ) ;
}
2013-06-06 16:03:00 -04:00
2013-08-14 18:00:30 -04:00
/**
* Console auto - completion for all servers
*/
static switch_status_t list_server ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
{
return list_actors ( line , cursor , matches , is_server_actor ) ;
}
2013-06-06 16:03:00 -04:00
2013-08-14 18:00:30 -04:00
/**
* @ return true if a call
*/
static switch_bool_t is_call_actor ( struct rayo_actor * actor )
{
return ! strcmp ( RAT_CALL , actor - > type ) ;
2013-06-06 16:03:00 -04:00
}
/**
2013-08-14 18:00:30 -04:00
* Console auto - completion for all calls
2013-06-06 16:03:00 -04:00
*/
2013-08-14 18:00:30 -04:00
static switch_status_t list_call ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
2013-06-06 16:03:00 -04:00
{
2013-08-14 18:00:30 -04:00
return list_actors ( line , cursor , matches , is_call_actor ) ;
}
/**
* @ return true if a component
*/
switch_bool_t is_component_actor ( struct rayo_actor * actor )
{
return ! strncmp ( RAT_COMPONENT , actor - > type , strlen ( RAT_COMPONENT ) ) ;
}
/**
* Console auto - completion for all components
*/
static switch_status_t list_component ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
{
return list_actors ( line , cursor , matches , is_component_actor ) ;
}
/**
* @ return true if a record component
*/
static switch_bool_t is_record_actor ( struct rayo_actor * actor )
{
return is_component_actor ( actor ) & & ! strcmp ( actor - > subtype , " record " ) ;
}
/**
* Console auto - completion for all components
*/
static switch_status_t list_record ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
{
return list_actors ( line , cursor , matches , is_record_actor ) ;
}
/**
* @ return true if an output component
*/
static switch_bool_t is_output_actor ( struct rayo_actor * actor )
{
return is_component_actor ( actor ) & & ! strcmp ( actor - > subtype , " output " ) ;
}
/**
* Console auto - completion for all components
*/
static switch_status_t list_output ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
{
return list_actors ( line , cursor , matches , is_output_actor ) ;
}
/**
* @ return true if an input component
*/
static switch_bool_t is_input_actor ( struct rayo_actor * actor )
{
return is_component_actor ( actor ) & & ! strcmp ( actor - > subtype , " input " ) ;
}
/**
* Console auto - completion for all components
*/
static switch_status_t list_input ( const char * line , const char * cursor , switch_console_callback_match_t * * matches )
{
return list_actors ( line , cursor , matches , is_input_actor ) ;
2013-06-06 16:03:00 -04:00
}
/**
* Load module
*/
SWITCH_MODULE_LOAD_FUNCTION ( mod_rayo_load )
{
switch_api_interface_t * api_interface ;
switch_application_interface_t * app_interface ;
* module_interface = switch_loadable_module_create_module_interface ( pool , modname ) ;
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Loading module \n " ) ;
memset ( & globals , 0 , sizeof ( globals ) ) ;
globals . pool = pool ;
switch_core_hash_init ( & globals . command_handlers , pool ) ;
switch_core_hash_init ( & globals . event_handlers , pool ) ;
switch_core_hash_init ( & globals . clients_roster , pool ) ;
switch_mutex_init ( & globals . clients_mutex , SWITCH_MUTEX_NESTED , pool ) ;
switch_core_hash_init ( & globals . actors , pool ) ;
switch_core_hash_init ( & globals . destroy_actors , pool ) ;
switch_core_hash_init ( & globals . actors_by_id , pool ) ;
switch_mutex_init ( & globals . actors_mutex , SWITCH_MUTEX_NESTED , pool ) ;
switch_core_hash_init ( & globals . dial_gateways , pool ) ;
switch_core_hash_init ( & globals . cmd_aliases , pool ) ;
2013-06-24 20:50:37 -04:00
switch_thread_rwlock_create ( & globals . shutdown_rwlock , pool ) ;
switch_queue_create ( & globals . msg_queue , 25000 , pool ) ;
2013-06-06 16:03:00 -04:00
/* server commands */
rayo_actor_command_handler_add ( RAT_SERVER , " " , " get: " IKS_NS_XMPP_PING " :ping " , on_iq_xmpp_ping ) ;
rayo_actor_command_handler_add ( RAT_SERVER , " " , " get: " IKS_NS_XMPP_DISCO " :query " , on_iq_get_xmpp_disco ) ;
rayo_actor_command_handler_add ( RAT_SERVER , " " , " set: " RAYO_NS " :dial " , on_rayo_dial ) ;
/* Rayo call commands */
rayo_actor_command_handler_add ( RAT_CALL , " " , " set: " RAYO_NS " :accept " , on_rayo_accept ) ;
rayo_actor_command_handler_add ( RAT_CALL , " " , " set: " RAYO_NS " :answer " , on_rayo_answer ) ;
rayo_actor_command_handler_add ( RAT_CALL , " " , " set: " RAYO_NS " :redirect " , on_rayo_redirect ) ;
rayo_actor_command_handler_add ( RAT_CALL , " " , " set: " RAYO_NS " :reject " , on_rayo_hangup ) ; /* handles both reject and hangup */
rayo_actor_command_handler_add ( RAT_CALL , " " , " set: " RAYO_NS " :hangup " , on_rayo_hangup ) ; /* handles both reject and hangup */
rayo_actor_command_handler_add ( RAT_CALL , " " , " set: " RAYO_NS " :join " , on_rayo_join ) ;
rayo_actor_command_handler_add ( RAT_CALL , " " , " set: " RAYO_NS " :unjoin " , on_rayo_unjoin ) ;
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_ORIGINATE , NULL , route_call_event , NULL ) ;
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_PROGRESS_MEDIA , NULL , route_call_event , NULL ) ;
2013-08-06 16:21:22 -04:00
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_PROGRESS , NULL , route_call_event , NULL ) ;
2013-06-06 16:03:00 -04:00
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_ANSWER , NULL , route_call_event , NULL ) ;
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_BRIDGE , NULL , route_call_event , NULL ) ;
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_UNBRIDGE , NULL , route_call_event , NULL ) ;
2013-10-15 14:17:33 -04:00
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_EXECUTE , NULL , route_call_event , NULL ) ;
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_EXECUTE_COMPLETE , NULL , route_call_event , NULL ) ;
2013-06-06 16:03:00 -04:00
switch_event_bind ( modname , SWITCH_EVENT_CHANNEL_DESTROY , NULL , on_call_end_event , NULL ) ;
switch_event_bind ( modname , SWITCH_EVENT_CUSTOM , " conference::maintenance " , route_mixer_event , NULL ) ;
SWITCH_ADD_APP ( app_interface , " rayo " , " Offer call control to Rayo client(s) " , " " , rayo_app , RAYO_USAGE , SAF_SUPPORT_NOMEDIA ) ;
SWITCH_ADD_API ( api_interface , " rayo " , " Query rayo status " , rayo_api , RAYO_API_SYNTAX ) ;
/* set up rayo components */
if ( rayo_components_load ( module_interface , pool , RAYO_CONFIG_FILE ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_TERM ;
}
/* configure / open sockets */
if ( do_config ( globals . pool , RAYO_CONFIG_FILE ) ! = SWITCH_STATUS_SUCCESS ) {
return SWITCH_STATUS_TERM ;
}
2013-06-24 20:50:37 -04:00
/* start up message threads */
{
int i ;
for ( i = 0 ; i < globals . num_message_threads ; i + + ) {
start_deliver_message_thread ( pool ) ;
}
}
2013-06-06 16:03:00 -04:00
/* create admin client */
globals . console = rayo_console_client_create ( ) ;
switch_console_set_complete ( " add rayo status " ) ;
switch_console_set_complete ( " add rayo msg ::rayo::list_external " ) ;
2013-08-14 18:00:30 -04:00
switch_console_set_complete ( " add rayo cmd ::rayo::list_all " ) ;
switch_console_set_complete ( " add rayo presence ::rayo::list_server online " ) ;
switch_console_set_complete ( " add rayo presence ::rayo::list_server offline " ) ;
switch_console_add_complete_func ( " ::rayo::list_all " , list_all ) ;
2013-06-06 16:03:00 -04:00
switch_console_add_complete_func ( " ::rayo::list_internal " , list_internal ) ;
switch_console_add_complete_func ( " ::rayo::list_external " , list_external ) ;
2013-08-14 18:00:30 -04:00
switch_console_add_complete_func ( " ::rayo::list_server " , list_server ) ;
switch_console_add_complete_func ( " ::rayo::list_call " , list_call ) ;
switch_console_add_complete_func ( " ::rayo::list_component " , list_component ) ;
switch_console_add_complete_func ( " ::rayo::list_record " , list_record ) ;
switch_console_add_complete_func ( " ::rayo::list_output " , list_output ) ;
switch_console_add_complete_func ( " ::rayo::list_input " , list_input ) ;
2013-06-06 16:03:00 -04:00
return SWITCH_STATUS_SUCCESS ;
}
/**
* Shutdown module . Notifies threads to stop .
*/
SWITCH_MODULE_SHUTDOWN_FUNCTION ( mod_rayo_shutdown )
{
2013-08-14 18:00:30 -04:00
switch_console_del_complete_func ( " ::rayo::list_all " ) ;
2013-06-25 07:54:59 -04:00
switch_console_del_complete_func ( " ::rayo::list_internal " ) ;
switch_console_del_complete_func ( " ::rayo::list_external " ) ;
2013-08-14 18:00:30 -04:00
switch_console_del_complete_func ( " ::rayo::list_server " ) ;
switch_console_del_complete_func ( " ::rayo::list_call " ) ;
switch_console_del_complete_func ( " ::rayo::list_component " ) ;
switch_console_del_complete_func ( " ::rayo::list_record " ) ;
switch_console_del_complete_func ( " ::rayo::list_output " ) ;
switch_console_del_complete_func ( " ::rayo::list_input " ) ;
2013-06-06 16:03:00 -04:00
switch_console_set_complete ( " del rayo " ) ;
2013-06-24 20:50:37 -04:00
/* stop XMPP streams */
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Waiting for XMPP threads to stop \n " ) ;
xmpp_stream_context_destroy ( globals . xmpp_context ) ;
2013-06-24 20:50:37 -04:00
/* stop message threads */
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Waiting for message threads to stop \n " ) ;
stop_deliver_message_threads ( ) ;
2013-06-24 21:55:58 -04:00
if ( globals . console ) {
RAYO_UNLOCK ( globals . console ) ;
RAYO_DESTROY ( globals . console ) ;
globals . console = NULL ;
}
if ( globals . server ) {
RAYO_UNLOCK ( globals . server ) ;
RAYO_DESTROY ( globals . server ) ;
globals . server = NULL ;
}
2013-06-06 16:03:00 -04:00
rayo_components_shutdown ( ) ;
/* cleanup module */
switch_event_unbind_callback ( route_call_event ) ;
switch_event_unbind_callback ( on_call_end_event ) ;
switch_event_unbind_callback ( route_mixer_event ) ;
2013-07-15 18:52:09 -04:00
switch_core_hash_destroy ( & globals . command_handlers ) ;
switch_core_hash_destroy ( & globals . event_handlers ) ;
switch_core_hash_destroy ( & globals . clients_roster ) ;
switch_core_hash_destroy ( & globals . actors ) ;
switch_core_hash_destroy ( & globals . destroy_actors ) ;
switch_core_hash_destroy ( & globals . actors_by_id ) ;
switch_core_hash_destroy ( & globals . dial_gateways ) ;
switch_core_hash_destroy ( & globals . cmd_aliases ) ;
2013-06-24 21:55:58 -04:00
2013-06-06 16:03:00 -04:00
switch_log_printf ( SWITCH_CHANNEL_LOG , SWITCH_LOG_DEBUG , " Module shutdown \n " ) ;
return SWITCH_STATUS_SUCCESS ;
}
/* For Emacs:
* Local Variables :
* mode : c
* indent - tabs - mode : t
* tab - width : 4
* c - basic - offset : 4
* End :
* For VIM :
2013-06-25 11:50:17 -05:00
* vim : set softtabstop = 4 shiftwidth = 4 tabstop = 4 noet
2013-06-06 16:03:00 -04:00
*/