diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index eb472da44b..7c6b6d819d 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -223,6 +223,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses void *session_data, void *peer_session_data); +/*! + \brief Bridge Signalling from one session to another + \param session one session + \param peer_session the other session + \return SWITCH_STATUS_SUCCESS if all is well +*/ +SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *session, switch_core_session_t *peer_session); /*! \brief Transfer an existing session to another location diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 9ccf831886..81ff52de7c 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -72,6 +72,11 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_HTDOCS_DIR SWITCH_PREFIX_DIR SWITCH_PATH_SEPARATOR "htdocs" #endif +#define SWITCH_R_SDP_VARIABLE "_switch_r_sdp_" +#define SWITCH_L_SDP_VARIABLE "_switch_l_sdp_" +#define SWITCH_BRIDGE_VARIABLE "BRIDGETO" +#define SWITCH_SIGNAL_BRIDGE_VARIABLE "SIGNAL_BRIDGETO" + #define SWITCH_BITS_PER_BYTE 8 typedef uint8_t switch_byte_t; @@ -232,7 +237,8 @@ typedef enum { SWITCH_MESSAGE_TRANSMIT_TEXT - A text message SWITCH_MESSAGE_INDICATE_PROGRESS - indicate progress SWITCH_MESSAGE_INDICATE_BRIDGE - indicate a bridge starting - SWITCH_MESSAGE_INDICATE_UNBRIDGE - indicate a bridge ending + SWITCH_MESSAGE_INDICATE_UNBRIDGE - indicate a bridge ending + SWITCH_MESSAGE_INDICATE_TRANSFER - indicate a transfer is taking place */ typedef enum { @@ -240,7 +246,8 @@ typedef enum { SWITCH_MESSAGE_TRANSMIT_TEXT, SWITCH_MESSAGE_INDICATE_PROGRESS, SWITCH_MESSAGE_INDICATE_BRIDGE, - SWITCH_MESSAGE_INDICATE_UNBRIDGE + SWITCH_MESSAGE_INDICATE_UNBRIDGE, + SWITCH_MESSAGE_INDICATE_TRANSFER } switch_core_session_message_types_t; @@ -392,6 +399,7 @@ CF_SERVICE = (1 << 9) - Channel has a service thread CF_TAGGED = (1 << 10) - Channel is tagged CF_WINNER = (1 << 11) - Channel is the winner CF_CONTROLLED = (1 << 12) - Channel is under control +CF_NOMEDIA = (1 << 13) - Channel has no media */ @@ -408,7 +416,8 @@ typedef enum { CF_SERVICE = (1 << 9), CF_TAGGED = (1 << 10), CF_WINNER = (1 << 11), - CF_CONTROLLED = (1 << 12) + CF_CONTROLLED = (1 << 12), + CF_NOMEDIA = (1 << 13) } switch_channel_flag_t; diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 02cb144507..10286a1d5d 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -192,6 +192,16 @@ if (vname) {free(vname); vname = NULL;}vname = strdup(string);} */ SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen); +/*! + \brief Escape a string by prefixing a list of characters with an escape character + \param pool a memory pool to use + \param in the string + \param delim the list of characters to escape + \param esc the escape character + \return the escaped string +*/ +SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, char *delim, char esc); + /*! \brief Create a set of file descriptors to poll \param poll the polfd to create diff --git a/src/mod/applications/mod_bridgecall/mod_bridgecall.c b/src/mod/applications/mod_bridgecall/mod_bridgecall.c index 2fec1c03f0..89e16549c6 100644 --- a/src/mod/applications/mod_bridgecall/mod_bridgecall.c +++ b/src/mod/applications/mod_bridgecall/mod_bridgecall.c @@ -51,23 +51,32 @@ static void audio_bridge_function(switch_core_session_t *session, char *data) timelimit = atoi(var); } + if ((var = switch_channel_get_variable(caller_channel, "no_media"))) { + switch_channel_set_flag(caller_channel, CF_NOMEDIA); + } + if (switch_ivr_originate(session, &peer_session, &cause, data, timelimit, NULL, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel!\n"); /* Hangup the channel with the cause code from the failed originate.*/ switch_channel_hangup(caller_channel, cause); return; } else { - switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL); + if (switch_channel_test_flag(caller_channel, CF_NOMEDIA)) { + switch_ivr_signal_bridge(session, peer_session); + } else { + switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL); + } } } - static const switch_application_interface_t bridge_application_interface = { /*.interface_name */ "bridge", - /*.application_function */ audio_bridge_function + /*.application_function */ audio_bridge_function, + /* long_desc */ "Bridge the audio between two sessions", + /* short_desc */ "Bridge Audio", + /* syntax */ "", }; - static const switch_loadable_module_interface_t mod_bridgecall_module_interface = { /*.module_name = */ modname, /*.endpoint_interface = */ NULL, diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 18c146fd79..7ab1e3a676 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -62,6 +62,7 @@ typedef struct private_object private_object_t; #define MULTICAST_EVENT "multicast::event" #define SOFIA_REPLACES_HEADER "_sofia_replaces_" + #include #include #include @@ -131,7 +132,10 @@ typedef enum { TFLAG_TIMER = (1 << 14), TFLAG_READY = (1 << 15), TFLAG_REINVITE = (1 << 16), - TFLAG_REFER = (1 << 17) + TFLAG_REFER = (1 << 17), + TFLAG_NOHUP = (1 << 18), + TFLAG_XFER = (1 << 19), + TFLAG_NOMEDIA = (1 << 20) } TFLAGS; static struct { @@ -250,11 +254,14 @@ struct private_object { char *local_sdp_str; char *dest; char *key; + char *xferto; + char *kick; unsigned long rm_rate; switch_payload_t pt; switch_mutex_t *flag_mutex; switch_payload_t te; nua_handle_t *nh; + nua_handle_t *nh2; su_home_t *home; sip_contact_t *contact; }; @@ -594,8 +601,10 @@ static void set_local_sdp(private_object_t *tech_pvt) char buf[1024]; switch_time_t now = switch_time_now(); - assert(tech_pvt != NULL); - + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { + return; + } + snprintf(buf, sizeof(buf), "v=0\n" "o=FreeSWITCH %d%"APR_TIME_T_FMT" %d%"APR_TIME_T_FMT" IN IP4 %s\n" @@ -653,6 +662,11 @@ static void set_local_sdp(private_object_t *tech_pvt) static void tech_set_codecs(private_object_t *tech_pvt) { + + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { + return; + } + if (tech_pvt->num_codecs) { return; } @@ -734,11 +748,11 @@ static switch_status_t tech_choose_port(private_object_t *tech_pvt) char *ip = tech_pvt->profile->rtpip; switch_port_t sdp_port; char *err; - - if (tech_pvt->adv_sdp_audio_port) { + + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA) || tech_pvt->adv_sdp_audio_port) { return SWITCH_STATUS_SUCCESS; } - + tech_pvt->local_sdp_audio_ip = ip; tech_pvt->local_sdp_audio_port = switch_rtp_request_port(); sdp_port = tech_pvt->local_sdp_audio_port; @@ -787,6 +801,8 @@ static void do_invite(switch_core_session_t *session) caller_profile = switch_channel_get_caller_profile(channel); + + if ((tech_pvt->from_str = switch_core_db_mprintf("\"%s\" ", (char *) caller_profile->caller_id_name, (char *) caller_profile->caller_id_number, @@ -794,21 +810,75 @@ static void do_invite(switch_core_session_t *session) ))) { char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER); - + tech_choose_port(tech_pvt); set_local_sdp(tech_pvt); + switch_set_flag_locked(tech_pvt, TFLAG_READY); - tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL, + if (!tech_pvt->nh) { + tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL, + SIPTAG_TO_STR(tech_pvt->dest), + SIPTAG_FROM_STR(tech_pvt->from_str), + SIPTAG_CONTACT_STR(tech_pvt->profile->url), + TAG_END()); + + tech_pvt->sofia_private.session = session; + nua_handle_bind(tech_pvt->nh, &tech_pvt->sofia_private); + + } + + nua_invite(tech_pvt->nh, + SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), + SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE), + SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), + TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), + TAG_END()); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); + } + +} + + + +static void do_xfer_invite(switch_core_session_t *session) +{ + private_object_t *tech_pvt; + switch_channel_t *channel = NULL; + switch_caller_profile_t *caller_profile; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + tech_pvt = (private_object_t *) switch_core_session_get_private(session); + assert(tech_pvt != NULL); + + caller_profile = switch_channel_get_caller_profile(channel); + + + + if ((tech_pvt->from_str = switch_core_db_mprintf("\"%s\" ", + (char *) caller_profile->caller_id_name, + (char *) caller_profile->caller_id_number, + tech_pvt->profile->sipip + ))) { + + char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER); + + + tech_pvt->nh2 = nua_handle(tech_pvt->profile->nua, NULL, SIPTAG_TO_STR(tech_pvt->dest), SIPTAG_FROM_STR(tech_pvt->from_str), SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END()); + - tech_pvt->sofia_private.session = session; - nua_handle_bind(tech_pvt->nh, &tech_pvt->sofia_private); - - nua_invite(tech_pvt->nh, + nua_handle_bind(tech_pvt->nh2, &tech_pvt->sofia_private); + + + + nua_invite(tech_pvt->nh2, SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), @@ -829,6 +899,7 @@ static switch_status_t sofia_on_init(switch_core_session_t *session) { private_object_t *tech_pvt; switch_channel_t *channel = NULL; + char *sdp; channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -841,6 +912,16 @@ static switch_status_t sofia_on_init(switch_core_session_t *session) switch_channel_set_variable(channel, "endpoint_disposition", "INIT"); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA INIT\n"); + if (switch_channel_test_flag(channel, CF_NOMEDIA)) { + switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA); + } + + if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) { + tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp); + switch_set_flag(tech_pvt, TFLAG_NOMEDIA); + switch_channel_set_flag(channel, CF_NOMEDIA); + } + if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) { do_invite(session); } @@ -937,6 +1018,7 @@ static int hangup_cause_to_sip(switch_call_cause_t cause) { static switch_status_t sofia_on_hangup(switch_core_session_t *session) { + switch_core_session_t *asession; private_object_t *tech_pvt; switch_channel_t *channel = NULL; switch_call_cause_t cause; @@ -958,6 +1040,13 @@ static switch_status_t sofia_on_hangup(switch_core_session_t *session) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s hanging up, cause: %s\n", switch_channel_get_name(channel), switch_channel_cause2str(cause), sip_cause); + + if (tech_pvt->kick && (asession = switch_core_session_locate(tech_pvt->kick))) { + switch_channel_t *a_channel = switch_core_session_get_channel(asession); + switch_channel_hangup(a_channel, switch_channel_get_cause(channel)); + switch_core_session_rwunlock(asession); + } + if (tech_pvt->nh) { if (!switch_test_flag(tech_pvt, TFLAG_BYE)) { if (switch_test_flag(tech_pvt, TFLAG_ANS)) { @@ -1088,6 +1177,9 @@ static switch_status_t activate_rtp(private_object_t *tech_pvt) channel = switch_core_session_get_channel(tech_pvt->session); assert(channel != NULL); + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { + return SWITCH_STATUS_SUCCESS; + } if (switch_rtp_ready(tech_pvt->rtp_session) && !switch_test_flag(tech_pvt, TFLAG_REINVITE)) { return SWITCH_STATUS_SUCCESS; @@ -1168,7 +1260,8 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) { private_object_t *tech_pvt; switch_channel_t *channel = NULL; - + char *sdp; + assert(session != NULL); channel = switch_core_session_get_channel(session); @@ -1177,13 +1270,25 @@ static switch_status_t sofia_answer_channel(switch_core_session_t *session) tech_pvt = (private_object_t *) switch_core_session_get_private(session); assert(tech_pvt != NULL); + if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) { + tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp); + switch_set_flag(tech_pvt, TFLAG_NOMEDIA); + switch_channel_set_flag(channel, CF_NOMEDIA); + } + + if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) { switch_set_flag_locked(tech_pvt, TFLAG_ANS); + + tech_choose_port(tech_pvt); set_local_sdp(tech_pvt); activate_rtp(tech_pvt); + if (tech_pvt->nh) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local SDP:\n%s\n", tech_pvt->local_sdp_str); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Local SDP %s:\n%s\n", + switch_channel_get_name(channel), + tech_pvt->local_sdp_str); nua_respond(tech_pvt->nh, SIP_200_OK, SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), @@ -1203,10 +1308,6 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f switch_channel_t *channel = NULL; int payload = 0; - //switch_time_t now, started = switch_time_now(), last_act = switch_time_now(); - //unsigned int elapsed; - //uint32_t hard_timeout = 60000 * 3; - channel = switch_core_session_get_channel(session); assert(channel != NULL); @@ -1246,7 +1347,6 @@ static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_f while (!switch_test_flag(tech_pvt, TFLAG_BYE) && switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) { - //now = switch_time_now(); tech_pvt->read_frame.flags = SFF_NONE; status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame); @@ -1448,6 +1548,34 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi switch (msg->message_id) { case SWITCH_MESSAGE_INDICATE_BRIDGE: + + if (switch_test_flag(tech_pvt, TFLAG_XFER)) { + switch_clear_flag_locked(tech_pvt, TFLAG_XFER); + if (msg->pointer_arg) { + switch_core_session_t *asession, *bsession = msg->pointer_arg; + + if ((asession = switch_core_session_locate(tech_pvt->xferto))) { + private_object_t *a_tech_pvt = switch_core_session_get_private(asession); + private_object_t *b_tech_pvt = switch_core_session_get_private(bsession); + + switch_set_flag_locked(a_tech_pvt, TFLAG_REINVITE); + a_tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(asession, b_tech_pvt->remote_sdp_audio_ip); + a_tech_pvt->remote_sdp_audio_port = b_tech_pvt->remote_sdp_audio_port; + a_tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(asession, b_tech_pvt->local_sdp_audio_ip); + a_tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port; + activate_rtp(a_tech_pvt); + + b_tech_pvt->kick = switch_core_session_strdup(bsession, tech_pvt->xferto); + + + switch_core_session_rwunlock(asession); + } + + + msg->pointer_arg = NULL; + return SWITCH_STATUS_FALSE; + } + } if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) { switch_rtp_clear_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "De-activate timed RTP!\n"); @@ -1462,17 +1590,26 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi case SWITCH_MESSAGE_INDICATE_PROGRESS: { struct private_object *tech_pvt; switch_channel_t *channel = NULL; - + char *sdp; + channel = switch_core_session_get_channel(session); assert(channel != NULL); tech_pvt = switch_core_session_get_private(session); assert(tech_pvt != NULL); - + if (!switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) { switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Asked to send early media by %s\n", msg->from); + + if ((sdp = switch_channel_get_variable(channel, SWITCH_L_SDP_VARIABLE))) { + tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp); + switch_set_flag(tech_pvt, TFLAG_NOMEDIA); + switch_channel_set_flag(channel, CF_NOMEDIA); + } + + /* Transmit 183 Progress with SDP */ tech_choose_port(tech_pvt); set_local_sdp(tech_pvt); @@ -1540,6 +1677,7 @@ static switch_status_t sofia_outgoing_channel(switch_core_session_t *session, sw switch_caller_profile_t *caller_profile = NULL; private_object_t *tech_pvt = NULL; switch_channel_t *channel; + switch_channel_t *nchannel; char *host; *new_session = NULL; @@ -1586,19 +1724,24 @@ static switch_status_t sofia_outgoing_channel(switch_core_session_t *session, sw tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5); snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest); } - - channel = switch_core_session_get_channel(nsession); - attach_private(nsession, profile, tech_pvt, dest); + attach_private(nsession, profile, tech_pvt, dest); + channel = switch_core_session_get_channel(session); + nchannel = switch_core_session_get_channel(nsession); caller_profile = switch_caller_profile_clone(nsession, outbound_profile); - switch_channel_set_caller_profile(channel, caller_profile); - switch_channel_set_flag(channel, CF_OUTBOUND); + switch_channel_set_caller_profile(nchannel, caller_profile); + switch_channel_set_flag(nchannel, CF_OUTBOUND); switch_set_flag_locked(tech_pvt, TFLAG_OUTBOUND); - switch_channel_set_state(channel, CS_INIT); - switch_channel_set_variable(channel, "endpoint_disposition", "OUTBOUND"); + switch_channel_set_state(nchannel, CS_INIT); + switch_channel_set_variable(nchannel, "endpoint_disposition", "OUTBOUND"); *new_session = nsession; status = SWITCH_STATUS_SUCCESS; if (session) { + char *val; switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER); + + if (switch_channel_test_flag(channel, CF_NOMEDIA) && (val = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE))) { + switch_channel_set_variable(nchannel, SWITCH_L_SDP_VARIABLE, val); + } } done: @@ -1723,7 +1866,6 @@ static void sip_i_state(int status, { char const *l_sdp = NULL, *r_sdp = NULL; - //int audio = nua_active_inactive, video = nua_active_inactive, chat = nua_active_inactive; int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0; int ss_state = nua_callstate_init; switch_channel_t *channel = NULL; @@ -1758,6 +1900,7 @@ static void sip_i_state(int status, if (r_sdp) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Remote SDP:\n%s\n", r_sdp); tech_pvt->remote_sdp_str = switch_core_session_strdup(session, (char *)r_sdp); + switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, (char *) r_sdp); } } @@ -1772,34 +1915,38 @@ static void sip_i_state(int status, case nua_callstate_proceeding: if (channel) { if (r_sdp) { - sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0); - sdp_session_t *sdp; - uint8_t match = 0; - - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = negotiate_sdp(session, sdp); - } - } - - if (parser) { - sdp_parser_free(parser); - } - - - if (match) { - tech_choose_port(tech_pvt); - activate_rtp(tech_pvt); - switch_channel_set_variable(channel, "endpoint_disposition", "EARLY MEDIA"); + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { switch_channel_pre_answer(channel); return; + } else { + sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0); + sdp_session_t *sdp; + uint8_t match = 0; + + if (tech_pvt->num_codecs) { + if ((sdp = sdp_session(parser))) { + match = negotiate_sdp(session, sdp); + } + } + + if (parser) { + sdp_parser_free(parser); + } + + + if (match) { + tech_choose_port(tech_pvt); + activate_rtp(tech_pvt); + switch_channel_set_variable(channel, "endpoint_disposition", "EARLY MEDIA"); + switch_channel_pre_answer(channel); + return; + } + switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS"); + nua_respond(nh, SIP_488_NOT_ACCEPTABLE, + TAG_END()); } - switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS"); - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, - TAG_END()); } } - break; case nua_callstate_completing: nua_ack(nh, TAG_END()); @@ -1807,60 +1954,69 @@ static void sip_i_state(int status, case nua_callstate_received: if (channel) { if (r_sdp) { - sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0); - sdp_session_t *sdp; - uint8_t match = 0; - - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = negotiate_sdp(session, sdp); - } - } - - if (parser) { - sdp_parser_free(parser); - } - - if (match) { - nua_handle_t *bnh; - sip_replaces_t *replaces; - - switch_channel_set_variable(channel, "endpoint_disposition", "RECEIVED"); + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { + switch_channel_set_variable(channel, "endpoint_disposition", "RECEIVED_NOMEDIA"); switch_channel_set_state(channel, CS_INIT); switch_set_flag_locked(tech_pvt, TFLAG_READY); switch_core_session_thread_launch(session); - - if (replaces_str && (replaces = sip_replaces_make(tech_pvt->home, replaces_str)) && (bnh = nua_handle_by_replaces(nua, replaces))) { - sofia_private_t *b_private; - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Attended Transfer\n"); - while (switch_channel_get_state(channel) < CS_EXECUTE) { - switch_yield(10000); + return; + } else { + sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0); + sdp_session_t *sdp; + uint8_t match = 0; + + if (tech_pvt->num_codecs) { + if ((sdp = sdp_session(parser))) { + match = negotiate_sdp(session, sdp); } + } - if ((b_private = nua_handle_fetch(bnh))) { - char *br_b = switch_channel_get_variable(channel, "BRIDGETO"); - char *br_a = switch_core_session_get_uuid(b_private->session); + if (parser) { + sdp_parser_free(parser); + } - if (br_b) { - switch_ivr_uuid_bridge(br_a, br_b); - switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER"); - switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER); + if (match) { + nua_handle_t *bnh; + sip_replaces_t *replaces; + + switch_channel_set_variable(channel, "endpoint_disposition", "RECEIVED"); + switch_channel_set_state(channel, CS_INIT); + switch_set_flag_locked(tech_pvt, TFLAG_READY); + switch_core_session_thread_launch(session); + + if (replaces_str && (replaces = sip_replaces_make(tech_pvt->home, replaces_str)) && (bnh = nua_handle_by_replaces(nua, replaces))) { + sofia_private_t *b_private; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Replaces Attended Transfer\n"); + while (switch_channel_get_state(channel) < CS_EXECUTE) { + switch_yield(10000); + } + + if ((b_private = nua_handle_fetch(bnh))) { + char *br_b = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE); + char *br_a = switch_core_session_get_uuid(b_private->session); + + if (br_b) { + switch_ivr_uuid_bridge(br_a, br_b); + switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER"); + switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER); + } else { + switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR"); + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } } else { switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR"); switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); } - } else { - switch_channel_set_variable(channel, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR"); - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + nua_handle_unref(bnh); } + return; } - return; - } - switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS"); - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, - TAG_END()); + switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS"); + nua_respond(nh, SIP_488_NOT_ACCEPTABLE, + TAG_END()); + } } } @@ -1869,76 +2025,103 @@ static void sip_i_state(int status, break; case nua_callstate_completed: if (tech_pvt && r_sdp) { - sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0); - sdp_session_t *sdp; - uint8_t match = 0; + if (r_sdp) { + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "What should i do?\n%s\n", r_sdp); + return; + } else { + sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0); + sdp_session_t *sdp; + uint8_t match = 0; - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = negotiate_sdp(session, sdp); + if (tech_pvt->num_codecs) { + if ((sdp = sdp_session(parser))) { + match = negotiate_sdp(session, sdp); + } + } + tech_choose_port(tech_pvt); + set_local_sdp(tech_pvt); + tech_set_codec(tech_pvt); + switch_set_flag_locked(tech_pvt, TFLAG_REINVITE); + activate_rtp(tech_pvt); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Reinvite\n"); + if (parser) { + sdp_parser_free(parser); + } } } - tech_choose_port(tech_pvt); - set_local_sdp(tech_pvt); - tech_set_codec(tech_pvt); - switch_set_flag_locked(tech_pvt, TFLAG_REINVITE); - activate_rtp(tech_pvt); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Processing Reinvite\n"); - if (parser) { - sdp_parser_free(parser); - } } break; case nua_callstate_ready: + if (nh == tech_pvt->nh2) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cheater Reinvite!\n"); + switch_set_flag_locked(tech_pvt, TFLAG_REINVITE); + tech_pvt->nh = tech_pvt->nh2; + tech_pvt->nh2 = NULL; + tech_choose_port(tech_pvt); + activate_rtp(tech_pvt); + return; + } + if (channel) { if (r_sdp) { - sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0); - sdp_session_t *sdp; - uint8_t match = 0; - - if (tech_pvt->num_codecs) { - if ((sdp = sdp_session(parser))) { - match = negotiate_sdp(session, sdp); - } - } - - if (parser) { - sdp_parser_free(parser); - } - - - if (match) { + if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) { switch_set_flag_locked(tech_pvt, TFLAG_ANS); - switch_channel_set_variable(channel, "endpoint_disposition", "ANSWER"); - tech_choose_port(tech_pvt); - activate_rtp(tech_pvt); switch_channel_answer(channel); return; - } + } else { + sdp_parser_t *parser = sdp_parse(tech_pvt->home, r_sdp, (int)strlen(r_sdp), 0); + sdp_session_t *sdp; + uint8_t match = 0; - switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS"); - nua_respond(nh, SIP_488_NOT_ACCEPTABLE, - TAG_END()); + if (tech_pvt->num_codecs) { + if ((sdp = sdp_session(parser))) { + match = negotiate_sdp(session, sdp); + } + } + + if (parser) { + sdp_parser_free(parser); + } + + + if (match) { + switch_set_flag_locked(tech_pvt, TFLAG_ANS); + switch_channel_set_variable(channel, "endpoint_disposition", "ANSWER"); + tech_choose_port(tech_pvt); + activate_rtp(tech_pvt); + switch_channel_answer(channel); + return; + } + + switch_channel_set_variable(channel, "endpoint_disposition", "NO CODECS"); + nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END()); + } } else if (switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) { switch_set_flag_locked(tech_pvt, TFLAG_ANS); switch_channel_set_variable(channel, "endpoint_disposition", "ANSWER"); switch_channel_answer(channel); return; } //else probably an ack - } - + break; case nua_callstate_terminating: break; - case nua_callstate_terminated: + case nua_callstate_terminated: if (session) { switch_set_flag_locked(tech_pvt, TFLAG_BYE); - terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__); + if (switch_test_flag(tech_pvt, TFLAG_NOHUP)) { + switch_clear_flag_locked(tech_pvt, TFLAG_NOHUP); + nua_handle_destroy(tech_pvt->nh); + tech_pvt->nh = NULL; + } else { + terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__); + } } break; } - + } @@ -2235,9 +2418,27 @@ static void sip_i_refer(nua_t *nua, if (session) { private_object_t *tech_pvt = NULL; - char *exten = NULL; + char *etmp = NULL, *exten = NULL; + switch_channel_t *channel_a = NULL, *channel_b = NULL; tech_pvt = switch_core_session_get_private(session); + channel_a = switch_core_session_get_channel(session); + + + if (!sip->sip_cseq || !(etmp = switch_core_db_mprintf("refer;id=%u", sip->sip_cseq->cs_seq))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); + goto done; + } + + + if (switch_channel_test_flag(channel_a, CF_NOMEDIA)) { + nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), + SIPTAG_EVENT_STR(etmp), + TAG_END()); + goto done; + } + from = sip->sip_from; to = sip->sip_to; @@ -2256,12 +2457,11 @@ static void sip_i_refer(nua_t *nua, char *rep; if ((rep = strchr(refer_to->r_url->url_headers, '='))) { - switch_channel_t *channel_a = NULL, *channel_b = NULL; char *br_a = NULL, *br_b = NULL; char *buf; rep++; - channel_a = switch_core_session_get_channel(session); + if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) { rep = url_unescape(buf, (const char *) rep); @@ -2272,45 +2472,86 @@ static void sip_i_refer(nua_t *nua, } if ((replaces = sip_replaces_make(tech_pvt->home, rep)) && (bnh = nua_handle_by_replaces(nua, replaces))) { sofia_private_t *b_private; - + + switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep); if ((b_private = nua_handle_fetch(bnh))) { channel_b = switch_core_session_get_channel(b_private->session); - br_a = switch_channel_get_variable(channel_a, "BRIDGETO"); - br_b = switch_channel_get_variable(channel_b, "BRIDGETO"); + br_a = switch_channel_get_variable(channel_a, SWITCH_BRIDGE_VARIABLE); + br_b = switch_channel_get_variable(channel_b, SWITCH_BRIDGE_VARIABLE); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Attended Transfer [%s][%s]\n", br_a, br_b); if (br_a && br_b) { switch_ivr_uuid_bridge(br_a, br_b); switch_channel_set_variable(channel_b, "endpoint_disposition", "ATTENDED_TRANSFER"); - switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER); - switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER"); - switch_channel_hangup(channel_a, SWITCH_CAUSE_ATTENDED_TRANSFER); + + nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), + SIPTAG_EVENT_STR(etmp), + TAG_END()); + } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s][%s]\n", br_a, br_b); - switch_channel_set_variable(channel_b, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR"); - switch_channel_hangup(channel_b, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); - switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR"); - switch_channel_hangup(channel_a, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + private_object_t *tech_pvt_b = (private_object_t *) switch_core_session_get_private(b_private->session); + + if (!br_a && !br_b) { + switch_set_flag_locked(tech_pvt, TFLAG_NOHUP); + switch_set_flag_locked(tech_pvt_b, TFLAG_XFER); + tech_pvt_b->xferto = switch_core_session_strdup(b_private->session, switch_core_session_get_uuid(session)); + } else if (!br_a && br_b) { + switch_core_session_t *bsession; + + if ((bsession = switch_core_session_locate(br_b))) { + private_object_t *b_tech_pvt = switch_core_session_get_private(bsession); + switch_channel_t *b_channel = switch_core_session_get_channel(bsession); + private_object_t *bp_tech_pvt = switch_core_session_get_private(b_private->session); + + switch_core_session_get_uuid(b_private->session); + switch_set_flag_locked(tech_pvt, TFLAG_NOHUP); + + switch_channel_clear_state_handler(b_channel, NULL); + switch_channel_set_state_flag(b_channel, CF_TRANSFER); + switch_channel_set_state(b_channel, CS_TRANSMIT); + + switch_set_flag_locked(tech_pvt, TFLAG_REINVITE); + tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(session, bp_tech_pvt->local_sdp_audio_ip); + tech_pvt->local_sdp_audio_port = bp_tech_pvt->local_sdp_audio_port; + + tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, b_tech_pvt->remote_sdp_audio_ip); + tech_pvt->remote_sdp_audio_port = b_tech_pvt->remote_sdp_audio_port; + activate_rtp(tech_pvt); + + b_tech_pvt->kick = switch_core_session_strdup(bsession, switch_core_session_get_uuid(session)); + + + switch_core_session_rwunlock(bsession); + } + + switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER); + } + + nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), + SIPTAG_EVENT_STR(etmp), + TAG_END()); + } } - nua_handle_unref(bnh); } else { /* the other channel is on a different box, we have to go find them */ - if (exten && (br_a = switch_channel_get_variable(channel_a, "BRIDGETO"))) { - switch_core_session_t *bsession; + if (exten && (br_a = switch_channel_get_variable(channel_a, SWITCH_BRIDGE_VARIABLE))) { + switch_core_session_t *asession; switch_channel_t *channel = switch_core_session_get_channel(session); - if ((bsession = switch_core_session_locate(br_a))) { + if ((asession = switch_core_session_locate(br_a))) { switch_core_session_t *tsession; switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; uint32_t timeout = 60; char *tuuid_str; - channel = switch_core_session_get_channel(bsession); + channel = switch_core_session_get_channel(asession); - exten = switch_core_db_mprintf("sofia/%s/%s@%s:%d", + exten = switch_core_db_mprintf("sofia/%s/%s@%s:%s", profile->name, (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host, @@ -2319,7 +2560,7 @@ static void sip_i_refer(nua_t *nua, switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep); - if (switch_ivr_originate(bsession, + if (switch_ivr_originate(asession, &tsession, &cause, exten, @@ -2329,14 +2570,21 @@ static void sip_i_refer(nua_t *nua, NULL, NULL) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot Create Outgoing Channel! [%s]\n", exten); + nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), + SIPTAG_EVENT_STR(etmp), + TAG_END()); goto done; } - switch_core_session_rwunlock(bsession); + switch_core_session_rwunlock(asession); tuuid_str = switch_core_session_get_uuid(tsession); switch_ivr_uuid_bridge(br_a, tuuid_str); switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER"); - switch_channel_hangup(channel_a, SWITCH_CAUSE_ATTENDED_TRANSFER); + nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), + SIPTAG_EVENT_STR(etmp), + TAG_END()); } else { goto error; } @@ -2344,7 +2592,10 @@ static void sip_i_refer(nua_t *nua, } else { error: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s]\n", br_a); switch_channel_set_variable(channel_a, "endpoint_disposition", "ATTENDED_TRANSFER_ERROR"); - switch_channel_hangup(channel_a, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), + SIPTAG_EVENT_STR(etmp), + TAG_END()); } } } else { @@ -2362,26 +2613,50 @@ static void sip_i_refer(nua_t *nua, switch_channel_t *channel = switch_core_session_get_channel(session); char *br; - switch_channel_set_variable(channel, "endpoint_disposition", "BLIND_TRANSFER"); - switch_channel_hangup(channel, SWITCH_CAUSE_BLIND_TRANSFER); - - if ((br = switch_channel_get_variable(channel, "BRIDGETO"))) { + if ((br = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) { switch_core_session_t *bsession; - + if ((bsession = switch_core_session_locate(br))) { channel = switch_core_session_get_channel(bsession); switch_channel_set_variable(channel, "TRANSFER_FALLBACK", (char *) from->a_user); switch_ivr_session_transfer(bsession, exten, profile->dialplan, profile->context); switch_core_session_rwunlock(bsession); } - } + switch_channel_set_variable(channel, "endpoint_disposition", "BLIND_TRANSFER"); + + nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), + SIPTAG_EVENT_STR(etmp), + TAG_END()); + } else { + exten = switch_core_db_mprintf("sip:%s@%s:%s", + (char *) refer_to->r_url->url_user, + (char *) refer_to->r_url->url_host, + refer_to->r_url->url_port); + tech_pvt->dest = switch_core_session_strdup(session, exten); + + + switch_set_flag_locked(tech_pvt, TFLAG_NOHUP); + + + nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"), + SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), + SIPTAG_EVENT_STR(etmp), + TAG_END()); + + do_xfer_invite(session); + + } } done: - if (strchr(exten, '@')) { + if (exten && strchr(exten, '@')) { switch_core_db_free(exten); } + if (etmp) { + switch_core_db_free(etmp); + } } } @@ -2394,11 +2669,11 @@ static void sip_i_invite(nua_t *nua, tagi_t tags[]) { switch_core_session_t *session = sofia_private ? sofia_private->session : NULL; - //refer_handle_t *refer = sofia_private ? sofia_private->refer : NULL; char key[128] = ""; - if (!session) { + if (!session) { + if ((profile->pflags & PFLAG_AUTH_CALLS)) { if (handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key))) { return; @@ -2510,7 +2785,6 @@ static void sip_i_register(nua_t *nua, sip_t const *sip, tagi_t tags[]) { - //switch_core_session_t *session = sofia_private ? sofia_private->session : NULL; handle_register(nua, profile, nh, sip, REG_REGISTER, NULL, 0); } @@ -2547,15 +2821,11 @@ static void sip_r_register(int status, if ((tech_pvt = switch_core_session_get_private(session)) && switch_test_flag(tech_pvt, TFLAG_REFER)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "received reply from refer\n"); - if (status == 200) { - //crap - } return; } } if (!oreg) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No authentication available!\n"); if (sofia_private->oreg) { nua_handle_destroy(nh); } @@ -2906,9 +3176,7 @@ static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t *thread, void } su_root_step(profile->s_root, 1000); - //su_root_run(profile->s_root); } - if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) { switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp"); diff --git a/src/switch_caller.c b/src/switch_caller.c index 20b2c7fdbd..03ec4e9bbc 100644 --- a/src/switch_caller.c +++ b/src/switch_caller.c @@ -145,55 +145,55 @@ SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_ if (caller_profile->username) { snprintf(header_name, sizeof(header_name), "%s-Username", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->username); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->username); } if (caller_profile->dialplan) { snprintf(header_name, sizeof(header_name), "%s-Dialplan", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->dialplan); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->dialplan); } if (caller_profile->caller_id_name) { snprintf(header_name, sizeof(header_name), "%s-Caller-ID-Name", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->caller_id_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->caller_id_name); } if (caller_profile->caller_id_number) { snprintf(header_name, sizeof(header_name), "%s-Caller-ID-Number", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->caller_id_number); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->caller_id_number); } if (caller_profile->network_addr) { snprintf(header_name, sizeof(header_name), "%s-Network-Addr", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->network_addr); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->network_addr); } if (caller_profile->ani) { snprintf(header_name, sizeof(header_name), "%s-ANI", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->ani); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->ani); } if (caller_profile->ani2) { snprintf(header_name, sizeof(header_name), "%s-ANI2", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->ani2); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->ani2); } if (caller_profile->destination_number) { snprintf(header_name, sizeof(header_name), "%s-Destination-Number", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->destination_number); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->destination_number); } if (caller_profile->uuid) { snprintf(header_name, sizeof(header_name), "%s-Unique-ID", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->uuid); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->uuid); } if (caller_profile->source) { snprintf(header_name, sizeof(header_name), "%s-Source", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->source); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->source); } if (caller_profile->context) { snprintf(header_name, sizeof(header_name), "%s-Context", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->context); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->context); } if (caller_profile->rdnis) { snprintf(header_name, sizeof(header_name), "%s-RDNIS", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->rdnis); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->rdnis); } if (caller_profile->chan_name) { snprintf(header_name, sizeof(header_name), "%s-Channel-Name", prefix); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, caller_profile->chan_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, header_name, "%s", caller_profile->chan_name); } } diff --git a/src/switch_console.c b/src/switch_console.c index c1aa794131..2b2d821f58 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -88,7 +88,7 @@ SWITCH_DECLARE(switch_status_t) switch_console_stream_write(switch_stream_handle ret = -1; } else { ret = 0; - snprintf(end, remaining, data); + snprintf(end, remaining, "%s", data); handle->data_len = strlen(buf); handle->end = (uint8_t *)(handle->data) + handle->data_len; } diff --git a/src/switch_core.c b/src/switch_core.c index 659df3c8d3..3a4345e2fc 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -2456,8 +2456,8 @@ static void switch_core_standard_on_execute(switch_core_session_t *session) if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(session->channel, event); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", extension->current_application->application_name); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", extension->current_application->application_data); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "%s", extension->current_application->application_name); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", extension->current_application->application_data); switch_event_fire(&event); } application_interface->application_function(session, extension->current_application->application_data); diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 6600d4a4d2..85f41a2590 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -1372,7 +1372,7 @@ static void *audio_bridge_thread(switch_thread_t *thread, void *obj) msg.from = __FILE__; switch_core_session_receive_message(session_a, &msg); - switch_channel_set_variable(chan_a, "BRIDGETO", NULL); + switch_channel_set_variable(chan_a, SWITCH_BRIDGE_VARIABLE, NULL); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "BRIDGE THREAD DONE [%s]\n", switch_channel_get_name(chan_a)); switch_channel_clear_flag(chan_a, CF_BRIDGED); @@ -1514,14 +1514,14 @@ static switch_status_t uuid_bridge_on_transmit(switch_core_session_t *session) if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(other_session)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(other_session)); switch_event_fire(&event); } if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(other_channel, event); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "uuid_bridge"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", switch_core_session_get_uuid(session)); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(session)); switch_event_fire(&event); } @@ -1912,7 +1912,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } endfor1: - if (session) { + if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) { switch_codec_t *read_codec = NULL; switch_channel_pre_answer(caller_channel); @@ -1946,7 +1946,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess check_channel_status(peer_channels, peer_sessions, argc, &idx, file, key) && ((time(NULL) - start) < (time_t)timelimit_sec)) { /* read from the channel while we wait if the audio is up on it */ - if (session && (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA))) { + if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA) && + (switch_channel_test_flag(caller_channel, CF_ANSWERED) || switch_channel_test_flag(caller_channel, CF_EARLY_MEDIA))) { switch_status_t status = switch_core_session_read_frame(session, &read_frame, 1000, 0); if (!SWITCH_READ_ACCEPTABLE(status)) { @@ -1964,7 +1965,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } - if (session) { + if (session && !switch_channel_test_flag(caller_channel, CF_NOMEDIA)) { switch_core_session_reset(session); } @@ -1987,6 +1988,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } if (caller_channel && switch_channel_test_flag(peer_channel, CF_ANSWERED)) { + char *val; + + if (switch_channel_test_flag(peer_channel, CF_NOMEDIA) && (val = switch_channel_get_variable(peer_channel, SWITCH_R_SDP_VARIABLE))) { + switch_channel_set_variable(caller_channel, SWITCH_L_SDP_VARIABLE, val); + } switch_channel_answer(caller_channel); } @@ -2042,6 +2048,100 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_originate(switch_core_session_t *sess } +static switch_status_t signal_bridge_on_hangup(switch_core_session_t *session) +{ + char *uuid; + switch_channel_t *channel = NULL; + switch_core_session_t *other_session; + switch_event_t *event; + + channel = switch_core_session_get_channel(session); + assert(channel != NULL); + + if (switch_channel_test_flag(channel, CF_ORIGINATOR)) { + switch_channel_clear_flag(channel, CF_ORIGINATOR); + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } + } + + + if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BRIDGE_VARIABLE)) && (other_session = switch_core_session_locate(uuid))) { + switch_channel_t *other_channel = NULL; + + other_channel = switch_core_session_get_channel(other_session); + assert(other_channel != NULL); + + switch_channel_hangup(other_channel, switch_channel_get_cause(channel)); + switch_core_session_rwunlock(other_session); + } + + return SWITCH_STATUS_SUCCESS; +} + +static const switch_state_handler_table_t signal_bridge_state_handlers = { + /*.on_init */ NULL, + /*.on_ring */ NULL, + /*.on_execute */ NULL, + /*.on_hangup */ signal_bridge_on_hangup, + /*.on_loopback */ NULL, + /*.on_transmit */ NULL, + /*.on_hold */ NULL +}; + + + +SWITCH_DECLARE(switch_status_t) switch_ivr_signal_bridge(switch_core_session_t *session, switch_core_session_t *peer_session) +{ + switch_channel_t *caller_channel, *peer_channel; + switch_event_t *event; + + caller_channel = switch_core_session_get_channel(session); + assert(caller_channel != NULL); + + switch_channel_set_flag(caller_channel, CF_ORIGINATOR); + + peer_channel = switch_core_session_get_channel(peer_session); + assert(peer_channel != NULL); + + switch_channel_set_variable(caller_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session)); + switch_channel_set_variable(peer_channel, SWITCH_SIGNAL_BRIDGE_VARIABLE, switch_core_session_get_uuid(session)); + + switch_channel_clear_state_handler(caller_channel, NULL); + switch_channel_clear_state_handler(peer_channel, NULL); + + switch_channel_add_state_handler(caller_channel, &signal_bridge_state_handlers); + switch_channel_add_state_handler(peer_channel, &signal_bridge_state_handlers); + + + /* fire events that will change the data table from "show channels" */ + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(caller_channel, event); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "signal_bridge"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(peer_session)); + switch_event_fire(&event); + } + + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_EXECUTE) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(peer_channel, event); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application", "signal_bridge"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Application-Data", "%s", switch_core_session_get_uuid(session)); + switch_event_fire(&event); + } + + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(caller_channel, event); + switch_event_fire(&event); + } + + switch_channel_set_state(caller_channel, CS_TRANSMIT); + switch_channel_set_state(peer_channel, CS_TRANSMIT); + + return SWITCH_STATUS_SUCCESS; +} + + SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_session_t *session, switch_core_session_t *peer_session, switch_input_callback_function_t input_callback, @@ -2102,18 +2202,32 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses switch_event_fire(&event); } - msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE; - msg.from = __FILE__; - msg.pointer_arg = session; - - switch_core_session_receive_message(peer_session, &msg); - msg.pointer_arg = peer_session; - switch_core_session_receive_message(session, &msg); - if (switch_core_session_read_lock(peer_session) == SWITCH_STATUS_SUCCESS) { - switch_channel_set_variable(caller_channel, "BRIDGETO", switch_core_session_get_uuid(peer_session)); - switch_channel_set_variable(peer_channel, "BRIDGETO", switch_core_session_get_uuid(session)); + switch_channel_set_variable(caller_channel, SWITCH_BRIDGE_VARIABLE, switch_core_session_get_uuid(peer_session)); + switch_channel_set_variable(peer_channel, SWITCH_BRIDGE_VARIABLE, switch_core_session_get_uuid(session)); + msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE; + msg.from = __FILE__; + msg.pointer_arg = session; + + switch_core_session_receive_message(peer_session, &msg); + + if (!msg.pointer_arg) { + status = SWITCH_STATUS_FALSE; + switch_core_session_rwunlock(peer_session); + goto done; + } + + msg.pointer_arg = peer_session; + switch_core_session_receive_message(session, &msg); + + if (!msg.pointer_arg) { + status = SWITCH_STATUS_FALSE; + switch_core_session_rwunlock(peer_session); + goto done; + } + + switch_channel_set_private(peer_channel, "_bridge_", other_audio_thread); switch_channel_set_state(peer_channel, CS_LOOPBACK); audio_bridge_thread(NULL, (void *) this_audio_thread); @@ -2164,6 +2278,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses switch_channel_hangup(peer_channel, SWITCH_CAUSE_NO_ANSWER); } + done: return status; } @@ -2219,6 +2334,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_ { switch_channel_t *channel; switch_caller_profile_t *profile, *new_profile; + switch_core_session_message_t msg = {0}; assert(session != NULL); assert(extension != NULL); @@ -2245,6 +2361,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_ switch_channel_set_caller_profile(channel, new_profile); switch_channel_set_flag(channel, CF_TRANSFER); switch_channel_set_state(channel, CS_RING); + + msg.message_id = SWITCH_MESSAGE_INDICATE_TRANSFER; + msg.from = __FILE__; + switch_core_session_receive_message(session, &msg); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Transfer %s to %s[%s@%s]\n", switch_channel_get_name(channel), dialplan, extension, context); return SWITCH_STATUS_SUCCESS; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 4aa667c5ad..c9a9f86213 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -329,6 +329,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_set_local_address(switch_rtp_t *rtp_s return SWITCH_STATUS_SOCKERR; } + if (switch_socket_opt_set(rtp_session->sock, SWITCH_SO_REUSEADDR, 1) != SWITCH_STATUS_SUCCESS) { + *err = "Socket Error!"; + return SWITCH_STATUS_FALSE; + } + if (switch_socket_bind(rtp_session->sock, rtp_session->local_addr) != SWITCH_STATUS_SUCCESS) { *err = "Bind Error!"; return SWITCH_STATUS_FALSE; diff --git a/src/switch_utils.c b/src/switch_utils.c index ca5b54e08e..14f54d33a6 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -72,6 +72,45 @@ SWITCH_DECLARE(unsigned char) switch_char_to_rfc2833(char key) return '\0'; } +SWITCH_DECLARE(char *) switch_escape_char(switch_memory_pool_t *pool, char *in, char *delim, char esc) +{ + char *data, *p, *d; + int count = 1, i = 0; + + p = in; + while(*p) { + d = delim; + while (*d) { + if (*p == *d) { + count++; + } + d++; + } + p++; + } + + if (count == 1) { + return in; + } + + data = switch_core_alloc(pool, strlen(in) + count); + + p = in; + while(*p) { + d = delim; + while (*d) { + if (*p == *d) { + data[i++] = esc; + } + d++; + } + data[i++] = *p; + p++; + } + return data; +} + + SWITCH_DECLARE(unsigned int) switch_separate_string(char *buf, char delim, char **array, int arraylen) { int argc;