From 0d23976f2a46b5f98511f71eae8735dcc0b1fc1f Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 6 Oct 2006 22:39:49 +0000 Subject: [PATCH] Insane amounts of yucky satanic code to make transfer and that kind of thing work. Transfers work better when both legs of the call live in thier own channel eg bridged calls A -> B where you want a to make B -> C when you route a call to an IVR or playback app you are not really bridging you have A all alone executing the script so it's hard to transfer that. I do have it aparently working but it's goofy and you are better off putting your IVR on it's own switch so they are all inbound calls then you have A -> B -> IVR now A can happily transfer B who can stay on line with IVR without stopping the execution. You can also accomplish this by calling in a loop back to the same box if you dont want to have 2 boxes. Also the beginning effort at bridging calls with no media is here set this magic variable in your dialplan to convince mod_sofia to pass A's sdp as it's own to B and return B's sdp back to A on 200 or 183 You will need a new sofia tarball for this version There is a bunch of other odds and ends added like a function or 2 etc Oh, And don't be suprised if it introduces all kinds of bugs! git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@2992 d0543943-73ff-0310-b7d9-9358b9ac24b2 --- src/include/switch_ivr.h | 7 + src/include/switch_types.h | 15 +- src/include/switch_utils.h | 10 + .../mod_bridgecall/mod_bridgecall.c | 17 +- src/mod/endpoints/mod_sofia/mod_sofia.c | 620 +++++++++++++----- src/switch_caller.c | 26 +- src/switch_console.c | 2 +- src/switch_core.c | 4 +- src/switch_ivr.c | 153 ++++- src/switch_rtp.c | 5 + src/switch_utils.c | 39 ++ 11 files changed, 683 insertions(+), 215 deletions(-) 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;