Freeswitch-trunk
Threads by month
- ----- 2026 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
March 2007
- 3 participants
- 369 discussions
31 Mar '07
Author: mikej
Date: Sat Mar 31 15:01:33 2007
New Revision: 4819
Added:
freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h
freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c
freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c
freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c
freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_reg.c
Modified:
freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile
freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c
freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.vcproj
Log:
breaking up is hard to do
Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile (original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/Makefile Sat Mar 31 15:01:33 2007
@@ -12,6 +12,7 @@
LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/soa -I$(SOFIAUA_DIR)/sresolv
LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/stun -I$(SOFIAUA_DIR)/su
LOCAL_CFLAGS += -I$(SOFIAUA_DIR)/tport -I$(SOFIAUA_DIR)/url
+LOCAL_OBJS=sofia.o sofia_glue.o sofia_presence.o sofia_reg.o
SOFIALA=$(SOFIAUA_DIR)/libsofia-sip-ua.la
Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c (original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c Sat Mar 31 15:01:33 2007
@@ -36,5776 +36,947 @@
/* Best viewed in a 160 x 60 VT100 Terminal or so the line below at least fits across your screen*/
/*************************************************************************************************************************************************************/
+#include "mod_sofia.h"
-/*Defines etc..*/
-/*************************************************************************************************************************************************************/
-#define HAVE_APR
-#include <switch.h>
-static const switch_state_handler_table_t noop_state_handler = { 0 };
-struct outbound_reg;
-typedef struct outbound_reg outbound_reg_t;
-
-struct sofia_profile;
-typedef struct sofia_profile sofia_profile_t;
-#define NUA_MAGIC_T sofia_profile_t
-
-struct sofia_private {
- char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1];
- outbound_reg_t *gateway;
-};
-
-typedef struct sofia_private sofia_private_t;
-
-struct private_object;
-typedef struct private_object private_object_t;
-#define NUA_HMAGIC_T sofia_private_t
-
-#define MY_EVENT_REGISTER "sofia::register"
-#define MY_EVENT_EXPIRE "sofia::expire"
-#define MULTICAST_EVENT "multicast::event"
-#define SOFIA_REPLACES_HEADER "_sofia_replaces_"
-#define SOFIA_USER_AGENT "FreeSWITCH(mod_sofia)"
-#define SOFIA_CHAT_PROTO "sip"
-#define SOFIA_SIP_HEADER_PREFIX "sip_h_"
-#define SOFIA_SIP_HEADER_PREFIX_T "~sip_h_"
-#define SOFIA_DEFAULT_PORT "5060"
-
-#include <sofia-sip/nua.h>
-#include <sofia-sip/sip_status.h>
-#include <sofia-sip/sdp.h>
-#include <sofia-sip/sip_protos.h>
-#include <sofia-sip/auth_module.h>
-#include <sofia-sip/su_md5.h>
-#include <sofia-sip/su_log.h>
-#include <sofia-sip/nea.h>
-#include <sofia-sip/msg_addr.h>
-
-extern su_log_t tport_log[];
+struct sofia_globals globals;
static switch_frame_t silence_frame = { 0 };
static char silence_data[13] = "";
-static char reg_sql[] =
- "CREATE TABLE sip_registrations (\n"
- " user VARCHAR(255),\n"
- " host VARCHAR(255),\n"
- " contact VARCHAR(1024),\n"
- " status VARCHAR(255),\n"
- " rpid VARCHAR(255),\n"
- " expires INTEGER(8)" ");\n";
-
-
-static char sub_sql[] =
- "CREATE TABLE sip_subscriptions (\n"
- " proto VARCHAR(255),\n"
- " user VARCHAR(255),\n"
- " host VARCHAR(255),\n"
- " sub_to_user VARCHAR(255),\n"
- " sub_to_host VARCHAR(255),\n"
- " event VARCHAR(255),\n"
- " contact VARCHAR(1024),\n"
- " call_id VARCHAR(255),\n"
- " full_from VARCHAR(255),\n"
- " full_via VARCHAR(255),\n"
- " expires INTEGER(8)" ");\n";
-
-
-static char auth_sql[] =
- "CREATE TABLE sip_authentication (\n"
- " user VARCHAR(255),\n"
- " host VARCHAR(255),\n"
- " passwd VARCHAR(255),\n"
- " nonce VARCHAR(255),\n"
- " expires INTEGER(8)"
- ");\n";
-
-static const char modname[] = "mod_sofia";
#define STRLEN 15
static switch_memory_pool_t *module_pool = NULL;
-#define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);}
-#define set_anchor(t,m) if (t->Anchor) {delete t->Anchor;} t->Anchor = new SipMessage(m);
-
-
-/* Local Structures */
-/*************************************************************************************************************************************************************/
-struct sip_alias_node {
- char *url;
- nua_t *nua;
- struct sip_alias_node *next;
-};
-
-typedef struct sip_alias_node sip_alias_node_t;
-
-typedef enum {
- PFLAG_AUTH_CALLS = (1 << 0),
- PFLAG_BLIND_REG = (1 << 1),
- PFLAG_AUTH_ALL = (1 << 2),
- PFLAG_FULL_ID = (1 << 3),
- PFLAG_PRESENCE = (1 << 4),
- PFLAG_PASS_RFC2833 = (1 << 5),
- PFLAG_DISABLE_TRANSCODING = (1 << 6)
-} PFLAGS;
-
-typedef enum {
- TFLAG_IO = (1 << 0),
- TFLAG_CHANGE_MEDIA = (1 << 1),
- TFLAG_OUTBOUND = (1 << 2),
- TFLAG_READING = (1 << 3),
- TFLAG_WRITING = (1 << 4),
- TFLAG_HUP = (1 << 5),
- TFLAG_RTP = (1 << 6),
- TFLAG_BYE = (1 << 7),
- TFLAG_ANS = (1 << 8),
- TFLAG_EARLY_MEDIA = (1 << 9),
- TFLAG_SECURE = (1 << 10),
- TFLAG_VAD_IN = (1 << 11),
- TFLAG_VAD_OUT = (1 << 12),
- TFLAG_VAD = (1 << 13),
- TFLAG_TIMER = (1 << 14),
- TFLAG_READY = (1 << 15),
- TFLAG_REINVITE = (1 << 16),
- TFLAG_REFER = (1 << 17),
- TFLAG_NOHUP = (1 << 18),
- TFLAG_XFER = (1 << 19),
- TFLAG_NOMEDIA = (1 << 20),
- TFLAG_BUGGY_2833 = (1 << 21),
- TFLAG_SIP_HOLD = (1 << 22),
- TFLAG_INB_NOMEDIA = (1 << 23),
- TFLAG_LATE_NEGOTIATION = (1 << 24)
-} TFLAGS;
-
-static struct {
- switch_hash_t *profile_hash;
- switch_hash_t *gateway_hash;
- switch_mutex_t *hash_mutex;
- uint32_t callid;
- int32_t running;
- switch_mutex_t *mutex;
- char guess_ip[80];
-} globals;
-
-typedef enum {
- REG_FLAG_AUTHED = (1 << 0),
-} reg_flags_t;
-
-typedef enum {
- REG_STATE_UNREGED,
- REG_STATE_TRYING,
- REG_STATE_REGISTER,
- REG_STATE_REGED,
- REG_STATE_FAILED,
- REG_STATE_EXPIRED
-} reg_state_t;
-
-struct outbound_reg {
- sofia_private_t *sofia_private;
- nua_handle_t *nh;
- sofia_profile_t *profile;
- char *name;
- char *register_scheme;
- char *register_realm;
- char *register_username;
- char *register_password;
- char *register_from;
- char *register_contact;
- char *register_to;
- char *register_proxy;
- char *register_context;
- char *expires_str;
- uint32_t freq;
- time_t expires;
- time_t retry;
- uint32_t flags;
- reg_state_t state;
- switch_memory_pool_t *pool;
- struct outbound_reg *next;
-};
-
-
-struct sofia_profile {
- int debug;
- char *name;
- char *dbname;
- char *dialplan;
- char *context;
- char *extrtpip;
- char *rtpip;
- char *sipip;
- char *extsipip;
- char *username;
- char *url;
- char *bindurl;
- char *sipdomain;
- char *timer_name;
- char *hold_music;
- int sip_port;
- char *codec_string;
- int running;
- int codec_ms;
- int dtmf_duration;
- unsigned int flags;
- unsigned int pflags;
- uint32_t max_calls;
- uint32_t nonce_ttl;
- nua_t *nua;
- switch_memory_pool_t *pool;
- su_root_t *s_root;
- sip_alias_node_t *aliases;
- switch_payload_t te;
- switch_payload_t cng_pt;
- uint32_t codec_flags;
- switch_mutex_t *ireg_mutex;
- switch_mutex_t *gateway_mutex;
- outbound_reg_t *gateways;
- su_home_t *home;
- switch_hash_t *profile_hash;
- switch_hash_t *chat_hash;
-};
-
-
-struct private_object {
- sofia_private_t *sofia_private;
- uint32_t flags;
- switch_payload_t agreed_pt;
- switch_core_session_t *session;
- switch_frame_t read_frame;
- char *codec_order[SWITCH_MAX_CODECS];
- int codec_order_last;
- const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
- int num_codecs;
- switch_codec_t read_codec;
- switch_codec_t write_codec;
- uint32_t codec_ms;
- switch_caller_profile_t *caller_profile;
- uint32_t timestamp_send;
- //int32_t timestamp_recv;
- switch_rtp_t *rtp_session;
- int ssrc;
- //switch_time_t last_read;
- sofia_profile_t *profile;
- char *local_sdp_audio_ip;
- switch_port_t local_sdp_audio_port;
- char *remote_sdp_audio_ip;
- switch_port_t remote_sdp_audio_port;
- char *adv_sdp_audio_ip;
- switch_port_t adv_sdp_audio_port;
- char *proxy_sdp_audio_ip;
- switch_port_t proxy_sdp_audio_port;
- char *from_uri;
- char *to_uri;
- char *from_address;
- char *to_address;
- char *callid;
- char *far_end_contact;
- char *contact_url;
- char *from_str;
- char *rm_encoding;
- char *rm_fmtp;
- char *fmtp_out;
- char *remote_sdp_str;
- char *local_sdp_str;
- char *dest;
- char *dest_to;
- char *key;
- char *xferto;
- char *kick;
- char *origin;
- char *hash_key;
- char *chat_from;
- char *chat_to;
- char *e_dest;
- char *call_id;
- unsigned long rm_rate;
- switch_payload_t pt;
- switch_mutex_t *flag_mutex;
- switch_payload_t te;
- switch_payload_t bte;
- switch_payload_t cng_pt;
- switch_payload_t bcng_pt;
- nua_handle_t *nh;
- nua_handle_t *nh2;
- su_home_t *home;
- sip_contact_t *contact;
-};
-
-/* Function Prototypes */
-/*************************************************************************************************************************************************************/
static switch_status_t sofia_on_init(switch_core_session_t *session);
-static switch_status_t sofia_on_hangup(switch_core_session_t *session);
static switch_status_t sofia_on_loopback(switch_core_session_t *session);
-
static switch_status_t sofia_on_transmit(switch_core_session_t *session);
-
static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session,
switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
switch_memory_pool_t **pool);
-
static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id);
-
static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id);
-
-static switch_status_t config_sofia(int reload);
-
static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig);
-static switch_status_t activate_rtp(private_object_t * tech_pvt);
-
-static void deactivate_rtp(private_object_t * tech_pvt);
-
-static void set_local_sdp(private_object_t * tech_pvt, char *ip, uint32_t port, char *sr, int force);
-
-static void tech_set_codecs(private_object_t * tech_pvt);
-static void attach_private(switch_core_session_t *session, sofia_profile_t * profile, private_object_t * tech_pvt, const char *channame);
-
-static void terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line);
-
-static switch_status_t tech_choose_port(private_object_t * tech_pvt);
-
-static switch_status_t do_invite(switch_core_session_t *session);
-
-static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t * sdp);
-
-static char *get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex);
-
-static void establish_presence(sofia_profile_t * profile);
-
-static void sip_i_state(int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
-
-
-static void sip_i_refer(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]);
-
-static void sip_i_info(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]);
+/* BODY OF THE MODULE */
+/*************************************************************************************************************************************************************/
-static void sip_i_invite(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
-static void sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+/*
+ State methods they get called when the state changes to the specific state
+ returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
+ so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
+*/
+static switch_status_t sofia_on_init(switch_core_session_t *session)
+{
+ private_object_t *tech_pvt;
+ switch_channel_t *channel = NULL;
-static void event_callback(nua_event_t event,
- int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+ 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);
-static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t * thread, void *obj);
+ tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
-static void launch_profile_thread(sofia_profile_t * profile);
+ 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);
+ sofia_glue_tech_absorb_sdp(tech_pvt);
+ }
-static switch_status_t chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint);
+ if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+ if (sofia_glue_do_invite(session) != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_FALSE;
+ }
+ }
-/* BODY OF THE MODULE */
-/*************************************************************************************************************************************************************/
+ /* Move Channel's State Machine to RING */
+ switch_channel_set_state(channel, CS_RING);
+ return SWITCH_STATUS_SUCCESS;
+}
-typedef enum {
- AUTH_OK,
- AUTH_FORBIDDEN,
- AUTH_STALE,
-} auth_res_t;
+static switch_status_t sofia_on_ring(switch_core_session_t *session)
+{
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
-static sofia_profile_t *find_profile(char *key)
-{
- static sofia_profile_t *profile;
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
- switch_mutex_lock(globals.hash_mutex);
- profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, key);
- switch_mutex_unlock(globals.hash_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA RING\n");
- return profile;
+ return SWITCH_STATUS_SUCCESS;
}
-static void add_profile(char *key, sofia_profile_t * profile)
-{
- switch_mutex_lock(globals.hash_mutex);
- switch_core_hash_insert(globals.profile_hash, key, profile);
- switch_mutex_unlock(globals.hash_mutex);
-}
-static outbound_reg_t *find_gateway(char *key)
+static switch_status_t sofia_on_execute(switch_core_session_t *session)
{
- outbound_reg_t *gateway;
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
- switch_mutex_lock(globals.hash_mutex);
- gateway = (outbound_reg_t *) switch_core_hash_find(globals.gateway_hash, key);
- switch_mutex_unlock(globals.hash_mutex);
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
- return gateway;
-}
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
-static void add_gateway(char *key, outbound_reg_t * gateway)
-{
- switch_mutex_lock(globals.hash_mutex);
- switch_core_hash_insert(globals.gateway_hash, key, gateway);
- switch_mutex_unlock(globals.hash_mutex);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA EXECUTE\n");
+
+ return SWITCH_STATUS_SUCCESS;
}
-static char *get_url_from_contact(char *buf, uint8_t to_dup)
+// map QSIG cause codes to SIP from RFC4497 section 8.4.1
+static int hangup_cause_to_sip(switch_call_cause_t cause)
{
- char *url = NULL, *e;
-
- if ((url = strchr(buf, '<')) && (e = strchr(url, '>'))) {
- url++;
- if (to_dup) {
- url = strdup(url);
- e = strchr(url, '>');
- }
-
- *e = '\0';
+ switch (cause) {
+ case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
+ case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
+ return 404;
+ case SWITCH_CAUSE_USER_BUSY:
+ return 486;
+ case SWITCH_CAUSE_NO_USER_RESPONSE:
+ return 408;
+ case SWITCH_CAUSE_NO_ANSWER:
+ return 480;
+ case SWITCH_CAUSE_SUBSCRIBER_ABSENT:
+ return 480;
+ case SWITCH_CAUSE_CALL_REJECTED:
+ return 603;
+ case SWITCH_CAUSE_NUMBER_CHANGED:
+ case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION:
+ return 410;
+ case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
+ return 502;
+ case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
+ return 484;
+ case SWITCH_CAUSE_FACILITY_REJECTED:
+ return 501;
+ case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
+ return 480;
+ case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
+ case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
+ case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
+ case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE:
+ case SWITCH_CAUSE_SWITCH_CONGESTION:
+ return 503;
+ case SWITCH_CAUSE_OUTGOING_CALL_BARRED:
+ case SWITCH_CAUSE_INCOMING_CALL_BARRED:
+ case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH:
+ return 403;
+ case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL:
+ return 503;
+ case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL:
+ return 488;
+ case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
+ case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED:
+ return 501;
+ case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
+ return 503;
+ case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE:
+ return 504;
+ case SWITCH_CAUSE_ORIGINATOR_CANCEL:
+ return 487;
+ default:
+ return 480;
}
- return url;
}
-
-static auth_res_t parse_auth(sofia_profile_t * profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen)
+switch_status_t sofia_on_hangup(switch_core_session_t *session)
{
- int indexnum;
- const char *cur;
- su_md5_t ctx;
- char uridigest[2 * SU_MD5_DIGEST_SIZE + 1];
- char bigdigest[2 * SU_MD5_DIGEST_SIZE + 1];
- char *nonce, *uri, *qop, *cnonce, *nc, *response, *input = NULL, *input2 = NULL;
- auth_res_t ret = AUTH_FORBIDDEN;
- char *npassword = NULL;
- int cnt = 0;
- nonce = uri = qop = cnonce = nc = response = NULL;
-
- if (authorization->au_params) {
- for (indexnum = 0; (cur = authorization->au_params[indexnum]); indexnum++) {
- char *var, *val, *p, *work;
- var = val = work = NULL;
- if ((work = strdup(cur))) {
- var = work;
- if ((val = strchr(var, '='))) {
- *val++ = '\0';
- while (*val == '"') {
- *val++ = '\0';
- }
- if ((p = strchr(val, '"'))) {
- *p = '\0';
- }
+ switch_core_session_t *a_session;
+ private_object_t *tech_pvt;
+ switch_channel_t *channel = NULL;
+ switch_call_cause_t cause;
+ int sip_cause;
- if (!strcasecmp(var, "nonce")) {
- nonce = strdup(val);
- cnt++;
- } else if (!strcasecmp(var, "uri")) {
- uri = strdup(val);
- cnt++;
- } else if (!strcasecmp(var, "qop")) {
- qop = strdup(val);
- cnt++;
- } else if (!strcasecmp(var, "cnonce")) {
- cnonce = strdup(val);
- cnt++;
- } else if (!strcasecmp(var, "response")) {
- response = strdup(val);
- cnt++;
- } else if (!strcasecmp(var, "nc")) {
- nc = strdup(val);
- cnt++;
- }
- }
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
- free(work);
- }
- }
- }
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
- if (cnt != 6) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Authorization header!\n");
- goto end;
- }
+ cause = switch_channel_get_cause(channel);
+ sip_cause = hangup_cause_to_sip(cause);
- if (switch_strlen_zero(np)) {
- if (!get_auth_data(profile->dbname, nonce, np, nplen, profile->ireg_mutex)) {
- ret = AUTH_STALE;
- goto end;
- }
- }
+ sofia_glue_deactivate_rtp(tech_pvt);
- npassword = np;
+ 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));
- if ((input = switch_mprintf("%s:%q", regstr, uri))) {
- su_md5_init(&ctx);
- su_md5_strupdate(&ctx, input);
- su_md5_hexdigest(&ctx, uridigest);
- su_md5_deinit(&ctx);
+ if (tech_pvt->hash_key) {
+ switch_core_hash_delete(tech_pvt->profile->chat_hash, tech_pvt->hash_key);
}
- if ((input2 = switch_mprintf("%q:%q:%q:%q:%q:%q", npassword, nonce, nc, cnonce, qop, uridigest))) {
- memset(&ctx, 0, sizeof(ctx));
- su_md5_init(&ctx);
- su_md5_strupdate(&ctx, input2);
- su_md5_hexdigest(&ctx, bigdigest);
- su_md5_deinit(&ctx);
+ if (tech_pvt->kick && (a_session = switch_core_session_locate(tech_pvt->kick))) {
+ switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
+ switch_channel_hangup(a_channel, switch_channel_get_cause(channel));
+ switch_core_session_rwunlock(a_session);
+ }
- if (!strcasecmp(bigdigest, response)) {
- ret = AUTH_OK;
- } else {
- ret = AUTH_FORBIDDEN;
+ if (tech_pvt->nh) {
+ if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
+ if (switch_test_flag(tech_pvt, TFLAG_ANS)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending BYE to %s\n", switch_channel_get_name(channel));
+ nua_bye(tech_pvt->nh, TAG_END());
+ } else {
+ if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to INVITE with: %d\n", sip_cause);
+ nua_respond(tech_pvt->nh, sip_cause, NULL, TAG_END());
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel));
+ nua_cancel(tech_pvt->nh, TAG_END());
+ }
+ }
+ switch_set_flag_locked(tech_pvt, TFLAG_BYE);
}
}
- end:
- switch_safe_free(input);
- switch_safe_free(input2);
- switch_safe_free(nonce);
- switch_safe_free(uri);
- switch_safe_free(qop);
- switch_safe_free(cnonce);
- switch_safe_free(nc);
- switch_safe_free(response);
-
- return ret;
-
-}
-
-
-static void execute_sql(char *dbname, char *sql, switch_mutex_t * mutex)
-{
- switch_core_db_t *db;
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
- if (mutex) {
- switch_mutex_lock(mutex);
+ if (tech_pvt->home) {
+ su_home_unref(tech_pvt->home);
+ tech_pvt->home = NULL;
}
- if (!(db = switch_core_db_open_file(dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname);
- goto end;
+ if (tech_pvt->sofia_private) {
+ *tech_pvt->sofia_private->uuid = '\0';
}
- switch_core_db_persistant_execute(db, sql, 25);
- switch_core_db_close(db);
- end:
- if (mutex) {
- switch_mutex_unlock(mutex);
- }
+ return SWITCH_STATUS_SUCCESS;
}
-
-struct callback_t {
- char *val;
- switch_size_t len;
- int matches;
-};
-
-static int find_callback(void *pArg, int argc, char **argv, char **columnNames)
+static switch_status_t sofia_on_loopback(switch_core_session_t *session)
{
- struct callback_t *cbt = (struct callback_t *) pArg;
-
- switch_copy_string(cbt->val, argv[0], cbt->len);
- cbt->matches++;
- return 0;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA LOOPBACK\n");
+ return SWITCH_STATUS_SUCCESS;
}
-static int del_callback(void *pArg, int argc, char **argv, char **columnNames)
+static switch_status_t sofia_on_transmit(switch_core_session_t *session)
{
- switch_event_t *s_event;
-
- if (argc >= 3) {
- if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", argv[0]);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "user", "%s", argv[1]);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "host", "%s", argv[2]);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", argv[3]);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%s", argv[4]);
- switch_event_fire(&s_event);
- }
- }
- return 0;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA TRANSMIT\n");
+ return SWITCH_STATUS_SUCCESS;
}
-static void check_expire(switch_core_db_t *db, sofia_profile_t * profile, time_t now)
+static switch_status_t sofia_answer_channel(switch_core_session_t *session)
{
- char sql[1024];
- char *errmsg;
+ private_object_t *tech_pvt;
+ switch_channel_t *channel = NULL;
+ switch_status_t status;
- if (!db) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
- return;
- }
+ assert(session != NULL);
- switch_mutex_lock(profile->ireg_mutex);
- snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires < %ld", profile->name, (long) now);
- switch_core_db_exec(db, sql, del_callback, NULL, &errmsg);
-
- if (errmsg) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", sql, errmsg);
- switch_safe_free(errmsg);
- errmsg = NULL;
- }
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
- snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires < %ld", (long) now);
- switch_core_db_persistant_execute(db, sql, 1000);
- snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires < %ld", (long) now);
- switch_core_db_persistant_execute(db, sql, 1000);
- snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires < %ld", (long) now);
- switch_core_db_persistant_execute(db, sql, 1000);
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
- switch_mutex_unlock(profile->ireg_mutex);
+ if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) {
+ switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-}
+ if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
+ char *sdp = NULL;
+ switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+ if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
+ tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
+ }
+ } else {
+ if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
+ char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
+ if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
+ nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+ return SWITCH_STATUS_FALSE;
+ }
+ switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
+ }
-static char *find_reg_url(sofia_profile_t * profile, const char *user, const char *host, char *val, switch_size_t len)
-{
- char *errmsg;
- struct callback_t cbt = { 0 };
- switch_core_db_t *db;
-
- if (!user) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Called with null user!\n");
- return NULL;
- }
-
- if (!(db = switch_core_db_open_file(profile->dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
- return NULL;
- }
-
- cbt.val = val;
- cbt.len = len;
- switch_mutex_lock(profile->ireg_mutex);
- if (host) {
- snprintf(val, len, "select contact from sip_registrations where user='%s' and host='%s'", user, host);
- } else {
- snprintf(val, len, "select contact from sip_registrations where user='%s'", user);
- }
+ if ((status = sofia_glue_tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
+ return status;
+ }
- switch_core_db_exec(db, val, find_callback, &cbt, &errmsg);
+ sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+ sofia_glue_activate_rtp(tech_pvt);
- if (errmsg) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", val, errmsg);
- switch_safe_free(errmsg);
- errmsg = NULL;
+ if (tech_pvt->nh) {
+ if (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,
+ SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+ SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
}
- switch_mutex_unlock(profile->ireg_mutex);
-
- switch_core_db_close(db);
- if (cbt.matches) {
- return val;
- } else {
- return NULL;
- }
+ return SWITCH_STATUS_SUCCESS;
}
-static void set_local_sdp(private_object_t * tech_pvt, char *ip, uint32_t port, char *sr, int force)
+static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id)
{
- char buf[2048];
- switch_time_t now = switch_time_now();
- int ptime = 0;
- int rate = 0;
+ private_object_t *tech_pvt = NULL;
+ switch_channel_t *channel = NULL;
+ int payload = 0;
- if (!force && !ip && !sr && switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
- return;
- }
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
- if (!ip) {
- if (!(ip = tech_pvt->adv_sdp_audio_ip)) {
- ip = tech_pvt->proxy_sdp_audio_ip;
- }
- }
- if (!port) {
- if (!(port = tech_pvt->adv_sdp_audio_port)) {
- port = tech_pvt->proxy_sdp_audio_port;
- }
- }
- if (!sr) {
- sr = "sendrecv";
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
+ return SWITCH_STATUS_FALSE;
}
- snprintf(buf, sizeof(buf),
- "v=0\n"
- "o=FreeSWITCH %d%" SWITCH_TIME_T_FMT " %d%" SWITCH_TIME_T_FMT " IN IP4 %s\n"
- "s=FreeSWITCH\n" "c=IN IP4 %s\n" "t=0 0\n" "a=%s\n" "m=audio %d RTP/AVP", port, now, port, now, ip, ip, sr, port);
-
- if (tech_pvt->rm_encoding) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt);
- } else if (tech_pvt->num_codecs) {
- int i;
- for (i = 0; i < tech_pvt->num_codecs; i++) {
- const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
-
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode);
- if (!ptime) {
- ptime = imp->microseconds_per_frame / 1000;
- }
+ while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+ if (switch_channel_ready(channel)) {
+ switch_yield(10000);
+ } else {
+ return SWITCH_STATUS_GENERR;
}
}
- if (tech_pvt->te > 95) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->te);
- }
- if (tech_pvt->cng_pt) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->cng_pt);
+ tech_pvt->read_frame.datalen = 0;
+ switch_set_flag_locked(tech_pvt, TFLAG_READING);
+
+#if 0
+ if (tech_pvt->last_read) {
+ elapsed = (unsigned int) ((switch_time_now() - tech_pvt->last_read) / 1000);
+ if (elapsed > 60000) {
+ return SWITCH_STATUS_TIMEOUT;
+ }
}
+#endif
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
- if (tech_pvt->rm_encoding) {
- rate = tech_pvt->rm_rate;
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%ld\n", tech_pvt->pt, tech_pvt->rm_encoding, tech_pvt->rm_rate);
- if (tech_pvt->fmtp_out) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->pt, tech_pvt->fmtp_out);
- }
- if (tech_pvt->read_codec.implementation && !ptime) {
- ptime = tech_pvt->read_codec.implementation->microseconds_per_frame / 1000;
+ if (switch_test_flag(tech_pvt, TFLAG_IO)) {
+ switch_status_t status;
+
+ if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+ return SWITCH_STATUS_GENERR;
}
- } else if (tech_pvt->num_codecs) {
- int i;
- for (i = 0; i < tech_pvt->num_codecs; i++) {
- const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
- uint32_t rfc_3551_sucks = imp->samples_per_second;
+ assert(tech_pvt->rtp_session != NULL);
+ tech_pvt->read_frame.datalen = 0;
- if (!rate) {
- rate = imp->samples_per_second;
- }
- if (ptime && ptime != imp->microseconds_per_frame / 1000) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "ptime %u != advertised ptime %u\n", imp->microseconds_per_frame / 1000, ptime);
- }
- if (rfc_3551_sucks && imp->ianacode == 9) {
- rfc_3551_sucks = 8000;
- }
+ while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
+ tech_pvt->read_frame.flags = SFF_NONE;
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame, rfc_3551_sucks);
- if (imp->fmtp) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp);
+ status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame);
+ if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
+ return SWITCH_STATUS_FALSE;
}
- }
- }
-
- if (tech_pvt->te > 95) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te);
- }
- if (tech_pvt->cng_pt) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d CN/%d\n", tech_pvt->cng_pt, rate);
- if (!tech_pvt->rm_encoding) {
- tech_pvt->cng_pt = 0;
- }
- }
- if (ptime) {
- snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime);
- }
- tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, buf);
-}
-static void tech_set_codecs(private_object_t * tech_pvt)
-{
- switch_channel_t *channel;
- char *abs, *codec_string = NULL;
- char *ocodec = NULL;
- if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
- return;
- }
+ payload = tech_pvt->read_frame.payload;
- if (tech_pvt->num_codecs) {
- return;
- }
+#if 0
+ elapsed = (unsigned int) ((switch_time_now() - started) / 1000);
- assert(tech_pvt->session != NULL);
+ if (timeout > -1) {
+ if (elapsed >= (unsigned int) timeout) {
+ return SWITCH_STATUS_BREAK;
+ }
+ }
- channel = switch_core_session_get_channel(tech_pvt->session);
- assert(channel != NULL);
+ elapsed = (unsigned int) ((switch_time_now() - last_act) / 1000);
+ if (elapsed >= hard_timeout) {
+ return SWITCH_STATUS_BREAK;
+ }
+#endif
+ if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
+ char dtmf[128];
+ switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf));
+ switch_channel_queue_dtmf(channel, dtmf);
+ }
- if ((abs = switch_channel_get_variable(channel, "absolute_codec_string"))) {
- codec_string = abs;
- } else {
- if (!(codec_string = switch_channel_get_variable(channel, "codec_string"))) {
- if (tech_pvt->profile->codec_string) {
- codec_string = tech_pvt->profile->codec_string;
- }
- }
+ if (tech_pvt->read_frame.datalen > 0) {
+ size_t bytes = 0;
+ int frames = 1;
- if ((ocodec = switch_channel_get_variable(channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
- if (!codec_string || (tech_pvt->profile->pflags & PFLAG_DISABLE_TRANSCODING)) {
- codec_string = ocodec;
- } else {
- if (!(codec_string = switch_core_session_sprintf(tech_pvt->session, "%s,%s", ocodec, codec_string))) {
- codec_string = ocodec;
+ if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) {
+ if ((bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame)) {
+ frames = (tech_pvt->read_frame.datalen / bytes);
+ }
+ tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_codec.implementation->samples_per_frame);
}
+ break;
}
}
}
- if (codec_string) {
- char *tmp_codec_string;
- if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) {
- tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS);
- tech_pvt->num_codecs =
- switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, SWITCH_MAX_CODECS, tech_pvt->codec_order, tech_pvt->codec_order_last);
- }
- } else {
- tech_pvt->num_codecs =
- switch_loadable_module_get_codecs(switch_core_session_get_pool(tech_pvt->session), tech_pvt->codecs,
- sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0]));
+ switch_clear_flag_locked(tech_pvt, TFLAG_READING);
+
+ if (tech_pvt->read_frame.datalen == 0) {
+ *frame = NULL;
+ return SWITCH_STATUS_GENERR;
}
+ *frame = &tech_pvt->read_frame;
+
+ return SWITCH_STATUS_SUCCESS;
}
-static void attach_private(switch_core_session_t *session, sofia_profile_t * profile, private_object_t * tech_pvt, const char *channame)
+static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id)
{
- switch_channel_t *channel;
- char name[256];
-
- assert(session != NULL);
- assert(profile != NULL);
- assert(tech_pvt != NULL);
+ private_object_t *tech_pvt;
+ switch_channel_t *channel = NULL;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ int bytes = 0, samples = 0, frames = 0;
- switch_core_session_add_stream(session, NULL);
channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
- //switch_channel_set_flag(channel, CF_ACCEPT_CNG);
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
- switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
- switch_mutex_lock(tech_pvt->flag_mutex);
- tech_pvt->flags = profile->flags;
- switch_mutex_unlock(tech_pvt->flag_mutex);
- tech_pvt->profile = profile;
- if (tech_pvt->bte) {
- tech_pvt->te = tech_pvt->bte;
- } else if (!tech_pvt->te) {
- tech_pvt->te = profile->te;
+ while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
+ if (switch_channel_ready(channel)) {
+ switch_yield(10000);
+ } else {
+ return SWITCH_STATUS_GENERR;
+ }
}
- if (tech_pvt->bcng_pt) {
- tech_pvt->cng_pt = tech_pvt->bcng_pt;
- } else if (!tech_pvt->cng_pt) {
- tech_pvt->cng_pt = profile->cng_pt;
+ if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
+ return SWITCH_STATUS_FALSE;
}
- tech_pvt->session = session;
- tech_pvt->home = su_home_new(sizeof(*tech_pvt->home));
+ if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
+ return SWITCH_STATUS_GENERR;
+ }
- switch_core_session_set_private(session, tech_pvt);
+ if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+ switch_set_flag_locked(tech_pvt, TFLAG_WRITING);
- snprintf(name, sizeof(name), "sofia/%s/%s", profile->name, channame);
- switch_channel_set_name(channel, name);
- //tech_set_codecs(tech_pvt);
+ if (!switch_test_flag(frame, SFF_CNG)) {
+ if (tech_pvt->read_codec.implementation->encoded_bytes_per_frame) {
+ bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
+ frames = ((int) frame->datalen / bytes);
+ } else
+ frames = 1;
-}
+ samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
+ }
+#if 0
+ printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n",
+ switch_channel_get_name(channel),
+ tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, tech_pvt->timestamp_send);
+#endif
-static void terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line)
-{
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Term called from line: %d\n", line);
- if (*session) {
- switch_channel_t *channel = switch_core_session_get_channel(*session);
- struct private_object *tech_pvt = NULL;
- unsigned running = switch_core_session_running(*session);
- tech_pvt = switch_core_session_get_private(*session);
+ tech_pvt->timestamp_send += samples;
+ //switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send);
+ switch_rtp_write_frame(tech_pvt->rtp_session, frame, 0);
- if (running) {
- switch_channel_hangup(channel, cause);
- } else {
- if (tech_pvt) {
- sofia_on_hangup(*session);
- }
- if (session && *session) {
- switch_core_session_destroy(session);
- }
- }
- }
+ switch_clear_flag_locked(tech_pvt, TFLAG_WRITING);
+ return status;
}
-static switch_status_t sofia_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool)
+static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig)
{
- char *error;
+ private_object_t *tech_pvt;
+ switch_channel_t *channel = NULL;
- if (!sourceip) {
- return SWITCH_STATUS_FALSE;
- }
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
- if (!strncasecmp(sourceip, "stun:", 5)) {
- char *stun_ip = sourceip + 5;
- if (!stun_ip) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stun Failed! NO STUN SERVER\n");
- return SWITCH_STATUS_FALSE;
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+
+ switch (sig) {
+ case SWITCH_SIG_BREAK:
+ if (switch_rtp_ready(tech_pvt->rtp_session)) {
+ switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK);
}
- if (switch_stun_lookup(ip, port, stun_ip, SWITCH_STUN_DEFAULT_PORT, &error, pool) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stun Failed! %s:%d [%s]\n", stun_ip, SWITCH_STUN_DEFAULT_PORT, error);
- return SWITCH_STATUS_FALSE;
+ break;
+ case SWITCH_SIG_KILL:
+ default:
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+ switch_set_flag_locked(tech_pvt, TFLAG_HUP);
+
+ if (switch_rtp_ready(tech_pvt->rtp_session)) {
+ switch_rtp_kill_socket(tech_pvt->rtp_session);
}
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stun Success [%s]:[%d]\n", *ip, *port);
- } else {
- *ip = sourceip;
+ break;
}
+
return SWITCH_STATUS_SUCCESS;
-}
+}
-static switch_status_t tech_choose_port(private_object_t * tech_pvt)
+static switch_status_t sofia_waitfor_read(switch_core_session_t *session, int ms, int stream_id)
{
- char *ip = tech_pvt->profile->rtpip;
- switch_channel_t *channel;
- switch_port_t sdp_port;
- char tmp[50];
-
- channel = switch_core_session_get_channel(tech_pvt->session);
-
- 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;
-
- if (tech_pvt->profile->extrtpip) {
- if (sofia_ext_address_lookup(&ip, &sdp_port, tech_pvt->profile->extrtpip, switch_core_session_get_pool(tech_pvt->session)) !=
- SWITCH_STATUS_SUCCESS) {
- terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- return SWITCH_STATUS_FALSE;
- }
- }
-
- tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip);
- tech_pvt->adv_sdp_audio_port = sdp_port;
+ private_object_t *tech_pvt;
+ switch_channel_t *channel = NULL;
- snprintf(tmp, sizeof(tmp), "%d", sdp_port);
- switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
- switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+ 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);
return SWITCH_STATUS_SUCCESS;
}
-static switch_status_t do_invite(switch_core_session_t *session)
+
+static switch_status_t sofia_waitfor_write(switch_core_session_t *session, int ms, int stream_id)
{
- char rpid[1024] = { 0 };
- char alert_info[1024] = { 0 };
- char max_forwards[8] = { 0 };
- char *alertbuf;
- char *forwardbuf;
- int forwardval;
private_object_t *tech_pvt;
switch_channel_t *channel = NULL;
- switch_caller_profile_t *caller_profile;
- char *cid_name, *cid_num;
- char *e_dest = NULL;
- const char *holdstr = "";
- switch_stream_handle_t stream = { 0 };
- switch_hash_index_t *hi;
- void *vval;
- char *extra_headers = NULL;
- const void *vvar;
- switch_status_t status = SWITCH_STATUS_FALSE;
- char *rep;
channel = switch_core_session_get_channel(session);
assert(channel != NULL);
- rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
-
tech_pvt = (private_object_t *) switch_core_session_get_private(session);
assert(tech_pvt != NULL);
- caller_profile = switch_channel_get_caller_profile(channel);
-
- cid_name = (char *) caller_profile->caller_id_name;
- cid_num = (char *) caller_profile->caller_id_number;
- tech_set_codecs(tech_pvt);
-
- if (!tech_pvt->from_str) {
- tech_pvt->from_str = switch_core_session_sprintf(tech_pvt->session, "\"%s\" <sip:%s@%s>",
- cid_name,
- cid_num, tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip);
+ return SWITCH_STATUS_SUCCESS;
- }
+}
- if (!tech_pvt->from_str) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
- return SWITCH_STATUS_FALSE;
- }
+static switch_status_t sofia_send_dtmf(switch_core_session_t *session, char *digits)
+{
+ private_object_t *tech_pvt;
-
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+ return switch_rtp_queue_rfc2833(tech_pvt->rtp_session,
+ digits, tech_pvt->profile->dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000));
- if ((alertbuf = switch_channel_get_variable(channel, "alert_info"))) {
- snprintf(alert_info, sizeof(alert_info) - 1, "Alert-Info: %s", alertbuf);
- }
+}
- if ((forwardbuf = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE))) {
- forwardval = atoi(forwardbuf) - 1;
- snprintf(max_forwards, sizeof(max_forwards) - 1, "%d", forwardval);
- }
+static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
+{
+ switch_channel_t *channel;
+ private_object_t *tech_pvt;
+ switch_status_t status;
- if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
- return status;
- }
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
- set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
- switch_set_flag_locked(tech_pvt, TFLAG_READY);
- // forge a RPID for now KHR -- Should wrap this in an if statement so it can be turned on and off
- if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
- const char *priv = "off";
- const char *screen = "no";
- if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NAME)) {
- priv = "name";
- if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
- priv = "yes";
- }
- } else if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
- priv = "yes";
- }
- if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
- screen = "yes";
- }
-
- snprintf(rpid, sizeof(rpid) - 1, "Remote-Party-ID: %s;party=calling;screen=%s;privacy=%s", tech_pvt->from_str, screen, priv);
-
- }
-
- if (!tech_pvt->nh) {
- char *url = get_url_from_contact(tech_pvt->dest, 1);
- tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
- NUTAG_URL(url),
- SIPTAG_TO_STR(tech_pvt->dest_to), SIPTAG_FROM_STR(tech_pvt->from_str), SIPTAG_CONTACT_STR(tech_pvt->profile->url),
- TAG_END());
- switch_safe_free(url);
-
- if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) {
- abort();
- }
- memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private));
- switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid));
- nua_handle_bind(tech_pvt->nh, tech_pvt->sofia_private);
-
- }
-
-
- if (tech_pvt->e_dest && (e_dest = strdup(tech_pvt->e_dest))) {
- char *user = e_dest, *host = NULL;
- char hash_key[256] = "";
-
- if ((host = strchr(user, '@'))) {
- *host++ = '\0';
- }
- snprintf(hash_key, sizeof(hash_key), "%s%s%s", user, host, cid_num);
-
- tech_pvt->chat_from = tech_pvt->from_str;
- tech_pvt->chat_to = tech_pvt->dest;
- tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
- switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
- free(e_dest);
- }
-
- holdstr = switch_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? "*" : "";
-
-
- SWITCH_STANDARD_STREAM(stream);
- for (hi = switch_channel_variable_first(channel, switch_core_session_get_pool(tech_pvt->session)); hi; hi = switch_hash_next(hi)) {
- switch_hash_this(hi, &vvar, NULL, &vval);
- if (vvar && vval) {
- const char *name = vvar;
- char *value = (char *) vval;
-
- if (!strncasecmp(name, SOFIA_SIP_HEADER_PREFIX, strlen(SOFIA_SIP_HEADER_PREFIX))) {
- const char *hname = name + strlen(SOFIA_SIP_HEADER_PREFIX);
- stream.write_function(&stream, "%s: %s\r\n", hname, value);
- }
- }
- }
-
- if (stream.data) {
- extra_headers = stream.data;
- }
-
- nua_invite(tech_pvt->nh,
- TAG_IF(!switch_strlen_zero(rpid), SIPTAG_HEADER_STR(rpid)),
- TAG_IF(!switch_strlen_zero(alert_info), SIPTAG_HEADER_STR(alert_info)),
- TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
- TAG_IF(!switch_strlen_zero(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)),
- //SIPTAG_CONTACT_STR(tech_pvt->profile->url),
- 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)), SOATAG_HOLD(holdstr), TAG_END());
-
- switch_safe_free(stream.data);
-
- return SWITCH_STATUS_SUCCESS;
-
-}
-
-
-
-static void do_xfer_invite(switch_core_session_t *session)
-{
- char rpid[1024];
- 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_session_sprintf(session, "\"%s\" <sip:%s@%s>",
- (char *) caller_profile->caller_id_name,
- (char *) caller_profile->caller_id_number,
- tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : 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());
-
-
- nua_handle_bind(tech_pvt->nh2, tech_pvt->sofia_private);
-
- nua_invite(tech_pvt->nh2,
- TAG_IF(rpid, SIPTAG_HEADER_STR(rpid)),
- SIPTAG_CONTACT_STR(tech_pvt->profile->url),
- 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 tech_absorb_sdp(private_object_t * tech_pvt)
-{
- switch_channel_t *channel;
- char *sdp_str;
-
- channel = switch_core_session_get_channel(tech_pvt->session);
- assert(channel != NULL);
-
- if ((sdp_str = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
- sdp_parser_t *parser;
- sdp_session_t *sdp;
- sdp_media_t *m;
- sdp_connection_t *connection;
-
- if ((parser = sdp_parse(tech_pvt->home, sdp_str, (int) strlen(sdp_str), 0))) {
- if ((sdp = sdp_session(parser))) {
- for (m = sdp->sdp_media; m; m = m->m_next) {
- if (m->m_type != sdp_media_audio) {
- continue;
- }
-
- connection = sdp->sdp_connection;
- if (m->m_connections) {
- connection = m->m_connections;
- }
-
- if (connection) {
- tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, connection->c_address);
- }
- tech_pvt->proxy_sdp_audio_port = (switch_port_t) m->m_port;
- if (tech_pvt->proxy_sdp_audio_ip && tech_pvt->proxy_sdp_audio_port) {
- break;
- }
- }
- }
- sdp_parser_free(parser);
- }
- tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, sdp_str);
- }
-}
-
-/*
- State methods they get called when the state changes to the specific state
- returning SWITCH_STATUS_SUCCESS tells the core to execute the standard state method next
- so if you fully implement the state you can return SWITCH_STATUS_FALSE to skip it.
-*/
-static switch_status_t sofia_on_init(switch_core_session_t *session)
-{
- private_object_t *tech_pvt;
- switch_channel_t *channel = NULL;
-
- 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);
-
- tech_pvt->read_frame.buflen = SWITCH_RTP_MAX_BUF_LEN;
-
- 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);
- tech_absorb_sdp(tech_pvt);
- }
-
- if (switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
- if (do_invite(session) != SWITCH_STATUS_SUCCESS) {
- return SWITCH_STATUS_FALSE;
- }
- }
-
- /* Move Channel's State Machine to RING */
- switch_channel_set_state(channel, CS_RING);
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t sofia_on_ring(switch_core_session_t *session)
-{
- switch_channel_t *channel = NULL;
- private_object_t *tech_pvt = NULL;
-
- 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);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA RING\n");
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-
-static switch_status_t sofia_on_execute(switch_core_session_t *session)
-{
- switch_channel_t *channel = NULL;
- private_object_t *tech_pvt = NULL;
-
- 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);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA EXECUTE\n");
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-// map QSIG cause codes to SIP from RFC4497 section 8.4.1
-static int hangup_cause_to_sip(switch_call_cause_t cause)
-{
- switch (cause) {
- case SWITCH_CAUSE_NO_ROUTE_TRANSIT_NET:
- case SWITCH_CAUSE_NO_ROUTE_DESTINATION:
- return 404;
- case SWITCH_CAUSE_USER_BUSY:
- return 486;
- case SWITCH_CAUSE_NO_USER_RESPONSE:
- return 408;
- case SWITCH_CAUSE_NO_ANSWER:
- return 480;
- case SWITCH_CAUSE_SUBSCRIBER_ABSENT:
- return 480;
- case SWITCH_CAUSE_CALL_REJECTED:
- return 603;
- case SWITCH_CAUSE_NUMBER_CHANGED:
- case SWITCH_CAUSE_REDIRECTION_TO_NEW_DESTINATION:
- return 410;
- case SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER:
- return 502;
- case SWITCH_CAUSE_INVALID_NUMBER_FORMAT:
- return 484;
- case SWITCH_CAUSE_FACILITY_REJECTED:
- return 501;
- case SWITCH_CAUSE_NORMAL_UNSPECIFIED:
- return 480;
- case SWITCH_CAUSE_REQUESTED_CHAN_UNAVAIL:
- case SWITCH_CAUSE_NORMAL_CIRCUIT_CONGESTION:
- case SWITCH_CAUSE_NETWORK_OUT_OF_ORDER:
- case SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE:
- case SWITCH_CAUSE_SWITCH_CONGESTION:
- return 503;
- case SWITCH_CAUSE_OUTGOING_CALL_BARRED:
- case SWITCH_CAUSE_INCOMING_CALL_BARRED:
- case SWITCH_CAUSE_BEARERCAPABILITY_NOTAUTH:
- return 403;
- case SWITCH_CAUSE_BEARERCAPABILITY_NOTAVAIL:
- return 503;
- case SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL:
- return 488;
- case SWITCH_CAUSE_FACILITY_NOT_IMPLEMENTED:
- case SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED:
- return 501;
- case SWITCH_CAUSE_INCOMPATIBLE_DESTINATION:
- return 503;
- case SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE:
- return 504;
- case SWITCH_CAUSE_ORIGINATOR_CANCEL:
- return 487;
- default:
- return 480;
- }
-
-}
-
-static switch_status_t sofia_on_hangup(switch_core_session_t *session)
-{
- switch_core_session_t *a_session;
- private_object_t *tech_pvt;
- switch_channel_t *channel = NULL;
- switch_call_cause_t cause;
- int sip_cause;
-
- 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);
-
- cause = switch_channel_get_cause(channel);
- sip_cause = hangup_cause_to_sip(cause);
-
- deactivate_rtp(tech_pvt);
-
- 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));
-
- if (tech_pvt->hash_key) {
- switch_core_hash_delete(tech_pvt->profile->chat_hash, tech_pvt->hash_key);
- }
-
- if (tech_pvt->kick && (a_session = switch_core_session_locate(tech_pvt->kick))) {
- switch_channel_t *a_channel = switch_core_session_get_channel(a_session);
- switch_channel_hangup(a_channel, switch_channel_get_cause(channel));
- switch_core_session_rwunlock(a_session);
- }
-
- if (tech_pvt->nh) {
- if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
- if (switch_test_flag(tech_pvt, TFLAG_ANS)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending BYE to %s\n", switch_channel_get_name(channel));
- nua_bye(tech_pvt->nh, TAG_END());
- } else {
- if (!switch_test_flag(tech_pvt, TFLAG_OUTBOUND)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Responding to INVITE with: %d\n", sip_cause);
- nua_respond(tech_pvt->nh, sip_cause, NULL, TAG_END());
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending CANCEL to %s\n", switch_channel_get_name(channel));
- nua_cancel(tech_pvt->nh, TAG_END());
- }
- }
- switch_set_flag_locked(tech_pvt, TFLAG_BYE);
- }
- }
-
- switch_clear_flag_locked(tech_pvt, TFLAG_IO);
-
- if (tech_pvt->home) {
- su_home_unref(tech_pvt->home);
- tech_pvt->home = NULL;
- }
-
- if (tech_pvt->sofia_private) {
- *tech_pvt->sofia_private->uuid = '\0';
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t sofia_on_loopback(switch_core_session_t *session)
-{
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA LOOPBACK\n");
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t sofia_on_transmit(switch_core_session_t *session)
-{
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SOFIA TRANSMIT\n");
- return SWITCH_STATUS_SUCCESS;
-}
-
-static void deactivate_rtp(private_object_t * tech_pvt)
-{
- int loops = 0; //, sock = -1;
- if (switch_rtp_ready(tech_pvt->rtp_session)) {
- while (loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
- switch_yield(10000);
- loops++;
- }
- switch_rtp_destroy(&tech_pvt->rtp_session);
- }
-}
-
-static switch_status_t tech_set_codec(private_object_t * tech_pvt, int force)
-{
- switch_channel_t *channel;
-
- if (tech_pvt->read_codec.implementation) {
- if (!force) {
- return SWITCH_STATUS_SUCCESS;
- }
- if (strcasecmp(tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding) ||
- tech_pvt->read_codec.implementation->samples_per_second != tech_pvt->rm_rate) {
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n",
- tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding);
- switch_core_codec_destroy(&tech_pvt->read_codec);
- switch_core_codec_destroy(&tech_pvt->write_codec);
- switch_core_session_reset(tech_pvt->session);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_codec.implementation->iananame);
- return SWITCH_STATUS_SUCCESS;
- }
- }
-
- channel = switch_core_session_get_channel(tech_pvt->session);
- assert(channel != NULL);
-
- if (!tech_pvt->rm_encoding) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec with no name?\n");
- terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- return SWITCH_STATUS_FALSE;
- }
-
- if (switch_core_codec_init(&tech_pvt->read_codec,
- tech_pvt->rm_encoding,
- tech_pvt->rm_fmtp,
- tech_pvt->rm_rate,
- tech_pvt->codec_ms,
- 1,
- SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
- NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
- terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- return SWITCH_STATUS_FALSE;
- } else {
- if (switch_core_codec_init(&tech_pvt->write_codec,
- tech_pvt->rm_encoding,
- tech_pvt->rm_fmtp,
- tech_pvt->rm_rate,
- tech_pvt->codec_ms,
- 1,
- SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
- NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
- terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- return SWITCH_STATUS_FALSE;
- } else {
- int ms;
- tech_pvt->read_frame.rate = tech_pvt->rm_rate;
- ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set Codec %s %s/%ld %d ms\n",
- switch_channel_get_name(channel), tech_pvt->rm_encoding, tech_pvt->rm_rate, tech_pvt->codec_ms);
- tech_pvt->read_frame.codec = &tech_pvt->read_codec;
-
- switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
- switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
- tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out);
- }
- }
- return SWITCH_STATUS_SUCCESS;
-}
-
-
-static switch_status_t activate_rtp(private_object_t * tech_pvt)
-{
- int bw, ms;
- switch_channel_t *channel;
- const char *err = NULL;
- char *val = NULL;
- switch_rtp_flag_t flags;
- switch_status_t status;
- char tmp[50];
- assert(tech_pvt != NULL);
-
- 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;
- }
-
- if ((status = tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
- return status;
- }
-
- bw = tech_pvt->read_codec.implementation->bits_per_second;
- ms = tech_pvt->read_codec.implementation->microseconds_per_frame;
-
- flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_RAW_WRITE | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
-
- if (switch_test_flag(tech_pvt, TFLAG_BUGGY_2833)) {
- flags |= SWITCH_RTP_FLAG_BUGGY_2833;
- }
-
- if ((tech_pvt->profile->pflags & PFLAG_PASS_RFC2833)
- || ((val = switch_channel_get_variable(channel, "pass_rfc2833")) && switch_true(val))) {
- flags |= SWITCH_RTP_FLAG_PASS_RFC2833;
- }
-
- if (tech_pvt->cng_pt) {
- flags |= SWITCH_RTP_FLAG_AUTO_CNG;
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
- switch_channel_get_name(channel),
- tech_pvt->local_sdp_audio_ip,
- tech_pvt->local_sdp_audio_port,
- tech_pvt->remote_sdp_audio_ip,
- tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_codec.implementation->microseconds_per_frame / 1000);
-
- snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
- switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
- switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
-
- if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_REINVITE)) {
- switch_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
-
- if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, &err) !=
- SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP CHANGING DEST TO: [%s:%d]\n",
- tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
- /* Reactivate the NAT buster flag. */
- switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
- }
- return SWITCH_STATUS_SUCCESS;
- }
-
- tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
- tech_pvt->local_sdp_audio_port,
- tech_pvt->remote_sdp_audio_ip,
- tech_pvt->remote_sdp_audio_port,
- tech_pvt->agreed_pt,
- tech_pvt->read_codec.implementation->samples_per_frame,
- tech_pvt->codec_ms * 1000,
- (switch_rtp_flag_t) flags,
- NULL, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session));
-
- if (switch_rtp_ready(tech_pvt->rtp_session)) {
- uint8_t vad_in = switch_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
- uint8_t vad_out = switch_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0;
- uint8_t inb = switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1;
-
- tech_pvt->ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
- switch_set_flag_locked(tech_pvt, TFLAG_RTP);
- switch_set_flag_locked(tech_pvt, TFLAG_IO);
-
- if ((vad_in && inb) || (vad_out && !inb)) {
- switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING);
- switch_set_flag_locked(tech_pvt, TFLAG_VAD);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP Engage VAD for %s ( %s %s )\n",
- switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : "");
- }
-
- if (tech_pvt->te) {
- switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
- }
- if (tech_pvt->cng_pt) {
- switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
- }
-
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
- terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- switch_clear_flag_locked(tech_pvt, TFLAG_IO);
- return SWITCH_STATUS_FALSE;
- }
-
- switch_set_flag_locked(tech_pvt, TFLAG_IO);
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t tech_media(private_object_t * tech_pvt, char *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;
- switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session);
-
- assert(tech_pvt != NULL);
-
- if (switch_strlen_zero(r_sdp)) {
- return SWITCH_STATUS_FALSE;
- }
-
- if (tech_pvt->num_codecs) {
- if ((sdp = sdp_session(parser))) {
- match = negotiate_sdp(tech_pvt->session, sdp);
- }
- }
-
- if (parser) {
- sdp_parser_free(parser);
- }
-
- if (match) {
- if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
- return SWITCH_STATUS_FALSE;
- }
- activate_rtp(tech_pvt);
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA");
- switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
- switch_channel_mark_pre_answered(channel);
- return SWITCH_STATUS_SUCCESS;
- }
-
- return SWITCH_STATUS_FALSE;
-}
-
-
-
-static switch_status_t sofia_answer_channel(switch_core_session_t *session)
-{
- private_object_t *tech_pvt;
- switch_channel_t *channel = NULL;
- switch_status_t status;
-
- assert(session != NULL);
-
- 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);
-
- if (!switch_test_flag(tech_pvt, TFLAG_ANS) && !switch_channel_test_flag(channel, CF_OUTBOUND)) {
- switch_set_flag_locked(tech_pvt, TFLAG_ANS);
-
- if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
- char *sdp = NULL;
- switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
- if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
- tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
- }
- } else {
- if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
- char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
- if (tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
- nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
- return SWITCH_STATUS_FALSE;
- }
- switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
- }
-
- if ((status = tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
- return status;
- }
-
- set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
- activate_rtp(tech_pvt);
-
- if (tech_pvt->nh) {
- if (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,
- SIPTAG_CONTACT_STR(tech_pvt->profile->url),
- SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), NUTAG_INCLUDE_EXTRA_SDP(1), TAG_END());
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-
-static switch_status_t sofia_read_frame(switch_core_session_t *session, switch_frame_t **frame, int timeout, switch_io_flag_t flags, int stream_id)
-{
- private_object_t *tech_pvt = NULL;
- switch_channel_t *channel = NULL;
- int payload = 0;
-
- 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);
-
- if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
- return SWITCH_STATUS_FALSE;
- }
-
- while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
- if (switch_channel_ready(channel)) {
- switch_yield(10000);
- } else {
- return SWITCH_STATUS_GENERR;
- }
- }
-
-
- tech_pvt->read_frame.datalen = 0;
- switch_set_flag_locked(tech_pvt, TFLAG_READING);
-
-#if 0
- if (tech_pvt->last_read) {
- elapsed = (unsigned int) ((switch_time_now() - tech_pvt->last_read) / 1000);
- if (elapsed > 60000) {
- return SWITCH_STATUS_TIMEOUT;
- }
- }
-#endif
-
-
- if (switch_test_flag(tech_pvt, TFLAG_IO)) {
- switch_status_t status;
-
- if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
- return SWITCH_STATUS_GENERR;
- }
-
- assert(tech_pvt->rtp_session != NULL);
- tech_pvt->read_frame.datalen = 0;
-
-
- while (switch_test_flag(tech_pvt, TFLAG_IO) && tech_pvt->read_frame.datalen == 0) {
- tech_pvt->read_frame.flags = SFF_NONE;
-
- status = switch_rtp_zerocopy_read_frame(tech_pvt->rtp_session, &tech_pvt->read_frame);
- if (status != SWITCH_STATUS_SUCCESS && status != SWITCH_STATUS_BREAK) {
- return SWITCH_STATUS_FALSE;
- }
-
-
-
- payload = tech_pvt->read_frame.payload;
-
-#if 0
- elapsed = (unsigned int) ((switch_time_now() - started) / 1000);
-
- if (timeout > -1) {
- if (elapsed >= (unsigned int) timeout) {
- return SWITCH_STATUS_BREAK;
- }
- }
-
- elapsed = (unsigned int) ((switch_time_now() - last_act) / 1000);
- if (elapsed >= hard_timeout) {
- return SWITCH_STATUS_BREAK;
- }
-#endif
- if (switch_rtp_has_dtmf(tech_pvt->rtp_session)) {
- char dtmf[128];
- switch_rtp_dequeue_dtmf(tech_pvt->rtp_session, dtmf, sizeof(dtmf));
- switch_channel_queue_dtmf(channel, dtmf);
- }
-
-
- if (tech_pvt->read_frame.datalen > 0) {
- size_t bytes = 0;
- int frames = 1;
-
- if (!switch_test_flag((&tech_pvt->read_frame), SFF_CNG)) {
- if ((bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame)) {
- frames = (tech_pvt->read_frame.datalen / bytes);
- }
- tech_pvt->read_frame.samples = (int) (frames * tech_pvt->read_codec.implementation->samples_per_frame);
- }
- break;
- }
- }
- }
-
- switch_clear_flag_locked(tech_pvt, TFLAG_READING);
-
- if (tech_pvt->read_frame.datalen == 0) {
- *frame = NULL;
- return SWITCH_STATUS_GENERR;
- }
-
- *frame = &tech_pvt->read_frame;
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-
-static switch_status_t sofia_write_frame(switch_core_session_t *session, switch_frame_t *frame, int timeout, switch_io_flag_t flags, int stream_id)
-{
- private_object_t *tech_pvt;
- switch_channel_t *channel = NULL;
- switch_status_t status = SWITCH_STATUS_SUCCESS;
- int bytes = 0, samples = 0, frames = 0;
-
- 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);
-
- while (!(tech_pvt->read_codec.implementation && switch_rtp_ready(tech_pvt->rtp_session))) {
- if (switch_channel_ready(channel)) {
- switch_yield(10000);
- } else {
- return SWITCH_STATUS_GENERR;
- }
- }
-
- if (switch_test_flag(tech_pvt, TFLAG_HUP)) {
- return SWITCH_STATUS_FALSE;
- }
-
- if (!switch_test_flag(tech_pvt, TFLAG_RTP)) {
- return SWITCH_STATUS_GENERR;
- }
-
- if (!switch_test_flag(tech_pvt, TFLAG_IO)) {
- return SWITCH_STATUS_SUCCESS;
- }
-
- switch_set_flag_locked(tech_pvt, TFLAG_WRITING);
-
- if (!switch_test_flag(frame, SFF_CNG)) {
- if (tech_pvt->read_codec.implementation->encoded_bytes_per_frame) {
- bytes = tech_pvt->read_codec.implementation->encoded_bytes_per_frame;
- frames = ((int) frame->datalen / bytes);
- } else
- frames = 1;
-
- samples = frames * tech_pvt->read_codec.implementation->samples_per_frame;
- }
-#if 0
- printf("%s %s->%s send %d bytes %d samples in %d frames ts=%d\n",
- switch_channel_get_name(channel),
- tech_pvt->local_sdp_audio_ip, tech_pvt->remote_sdp_audio_ip, frame->datalen, samples, frames, tech_pvt->timestamp_send);
-#endif
-
- tech_pvt->timestamp_send += samples;
- //switch_rtp_write_frame(tech_pvt->rtp_session, frame, tech_pvt->timestamp_send);
- switch_rtp_write_frame(tech_pvt->rtp_session, frame, 0);
-
- switch_clear_flag_locked(tech_pvt, TFLAG_WRITING);
- return status;
-}
-
-
-
-static switch_status_t sofia_kill_channel(switch_core_session_t *session, int sig)
-{
- private_object_t *tech_pvt;
- switch_channel_t *channel = NULL;
-
- 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);
-
-
- switch (sig) {
- case SWITCH_SIG_BREAK:
- if (switch_rtp_ready(tech_pvt->rtp_session)) {
- switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_BREAK);
- }
- break;
- case SWITCH_SIG_KILL:
- default:
- switch_clear_flag_locked(tech_pvt, TFLAG_IO);
- switch_set_flag_locked(tech_pvt, TFLAG_HUP);
-
- if (switch_rtp_ready(tech_pvt->rtp_session)) {
- switch_rtp_kill_socket(tech_pvt->rtp_session);
- }
- break;
- }
-
- return SWITCH_STATUS_SUCCESS;
-
-}
-
-static switch_status_t sofia_waitfor_read(switch_core_session_t *session, int ms, int stream_id)
-{
- private_object_t *tech_pvt;
- switch_channel_t *channel = NULL;
-
- 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);
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-
-static switch_status_t sofia_waitfor_write(switch_core_session_t *session, int ms, int stream_id)
-{
- private_object_t *tech_pvt;
- switch_channel_t *channel = NULL;
-
- 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);
-
- return SWITCH_STATUS_SUCCESS;
-
-}
-
-static switch_status_t sofia_send_dtmf(switch_core_session_t *session, char *digits)
-{
- private_object_t *tech_pvt;
-
- tech_pvt = (private_object_t *) switch_core_session_get_private(session);
- assert(tech_pvt != NULL);
-
- return switch_rtp_queue_rfc2833(tech_pvt->rtp_session,
- digits, tech_pvt->profile->dtmf_duration * (tech_pvt->read_codec.implementation->samples_per_second / 1000));
-
-}
-
-static switch_status_t sofia_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
-{
- switch_channel_t *channel;
- private_object_t *tech_pvt;
- switch_status_t status;
-
- 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);
-
-
- switch (msg->message_id) {
- case SWITCH_MESSAGE_INDICATE_NOMEDIA:{
- char *uuid;
- switch_core_session_t *other_session;
- switch_channel_t *other_channel;
- char *ip = NULL, *port = NULL;
-
- switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
- tech_pvt->local_sdp_str = NULL;
- if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
- && (other_session = switch_core_session_locate(uuid))) {
- other_channel = switch_core_session_get_channel(other_session);
- ip = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
- port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
- switch_core_session_rwunlock(other_session);
- if (ip && port) {
- set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1);
- }
- }
- if (!tech_pvt->local_sdp_str) {
- tech_absorb_sdp(tech_pvt);
- }
- do_invite(session);
- }
- break;
- case SWITCH_MESSAGE_INDICATE_MEDIA:{
- switch_clear_flag_locked(tech_pvt, TFLAG_NOMEDIA);
- tech_pvt->local_sdp_str = NULL;
- if (!switch_rtp_ready(tech_pvt->rtp_session)) {
- tech_set_codecs(tech_pvt);
- if ((status = tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
- return status;
- }
- }
- set_local_sdp(tech_pvt, NULL, 0, NULL, 1);
- do_invite(session);
- while (!switch_rtp_ready(tech_pvt->rtp_session) && switch_channel_get_state(channel) < CS_HANGUP) {
- switch_yield(1000);
- }
- }
- break;
-
- case SWITCH_MESSAGE_INDICATE_HOLD:{
- switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
- do_invite(session);
- }
- break;
-
- case SWITCH_MESSAGE_INDICATE_UNHOLD:{
- switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
- do_invite(session);
- }
- break;
- 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 *a_session, *b_session = msg->pointer_arg;
-
- if ((a_session = switch_core_session_locate(tech_pvt->xferto))) {
- private_object_t *a_tech_pvt = switch_core_session_get_private(a_session);
- private_object_t *b_tech_pvt = switch_core_session_get_private(b_session);
-
- switch_set_flag_locked(a_tech_pvt, TFLAG_REINVITE);
- a_tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(a_session, 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(a_session, 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(b_session, tech_pvt->xferto);
- switch_core_session_rwunlock(a_session);
- }
-
-
- 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");
- }
- break;
- case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
- if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) {
- switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-activate timed RTP!\n");
- }
- break;
- case SWITCH_MESSAGE_INDICATE_REDIRECT:
- if (msg->string_arg) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-directing to %s\n", msg->string_arg);
- nua_respond(tech_pvt->nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg->string_arg), TAG_END());
- }
- break;
- case SWITCH_MESSAGE_INDICATE_RINGING:
- nua_respond(tech_pvt->nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END());
- break;
- case SWITCH_MESSAGE_INDICATE_PROGRESS:{
- if (!switch_test_flag(tech_pvt, TFLAG_ANS)) {
- 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);
-
- /* Transmit 183 Progress with SDP */
- if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
- char *sdp = NULL;
- switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
- if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
- tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
- }
- } else {
- if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
- char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
- if (tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
- nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
- return SWITCH_STATUS_FALSE;
- }
- switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
- }
-
- if ((status = tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
- return status;
- }
- set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
- activate_rtp(tech_pvt);
- if (tech_pvt->local_sdp_str) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Ring SDP:\n%s\n", tech_pvt->local_sdp_str);
- }
- }
-
- nua_respond(tech_pvt->nh,
- SIP_183_SESSION_PROGRESS,
- SIPTAG_CONTACT_STR(tech_pvt->profile->url),
- SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END());
- }
- }
- break;
- default:
- break;
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status_t sofia_receive_event(switch_core_session_t *session, switch_event_t *event)
-{
- switch_channel_t *channel;
- struct private_object *tech_pvt;
- char *body;
- nua_handle_t *msg_nh;
-
- channel = switch_core_session_get_channel(session);
- assert(channel != NULL);
-
- tech_pvt = switch_core_session_get_private(session);
- assert(tech_pvt != NULL);
-
-
- if (!(body = switch_event_get_body(event))) {
- body = "";
- }
-
- if (tech_pvt->hash_key) {
- msg_nh = nua_handle(tech_pvt->profile->nua, NULL,
- SIPTAG_FROM_STR(tech_pvt->chat_from),
- NUTAG_URL(tech_pvt->chat_to), SIPTAG_TO_STR(tech_pvt->chat_to), SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END());
-
- nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END());
- }
-
- return SWITCH_STATUS_SUCCESS;
-}
-
-static const switch_io_routines_t sofia_io_routines = {
- /*.outgoing_channel */ sofia_outgoing_channel,
- /*.answer_channel */ sofia_answer_channel,
- /*.read_frame */ sofia_read_frame,
- /*.write_frame */ sofia_write_frame,
- /*.kill_channel */ sofia_kill_channel,
- /*.waitfor_read */ sofia_waitfor_read,
- /*.waitfor_read */ sofia_waitfor_write,
- /*.send_dtmf */ sofia_send_dtmf,
- /*.receive_message */ sofia_receive_message,
- /*.receive_event */ sofia_receive_event
-};
-
-static const switch_state_handler_table_t sofia_event_handlers = {
- /*.on_init */ sofia_on_init,
- /*.on_ring */ sofia_on_ring,
- /*.on_execute */ sofia_on_execute,
- /*.on_hangup */ sofia_on_hangup,
- /*.on_loopback */ sofia_on_loopback,
- /*.on_transmit */ sofia_on_transmit
-};
-
-static const switch_endpoint_interface_t sofia_endpoint_interface = {
- /*.interface_name */ "sofia",
- /*.io_routines */ &sofia_io_routines,
- /*.event_handlers */ &sofia_event_handlers,
- /*.private */ NULL,
- /*.next */ NULL
-};
-
-static const switch_chat_interface_t sofia_chat_interface = {
- /*.name */ SOFIA_CHAT_PROTO,
- /*.chat_send */ chat_send,
-
-};
-
-static switch_status_t sofia_manage(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen)
-{
- return SWITCH_STATUS_SUCCESS;
-}
-
-static const switch_management_interface_t sofia_management_interface = {
- /*.relative_oid */ "1",
- /*.management_function */ sofia_manage
-};
-
-static const switch_loadable_module_interface_t sofia_module_interface = {
- /*.module_name */ modname,
- /*.endpoint_interface */ &sofia_endpoint_interface,
- /*.timer_interface */ NULL,
- /*.dialplan_interface */ NULL,
- /*.codec_interface */ NULL,
- /*.application_interface */ NULL,
- /*.api_interface */ NULL,
- /*.file_interface */ NULL,
- /*.speech_interface */ NULL,
- /*.directory_interface */ NULL,
- /*.chat_interface */ &sofia_chat_interface,
- /*.say_interface */ NULL,
- /*.asr_interface */ NULL,
- /*.management_interface */ &sofia_management_interface
-};
-
-
-static void logger(void *logarg, char const *fmt, va_list ap)
-{
- char *data = NULL;
-
- if (fmt) {
-#ifdef HAVE_VASPRINTF
- int ret;
- ret = vasprintf(&data, fmt, ap);
- if ((ret == -1) || !data) {
- return;
- }
-#else
- data = (char *) malloc(2048);
- if (data) {
- vsnprintf(data, 2048, fmt, ap);
- } else {
- return;
- }
-#endif
- }
- if (data) {
- switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, (char *) "%s", data);
- free(data);
- }
-}
-
-
-static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session,
- switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
- switch_memory_pool_t **pool)
-{
- switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
- switch_core_session_t *nsession;
- char *data, *profile_name, *dest;
- sofia_profile_t *profile;
- switch_caller_profile_t *caller_profile = NULL;
- private_object_t *tech_pvt = NULL;
- switch_channel_t *nchannel;
- char *host, *dest_to;
-
- *new_session = NULL;
-
- if (!(nsession = switch_core_session_request(&sofia_endpoint_interface, pool))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
- goto done;
- }
-
- if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
- terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- goto done;
- }
-
- data = switch_core_session_strdup(nsession, outbound_profile->destination_number);
- profile_name = data;
-
- if (!strncasecmp(profile_name, "gateway", 7)) {
- char *gw;
- outbound_reg_t *gateway_ptr;
-
-
- if (!(gw = strchr(profile_name, '/'))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
- terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
- goto done;
- }
-
- *gw++ = '\0';
-
- if (!(dest = strchr(gw, '/'))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
- terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
- goto done;
- }
-
- *dest++ = '\0';
-
- if (!(gateway_ptr = find_gateway(gw))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Gateway\n");
- terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
- goto done;
- }
-
- profile = gateway_ptr->profile;
- tech_pvt->from_str = switch_core_session_strdup(nsession, gateway_ptr->register_from);
- if (!strchr(dest, '@')) {
- tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s@%s", dest, gateway_ptr->register_proxy + 4);
- } else {
- tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s", dest);
- }
- } else {
- if (!(dest = strchr(profile_name, '/'))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
- terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
- goto done;
- }
- *dest++ = '\0';
-
- if (!(profile = find_profile(profile_name))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
- terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
- cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
- goto done;
- }
-
- if ((dest_to = strchr(dest, '^'))) {
- *dest_to++ = '\0';
- tech_pvt->dest_to = switch_core_session_alloc(nsession, strlen(dest_to) + 5);
- snprintf(tech_pvt->dest_to, strlen(dest_to) + 5, "sip:%s", dest_to);
- }
-
- if ((host = strchr(dest, '%'))) {
- char buf[128];
- *host = '@';
- tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
- *host++ = '\0';
- if (find_reg_url(profile, dest, host, buf, sizeof(buf))) {
- tech_pvt->dest = switch_core_session_strdup(nsession, buf);
-
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, host);
- cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION;
- terminate_session(&nsession, cause, __LINE__);
- goto done;
- }
- } else if (!strchr(dest, '@')) {
- char buf[128];
- tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
- if (find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) {
- tech_pvt->dest = switch_core_session_strdup(nsession, buf);
-
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, profile_name);
- cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION;
- terminate_session(&nsession, cause, __LINE__);
- goto done;
- }
- } else {
- tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5);
- snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest);
- }
- }
-
- if (!tech_pvt->dest_to) {
- tech_pvt->dest_to = tech_pvt->dest;
- }
-
- attach_private(nsession, profile, tech_pvt, dest);
-
- nchannel = switch_core_session_get_channel(nsession);
- caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
- 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(nchannel, CS_INIT);
- *new_session = nsession;
- cause = SWITCH_CAUSE_SUCCESS;
- if (session) {
- //char *val;
- //switch_channel_t *channel = switch_core_session_get_channel(session);
- switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
- switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_HEADER_PREFIX_T);
- if (switch_core_session_compare(session, nsession)) {
- /* It's another sofia channel! so lets cache what they use as a pt for telephone event so
- we can keep it the same
- */
- private_object_t *ctech_pvt;
- ctech_pvt = switch_core_session_get_private(session);
- assert(ctech_pvt != NULL);
- tech_pvt->bte = ctech_pvt->te;
- tech_pvt->bcng_pt = ctech_pvt->cng_pt;
- }
- }
-
- done:
- return cause;
-}
-
-
-static uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t * sdp)
-{
- uint8_t match = 0;
- switch_payload_t te = 0, cng_pt = 0;
- private_object_t *tech_pvt;
- sdp_media_t *m;
- sdp_attribute_t *a;
- switch_channel_t *channel;
- int ptime = 0, dptime = 0;
-
- tech_pvt = switch_core_session_get_private(session);
- assert(tech_pvt != NULL);
-
- channel = switch_core_session_get_channel(session);
-
- if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
- if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) {
- switch_set_flag_locked(tech_pvt, TFLAG_BUGGY_2833);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n");
- }
- }
-
- for (a = sdp->sdp_attributes; a; a = a->a_next) {
- if (switch_strlen_zero(a->a_name)) {
- continue;
- }
- if (!strcasecmp(a->a_name, "sendonly")) {
- if (!switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
- char *stream;
-
- switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
- switch_channel_set_flag(channel, CF_HOLD);
- if (!(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
- stream = tech_pvt->profile->hold_music;
- }
- if (stream) {
- switch_ivr_broadcast(switch_core_session_get_uuid(tech_pvt->session), stream, SMF_ECHO_BLEG | SMF_LOOP);
- }
- }
- } else if (!strcasecmp(a->a_name, "sendrecv")) {
- if (switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
- switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
- switch_channel_clear_flag(channel, CF_HOLD);
- switch_channel_clear_flag_partner(channel, CF_BROADCAST);
- switch_channel_set_flag_partner(channel, CF_BREAK);
- }
- } else if (!strcasecmp(a->a_name, "ptime")) {
- dptime = atoi(a->a_value);
- }
- }
-
- for (m = sdp->sdp_media; m; m = m->m_next) {
- sdp_connection_t *connection;
-
- ptime = dptime;
- for (a = m->m_attributes; a; a = a->a_next) {
- if (!strcasecmp(a->a_name, "ptime") && a->a_value) {
- ptime = atoi(a->a_value);
- }
- }
-
- if (m->m_type == sdp_media_audio) {
- sdp_rtpmap_t *map;
-
- connection = sdp->sdp_connection;
- if (m->m_connections) {
- connection = m->m_connections;
- }
-
- if (!connection) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
- match = 0;
- break;
- }
-
- for (map = m->m_rtpmaps; map; map = map->rm_next) {
- int32_t i;
- const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
- const char *rm_encoding;
-
-
- if (!(rm_encoding = map->rm_encoding)) {
- rm_encoding = "";
- }
-
- if (!te && !strcasecmp(rm_encoding, "telephone-event")) {
- te = tech_pvt->te = (switch_payload_t) map->rm_pt;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set 2833 dtmf payload to %u\n", te);
- if (tech_pvt->rtp_session) {
- switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
- }
- }
-
- if (!cng_pt && !strcasecmp(rm_encoding, "CN")) {
- cng_pt = tech_pvt->cng_pt = (switch_payload_t) map->rm_pt;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
- if (tech_pvt->rtp_session) {
- switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
- switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTO_CNG);
- }
- }
-
- if (match) {
- if (te && cng_pt) {
- break;
- }
- continue;
- }
-
- for (i = 0; i < tech_pvt->num_codecs; i++) {
- const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Codec Compare [%s:%d]/[%s:%d]\n",
- rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
- if (map->rm_pt < 96) {
- match = (map->rm_pt == imp->ianacode) ? 1 : 0;
- } else {
- match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
- }
-
- if (match && (map->rm_rate == imp->samples_per_second)) {
- if (ptime && ptime * 1000 != imp->microseconds_per_frame) {
- near_match = imp;
- match = 0;
- continue;
- }
- mimp = imp;
- break;
- } else {
- match = 0;
- }
- }
-
- if (!match && near_match) {
- const switch_codec_implementation_t *search[1];
- char *prefs[1];
- char tmp[80];
- int num;
-
- snprintf(tmp, sizeof(tmp), "%s@%uk@%ui", near_match->iananame, near_match->samples_per_second, ptime);
-
- prefs[0] = tmp;
- num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
-
- if (num) {
- mimp = search[0];
- } else {
- mimp = near_match;
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Substituting codec %s@%ums\n",
- mimp->iananame, mimp->microseconds_per_frame / 1000);
- match = 1;
- }
-
- if (mimp) {
- if ((tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) {
- char tmp[50];
- tech_pvt->pt = (switch_payload_t) map->rm_pt;
- tech_pvt->rm_rate = map->rm_rate;
- tech_pvt->codec_ms = mimp->microseconds_per_frame / 1000;
- tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address);
- tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
- tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port;
- tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt;
- snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
- switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
- switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
- } else {
- match = 0;
- }
- }
-
- if (match) {
- if (tech_set_codec(tech_pvt, 1) != SWITCH_STATUS_SUCCESS) {
- match = 0;
- }
- }
- }
- }
- }
-
- return match;
-}
-
-// map sip responses to QSIG cause codes ala RFC4497 section 8.4.4
-static switch_call_cause_t sip_cause_to_freeswitch(int status)
-{
- switch (status) {
- case 200:
- return SWITCH_CAUSE_NORMAL_CLEARING;
- case 401:
- case 402:
- case 403:
- case 407:
- case 603:
- return SWITCH_CAUSE_CALL_REJECTED;
- case 404:
- case 485:
- case 604:
- return SWITCH_CAUSE_NO_ROUTE_DESTINATION;
- case 408:
- case 504:
- return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
- case 410:
- return SWITCH_CAUSE_NUMBER_CHANGED;
- case 413:
- case 414:
- case 416:
- case 420:
- case 421:
- case 423:
- case 505:
- case 513:
- return SWITCH_CAUSE_INTERWORKING;
- case 480:
- return SWITCH_CAUSE_NO_USER_RESPONSE;
- case 400:
- case 481:
- case 500:
- case 503:
- return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE;
- case 486:
- case 600:
- return SWITCH_CAUSE_USER_BUSY;
- case 484:
- return SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
- case 488:
- case 606:
- return SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL;
- case 502:
- return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
- case 405:
- return SWITCH_CAUSE_SERVICE_UNAVAILABLE;
- case 406:
- case 415:
- case 501:
- return SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED;
- case 482:
- case 483:
- return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR;
- case 487:
- return SWITCH_CAUSE_ORIGINATOR_CANCEL;
-
- default:
- return SWITCH_CAUSE_NORMAL_UNSPECIFIED;
-
- }
-}
-
-
-static void set_hash_key(char *hash_key, int32_t len, sip_t const *sip)
-{
-
- snprintf(hash_key, len, "%s%s%s", (char *) sip->sip_from->a_url->url_user, (char *) sip->sip_from->a_url->url_host,
- (char *) sip->sip_to->a_url->url_user);
-
-
-#if 0
- /* nicer one we cant use in both directions >=0 */
- snprintf(hash_key, len, "%s%s%s%s%s%s",
- (char *) sip->sip_to->a_url->url_user,
- (char *) sip->sip_to->a_url->url_host,
- (char *) sip->sip_to->a_url->url_params,
- (char *) sip->sip_from->a_url->url_user, (char *) sip->sip_from->a_url->url_host, (char *) sip->sip_from->a_url->url_params);
-#endif
-
-}
-
-static void set_chat_hash(private_object_t * tech_pvt, sip_t const *sip)
-{
- char hash_key[256] = "";
- char buf[512];
-
- if (tech_pvt->hash_key || !sip || !sip->sip_from || !sip->sip_from->a_url || !sip->sip_from->a_url->url_user || !sip->sip_from->a_url->url_host) {
- return;
- }
-
- if (find_reg_url(tech_pvt->profile, sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host, buf, sizeof(buf))) {
- tech_pvt->chat_from = sip_header_as_string(tech_pvt->home, (const sip_header_t *) sip->sip_to);
- tech_pvt->chat_to = switch_core_session_strdup(tech_pvt->session, buf);
- set_hash_key(hash_key, sizeof(hash_key), sip);
- } else {
- return;
- }
-
- tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
- switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
-
-}
-
-
-static void sip_i_message(int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- if (sip) {
- sip_from_t const *from = sip->sip_from;
- char *from_user = NULL;
- char *from_host = NULL;
- sip_to_t const *to = sip->sip_to;
- char *to_user = NULL;
- char *to_host = NULL;
- sip_subject_t const *sip_subject = sip->sip_subject;
- sip_payload_t *payload = sip->sip_payload;
- const char *subject = "n/a";
- char *msg = NULL;
-
- if (sip->sip_content_type) {
- if (strstr((char *) sip->sip_content_type->c_subtype, "composing")) {
- return;
- }
- }
-
- if (from) {
- from_user = (char *) from->a_url->url_user;
- from_host = (char *) from->a_url->url_host;
- }
-
- if (to) {
- to_user = (char *) to->a_url->url_user;
- to_host = (char *) to->a_url->url_host;
- }
-
-
- if (!to_user) {
- return;
- }
-
- if (payload) {
- msg = payload->pl_data;
- }
-
- if (sip_subject) {
- subject = sip_subject->g_value;
- }
-
- if (nh) {
- char hash_key[512];
- private_object_t *tech_pvt;
- switch_channel_t *channel;
- switch_event_t *event;
- char *to_addr;
- char *from_addr;
- char *p;
- char *full_from;
- char proto[512] = SOFIA_CHAT_PROTO;
-
- full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
-
- if ((p = strchr(to_user, '+'))) {
- switch_copy_string(proto, to_user, sizeof(proto));
- p = strchr(proto, '+');
- *p++ = '\0';
-
- if ((to_addr = strdup(p))) {
- if ((p = strchr(to_addr, '+'))) {
- *p = '@';
- }
- }
-
- } else {
- to_addr = switch_mprintf("%s@%s", to_user, to_host);
- }
-
- from_addr = switch_mprintf("%s@%s", from_user, from_host);
-
-
- set_hash_key(hash_key, sizeof(hash_key), sip);
- if ((tech_pvt = (private_object_t *) switch_core_hash_find(profile->chat_hash, hash_key))) {
- channel = switch_core_session_get_channel(tech_pvt->session);
- if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", tech_pvt->hash_key);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", to_addr);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "subject", "SIMPLE MESSAGE");
- if (msg) {
- switch_event_add_body(event, "%s", msg);
- }
- if (switch_core_session_queue_event(tech_pvt->session, &event) != SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
- switch_event_fire(&event);
- }
- }
- } else {
- switch_chat_interface_t *ci;
-
- if ((ci = switch_loadable_module_get_chat_interface(proto))) {
- ci->chat_send(SOFIA_CHAT_PROTO, from_addr, to_addr, "", msg, full_from);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Chat Interface [%s]!\n", proto ? proto : "(none)");
- }
-
- }
- switch_safe_free(to_addr);
- switch_safe_free(from_addr);
- if (full_from) {
- su_free(profile->home, full_from);
- }
- }
-
- }
-}
-
-static void pass_sdp(private_object_t * tech_pvt, char *sdp)
-{
- char *val;
- switch_channel_t *channel;
- switch_core_session_t *other_session;
- switch_channel_t *other_channel;
-
- channel = switch_core_session_get_channel(tech_pvt->session);
- assert(channel != NULL);
-
- if ((val = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
- && (other_session = switch_core_session_locate(val))) {
- other_channel = switch_core_session_get_channel(other_session);
- assert(other_channel != NULL);
- switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp);
-
- if (!switch_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) && (switch_channel_test_flag(other_channel, CF_OUTBOUND) &&
- //switch_channel_test_flag(other_channel, CF_NOMEDIA) &&
- switch_channel_test_flag(channel, CF_OUTBOUND) &&
- switch_channel_test_flag(channel, CF_NOMEDIA))) {
- switch_ivr_nomedia(val, SMF_FORCE);
- switch_set_flag_locked(tech_pvt, TFLAG_CHANGE_MEDIA);
- }
-
- switch_core_session_rwunlock(other_session);
- }
-}
-
-static void sip_i_state(int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- const char *l_sdp = NULL, *r_sdp = NULL;
- int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
- int ss_state = nua_callstate_init;
- switch_channel_t *channel = NULL;
- private_object_t *tech_pvt = NULL;
- switch_core_session_t *session = NULL;
- const char *replaces_str = NULL;
- char *uuid;
- switch_core_session_t *other_session = NULL;
- switch_channel_t *other_channel = NULL;
- char st[80] = "";
-
-
- if (sofia_private) {
- if (!switch_strlen_zero(sofia_private->uuid)) {
- if (!(session = switch_core_session_locate(sofia_private->uuid))) {
- /* too late */
- return;
- }
- }
- }
-
-
- tl_gets(tags,
- NUTAG_CALLSTATE_REF(ss_state),
- NUTAG_OFFER_RECV_REF(offer_recv),
- NUTAG_ANSWER_RECV_REF(answer_recv),
- NUTAG_OFFER_SENT_REF(offer_sent),
- NUTAG_ANSWER_SENT_REF(answer_sent),
- SIPTAG_REPLACES_STR_REF(replaces_str), SOATAG_LOCAL_SDP_STR_REF(l_sdp), SOATAG_REMOTE_SDP_STR_REF(r_sdp), TAG_END());
-
- if (session) {
- channel = switch_core_session_get_channel(session);
- assert(channel != NULL);
-
- tech_pvt = switch_core_session_get_private(session);
- assert(tech_pvt != NULL);
- assert(tech_pvt->nh != NULL);
-
- if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
- switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s entering state [%s]\n",
- switch_channel_get_name(channel), nua_callstate_name(ss_state));
-
- 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, r_sdp);
- switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
- pass_sdp(tech_pvt, (char *) r_sdp);
-
- }
- }
-
- if (status == 988) {
- goto done;
- }
-
- switch ((enum nua_callstate) ss_state) {
- case nua_callstate_init:
- break;
- case nua_callstate_authenticating:
- break;
- case nua_callstate_calling:
- break;
- case nua_callstate_proceeding:
- if (channel) {
- if (status == 180) {
- switch_channel_mark_ring_ready(channel);
- if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK)) {
- if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
- if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
- && (other_session = switch_core_session_locate(uuid))) {
- switch_core_session_message_t msg;
- msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING;
- msg.from = __FILE__;
- switch_core_session_receive_message(other_session, &msg);
- switch_core_session_rwunlock(other_session);
- }
-
- } else {
- switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
- }
- }
- }
-
- if (r_sdp) {
- if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
- switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
- switch_channel_mark_pre_answered(channel);
- if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK) && (uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
- && (other_session = switch_core_session_locate(uuid))) {
- other_channel = switch_core_session_get_channel(other_session);
- if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
- switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
- }
-
- switch_channel_pre_answer(other_channel);
- switch_core_session_rwunlock(other_session);
- }
- goto done;
- } else {
- if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
- } else {
- if (tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
- nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
- }
- }
- goto done;
- }
- }
- }
- break;
- case nua_callstate_completing:
- nua_ack(nh, TAG_END());
- break;
- case nua_callstate_received:
-
- if (session && switch_core_session_running(session)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Re-Entering Call State Received!\n");
- goto done;
- }
-
- if (channel) {
- if (r_sdp) {
- if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOMEDIA");
- switch_channel_set_state(channel, CS_INIT);
- switch_set_flag_locked(tech_pvt, TFLAG_READY);
- switch_core_session_thread_launch(session);
- goto done;
- } 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) {
- nua_handle_t *bnh;
- sip_replaces_t *replaces;
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "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_magic(bnh))) {
- char *br_b = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
- char *br_a = b_private->uuid;
-
- if (br_b) {
- switch_ivr_uuid_bridge(br_a, br_b);
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
- switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
- } else {
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
- switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
- }
- } else {
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
- switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
- }
- nua_handle_unref(bnh);
- }
- goto done;
- }
-
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
- nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
- }
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Invite with no SDP activating no-media-mode\n");
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
-
- switch_set_flag(tech_pvt, TFLAG_LATE_NEGOTIATION);
- switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
- switch_channel_set_flag(channel, CF_NOMEDIA);
- switch_channel_set_state(channel, CS_INIT);
- switch_set_flag_locked(tech_pvt, TFLAG_READY);
- switch_core_session_thread_launch(session);
- goto done;
- }
- }
-
- break;
- case nua_callstate_early:
- break;
- case nua_callstate_completed:
- if (tech_pvt && r_sdp) {
- if (r_sdp) {
- if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
- goto done;
- } 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 (match) {
- if (tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
- goto done;
- }
- set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
- 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 (tech_pvt && 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;
- if (tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
- activate_rtp(tech_pvt);
- }
- goto done;
- }
-
- if (channel) {
- if (switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
- switch_set_flag_locked(tech_pvt, TFLAG_ANS);
- switch_channel_mark_answered(channel);
- if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
- && (other_session = switch_core_session_locate(uuid))) {
- other_channel = switch_core_session_get_channel(other_session);
- switch_channel_answer(other_channel);
- switch_core_session_rwunlock(other_session);
- }
- goto done;
- }
-
- if (!r_sdp) {
- r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
- }
- if (r_sdp) {
- if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
- switch_set_flag_locked(tech_pvt, TFLAG_ANS);
- switch_channel_mark_answered(channel);
- if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
- && (other_session = switch_core_session_locate(uuid))) {
- other_channel = switch_core_session_get_channel(other_session);
- if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
- switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
- }
- switch_channel_answer(other_channel);
- switch_core_session_rwunlock(other_session);
- }
- goto done;
- } 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) {
- switch_set_flag_locked(tech_pvt, TFLAG_ANS);
- if (tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
- activate_rtp(tech_pvt);
- switch_channel_mark_answered(channel);
- goto done;
- }
- }
-
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
- nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
- }
- }
-
- }
-
- break;
- case nua_callstate_terminating:
- break;
- case nua_callstate_terminated:
- if (session) {
- if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
-
- switch_set_flag_locked(tech_pvt, TFLAG_BYE);
- if (switch_test_flag(tech_pvt, TFLAG_NOHUP)) {
- switch_clear_flag_locked(tech_pvt, TFLAG_NOHUP);
- } else {
- snprintf(st, sizeof(st), "%d", status);
- switch_channel_set_variable(channel, "sip_term_status", st);
- terminate_session(&session, sip_cause_to_freeswitch(status), __LINE__);
- }
- }
-
- if (tech_pvt->sofia_private) {
- free(tech_pvt->sofia_private);
- tech_pvt->sofia_private = NULL;
- }
- tech_pvt->nh = NULL;
- } else if (sofia_private) {
- free(sofia_private);
- }
-
- if (nh) {
- nua_handle_bind(nh, NULL);
- nua_handle_destroy(nh);
- }
- break;
- }
-
- done:
-
- if (session) {
- switch_core_session_rwunlock(session);
- }
-}
-
-
-static char *get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex)
-{
- switch_core_db_t *db;
- switch_core_db_stmt_t *stmt;
- char *sql = NULL, *ret = NULL;
-
- if (mutex) {
- switch_mutex_lock(mutex);
- }
-
- if (!dbname) {
- goto end;
- }
-
- if (!(db = switch_core_db_open_file(dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname);
- goto end;
- }
-
- sql = switch_mprintf("select passwd from sip_authentication where nonce='%q'", nonce);
- if (switch_core_db_prepare(db, sql, -1, &stmt, 0)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Statement Error!\n");
- goto fail;
- } else {
- int running = 1;
- int colcount;
-
- while (running < 5000) {
- int result = switch_core_db_step(stmt);
-
- if (result == SWITCH_CORE_DB_ROW) {
- if ((colcount = switch_core_db_column_count(stmt))) {
- switch_copy_string(npassword, (char *) switch_core_db_column_text(stmt, 0), len);
- ret = npassword;
- }
- break;
- } else if (result == SWITCH_CORE_DB_BUSY) {
- running++;
- switch_yield(1000);
- continue;
- }
- break;
- }
-
- switch_core_db_finalize(stmt);
- }
-
-
- fail:
-
- switch_core_db_close(db);
-
- end:
- if (mutex) {
- switch_mutex_unlock(mutex);
- }
-
- if (sql) {
- switch_safe_free(sql);
- }
-
- return ret;
-}
-
-
-typedef enum {
- REG_REGISTER,
- REG_INVITE
-} sofia_regtype_t;
-
-static uint8_t handle_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key,
- uint32_t keylen)
-{
- sip_from_t const *from = NULL;
- sip_expires_t const *expires = NULL;
- sip_authorization_t const *authorization = NULL;
- sip_contact_t const *contact = NULL;
- switch_xml_t domain, xml, user, param, xparams;
- char params[1024] = "";
- char *sql;
- switch_event_t *s_event;
- const char *from_user = NULL;
- const char *from_host = NULL;
- char contact_str[1024] = "";
- char buf[512];
- const char *passwd = NULL;
- const char *a1_hash = NULL;
- uint8_t stale = 0, ret = 0, forbidden = 0;
- auth_res_t auth_res;
- long exptime = 60;
- switch_event_t *event;
- const char *rpid = "unknown";
- const char *display = "\"user\"";
-
- /* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */
- assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL);
-
- expires = sip->sip_expires;
- authorization = sip->sip_authorization;
- contact = sip->sip_contact;
- from = sip->sip_from;
-
- if (from) {
- from_user = from->a_url->url_user;
- from_host = from->a_url->url_host;
- }
-
- if (!from_user || !from_host) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can not do authorization without a complete from header\n");
- nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
- return 1;
- }
-
- if (contact->m_url) {
- const char *port = contact->m_url->url_port;
- display = contact->m_display;
-
- if (switch_strlen_zero(display)) {
- if (from) {
- display = from->a_display;
- if (switch_strlen_zero(display)) {
- display = "\"user\"";
- }
- }
- }
-
- if (!port) {
- port = SOFIA_DEFAULT_PORT;
- }
-
- if (contact->m_url->url_params) {
- snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s;%s>",
- display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params);
- } else {
- snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s>", display, contact->m_url->url_user, contact->m_url->url_host, port);
- }
- }
-
- if (expires) {
- exptime = expires->ex_delta;
- } else if (contact->m_expires) {
- exptime = atol(contact->m_expires);
- }
-
- if (regtype == REG_REGISTER) {
- authorization = sip->sip_authorization;
- } else if (regtype == REG_INVITE) {
- authorization = sip->sip_proxy_authorization;
- }
-
- if ((profile->pflags & PFLAG_BLIND_REG)) {
- goto reg;
- }
-
- if (authorization) {
- if ((auth_res = parse_auth(profile, authorization, sip->sip_request->rq_method_name, key, keylen)) == AUTH_STALE) {
- stale = 1;
- }
-
- if (auth_res != AUTH_OK && !stale) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send %s for [%s@%s]\n", forbidden ? "forbidden" : "challange", from_user, from_host);
- if (auth_res == AUTH_FORBIDDEN) {
- nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
- } else {
- nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END());
- }
- return 1;
- }
- }
-
- if (!authorization || stale) {
- snprintf(params, sizeof(params), "from_user=%s&from_host=%s&contact=%s", from_user, from_host, contact_str);
-
-
- if (switch_xml_locate("directory", "domain", "name", from_host, &xml, &domain, params) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find domain for [%s@%s]\n", from_user, from_host);
- nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
- return 1;
- }
-
- if (!(user = switch_xml_find_child(domain, "user", "id", from_user))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", from_user, from_host);
- nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
- switch_xml_free(xml);
- return 1;
- }
-
- if (!(xparams = switch_xml_child(user, "params"))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find params for user [%s@%s]\n", from_user, from_host);
- nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
- switch_xml_free(xml);
- return 1;
- }
-
-
- for (param = switch_xml_child(xparams, "param"); param; param = param->next) {
- const char *var = switch_xml_attr_soft(param, "name");
- const char *val = switch_xml_attr_soft(param, "value");
-
- if (!strcasecmp(var, "password")) {
- passwd = val;
- }
-
- if (!strcasecmp(var, "a1-hash")) {
- a1_hash = val;
- }
- }
-
- if (passwd || a1_hash) {
- switch_uuid_t uuid;
- char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
- char *sql, *auth_str;
-
- su_md5_t ctx;
- char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1];
- char *input;
-
- if (!a1_hash) {
- input = switch_mprintf("%s:%s:%s", from_user, from_host, passwd);
- su_md5_init(&ctx);
- su_md5_strupdate(&ctx, input);
- su_md5_hexdigest(&ctx, hexdigest);
- su_md5_deinit(&ctx);
- switch_safe_free(input);
-
- switch_uuid_get(&uuid);
- switch_uuid_format(uuid_str, &uuid);
- a1_hash = hexdigest;
- }
-
- sql = switch_mprintf("delete from sip_authentication where user='%q' and host='%q';\n"
- "insert into sip_authentication values('%q','%q','%q','%q', %ld)",
- from_user, from_host, from_user, from_host, a1_hash, uuid_str, time(NULL) + profile->nonce_ttl);
- auth_str =
- switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", from_host, uuid_str, stale ? " stale=\"true\"," : "");
-
-
- if (regtype == REG_REGISTER) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting Registration from: [%s@%s]\n", from_user, from_host);
- nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());
- } else if (regtype == REG_INVITE) {
- nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED, NUTAG_WITH_THIS(nua), SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
-
- }
-
- execute_sql(profile->dbname, sql, profile->ireg_mutex);
- switch_safe_free(sql);
- switch_safe_free(auth_str);
- ret = 1;
- } else {
- ret = 0;
- }
-
- switch_xml_free(xml);
-
- if (ret) {
- return ret;
- }
- }
- reg:
-
- if (exptime) {
- if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
- sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Registered', '%q', %ld)",
- from_user, from_host, contact_str, rpid, (long) time(NULL) + (long) exptime * 2);
-
- } else {
- sql =
- switch_mprintf
- ("update sip_registrations set contact='%q', expires=%ld, rpid='%q' where user='%q' and host='%q'",
- contact_str, (long) time(NULL) + (long) exptime * 2, rpid, from_user, from_host);
-
- }
-
- if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", profile->name);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-user", "%s", from_user);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-host", "%s", from_host);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", contact_str);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
- switch_event_fire(&s_event);
- }
-
- if (sql) {
- execute_sql(profile->dbname, sql, profile->ireg_mutex);
- switch_safe_free(sql);
- sql = NULL;
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
- "Register:\nFrom: [%s@%s]\nContact: [%s]\nExpires: [%ld]\n", from_user, from_host, contact_str, (long) exptime);
-
-
- if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
-
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Registered");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
- switch_event_fire(&event);
- }
- } else {
- if ((sql = switch_mprintf("delete from sip_subscriptions where user='%q' and host='%q'", from_user, from_host))) {
- execute_sql(profile->dbname, sql, profile->ireg_mutex);
- switch_safe_free(sql);
- sql = NULL;
- }
- if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_PROTO, from_user, from_host);
-
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "unavailable");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
- switch_event_fire(&event);
- }
- }
-
-
- if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
- switch_event_fire(&event);
- }
-
- if (regtype == REG_REGISTER) {
- nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(contact), NUTAG_WITH_THIS(nua), TAG_END());
- return 1;
- }
-
- return 0;
-}
-
-
-static int sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
-{
- sofia_profile_t *profile = (sofia_profile_t *) pArg;
- //char *proto = argv[0];
- char *user = argv[1];
- char *host = argv[2];
- switch_event_t *event;
- char *status = NULL;
- if (switch_strlen_zero(status)) {
- status = "Available";
- }
- if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe");
- switch_event_fire(&event);
- }
-
- return 0;
-}
-
-static int resub_callback(void *pArg, int argc, char **argv, char **columnNames)
-{
- sofia_profile_t *profile = (sofia_profile_t *) pArg;
- char *user = argv[0];
- char *host = argv[1];
- char *status = argv[2];
- char *rpid = argv[3];
- char *proto = argv[4];
- switch_event_t *event;
-
- if (switch_strlen_zero(proto)) {
- proto = NULL;
- }
-
- if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "%s", proto ? proto : SOFIA_CHAT_PROTO);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
- switch_event_fire(&event);
- }
-
- return 0;
-}
-
-static int sub_callback(void *pArg, int argc, char **argv, char **columnNames)
-{
- sofia_profile_t *profile = (sofia_profile_t *) pArg;
- char *pl;
- char *id, *note;
- uint32_t in = atoi(argv[0]);
- char *status = argv[1];
- char *rpid = argv[2];
- char *proto = argv[3];
- char *user = argv[4];
- char *host = argv[5];
- char *sub_to_user = argv[6];
- char *sub_to_host = argv[7];
- char *event = argv[8];
- char *contact = argv[9];
- char *callid = argv[10];
- char *full_from = argv[11];
- char *full_via = argv[12];
- nua_handle_t *nh;
- char *to;
- char *open;
- char *tmp;
-
- if (!rpid) {
- rpid = "unknown";
- }
-
- if (in) {
- note = switch_mprintf("<dm:note>%s</dm:note>", status);
- open = "open";
- } else {
- note = NULL;
- open = "closed";
- }
-
- if (!strcasecmp(sub_to_host, host)) {
- /* same host */
- id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
- } else if (strcasecmp(proto, SOFIA_CHAT_PROTO)) {
- /*encapsulate */
- id = switch_mprintf("sip:%s+%s+%s@%s", proto, sub_to_user, sub_to_host, host);
- } else {
- id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
- }
-
- to = switch_mprintf("sip:%s@%s", user, host);
- pl = switch_mprintf("<?xml version='1.0' encoding='UTF-8'?>\r\n"
- "<presence xmlns='urn:ietf:params:xml:ns:pidf'\r\n"
- "xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'\r\n"
- "xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'\r\n"
- "xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'\r\n"
- "entity='pres:%s'>\r\n"
- "<tuple id='t6a5ed77e'>\r\n"
- "<status>\r\n"
- "<basic>%s</basic>\r\n"
- "</status>\r\n"
- "</tuple>\r\n"
- "<dm:person id='p06360c4a'>\r\n"
- "<rpid:activities>\r\n" "<rpid:%s/>\r\n" "</rpid:activities>%s</dm:person>\r\n" "</presence>", id, open, rpid, note);
-
-
-
- nh = nua_handle(profile->nua, NULL, TAG_END());
- tmp = contact;
- contact = get_url_from_contact(tmp, 0);
-
- nua_notify(nh,
- NUTAG_URL(contact),
- SIPTAG_TO_STR(full_from),
- SIPTAG_FROM_STR(id),
- SIPTAG_CONTACT_STR(profile->url),
- SIPTAG_CALL_ID_STR(callid),
- SIPTAG_VIA_STR(full_via),
- SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=3600"),
- SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END());
-
- switch_safe_free(id);
- switch_safe_free(note);
- switch_safe_free(pl);
- switch_safe_free(to);
-
- return 0;
-}
-
-static void sip_i_subscribe(int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- if (sip) {
- long exp, exp_raw;
- sip_to_t const *to = sip->sip_to;
- sip_from_t const *from = sip->sip_from;
- sip_contact_t const *contact = sip->sip_contact;
- char *from_user = NULL;
- char *from_host = NULL;
- char *to_user = NULL;
- char *to_host = NULL;
- char *sql, *event = NULL;
- char *proto = "sip";
- char *d_user = NULL;
- char *contact_str = "";
- char *call_id = NULL;
- char *to_str = NULL;
- char *full_from = NULL;
- char *full_via = NULL;
- switch_core_db_t *db;
- char *errmsg;
- char *sstr;
- const char *display = "\"user\"";
- switch_event_t *sevent;
-
- if (contact) {
- char *port = (char *) contact->m_url->url_port;
-
- display = contact->m_display;
-
- if (switch_strlen_zero(display)) {
- if (from) {
- display = from->a_display;
- if (switch_strlen_zero(display)) {
- display = "\"user\"";
- }
- }
- } else {
- display = "\"user\"";
- }
-
- if (!port) {
- port = SOFIA_DEFAULT_PORT;
- }
-
- if (contact->m_url->url_params) {
- contact_str = switch_mprintf("%s <sip:%s@%s:%s;%s>",
- display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params);
- } else {
- contact_str = switch_mprintf("%s <sip:%s@%s:%s>", display, contact->m_url->url_user, contact->m_url->url_host, port);
- }
- }
-
- if (to) {
- to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host); //, to->a_url->url_port);
- }
-
- if (to) {
- to_user = (char *) to->a_url->url_user;
- to_host = (char *) to->a_url->url_host;
- }
-
-
- if (strstr(to_user, "ext+") || strstr(to_user, "user+") || strstr(to_user, "conf+")) {
- char proto[80];
- char *p;
-
- switch_copy_string(proto, to_user, sizeof(proto));
- if ((p = strchr(proto, '+'))) {
- *p = '\0';
- }
-
- if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
- switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "login", "%s", profile->name);
- switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, to_host);
- switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "rpid", "unknown");
- switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call");
- switch_event_fire(&sevent);
- }
- }
-
- if (strchr(to_user, '+')) {
- char *h;
- if ((proto = (d_user = strdup(to_user)))) {
- if ((to_user = strchr(d_user, '+'))) {
- *to_user++ = '\0';
- if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) {
- *h++ = '\0';
- to_host = h;
- }
- }
- }
-
- if (!(proto && to_user && to_host)) {
- nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
- goto end;
- }
- }
-
- call_id = sip_header_as_string(profile->home, (void *) sip->sip_call_id);
- event = sip_header_as_string(profile->home, (void *) sip->sip_event);
- full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
- full_via = sip_header_as_string(profile->home, (void *) sip->sip_via);
-
- exp_raw = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
- exp = (long) time(NULL) + exp_raw;
-
- if (sip && sip->sip_from) {
- from_user = (char *) sip->sip_from->a_url->url_user;
- from_host = (char *) sip->sip_from->a_url->url_host;
- } else {
- from_user = "n/a";
- from_host = "n/a";
- }
-
- if ((sql = switch_mprintf("delete from sip_subscriptions where "
- "proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q';\n"
- "insert into sip_subscriptions values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld)",
- proto,
- from_user,
- from_host,
- to_user,
- to_host, event, proto, from_user, from_host, to_user, to_host, event, contact_str, call_id, full_from, full_via, exp))) {
- execute_sql(profile->dbname, sql, profile->ireg_mutex);
- switch_safe_free(sql);
- }
-
- sstr = switch_mprintf("active;expires=%ld", exp_raw);
-
- nua_respond(nh, SIP_202_ACCEPTED,
- NUTAG_WITH_THIS(nua),
- SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), SIPTAG_CONTACT_STR(to_str), TAG_END());
-
-
-
- switch_safe_free(sstr);
-
- if (!(db = switch_core_db_open_file(profile->dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
- goto end;
- }
- if ((sql = switch_mprintf("select * from sip_subscriptions where user='%q' and host='%q'", to_user, to_host, to_user, to_host))) {
- switch_mutex_lock(profile->ireg_mutex);
- switch_core_db_exec(db, sql, sub_reg_callback, profile, &errmsg);
- switch_mutex_unlock(profile->ireg_mutex);
- switch_safe_free(sql);
- }
- switch_core_db_close(db);
- end:
-
- if (event) {
- su_free(profile->home, event);
- }
- if (call_id) {
- su_free(profile->home, call_id);
- }
- if (full_from) {
- su_free(profile->home, full_from);
- }
- if (full_via) {
- su_free(profile->home, full_via);
- }
-
- switch_safe_free(d_user);
- switch_safe_free(to_str);
- switch_safe_free(contact_str);
- }
-}
-
-static void sip_r_subscribe(int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
-
-}
-
-
-/*---------------------------------------*/
-static void sip_i_refer(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
-{
- /* Incoming refer */
- sip_from_t const *from;
- sip_to_t const *to;
- sip_refer_to_t const *refer_to;
- private_object_t *tech_pvt = 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_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"),
- NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
- goto done;
- }
-
- from = sip->sip_from;
- to = sip->sip_to;
-
- if ((refer_to = sip->sip_refer_to)) {
- if (profile->pflags & PFLAG_FULL_ID) {
- exten = switch_mprintf("%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host);
- } else {
- exten = (char *) refer_to->r_url->url_user;
- }
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host);
-
- if (refer_to->r_url->url_headers) {
- sip_replaces_t *replaces;
- nua_handle_t *bnh;
- char *rep;
-
- if ((rep = strchr(refer_to->r_url->url_headers, '='))) {
- char *br_a = NULL, *br_b = NULL;
- char *buf;
- rep++;
-
-
-
- if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
- rep = url_unescape(buf, (const char *) rep);
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Replaces: [%s]\n", rep);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
- goto done;
- }
- if ((replaces = sip_replaces_make(tech_pvt->home, rep))
- && (bnh = nua_handle_by_replaces(nua, replaces))) {
- sofia_private_t *b_private = NULL;
- private_object_t *b_tech_pvt = NULL;
- switch_core_session_t *b_session = NULL;
-
- switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep);
- if ((b_private = nua_handle_magic(bnh))) {
- if (!(b_session = switch_core_session_locate(b_private->uuid))) {
- goto done;
- }
- b_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session);
- channel_b = switch_core_session_get_channel(b_session);
-
- br_a = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
- br_b = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_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, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
- switch_set_flag_locked(tech_pvt, TFLAG_BYE);
- switch_set_flag_locked(b_tech_pvt, TFLAG_BYE);
- nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
- NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
-
- } else {
- if (!br_a && !br_b) {
- switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
- switch_set_flag_locked(b_tech_pvt, TFLAG_XFER);
- b_tech_pvt->xferto = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session));
- } else if (!br_a && br_b) {
- switch_core_session_t *br_b_session;
-
- if ((br_b_session = switch_core_session_locate(br_b))) {
- private_object_t *br_b_tech_pvt = switch_core_session_get_private(br_b_session);
- switch_channel_t *br_b_channel = switch_core_session_get_channel(br_b_session);
-
- switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
-
- switch_channel_clear_state_handler(br_b_channel, NULL);
- switch_channel_set_state_flag(br_b_channel, CF_TRANSFER);
- switch_channel_set_state(br_b_channel, CS_TRANSMIT);
-
- switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
- tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(session, b_tech_pvt->local_sdp_audio_ip);
- tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port;
-
- tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, br_b_tech_pvt->remote_sdp_audio_ip);
- tech_pvt->remote_sdp_audio_port = br_b_tech_pvt->remote_sdp_audio_port;
- activate_rtp(tech_pvt);
-
- br_b_tech_pvt->kick = switch_core_session_strdup(br_b_session, switch_core_session_get_uuid(session));
-
-
- switch_core_session_rwunlock(br_b_session);
- }
-
- switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
- }
- switch_set_flag_locked(tech_pvt, TFLAG_BYE);
- nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
- NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
-
- }
- if (b_session) {
- switch_core_session_rwunlock(b_session);
- }
- }
- 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, SWITCH_SIGNAL_BOND_VARIABLE))) {
- switch_core_session_t *a_session;
- switch_channel_t *channel = switch_core_session_get_channel(session);
-
- if ((a_session = 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(a_session);
-
- exten = switch_mprintf("sofia/%s/%s@%s:%s",
- profile->name,
- (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host, refer_to->r_url->url_port);
-
- switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep);
-
- if (switch_ivr_originate(a_session,
- &tsession, &cause, exten, timeout, &noop_state_handler, NULL, 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"),
- NUTAG_SUBSTATE(nua_substate_terminated),
- SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
- goto done;
- }
-
- switch_core_session_rwunlock(a_session);
- tuuid_str = switch_core_session_get_uuid(tsession);
- switch_ivr_uuid_bridge(br_a, tuuid_str);
- switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
- switch_set_flag_locked(tech_pvt, TFLAG_BYE);
- nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
- NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
- } else {
- goto error;
- }
-
- } else {
- error:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s]\n", br_a);
- switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
- nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
- NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp),
- TAG_END());
- }
- }
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot parse Replaces!\n");
- }
- goto done;
- }
-
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Refer-To\n");
- goto done;
- }
-
- if (exten) {
- switch_channel_t *channel = switch_core_session_get_channel(session);
- char *br;
-
- if ((br = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
- switch_core_session_t *b_session;
-
- if ((b_session = switch_core_session_locate(br))) {
- switch_channel_set_variable(channel, "TRANSFER_FALLBACK", from->a_user);
- switch_ivr_session_transfer(b_session, exten, profile->dialplan, profile->context);
- switch_core_session_rwunlock(b_session);
- }
-
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "BLIND_TRANSFER");
-
- /*
- nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
- NUTAG_SUBSTATE(nua_substate_terminated),
- SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
- SIPTAG_EVENT_STR(etmp),
- TAG_END());
- */
- } else {
- exten = switch_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"),
- NUTAG_SUBSTATE(nua_substate_terminated),
- SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
- SIPTAG_EVENT_STR(etmp),
- TAG_END());
- */
- do_xfer_invite(session);
-
- }
- }
-
- done:
- if (exten && strchr(exten, '@')) {
- switch_safe_free(exten);
- }
- if (etmp) {
- switch_safe_free(etmp);
- }
-
-
-}
-
-
-static void sip_i_publish(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- if (sip) {
- sip_from_t const *from = sip->sip_from;
- char *from_user = NULL;
- char *from_host = NULL;
- char *rpid = "unknown";
- sip_payload_t *payload = sip->sip_payload;
- char *event_type;
-
- if (from) {
- from_user = (char *) from->a_url->url_user;
- from_host = (char *) from->a_url->url_host;
- }
-
- if (payload) {
- switch_xml_t xml, note, person, tuple, status, basic, act;
- switch_event_t *event;
- uint8_t in = 0;
- char *sql;
-
- if ((xml = switch_xml_parse_str(payload->pl_data, strlen(payload->pl_data)))) {
- char *status_txt = "", *note_txt = "";
-
- if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status"))
- && (basic = switch_xml_child(status, "basic"))) {
- status_txt = basic->txt;
- }
-
- if ((person = switch_xml_child(xml, "dm:person")) && (note = switch_xml_child(person, "dm:note"))) {
- note_txt = note->txt;
- }
-
- if (person && (act = switch_xml_child(person, "rpid:activities"))) {
- if ((rpid = strchr(act->child->name, ':'))) {
- rpid++;
- } else {
- rpid = act->child->name;
- }
- }
-
- if (!strcasecmp(status_txt, "open")) {
- if (switch_strlen_zero(note_txt)) {
- note_txt = "Available";
- }
- in = 1;
- } else if (!strcasecmp(status_txt, "closed")) {
- if (switch_strlen_zero(note_txt)) {
- note_txt = "Unavailable";
- }
- }
-
- if ((sql =
- switch_mprintf("update sip_registrations set status='%q',rpid='%q' where user='%q' and host='%q'",
- note_txt, rpid, from_user, from_host))) {
- execute_sql(profile->dbname, sql, profile->ireg_mutex);
- switch_safe_free(sql);
- }
-
- event_type = sip_header_as_string(profile->home, (void *) sip->sip_event);
-
- if (in) {
- if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
-
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", note_txt);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type);
- switch_event_fire(&event);
- }
- } else {
- if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
-
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type);
- switch_event_fire(&event);
- }
- }
-
- if (event_type) {
- su_free(profile->home, event_type);
- }
-
- switch_xml_free(xml);
- }
-
- }
-
- }
-
- nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
-
-}
-
-static void sip_i_info(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
-{
-
- //placeholder for string searching
- char *signal_ptr;
-
- //Try and find signal information in the payload
- signal_ptr = strstr(sip->sip_payload->pl_data, "Signal=");
-
- //See if we found a match
- if (signal_ptr) {
- struct private_object *tech_pvt = NULL;
- switch_channel_t *channel = NULL;
- char dtmf_digit[2] = { 0, 0 };
-
- //Get the channel
- channel = switch_core_session_get_channel(session);
-
- //Barf if we didn't get it
- assert(channel != NULL);
-
- //make sure we have our privates
- tech_pvt = switch_core_session_get_private(session);
-
- //Barf if we didn't get it
- assert(tech_pvt != NULL);
-
- //move signal_ptr where we need it (right past Signal=)
- signal_ptr = signal_ptr + 7;
-
- //put the digit somewhere we can muck with
- strncpy(dtmf_digit, signal_ptr, 1);
-
- //queue it up
- switch_channel_queue_dtmf(channel, dtmf_digit);
-
- //print debug info
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "INFO DTMF(%s)\n", dtmf_digit);
-
- } else { //unknown info type
- sip_from_t const *from;
-
- from = sip->sip_from;
-
- //print in the logs if something comes through we don't understand
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unknown INFO Recieved: %s%s" URL_PRINT_FORMAT "[%s]\n",
- from->a_display ? from->a_display : "", from->a_display ? " " : "", URL_PRINT_ARGS(from->a_url), sip->sip_payload->pl_data);
- }
-
- return;
-}
-
-
-#define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix "_user", #varprefix "_host", #varprefix "_port", #varprefix "_uri")
-static const char *_url_set_chanvars(switch_core_session_t *session, url_t * url, const char *user_var,
- const char *host_var, const char *port_var, const char *uri_var)
-{
- const char *user = NULL, *host = NULL, *port = NULL;
- char *uri = NULL;
- switch_channel_t *channel = switch_core_session_get_channel(session);
-
- if (url) {
- user = url->url_user;
- host = url->url_host;
- port = url->url_port;
- }
-
- if (user) {
- switch_channel_set_variable(channel, user_var, user);
- }
-
- if (!port) {
- port = SOFIA_DEFAULT_PORT;
- }
-
- switch_channel_set_variable(channel, port_var, port);
- if (host) {
- if (user) {
- uri = switch_core_session_sprintf(session, "%s@%s:%s", user, host, port);
- } else {
- uri = switch_core_session_sprintf(session, "%s:%s", host, port);
- }
- switch_channel_set_variable_nodup(channel, uri_var, uri);
- switch_channel_set_variable(channel, host_var, host);
- }
-
- return uri;
-}
-
-static void process_rpid(sip_unknown_t * un, private_object_t * tech_pvt)
-{
- int argc, x, screen = 1;
- char *mydata, *argv[10] = { 0 };
- if (!switch_strlen_zero(un->un_value)) {
- if ((mydata = strdup(un->un_value))) {
- argc = switch_separate_string(mydata, ';', argv, (sizeof(argv) / sizeof(argv[0])));
-
- // Do We really need this at this time
- // clid_uri = argv[0];
-
- for (x = 1; x < argc && argv[x]; x++) {
- // we dont need to do anything with party yet we should only be seeing party=calling here anyway
- // maybe thats a dangerous assumption bit oh well yell at me later
- // if (!strncasecmp(argv[x], "party", 5)) {
- // party = argv[x];
- // } else
- if (!strncasecmp(argv[x], "privacy=", 8)) {
- char *arg = argv[x] + 9;
-
- if (!strcasecmp(arg, "yes")) {
- switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
- } else if (!strcasecmp(arg, "full")) {
- switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
- } else if (!strcasecmp(arg, "name")) {
- switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME);
- } else if (!strcasecmp(arg, "number")) {
- switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER);
- } else {
- switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME);
- switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER);
- }
-
- } else if (!strncasecmp(argv[x], "screen=", 7) && screen > 0) {
- char *arg = argv[x] + 8;
- if (!strcasecmp(arg, "no")) {
- screen = 0;
- switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
- }
- }
- }
- free(mydata);
- }
- }
-}
-
-static void sip_i_invite(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- switch_core_session_t *session = NULL;
- char key[128] = "";
- sip_unknown_t *un;
- private_object_t *tech_pvt = NULL;
- switch_channel_t *channel = NULL;
- const char *channel_name = NULL;
- const char *displayname = NULL;
- const char *destination_number = NULL;
- const char *from_user = NULL, *from_host = NULL;
- const char *context = NULL;
- char network_ip[80];
-
- if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
- nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
- return;
- }
-
-
- if (!(sip->sip_contact && sip->sip_contact->m_url)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
- nua_respond(nh, 400, "Missing Contact Header", TAG_END());
- return;
- }
-
- if ((profile->pflags & PFLAG_AUTH_CALLS)) {
- if (handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key))) {
- return;
- }
- }
-
- if (!(session = switch_core_session_request(&sofia_endpoint_interface, NULL))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Session Alloc Failed!\n");
- nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
- return;
- }
-
- if (!(tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
- nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
- terminate_session(&session, SWITCH_CAUSE_SWITCH_CONGESTION, __LINE__);
- return;
- }
-
- if (!switch_strlen_zero(key)) {
- tech_pvt->key = switch_core_session_strdup(session, key);
- }
-
- get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_addr);
-
- channel = switch_core_session_get_channel(session);
-
- if (sip->sip_from && sip->sip_from->a_url) {
- from_user = sip->sip_from->a_url->url_user;
- from_host = sip->sip_from->a_url->url_host;
- channel_name = url_set_chanvars(session, sip->sip_from->a_url, sip_from);
-
- if (!switch_strlen_zero(from_user)) {
- if (*from_user == '+') {
- switch_channel_set_variable(channel, "sip_from_user_stripped", (const char *) (from_user + 1));
- } else {
- switch_channel_set_variable(channel, "sip_from_user_stripped", from_user);
- }
- }
-
- if (!switch_strlen_zero(sip->sip_from->a_display)) {
- char *tmp;
- tmp = switch_core_session_strdup(session, sip->sip_from->a_display);
- if (*tmp == '"') {
- char *p;
-
- tmp++;
- if ((p = strchr(tmp, '"'))) {
- *p = '\0';
- }
- }
- displayname = tmp;
- } else {
- displayname = switch_strlen_zero(from_user) ? "unkonwn" : from_user;
- }
- }
-
- if (sip->sip_request->rq_url) {
- const char *req_uri = url_set_chanvars(session, sip->sip_request->rq_url, sip_req);
- if (profile->pflags & PFLAG_FULL_ID) {
- destination_number = req_uri;
- } else {
- destination_number = sip->sip_request->rq_url->url_user;
- }
- }
-
- if (sip->sip_to && sip->sip_to->a_url) {
- url_set_chanvars(session, sip->sip_to->a_url, sip_to);
- }
-
- if (sip->sip_contact && sip->sip_contact->m_url) {
- const char *contact_uri = url_set_chanvars(session, sip->sip_contact->m_url, sip_contact);
- if (!channel_name) {
- channel_name = contact_uri;
- }
- }
-
- attach_private(session, profile, tech_pvt, channel_name);
- tech_set_codecs(tech_pvt);
-
- switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "INBOUND CALL");
- set_chat_hash(tech_pvt, sip);
-
- if (switch_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
- switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
- switch_channel_set_flag(channel, CF_NOMEDIA);
- }
-
- if (!tech_pvt->call_id && sip->sip_call_id && sip->sip_call_id->i_id) {
- tech_pvt->call_id = switch_core_session_strdup(session, sip->sip_call_id->i_id);
- switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id);
- }
-
- if (sip->sip_via) {
- if (sip->sip_via->v_host) {
- switch_channel_set_variable(channel, "sip_via_host", sip->sip_via->v_host);
- }
- if (sip->sip_via->v_port) {
- switch_channel_set_variable(channel, "sip_via_port", sip->sip_via->v_port);
- }
- if (sip->sip_via->v_rport) {
- switch_channel_set_variable(channel, "sip_via_rport", sip->sip_via->v_rport);
- }
- }
-
- if (sip->sip_max_forwards) {
- char max_forwards[32];
- snprintf(max_forwards, sizeof(max_forwards), "%lu", sip->sip_max_forwards->mf_count);
- switch_channel_set_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
- }
-
-
- if (sip->sip_request->rq_url) {
- outbound_reg_t *gateway;
- char *from_key = switch_core_session_sprintf(session, "sip:%s@%s",
- (char *) sip->sip_request->rq_url->url_user,
- (char *) sip->sip_request->rq_url->url_host);
-
- if ((gateway = find_gateway(from_key))) {
- context = gateway->register_context;
- switch_channel_set_variable(channel, "sip_gateway", gateway->name);
- }
- }
-
-
- if (!context) {
- if (profile->context && !strcasecmp(profile->context, "_domain_")) {
- context = from_host;
- } else {
- context = profile->context;
- }
- }
-
- tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
- from_user,
- profile->dialplan,
- displayname, from_user, network_ip, NULL, NULL, NULL, modname, context, destination_number);
-
- if (tech_pvt->caller_profile) {
-
- /* Loop thru unknown Headers Here so we can do something with them */
- for (un = sip->sip_unknown; un; un = un->un_next) {
- if (!strncasecmp(un->un_name, "Alert-Info", 10)) {
- if (!switch_strlen_zero(un->un_value)) {
- switch_channel_set_variable(channel, "alert_info", un->un_value);
- }
- } else if (!strncasecmp(un->un_name, "Remote-Party-ID", 15)) {
- process_rpid(un, tech_pvt);
- } else if (!strncasecmp(un->un_name, "X-", 2)) {
- if (!switch_strlen_zero(un->un_value)) {
- char *new_name;
- if ((new_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) {
- switch_channel_set_variable(channel, new_name, un->un_value);
- free(new_name);
- }
- }
- }
- }
-
- switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
- }
-
- if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) {
- abort();
- }
- memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private));
- switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid));
- nua_handle_bind(nh, tech_pvt->sofia_private);
- tech_pvt->nh = nh;
-}
-
-static void sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- char key[128] = "";
-
- if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
- nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
- return;
- }
-
- if (!(sip->sip_contact && sip->sip_contact->m_url)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
- nua_respond(nh, 400, "Missing Contact Header", TAG_END());
- return;
- }
-
- handle_register(nua, profile, nh, sip, REG_REGISTER, key, sizeof(key));
-}
-
-
-static void sip_i_options(int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- nua_respond(nh, SIP_200_OK,
- //SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
- //SOATAG_AUDIO_AUX("cn telephone-event"),
- //NUTAG_INCLUDE_EXTRA_SDP(1),
- TAG_END());
-}
-
-
-static void sip_r_register(int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- if (sofia_private && sofia_private->gateway) {
- switch (status) {
- case 200:
- if (sip && sip->sip_contact && sip->sip_contact->m_expires) {
- char *new_expires = (char *) sip->sip_contact->m_expires;
- uint32_t expi = (uint32_t) atoi(new_expires);
-
- if (expi != sofia_private->gateway->freq) {
- sofia_private->gateway->freq = expi;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
- "Changing expire time to %d by request of proxy %s\n", expi, sofia_private->gateway->register_proxy);
- }
-
- }
- sofia_private->gateway->state = REG_STATE_REGISTER;
- break;
- case 100:
- break;
- default:
- sofia_private->gateway->state = REG_STATE_FAILED;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Registration Failed with status %d\n", status);
- break;
- }
- }
-}
-
-static void sip_r_challenge(int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
-{
- outbound_reg_t *gateway = NULL;
- sip_www_authenticate_t const *authenticate = NULL;
- char const *realm = NULL;
- char *p = NULL, *duprealm = NULL, *qrealm = NULL;
- char const *scheme = NULL;
- int indexnum;
- char *cur;
- char authentication[256] = "";
- int ss_state;
-
- if (session) {
- private_object_t *tech_pvt;
- 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");
- return;
- }
- }
-
-
- if (sip->sip_www_authenticate) {
- authenticate = sip->sip_www_authenticate;
- } else if (sip->sip_proxy_authenticate) {
- authenticate = sip->sip_proxy_authenticate;
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Missing Authenticate Header!\n");
- return;
- }
- scheme = (char const *) authenticate->au_scheme;
- if (authenticate->au_params) {
- for (indexnum = 0; (cur = (char *) authenticate->au_params[indexnum]); indexnum++) {
- if ((realm = strstr(cur, "realm="))) {
- realm += 6;
- break;
- }
- }
- }
-
- if (!(scheme && realm)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No scheme and realm!\n");
- return;
- }
-
- if (profile) {
- outbound_reg_t *gateway_ptr;
-
- if ((duprealm = strdup(realm))) {
- qrealm = duprealm;
-
- while (*qrealm && *qrealm == '"') {
- qrealm++;
- }
-
- if ((p = strchr(qrealm, '"'))) {
- *p = '\0';
- }
-
- if (sip->sip_from) {
- char *from_key = switch_mprintf("sip:%s@%s",
- (char *) sip->sip_from->a_url->url_user,
- (char *) sip->sip_from->a_url->url_host);
-
- if (!(gateway = find_gateway(from_key))) {
- gateway = find_gateway(qrealm);
- }
-
- switch_safe_free(from_key);
- }
-
- if (!gateway) {
- for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
- if (scheme && qrealm && !strcasecmp(gateway_ptr->register_scheme, scheme)
- && !strcasecmp(gateway_ptr->register_realm, qrealm)) {
- gateway = gateway_ptr;
- break;
- }
- }
- }
-
- if (!gateway) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Match for Scheme [%s] Realm [%s]\n", scheme, qrealm);
- return;
- }
- switch_safe_free(duprealm);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
- return;
- }
- }
-
- snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, gateway->register_username, gateway->register_password);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Authenticating '%s' with '%s'.\n", profile->username, authentication);
-
-
- ss_state = nua_callstate_authenticating;
-
- tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), SIPTAG_WWW_AUTHENTICATE_REF(authenticate), TAG_END());
-
- nua_authenticate(nh, SIPTAG_EXPIRES_STR(gateway->expires_str), NUTAG_AUTH(authentication), TAG_END());
-
-}
-
-static void event_callback(nua_event_t event,
- int status,
- char const *phrase,
- nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
-{
- struct private_object *tech_pvt = NULL;
- auth_res_t auth_res = AUTH_FORBIDDEN;
- switch_core_session_t *session = NULL;
- switch_channel_t *channel = NULL;
-
- if (sofia_private) {
- if (!switch_strlen_zero(sofia_private->uuid)) {
-
- if ((session = switch_core_session_locate(sofia_private->uuid))) {
- tech_pvt = switch_core_session_get_private(session);
- channel = switch_core_session_get_channel(tech_pvt->session);
- if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
- switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
- }
- if (!tech_pvt->call_id && sip && sip->sip_call_id && sip->sip_call_id->i_id) {
- tech_pvt->call_id = switch_core_session_strdup(session, (char *) sip->sip_call_id->i_id);
- switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id);
- }
- } else {
- /* too late */
- return;
- }
- }
- }
-
-
- if (status != 100 && status != 200) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] session: %s\n",
- nua_event_name(event), status, phrase, session ? switch_channel_get_name(channel) : "n/a");
- }
-
- if ((profile->pflags & PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) {
- sip_authorization_t const *authorization = NULL;
-
- if (sip->sip_authorization) {
- authorization = sip->sip_authorization;
- } else if (sip->sip_proxy_authorization) {
- authorization = sip->sip_proxy_authorization;
- }
-
- if (authorization) {
- auth_res = parse_auth(profile, authorization, (char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key));
- }
-
- if (auth_res != AUTH_OK) {
- switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
- nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
- goto done;
- }
-
- if (channel) {
- switch_channel_set_variable(channel, "sip_authorized", "true");
- }
- }
-
- if (sip && (status == 401 || status == 407)) {
- sip_r_challenge(status, phrase, nua, profile, nh, session, sip, tags);
- goto done;
- }
+ switch (msg->message_id) {
+ case SWITCH_MESSAGE_INDICATE_NOMEDIA:{
+ char *uuid;
+ switch_core_session_t *other_session;
+ switch_channel_t *other_channel;
+ char *ip = NULL, *port = NULL;
- switch (event) {
- case nua_r_shutdown:
- case nua_r_get_params:
- case nua_r_invite:
- case nua_r_unregister:
- case nua_r_options:
- case nua_i_fork:
- case nua_r_info:
- case nua_r_bye:
- case nua_i_bye:
- case nua_r_unsubscribe:
- case nua_r_publish:
- case nua_r_message:
- case nua_r_notify:
- case nua_i_notify:
- case nua_i_cancel:
- case nua_i_error:
- case nua_i_active:
- case nua_i_ack:
- case nua_i_terminated:
- case nua_r_set_params:
- break;
- case nua_r_register:
- sip_r_register(status, phrase, nua, profile, nh, sofia_private, sip, tags);
- break;
- case nua_i_options:
- sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, tags);
- break;
- case nua_i_invite:
- if (!session) {
- sip_i_invite(nua, profile, nh, sofia_private, sip, tags);
- }
- break;
- case nua_i_publish:
- sip_i_publish(nua, profile, nh, sofia_private, sip, tags);
- break;
- case nua_i_register:
- sip_i_register(nua, profile, nh, sofia_private, sip, tags);
- break;
- case nua_i_prack:
- break;
- case nua_i_state:
- sip_i_state(status, phrase, nua, profile, nh, sofia_private, sip, tags);
- break;
- case nua_i_message:
- sip_i_message(status, phrase, nua, profile, nh, sofia_private, sip, tags);
- break;
- case nua_i_info:
- sip_i_info(nua, profile, nh, session, sip, tags);
- break;
- case nua_r_refer:
- break;
- case nua_i_refer:
- if (session) {
- sip_i_refer(nua, profile, nh, session, sip, tags);
- }
- break;
- case nua_r_subscribe:
- sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
- break;
- case nua_i_subscribe:
- sip_i_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
- break;
- default:
- if (status > 100) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: unknown event %d: %03d %s\n", nua_event_name(event), event, status, phrase);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: unknown event %d\n", nua_event_name(event), event);
+ switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+ tech_pvt->local_sdp_str = NULL;
+ if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+ && (other_session = switch_core_session_locate(uuid))) {
+ other_channel = switch_core_session_get_channel(other_session);
+ ip = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE);
+ port = switch_channel_get_variable(other_channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE);
+ switch_core_session_rwunlock(other_session);
+ if (ip && port) {
+ sofia_glue_set_local_sdp(tech_pvt, ip, atoi(port), NULL, 1);
+ }
+ }
+ if (!tech_pvt->local_sdp_str) {
+ sofia_glue_tech_absorb_sdp(tech_pvt);
+ }
+ sofia_glue_do_invite(session);
}
break;
- }
-
- done:
-
- if (session) {
- switch_core_session_rwunlock(session);
- }
-}
-
-
-static void unreg(sofia_profile_t * profile)
-{
- outbound_reg_t *gateway_ptr;
- for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
- if (gateway_ptr->sofia_private) {
- free(gateway_ptr->sofia_private);
- nua_handle_bind(gateway_ptr->nh, NULL);
- gateway_ptr->sofia_private = NULL;
- }
- nua_handle_destroy(gateway_ptr->nh);
- }
-}
-
-static void check_gateway(sofia_profile_t * profile, time_t now)
-{
- outbound_reg_t *gateway_ptr;
- for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
- int ss_state = nua_callstate_authenticating;
- reg_state_t ostate = gateway_ptr->state;
-
- switch (ostate) {
- case REG_STATE_REGISTER:
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "registered %s\n", gateway_ptr->name);
- gateway_ptr->expires = now + gateway_ptr->freq;
- gateway_ptr->state = REG_STATE_REGED;
- break;
- case REG_STATE_UNREGED:
- if ((gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL,
- NUTAG_URL(gateway_ptr->register_proxy),
- SIPTAG_TO_STR(gateway_ptr->register_to),
- NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END()))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "registering %s\n", gateway_ptr->name);
-
- if (!(gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private)))) {
- abort();
+ case SWITCH_MESSAGE_INDICATE_MEDIA:{
+ switch_clear_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+ tech_pvt->local_sdp_str = NULL;
+ if (!switch_rtp_ready(tech_pvt->rtp_session)) {
+ sofia_glue_sofia_glue_tech_set_codecs(tech_pvt);
+ if ((status = sofia_glue_tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
+ return status;
}
- memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private));
-
- gateway_ptr->sofia_private->gateway = gateway_ptr;
- nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private);
-
- nua_register(gateway_ptr->nh,
- SIPTAG_FROM_STR(gateway_ptr->register_from),
- SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
- SIPTAG_EXPIRES_STR(gateway_ptr->expires_str),
- NUTAG_REGISTRAR(gateway_ptr->register_proxy),
- NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL());
- gateway_ptr->retry = now + 10;
- gateway_ptr->state = REG_STATE_TRYING;
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error registering %s\n", gateway_ptr->name);
- gateway_ptr->state = REG_STATE_FAILED;
}
- break;
-
- case REG_STATE_TRYING:
- if (gateway_ptr->retry && now >= gateway_ptr->retry) {
- gateway_ptr->state = REG_STATE_UNREGED;
- gateway_ptr->retry = 0;
- }
- break;
- default:
- if (now >= gateway_ptr->expires) {
- gateway_ptr->state = REG_STATE_UNREGED;
+ sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 1);
+ sofia_glue_do_invite(session);
+ while (!switch_rtp_ready(tech_pvt->rtp_session) && switch_channel_get_state(channel) < CS_HANGUP) {
+ switch_yield(1000);
}
- break;
- }
- }
-
-}
-
-#define IREG_SECONDS 30
-#define GATEWAY_SECONDS 1
-static void *SWITCH_THREAD_FUNC profile_thread_run(switch_thread_t * thread, void *obj)
-{
- sofia_profile_t *profile = (sofia_profile_t *) obj;
- switch_memory_pool_t *pool;
- sip_alias_node_t *node;
- uint32_t ireg_loops = 0;
- uint32_t gateway_loops = 0;
- switch_core_db_t *db;
- switch_event_t *s_event;
-
- profile->s_root = su_root_create(NULL);
- profile->home = su_home_new(sizeof(*profile->home));
-
- profile->nua = nua_create(profile->s_root, /* Event loop */
- event_callback, /* Callback for processing events */
- profile, /* Additional data to pass to callback */
- NUTAG_URL(profile->bindurl), NTATAG_UDP_MTU(65536), TAG_END()); /* Last tag should always finish the sequence */
-
- nua_set_params(profile->nua,
- //NUTAG_EARLY_MEDIA(1),
- NUTAG_AUTOANSWER(0),
- NUTAG_AUTOALERT(0),
- NUTAG_ALLOW("REGISTER"),
- NUTAG_ALLOW("REFER"),
- NUTAG_ALLOW("INFO"),
- TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")),
- TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("NOTIFY")),
- TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("SUBSCRIBE")),
- TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
- TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence")),
- TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence.winfo")),
- SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END());
-
-
- for (node = profile->aliases; node; node = node->next) {
- node->nua = nua_create(profile->s_root, /* Event loop */
- event_callback, /* Callback for processing events */
- profile, /* Additional data to pass to callback */
- NUTAG_URL(node->url), TAG_END()); /* Last tag should always finish the sequence */
-
- nua_set_params(node->nua,
- NUTAG_EARLY_MEDIA(1),
- NUTAG_AUTOANSWER(0),
- NUTAG_AUTOALERT(0),
- NUTAG_ALLOW("REGISTER"),
- NUTAG_ALLOW("REFER"),
- NUTAG_ALLOW("INFO"),
- TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")),
- TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
- SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END());
-
- }
-
-
- if ((db = switch_core_db_open_file(profile->dbname))) {
- switch_core_db_test_reactive(db, "select contact from sip_registrations", reg_sql);
- switch_core_db_test_reactive(db, "select contact from sip_subscriptions", sub_sql);
- switch_core_db_test_reactive(db, "select * from sip_authentication", auth_sql);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n");
- return NULL;
- }
-
-
- switch_mutex_init(&profile->ireg_mutex, SWITCH_MUTEX_NESTED, profile->pool);
- switch_mutex_init(&profile->gateway_mutex, SWITCH_MUTEX_NESTED, profile->pool);
-
- ireg_loops = IREG_SECONDS;
- gateway_loops = GATEWAY_SECONDS;
-
- if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
- switch_event_fire(&s_event);
- }
-
- if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._tcp");
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
- switch_event_fire(&s_event);
- }
-
- if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._sctp");
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
- switch_event_fire(&s_event);
- }
-
- add_profile(profile->name, profile);
-
- if (profile->pflags & PFLAG_PRESENCE) {
- establish_presence(profile);
- }
-
- while (globals.running == 1) {
- if (++ireg_loops >= IREG_SECONDS) {
- check_expire(db, profile, time(NULL));
- ireg_loops = 0;
}
+ break;
- if (++gateway_loops >= GATEWAY_SECONDS) {
- check_gateway(profile, time(NULL));
- gateway_loops = 0;
+ case SWITCH_MESSAGE_INDICATE_HOLD:{
+ switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ sofia_glue_do_invite(session);
}
+ break;
- su_root_step(profile->s_root, 1000);
- }
-
- switch_core_db_close(db);
- unreg(profile);
- su_home_unref(profile->home);
-
-
- if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
- switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
- switch_event_fire(&s_event);
- }
-
- su_root_destroy(profile->s_root);
- pool = profile->pool;
- switch_core_destroy_memory_pool(&pool);
- switch_mutex_lock(globals.mutex);
- globals.running = 0;
- switch_mutex_unlock(globals.mutex);
-
- return NULL;
-}
-
-static void launch_profile_thread(sofia_profile_t * profile)
-{
- switch_thread_t *thread;
- switch_threadattr_t *thd_attr = NULL;
-
- switch_threadattr_create(&thd_attr, profile->pool);
- switch_threadattr_detach_set(thd_attr, 1);
- switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
- switch_thread_create(&thread, thd_attr, profile_thread_run, profile, profile->pool);
-}
-
-
-
-static switch_status_t config_sofia(int reload)
-{
- char *cf = "sofia.conf";
- switch_xml_t cfg, xml = NULL, xprofile, param, settings, profiles, gateway_tag, gateways_tag;
- switch_status_t status = SWITCH_STATUS_SUCCESS;
- sofia_profile_t *profile = NULL;
- char url[512] = "";
- switch_mutex_lock(globals.mutex);
- globals.running = 1;
- switch_mutex_unlock(globals.mutex);
-
- if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
- status = SWITCH_STATUS_FALSE;
- goto done;
- }
-
- if ((settings = switch_xml_child(cfg, "global_settings"))) {
- for (param = switch_xml_child(settings, "param"); param; param = param->next) {
- char *var = (char *) switch_xml_attr_soft(param, "name");
- char *val = (char *) switch_xml_attr_soft(param, "value");
- if (!strcasecmp(var, "log-level")) {
- su_log_set_level(NULL, atoi(val));
- } else if (!strcasecmp(var, "log-level-trace")) {
- su_log_set_level(tport_log, atoi(val));
- }
+ case SWITCH_MESSAGE_INDICATE_UNHOLD:{
+ switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ sofia_glue_do_invite(session);
}
- }
-
- if ((profiles = switch_xml_child(cfg, "profiles"))) {
- for (xprofile = switch_xml_child(profiles, "profile"); xprofile; xprofile = xprofile->next) {
- if (!(settings = switch_xml_child(xprofile, "settings"))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Settings, check the new config!\n");
- } else {
- char *xprofilename = (char *) switch_xml_attr_soft(xprofile, "name");
- switch_memory_pool_t *pool = NULL;
-
-
- /* Setup the pool */
- if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
- goto done;
- }
-
- if (!(profile = (sofia_profile_t *) switch_core_alloc(pool, sizeof(*profile)))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
- goto done;
- }
-
- if (!xprofilename) {
- xprofilename = "unnamed";
- }
-
- profile->pool = pool;
-
- profile->name = switch_core_strdup(profile->pool, xprofilename);
- snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename);
- profile->dbname = switch_core_strdup(profile->pool, url);
- switch_core_hash_init(&profile->chat_hash, profile->pool);
-
- profile->dtmf_duration = 100;
- profile->codec_ms = 20;
-
- for (param = switch_xml_child(settings, "param"); param; param = param->next) {
- char *var = (char *) switch_xml_attr_soft(param, "name");
- char *val = (char *) switch_xml_attr_soft(param, "value");
-
- if (!strcasecmp(var, "debug")) {
- profile->debug = atoi(val);
- } else if (!strcasecmp(var, "use-rtp-timer") && switch_true(val)) {
- switch_set_flag(profile, TFLAG_TIMER);
- } else if (!strcasecmp(var, "inbound-no-media") && switch_true(val)) {
- switch_set_flag(profile, TFLAG_INB_NOMEDIA);
- } else if (!strcasecmp(var, "inbound-late-negotiation") && switch_true(val)) {
- switch_set_flag(profile, TFLAG_LATE_NEGOTIATION);
- } else if (!strcasecmp(var, "rfc2833-pt")) {
- profile->te = (switch_payload_t) atoi(val);
- } else if (!strcasecmp(var, "cng-pt")) {
- profile->cng_pt = (switch_payload_t) atoi(val);
- } else if (!strcasecmp(var, "sip-port")) {
- profile->sip_port = atoi(val);
- } else if (!strcasecmp(var, "vad")) {
- if (!strcasecmp(val, "in")) {
- switch_set_flag(profile, TFLAG_VAD_IN);
- } else if (!strcasecmp(val, "out")) {
- switch_set_flag(profile, TFLAG_VAD_OUT);
- } else if (!strcasecmp(val, "both")) {
- switch_set_flag(profile, TFLAG_VAD_IN);
- switch_set_flag(profile, TFLAG_VAD_OUT);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invald option %s for VAD\n", val);
- }
- } else if (!strcasecmp(var, "ext-rtp-ip")) {
- profile->extrtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
- } else if (!strcasecmp(var, "rtp-ip")) {
- profile->rtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
- } else if (!strcasecmp(var, "sip-ip")) {
- profile->sipip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
- } else if (!strcasecmp(var, "ext-sip-ip")) {
- if (!strcasecmp(val, "auto")) {
- profile->extsipip = switch_core_strdup(profile->pool, globals.guess_ip);
- } else {
- char *ip = NULL;
- switch_port_t port = 0;
- if (sofia_ext_address_lookup(&ip, &port, val, profile->pool) == SWITCH_STATUS_SUCCESS) {
-
- if (ip) {
- profile->extsipip = switch_core_strdup(profile->pool, ip);
- }
- }
- }
-
- } else if (!strcasecmp(var, "sip-domain")) {
- profile->sipdomain = switch_core_strdup(profile->pool, val);
- } else if (!strcasecmp(var, "rtp-timer-name")) {
- profile->timer_name = switch_core_strdup(profile->pool, val);
- } else if (!strcasecmp(var, "hold-music")) {
- profile->hold_music = switch_core_strdup(profile->pool, val);
- } else if (!strcasecmp(var, "manage-presence")) {
- if (switch_true(val)) {
- profile->pflags |= PFLAG_PRESENCE;
- }
- } else if (!strcasecmp(var, "pass-rfc2833")) {
- if (switch_true(val)) {
- profile->pflags |= PFLAG_PASS_RFC2833;
- }
- } else if (!strcasecmp(var, "disable-transcoding")) {
- if (switch_true(val)) {
- profile->pflags |= PFLAG_DISABLE_TRANSCODING;
- }
- } else if (!strcasecmp(var, "auth-calls")) {
- if (switch_true(val)) {
- profile->pflags |= PFLAG_AUTH_CALLS;
- }
- } else if (!strcasecmp(var, "nonce-ttl")) {
- profile->nonce_ttl = atoi(val);
- } else if (!strcasecmp(var, "accept-blind-reg")) {
- if (switch_true(val)) {
- profile->pflags |= PFLAG_BLIND_REG;
- }
- } else if (!strcasecmp(var, "auth-all-packets")) {
- if (switch_true(val)) {
- profile->pflags |= PFLAG_AUTH_ALL;
- }
- } else if (!strcasecmp(var, "full-id-in-dialplan")) {
- if (switch_true(val)) {
- profile->pflags |= PFLAG_FULL_ID;
- }
- } else if (!strcasecmp(var, "bitpacking")) {
- if (!strcasecmp(val, "aal2")) {
- profile->codec_flags = SWITCH_CODEC_FLAG_AAL2;
- }
- } else if (!strcasecmp(var, "username")) {
- profile->username = switch_core_strdup(profile->pool, val);
- } else if (!strcasecmp(var, "context")) {
- profile->context = switch_core_strdup(profile->pool, val);
- } else if (!strcasecmp(var, "alias")) {
- sip_alias_node_t *node;
- if ((node = switch_core_alloc(profile->pool, sizeof(*node)))) {
- if ((node->url = switch_core_strdup(profile->pool, val))) {
- node->next = profile->aliases;
- profile->aliases = node;
- }
- }
- } else if (!strcasecmp(var, "dialplan")) {
- profile->dialplan = switch_core_strdup(profile->pool, val);
- } else if (!strcasecmp(var, "max-calls")) {
- profile->max_calls = atoi(val);
- } else if (!strcasecmp(var, "codec-prefs")) {
- profile->codec_string = switch_core_strdup(profile->pool, val);
- } else if (!strcasecmp(var, "codec-ms")) {
- profile->codec_ms = atoi(val);
- } else if (!strcasecmp(var, "dtmf-duration")) {
- int dur = atoi(val);
- if (dur > 10 && dur < 8000) {
- profile->dtmf_duration = dur;
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds!\n");
- }
- }
- }
-
- if (!profile->cng_pt) {
- profile->cng_pt = SWITCH_RTP_CNG_PAYLOAD;
- }
-
- if (!profile->sipip) {
- profile->sipip = switch_core_strdup(profile->pool, globals.guess_ip);
- }
-
- if (!profile->rtpip) {
- profile->rtpip = switch_core_strdup(profile->pool, globals.guess_ip);
- }
-
- if (profile->nonce_ttl < 60) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting nonce TTL to 60 seconds\n");
- profile->nonce_ttl = 60;
- }
-
- if (switch_test_flag(profile, TFLAG_TIMER) && !profile->timer_name) {
- profile->timer_name = switch_core_strdup(profile->pool, "soft");
- }
-
- if (!profile->username) {
- profile->username = switch_core_strdup(profile->pool, "FreeSWITCH");
- }
+ break;
+ case SWITCH_MESSAGE_INDICATE_BRIDGE:
- if (!profile->rtpip) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Setting ip to '127.0.0.1'\n");
- profile->rtpip = switch_core_strdup(profile->pool, "127.0.0.1");
- }
+ if (switch_test_flag(tech_pvt, TFLAG_XFER)) {
+ switch_clear_flag_locked(tech_pvt, TFLAG_XFER);
+ if (msg->pointer_arg) {
+ switch_core_session_t *a_session, *b_session = msg->pointer_arg;
- if (!profile->sip_port) {
- profile->sip_port = atoi(SOFIA_DEFAULT_PORT);
- }
+ if ((a_session = switch_core_session_locate(tech_pvt->xferto))) {
+ private_object_t *a_tech_pvt = switch_core_session_get_private(a_session);
+ private_object_t *b_tech_pvt = switch_core_session_get_private(b_session);
- if (!profile->dialplan) {
- profile->dialplan = switch_core_strdup(profile->pool, "XML");
- }
+ switch_set_flag_locked(a_tech_pvt, TFLAG_REINVITE);
+ a_tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(a_session, 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(a_session, b_tech_pvt->local_sdp_audio_ip);
+ a_tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port;
+ sofia_glue_activate_rtp(a_tech_pvt);
- if (!profile->sipdomain) {
- profile->sipdomain = switch_core_strdup(profile->pool, profile->sipip);
- }
- if (profile->extsipip) {
- profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->extsipip, profile->sip_port);
- profile->bindurl = switch_core_sprintf(profile->pool, "%s;maddr=%s", profile->url, profile->sipip);
- } else {
- profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->sipip, profile->sip_port);
- profile->bindurl = profile->url;
- }
- }
- if (profile) {
- if ((gateways_tag = switch_xml_child(xprofile, "registrations"))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
- "The <registrations> syntax has been discontinued, please see the new syntax in the default configuration examples\n");
+ b_tech_pvt->kick = switch_core_session_strdup(b_session, tech_pvt->xferto);
+ switch_core_session_rwunlock(a_session);
}
- if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) {
- for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) {
- char *name = (char *) switch_xml_attr_soft(gateway_tag, "name");
- outbound_reg_t *gateway;
-
- if (switch_strlen_zero(name)) {
- name = "anonymous";
- }
-
- if ((gateway = switch_core_alloc(profile->pool, sizeof(*gateway)))) {
- char *scheme = "Digest",
- *realm = NULL,
- *username = NULL, *password = NULL, *extension = NULL, *proxy = NULL, *context = "default", *expire_seconds = "3600";
-
- gateway->pool = profile->pool;
- gateway->profile = profile;
- gateway->name = switch_core_strdup(gateway->pool, name);
- gateway->freq = 0;
-
-
- for (param = switch_xml_child(gateway_tag, "param"); param; param = param->next) {
- char *var = (char *) switch_xml_attr_soft(param, "name");
- char *val = (char *) switch_xml_attr_soft(param, "value");
-
- if (!strcmp(var, "scheme")) {
- scheme = val;
- } else if (!strcmp(var, "realm")) {
- realm = val;
- } else if (!strcmp(var, "username")) {
- username = val;
- } else if (!strcmp(var, "password")) {
- password = val;
- } else if (!strcmp(var, "extension")) {
- extension = val;
- } else if (!strcmp(var, "proxy")) {
- proxy = val;
- } else if (!strcmp(var, "context")) {
- context = val;
- } else if (!strcmp(var, "expire-seconds")) {
- expire_seconds = val;
- }
- }
-
- if (switch_strlen_zero(realm)) {
- realm = name;
- }
-
- if (switch_strlen_zero(username)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: username param is REQUIRED!\n");
- switch_xml_free(xml);
- goto skip;
- }
-
- if (switch_strlen_zero(password)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: password param is REQUIRED!\n");
- switch_xml_free(xml);
- goto skip;
- }
-
- if (switch_strlen_zero(extension)) {
- extension = username;
- }
-
- if (switch_strlen_zero(proxy)) {
- proxy = realm;
- }
-
- gateway->register_scheme = switch_core_strdup(gateway->pool, scheme);
- gateway->register_context = switch_core_strdup(gateway->pool, context);
- gateway->register_realm = switch_core_strdup(gateway->pool, realm);
- gateway->register_username = switch_core_strdup(gateway->pool, username);
- gateway->register_password = switch_core_strdup(gateway->pool, password);
- gateway->register_from = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, realm);
- gateway->register_contact = switch_core_sprintf(gateway->pool, "sip:%s@%s:%d", extension, profile->sipip, profile->sip_port);
-
- if (!strncasecmp(proxy, "sip:", 4)) {
- gateway->register_proxy = switch_core_strdup(gateway->pool, proxy);
- gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4);
- } else {
- gateway->register_proxy = switch_core_sprintf(gateway->pool, "sip:%s", proxy);
- gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy);
- }
-
- gateway->expires_str = switch_core_strdup(gateway->pool, expire_seconds);
-
- if ((gateway->freq = atoi(gateway->expires_str)) < 5) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
- "Invalid Freq: %d. Setting Register-Frequency to 3600\n", gateway->freq);
- gateway->freq = 3600;
- }
- gateway->freq -= 2;
-
- gateway->next = profile->gateways;
- profile->gateways = gateway;
-
- if (find_gateway(gateway->name)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", gateway->name);
- } else if (find_gateway(gateway->register_from)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate uri '%s'\n", gateway->register_from);
- } else if (find_gateway(gateway->register_contact)) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate contact '%s'\n", gateway->register_from);
- } else {
- add_gateway(gateway->name, gateway);
- add_gateway(gateway->register_from, gateway);
- add_gateway(gateway->register_contact, gateway);
- }
- }
-
- skip:
- assert(gateway_tag);
- }
- }
- if (profile->sipip) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Started Profile %s [%s]\n", profile->name, url);
- launch_profile_thread(profile);
- } else {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Unable to start Profile %s due to no configured sip-ip\n", profile->name);
- }
- profile = NULL;
+ msg->pointer_arg = NULL;
+ return SWITCH_STATUS_FALSE;
}
}
- }
- done:
- if (xml) {
- switch_xml_free(xml);
- }
-
- return status;
-
-}
-
-static void event_handler(switch_event_t *event)
-{
- char *subclass, *sql;
-
- if ((subclass = switch_event_get_header(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_REGISTER)) {
- char *from_user = switch_event_get_header(event, "orig-from-user");
- char *from_host = switch_event_get_header(event, "orig-from-host");
- char *contact_str = switch_event_get_header(event, "orig-contact");
- char *exp_str = switch_event_get_header(event, "orig-expires");
- char *rpid = switch_event_get_header(event, "orig-rpid");
- long expires = (long) time(NULL) + atol(exp_str);
- char *profile_name = switch_event_get_header(event, "orig-profile-name");
- sofia_profile_t *profile;
- char buf[512];
-
- if (!rpid) {
- rpid = "unknown";
- }
-
- if (!profile_name || !(profile = find_profile(profile_name))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
- return;
- }
-
-
- if (!find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
- sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Regestered', '%q', %ld)",
- from_user, from_host, contact_str, rpid, expires);
- } else {
- sql =
- switch_mprintf
- ("update sip_registrations set contact='%q', rpid='%q', expires=%ld where user='%q' and host='%q'",
- contact_str, rpid, expires, from_user, from_host);
-
- }
-
- if (sql) {
- execute_sql(profile->dbname, sql, profile->ireg_mutex);
- switch_safe_free(sql);
- sql = NULL;
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Propagating registration for %s@%s->%s\n", from_user, from_host, contact_str);
-
- }
-
- }
-}
-
-
-static switch_status_t chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint)
-{
- char buf[256];
- char *user, *host;
- sofia_profile_t *profile;
- char *ffrom = NULL;
- nua_handle_t *msg_nh;
- char *contact;
-
- if (to && (user = strdup(to))) {
- if ((host = strchr(user, '@'))) {
- *host++ = '\0';
+ 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");
}
-
- if (!host || !(profile = find_profile(host))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
- "Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n", proto, from, to,
- body ? body : "[no body]", host ? host : "NULL");
- return SWITCH_STATUS_FALSE;
+ break;
+ case SWITCH_MESSAGE_INDICATE_UNBRIDGE:
+ if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_TIMER)) {
+ switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_USE_TIMER);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-activate timed RTP!\n");
}
-
- if (!find_reg_url(profile, user, host, buf, sizeof(buf))) {
- return SWITCH_STATUS_FALSE;
+ break;
+ case SWITCH_MESSAGE_INDICATE_REDIRECT:
+ if (msg->string_arg) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Re-directing to %s\n", msg->string_arg);
+ nua_respond(tech_pvt->nh, SIP_302_MOVED_TEMPORARILY, SIPTAG_CONTACT_STR(msg->string_arg), TAG_END());
}
+ break;
+ case SWITCH_MESSAGE_INDICATE_RINGING:
+ nua_respond(tech_pvt->nh, SIP_180_RINGING, SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END());
+ break;
+ case SWITCH_MESSAGE_INDICATE_PROGRESS:{
+ if (!switch_test_flag(tech_pvt, TFLAG_ANS)) {
+ 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 (!strcmp(proto, SOFIA_CHAT_PROTO)) {
- from = hint;
- } else {
- char *fp, *p, *fu = NULL;
+ /* Transmit 183 Progress with SDP */
+ if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
+ char *sdp = NULL;
+ switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+ if ((sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
+ tech_pvt->local_sdp_str = switch_core_session_strdup(session, sdp);
+ }
+ } else {
+ if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
+ char *r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
+ if (sofia_glue_tech_media(tech_pvt, r_sdp) != SWITCH_STATUS_SUCCESS) {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
+ nua_respond(tech_pvt->nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+ return SWITCH_STATUS_FALSE;
+ }
+ switch_clear_flag_locked(tech_pvt, TFLAG_LATE_NEGOTIATION);
+ }
- if (!(fp = strdup(from))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
- return SWITCH_STATUS_FALSE;
- }
+ if ((status = sofia_glue_tech_choose_port(tech_pvt)) != SWITCH_STATUS_SUCCESS) {
+ return status;
+ }
+ sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+ sofia_glue_activate_rtp(tech_pvt);
+ if (tech_pvt->local_sdp_str) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Ring SDP:\n%s\n", tech_pvt->local_sdp_str);
+ }
+ }
- if ((p = strchr(fp, '@'))) {
- *p = '\0';
- fu = strdup(fp);
- *p = '+';
+ nua_respond(tech_pvt->nh,
+ SIP_183_SESSION_PROGRESS,
+ SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+ SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str), SOATAG_AUDIO_AUX("cn telephone-event"), TAG_END());
}
-
- ffrom = switch_mprintf("\"%s\" <sip:%s+%s@%s>", fu, proto, fp, profile->name);
- from = ffrom;
- switch_safe_free(fu);
- switch_safe_free(fp);
}
-
- contact = get_url_from_contact(buf, 1);
- msg_nh = nua_handle(profile->nua, NULL, SIPTAG_FROM_STR(from), NUTAG_URL(contact), SIPTAG_TO_STR(buf), // if this cries, add contact here too, change the 1 to 0 and omit the safe_free
- SIPTAG_CONTACT_STR(profile->url), TAG_END());
-
- switch_safe_free(contact);
-
-
- nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END());
-
-
- switch_safe_free(ffrom);
- free(user);
+ break;
+ default:
+ break;
}
return SWITCH_STATUS_SUCCESS;
}
-static void cancel_presence(void)
+static switch_status_t sofia_receive_event(switch_core_session_t *session, switch_event_t *event)
{
- char *sql, *errmsg = NULL;
- switch_core_db_t *db;
- sofia_profile_t *profile;
- switch_hash_index_t *hi;
- void *val;
+ switch_channel_t *channel;
+ struct private_object *tech_pvt;
+ char *body;
+ nua_handle_t *msg_nh;
- if ((sql = switch_mprintf("select 0,'unavailable','unavailable',* from sip_subscriptions where event='presence'"))) {
- switch_mutex_lock(globals.hash_mutex);
- for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
- switch_hash_this(hi, NULL, NULL, &val);
- profile = (sofia_profile_t *) val;
- if (!(profile->pflags & PFLAG_PRESENCE)) {
- continue;
- }
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
- if (!(db = switch_core_db_open_file(profile->dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
- continue;
- }
- switch_mutex_lock(profile->ireg_mutex);
- switch_core_db_exec(db, sql, sub_callback, profile, &errmsg);
- switch_mutex_unlock(profile->ireg_mutex);
- switch_core_db_close(db);
- }
- switch_safe_free(sql);
- }
- switch_mutex_unlock(globals.hash_mutex);
-}
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
-static void establish_presence(sofia_profile_t * profile)
-{
- char *sql, *errmsg = NULL;
- switch_core_db_t *db;
- if (!(db = switch_core_db_open_file(profile->dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
- return;
+ if (!(body = switch_event_get_body(event))) {
+ body = "";
}
- if ((sql = switch_mprintf("select user,host,'Registered','unknown','' from sip_registrations"))) {
- switch_mutex_lock(profile->ireg_mutex);
- switch_core_db_exec(db, sql, resub_callback, profile, &errmsg);
- switch_mutex_unlock(profile->ireg_mutex);
- switch_safe_free(sql);
- }
+ if (tech_pvt->hash_key) {
+ msg_nh = nua_handle(tech_pvt->profile->nua, NULL,
+ SIPTAG_FROM_STR(tech_pvt->chat_from),
+ NUTAG_URL(tech_pvt->chat_to), SIPTAG_TO_STR(tech_pvt->chat_to), SIPTAG_CONTACT_STR(tech_pvt->profile->url), TAG_END());
- if ((sql = switch_mprintf("select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions "
- "where proto='ext' or proto='user' or proto='conf'"))) {
- switch_mutex_lock(profile->ireg_mutex);
- switch_core_db_exec(db, sql, resub_callback, profile, &errmsg);
- switch_mutex_unlock(profile->ireg_mutex);
- switch_safe_free(sql);
+ nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END());
}
- switch_core_db_close(db);
-
+ return SWITCH_STATUS_SUCCESS;
}
+static const switch_io_routines_t sofia_io_routines = {
+ /*.outgoing_channel */ sofia_outgoing_channel,
+ /*.answer_channel */ sofia_answer_channel,
+ /*.read_frame */ sofia_read_frame,
+ /*.write_frame */ sofia_write_frame,
+ /*.kill_channel */ sofia_kill_channel,
+ /*.waitfor_read */ sofia_waitfor_read,
+ /*.waitfor_read */ sofia_waitfor_write,
+ /*.send_dtmf */ sofia_send_dtmf,
+ /*.receive_message */ sofia_receive_message,
+ /*.receive_event */ sofia_receive_event
+};
+
+static const switch_state_handler_table_t sofia_event_handlers = {
+ /*.on_init */ sofia_on_init,
+ /*.on_ring */ sofia_on_ring,
+ /*.on_execute */ sofia_on_execute,
+ /*.on_hangup */ sofia_on_hangup,
+ /*.on_loopback */ sofia_on_loopback,
+ /*.on_transmit */ sofia_on_transmit
+};
+const switch_endpoint_interface_t sofia_endpoint_interface = {
+ /*.interface_name */ "sofia",
+ /*.io_routines */ &sofia_io_routines,
+ /*.event_handlers */ &sofia_event_handlers,
+ /*.private */ NULL,
+ /*.next */ NULL
+};
-static char *translate_rpid(char *in, char *ext)
-{
- char *r = NULL;
+static const switch_chat_interface_t sofia_chat_interface = {
+ /*.name */ SOFIA_CHAT_PROTO,
+ /*.sofia_presence_chat_send */ sofia_presence_chat_send,
- if (in && (strstr(in, "null") || strstr(in, "NULL"))) {
- in = NULL;
- }
+};
- if (!in) {
- in = ext;
- }
+static switch_status_t sofia_manage(char *relative_oid, switch_management_action_t action, char *data, switch_size_t datalen)
+{
+ return SWITCH_STATUS_SUCCESS;
+}
- if (!in) {
- return NULL;
- }
+static const switch_management_interface_t sofia_management_interface = {
+ /*.relative_oid */ "1",
+ /*.management_function */ sofia_manage
+};
- if (!strcasecmp(in, "dnd")) {
- r = "busy";
- }
+static const switch_loadable_module_interface_t sofia_module_interface = {
+ /*.module_name */ modname,
+ /*.endpoint_interface */ &sofia_endpoint_interface,
+ /*.timer_interface */ NULL,
+ /*.dialplan_interface */ NULL,
+ /*.codec_interface */ NULL,
+ /*.application_interface */ NULL,
+ /*.api_interface */ NULL,
+ /*.file_interface */ NULL,
+ /*.speech_interface */ NULL,
+ /*.directory_interface */ NULL,
+ /*.chat_interface */ &sofia_chat_interface,
+ /*.say_interface */ NULL,
+ /*.asr_interface */ NULL,
+ /*.management_interface */ &sofia_management_interface
+};
- if (ext && !strcasecmp(ext, "away")) {
- r = "idle";
- }
- return r;
-}
-static void pres_event_handler(switch_event_t *event)
+static switch_call_cause_t sofia_outgoing_channel(switch_core_session_t *session,
+ switch_caller_profile_t *outbound_profile, switch_core_session_t **new_session,
+ switch_memory_pool_t **pool)
{
+ switch_call_cause_t cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ switch_core_session_t *nsession;
+ char *data, *profile_name, *dest;
sofia_profile_t *profile;
- switch_hash_index_t *hi;
- void *val;
- char *from = switch_event_get_header(event, "from");
- char *proto = switch_event_get_header(event, "proto");
- char *rpid = switch_event_get_header(event, "rpid");
- char *status = switch_event_get_header(event, "status");
- char *event_type = switch_event_get_header(event, "event_type");
- //char *event_subtype = switch_event_get_header(event, "event_subtype");
- char *sql = NULL;
- char *euser = NULL, *user = NULL, *host = NULL;
- char *errmsg;
- switch_core_db_t *db;
-
+ switch_caller_profile_t *caller_profile = NULL;
+ private_object_t *tech_pvt = NULL;
+ switch_channel_t *nchannel;
+ char *host, *dest_to;
- if (rpid && !strcasecmp(rpid, "n/a")) {
- rpid = NULL;
- }
+ *new_session = NULL;
- if (status && !strcasecmp(status, "n/a")) {
- status = NULL;
+ if (!(nsession = switch_core_session_request(&sofia_endpoint_interface, pool))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
+ goto done;
}
- if (rpid) {
- rpid = translate_rpid(rpid, status);
+ if (!(tech_pvt = (struct private_object *) switch_core_session_alloc(nsession, sizeof(*tech_pvt)))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Error Creating Session\n");
+ sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ goto done;
}
- if (!status) {
- status = "Available";
-
- if (rpid) {
- if (!strcasecmp(rpid, "busy")) {
- status = "Busy";
- } else if (!strcasecmp(rpid, "unavailable")) {
- status = "Idle";
- } else if (!strcasecmp(rpid, "away")) {
- status = "Idle";
- }
- }
- }
+ data = switch_core_session_strdup(nsession, outbound_profile->destination_number);
+ profile_name = data;
- if (!rpid) {
- rpid = "unknown";
- }
+ if (!strncasecmp(profile_name, "gateway", 7)) {
+ char *gw;
+ outbound_reg_t *gateway_ptr;
- if (event->event_id == SWITCH_EVENT_ROSTER) {
- if (from) {
- sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence' and full_from like '%%%q%%'", status, rpid, from);
- } else {
- sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence'", status, rpid);
+ if (!(gw = strchr(profile_name, '/'))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
+ sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+ goto done;
}
- switch_mutex_lock(globals.hash_mutex);
- for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
- switch_hash_this(hi, NULL, NULL, &val);
- profile = (sofia_profile_t *) val;
- if (!(profile->pflags & PFLAG_PRESENCE)) {
- continue;
- }
-
- if (sql) {
- if (!(db = switch_core_db_open_file(profile->dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
- continue;
- }
- switch_mutex_lock(profile->ireg_mutex);
- switch_core_db_exec(db, sql, sub_callback, profile, &errmsg);
- switch_mutex_unlock(profile->ireg_mutex);
- switch_core_db_close(db);
- }
+ *gw++ = '\0';
+ if (!(dest = strchr(gw, '/'))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
+ sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+ goto done;
}
- switch_mutex_unlock(globals.hash_mutex);
-
- return;
- }
- if (switch_strlen_zero(event_type)) {
- event_type = "presence";
- }
+ *dest++ = '\0';
- if ((user = strdup(from))) {
- if ((host = strchr(user, '@'))) {
- char *p;
- *host++ = '\0';
- if ((p = strchr(host, '/'))) {
- *p = '\0';
- }
- } else {
- switch_safe_free(user);
- return;
+ if (!(gateway_ptr = sofia_reg_find_gateway(gw))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Gateway\n");
+ sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+ goto done;
}
- if ((euser = strchr(user, '+'))) {
- euser++;
+
+ profile = gateway_ptr->profile;
+ tech_pvt->from_str = switch_core_session_strdup(nsession, gateway_ptr->register_from);
+ if (!strchr(dest, '@')) {
+ tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s@%s", dest, gateway_ptr->register_proxy + 4);
} else {
- euser = user;
+ tech_pvt->dest = switch_core_session_sprintf(nsession, "sip:%s", dest);
}
-
} else {
- return;
- }
+ if (!(dest = strchr(profile_name, '/'))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid URL\n");
+ sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ cause = SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+ goto done;
+ }
+ *dest++ = '\0';
+ if (!(profile = sofia_glue_find_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
+ sofia_glue_terminate_session(&nsession, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ cause = SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER;
+ goto done;
+ }
- switch (event->event_id) {
- case SWITCH_EVENT_PRESENCE_PROBE:
- if (proto) {
- switch_core_db_t *db = NULL;
- char *to = switch_event_get_header(event, "to");
- char *user, *euser, *host, *p;
+ if ((dest_to = strchr(dest, '^'))) {
+ *dest_to++ = '\0';
+ tech_pvt->dest_to = switch_core_session_alloc(nsession, strlen(dest_to) + 5);
+ snprintf(tech_pvt->dest_to, strlen(dest_to) + 5, "sip:%s", dest_to);
+ }
- if (!to || !(user = strdup(to))) {
- return;
- }
+ if ((host = strchr(dest, '%'))) {
+ char buf[128];
+ *host = '@';
+ tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
+ *host++ = '\0';
+ if (sofia_reg_find_reg_url(profile, dest, host, buf, sizeof(buf))) {
+ tech_pvt->dest = switch_core_session_strdup(nsession, buf);
- if ((host = strchr(user, '@'))) {
- *host++ = '\0';
- }
- euser = user;
- if ((p = strchr(euser, '+'))) {
- euser = (p + 1);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, host);
+ cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION;
+ sofia_glue_terminate_session(&nsession, cause, __LINE__);
+ goto done;
}
+ } else if (!strchr(dest, '@')) {
+ char buf[128];
+ tech_pvt->e_dest = switch_core_session_strdup(nsession, dest);
+ if (sofia_reg_find_reg_url(profile, dest, profile_name, buf, sizeof(buf))) {
+ tech_pvt->dest = switch_core_session_strdup(nsession, buf);
- if (euser && host &&
- (sql =
- switch_mprintf("select user,host,status,rpid,'' from sip_registrations where user='%q' and host='%q'",
- euser, host)) && (profile = find_profile(host))) {
- if (!(db = switch_core_db_open_file(profile->dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
- switch_safe_free(user);
- switch_safe_free(sql);
- return;
- }
-
- switch_mutex_lock(profile->ireg_mutex);
- switch_core_db_exec(db, sql, resub_callback, profile, &errmsg);
- switch_mutex_unlock(profile->ireg_mutex);
- switch_safe_free(sql);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Cannot locate registered user %s@%s\n", dest, profile_name);
+ cause = SWITCH_CAUSE_NO_ROUTE_DESTINATION;
+ sofia_glue_terminate_session(&nsession, cause, __LINE__);
+ goto done;
}
- switch_safe_free(user);
- switch_core_db_close(db);
+ } else {
+ tech_pvt->dest = switch_core_session_alloc(nsession, strlen(dest) + 5);
+ snprintf(tech_pvt->dest, strlen(dest) + 5, "sip:%s", dest);
}
- return;
- case SWITCH_EVENT_PRESENCE_IN:
- sql =
- switch_mprintf
- ("select 1,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'",
- status, rpid, proto, event_type, euser, host);
- break;
- case SWITCH_EVENT_PRESENCE_OUT:
- sql =
- switch_mprintf
- ("select 0,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'",
- status, rpid, proto, event_type, euser, host);
- break;
- default:
- break;
}
- switch_mutex_lock(globals.hash_mutex);
- for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
- switch_hash_this(hi, NULL, NULL, &val);
- profile = (sofia_profile_t *) val;
- if (!(profile->pflags & PFLAG_PRESENCE)) {
- continue;
- }
+ if (!tech_pvt->dest_to) {
+ tech_pvt->dest_to = tech_pvt->dest;
+ }
- if (sql) {
- if (!(db = switch_core_db_open_file(profile->dbname))) {
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
- continue;
- }
- switch_mutex_lock(profile->ireg_mutex);
- switch_core_db_exec(db, sql, sub_callback, profile, &errmsg);
- switch_mutex_unlock(profile->ireg_mutex);
+ sofia_glue_attach_private(nsession, profile, tech_pvt, dest);
- switch_core_db_close(db);
+ nchannel = switch_core_session_get_channel(nsession);
+ caller_profile = switch_caller_profile_clone(nsession, outbound_profile);
+ 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(nchannel, CS_INIT);
+ *new_session = nsession;
+ cause = SWITCH_CAUSE_SUCCESS;
+ if (session) {
+ //char *val;
+ //switch_channel_t *channel = switch_core_session_get_channel(session);
+ switch_ivr_transfer_variable(session, nsession, SOFIA_REPLACES_HEADER);
+ switch_ivr_transfer_variable(session, nsession, SOFIA_SIP_HEADER_PREFIX_T);
+ if (switch_core_session_compare(session, nsession)) {
+ /* It's another sofia channel! so lets cache what they use as a pt for telephone event so
+ we can keep it the same
+ */
+ private_object_t *ctech_pvt;
+ ctech_pvt = switch_core_session_get_private(session);
+ assert(ctech_pvt != NULL);
+ tech_pvt->bte = ctech_pvt->te;
+ tech_pvt->bcng_pt = ctech_pvt->cng_pt;
}
}
- switch_mutex_unlock(globals.hash_mutex);
- switch_safe_free(sql);
- switch_safe_free(user);
+ done:
+ return cause;
}
-
SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(const switch_loadable_module_interface_t **module_interface, char *filename)
{
@@ -5830,10 +1001,6 @@
return SWITCH_STATUS_TERM;
}
- su_init();
- su_log_redirect(NULL, logger, NULL);
- su_log_redirect(tport_log, logger, NULL);
-
switch_core_hash_init(&globals.profile_hash, module_pool);
switch_core_hash_init(&globals.gateway_hash, module_pool);
switch_mutex_init(&globals.hash_mutex, SWITCH_MUTEX_NESTED, module_pool);
@@ -5841,22 +1008,22 @@
config_sofia(0);
- if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+ if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_IN, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
return SWITCH_STATUS_GENERR;
}
- if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+ if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_OUT, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
return SWITCH_STATUS_GENERR;
}
- if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+ if (switch_event_bind((char *) modname, SWITCH_EVENT_PRESENCE_PROBE, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
return SWITCH_STATUS_GENERR;
}
- if (switch_event_bind((char *) modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, pres_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
+ if (switch_event_bind((char *) modname, SWITCH_EVENT_ROSTER, SWITCH_EVENT_SUBCLASS_ANY, sofia_presence_event_handler, NULL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind!\n");
return SWITCH_STATUS_GENERR;
}
@@ -5872,7 +1039,7 @@
SWITCH_MOD_DECLARE(switch_status_t) switch_module_shutdown(void)
{
- cancel_presence();
+ sofia_presence_cancel();
switch_mutex_lock(globals.mutex);
if (globals.running == 1) {
@@ -5899,3 +1066,4 @@
* For VIM:
* vim:set softtabstop=4 shiftwidth=4 tabstop=4 expandtab:
*/
+
Added: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.h Sat Mar 31 15:01:33 2007
@@ -0,0 +1,406 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct(a)yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct(a)yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct(a)yahoo.com>
+ * Ken Rice, Asteria Solutions Group, Inc <ken(a)asteriasgi.com>
+ * Paul D. Tinsley <pdt at jackhammer.org>
+ * Bret McDanel <trixter AT 0xdecafbad.com>
+ *
+ *
+ * mod_sofia.h -- SOFIA SIP Endpoint
+ *
+ */
+
+/*Defines etc..*/
+/*************************************************************************************************************************************************************/
+#define IREG_SECONDS 30
+#define GATEWAY_SECONDS 1
+
+#define HAVE_APR
+#include <switch.h>
+
+static const char modname[] = "mod_sofia";
+static const switch_state_handler_table_t noop_state_handler = { 0 };
+struct outbound_reg;
+typedef struct outbound_reg outbound_reg_t;
+
+struct sofia_profile;
+typedef struct sofia_profile sofia_profile_t;
+#define NUA_MAGIC_T sofia_profile_t
+
+struct sofia_private {
+ char uuid[SWITCH_UUID_FORMATTED_LENGTH + 1];
+ outbound_reg_t *gateway;
+};
+
+typedef struct sofia_private sofia_private_t;
+
+struct private_object;
+typedef struct private_object private_object_t;
+#define NUA_HMAGIC_T sofia_private_t
+
+#define MY_EVENT_REGISTER "sofia::register"
+#define MY_EVENT_EXPIRE "sofia::expire"
+#define MULTICAST_EVENT "multicast::event"
+#define SOFIA_REPLACES_HEADER "_sofia_replaces_"
+#define SOFIA_USER_AGENT "FreeSWITCH(mod_sofia)"
+#define SOFIA_CHAT_PROTO "sip"
+#define SOFIA_SIP_HEADER_PREFIX "sip_h_"
+#define SOFIA_SIP_HEADER_PREFIX_T "~sip_h_"
+#define SOFIA_DEFAULT_PORT "5060"
+
+#include <sofia-sip/nua.h>
+#include <sofia-sip/sip_status.h>
+#include <sofia-sip/sdp.h>
+#include <sofia-sip/sip_protos.h>
+#include <sofia-sip/auth_module.h>
+#include <sofia-sip/su_md5.h>
+#include <sofia-sip/su_log.h>
+#include <sofia-sip/nea.h>
+#include <sofia-sip/msg_addr.h>
+
+
+#define set_param(ptr,val) if (ptr) {free(ptr) ; ptr = NULL;} if (val) {ptr = strdup(val);}
+#define set_anchor(t,m) if (t->Anchor) {delete t->Anchor;} t->Anchor = new SipMessage(m);
+
+/* Local Structures */
+/*************************************************************************************************************************************************************/
+struct sip_alias_node {
+ char *url;
+ nua_t *nua;
+ struct sip_alias_node *next;
+};
+
+typedef struct sip_alias_node sip_alias_node_t;
+
+typedef enum {
+ PFLAG_AUTH_CALLS = (1 << 0),
+ PFLAG_BLIND_REG = (1 << 1),
+ PFLAG_AUTH_ALL = (1 << 2),
+ PFLAG_FULL_ID = (1 << 3),
+ PFLAG_PRESENCE = (1 << 4),
+ PFLAG_PASS_RFC2833 = (1 << 5),
+ PFLAG_DISABLE_TRANSCODING = (1 << 6)
+} PFLAGS;
+
+typedef enum {
+ TFLAG_IO = (1 << 0),
+ TFLAG_CHANGE_MEDIA = (1 << 1),
+ TFLAG_OUTBOUND = (1 << 2),
+ TFLAG_READING = (1 << 3),
+ TFLAG_WRITING = (1 << 4),
+ TFLAG_HUP = (1 << 5),
+ TFLAG_RTP = (1 << 6),
+ TFLAG_BYE = (1 << 7),
+ TFLAG_ANS = (1 << 8),
+ TFLAG_EARLY_MEDIA = (1 << 9),
+ TFLAG_SECURE = (1 << 10),
+ TFLAG_VAD_IN = (1 << 11),
+ TFLAG_VAD_OUT = (1 << 12),
+ TFLAG_VAD = (1 << 13),
+ TFLAG_TIMER = (1 << 14),
+ TFLAG_READY = (1 << 15),
+ TFLAG_REINVITE = (1 << 16),
+ TFLAG_REFER = (1 << 17),
+ TFLAG_NOHUP = (1 << 18),
+ TFLAG_XFER = (1 << 19),
+ TFLAG_NOMEDIA = (1 << 20),
+ TFLAG_BUGGY_2833 = (1 << 21),
+ TFLAG_SIP_HOLD = (1 << 22),
+ TFLAG_INB_NOMEDIA = (1 << 23),
+ TFLAG_LATE_NEGOTIATION = (1 << 24)
+} TFLAGS;
+
+struct sofia_globals {
+ switch_hash_t *profile_hash;
+ switch_hash_t *gateway_hash;
+ switch_mutex_t *hash_mutex;
+ uint32_t callid;
+ int32_t running;
+ switch_mutex_t *mutex;
+ char guess_ip[80];
+};
+extern struct sofia_globals globals;
+
+
+typedef enum {
+ REG_FLAG_AUTHED = (1 << 0),
+} reg_flags_t;
+
+typedef enum {
+ REG_STATE_UNREGED,
+ REG_STATE_TRYING,
+ REG_STATE_REGISTER,
+ REG_STATE_REGED,
+ REG_STATE_FAILED,
+ REG_STATE_EXPIRED
+} reg_state_t;
+
+struct outbound_reg {
+ sofia_private_t *sofia_private;
+ nua_handle_t *nh;
+ sofia_profile_t *profile;
+ char *name;
+ char *register_scheme;
+ char *register_realm;
+ char *register_username;
+ char *register_password;
+ char *register_from;
+ char *register_contact;
+ char *register_to;
+ char *register_proxy;
+ char *register_context;
+ char *expires_str;
+ uint32_t freq;
+ time_t expires;
+ time_t retry;
+ uint32_t flags;
+ reg_state_t state;
+ switch_memory_pool_t *pool;
+ struct outbound_reg *next;
+};
+
+
+struct sofia_profile {
+ int debug;
+ char *name;
+ char *dbname;
+ char *dialplan;
+ char *context;
+ char *extrtpip;
+ char *rtpip;
+ char *sipip;
+ char *extsipip;
+ char *username;
+ char *url;
+ char *bindurl;
+ char *sipdomain;
+ char *timer_name;
+ char *hold_music;
+ int sip_port;
+ char *codec_string;
+ int running;
+ int codec_ms;
+ int dtmf_duration;
+ unsigned int flags;
+ unsigned int pflags;
+ uint32_t max_calls;
+ uint32_t nonce_ttl;
+ nua_t *nua;
+ switch_memory_pool_t *pool;
+ su_root_t *s_root;
+ sip_alias_node_t *aliases;
+ switch_payload_t te;
+ switch_payload_t cng_pt;
+ uint32_t codec_flags;
+ switch_mutex_t *ireg_mutex;
+ switch_mutex_t *gateway_mutex;
+ outbound_reg_t *gateways;
+ su_home_t *home;
+ switch_hash_t *profile_hash;
+ switch_hash_t *chat_hash;
+};
+
+
+struct private_object {
+ sofia_private_t *sofia_private;
+ uint32_t flags;
+ switch_payload_t agreed_pt;
+ switch_core_session_t *session;
+ switch_frame_t read_frame;
+ char *codec_order[SWITCH_MAX_CODECS];
+ int codec_order_last;
+ const switch_codec_implementation_t *codecs[SWITCH_MAX_CODECS];
+ int num_codecs;
+ switch_codec_t read_codec;
+ switch_codec_t write_codec;
+ uint32_t codec_ms;
+ switch_caller_profile_t *caller_profile;
+ uint32_t timestamp_send;
+ //int32_t timestamp_recv;
+ switch_rtp_t *rtp_session;
+ int ssrc;
+ //switch_time_t last_read;
+ sofia_profile_t *profile;
+ char *local_sdp_audio_ip;
+ switch_port_t local_sdp_audio_port;
+ char *remote_sdp_audio_ip;
+ switch_port_t remote_sdp_audio_port;
+ char *adv_sdp_audio_ip;
+ switch_port_t adv_sdp_audio_port;
+ char *proxy_sdp_audio_ip;
+ switch_port_t proxy_sdp_audio_port;
+ char *from_uri;
+ char *to_uri;
+ char *from_address;
+ char *to_address;
+ char *callid;
+ char *far_end_contact;
+ char *contact_url;
+ char *from_str;
+ char *rm_encoding;
+ char *rm_fmtp;
+ char *fmtp_out;
+ char *remote_sdp_str;
+ char *local_sdp_str;
+ char *dest;
+ char *dest_to;
+ char *key;
+ char *xferto;
+ char *kick;
+ char *origin;
+ char *hash_key;
+ char *chat_from;
+ char *chat_to;
+ char *e_dest;
+ char *call_id;
+ unsigned long rm_rate;
+ switch_payload_t pt;
+ switch_mutex_t *flag_mutex;
+ switch_payload_t te;
+ switch_payload_t bte;
+ switch_payload_t cng_pt;
+ switch_payload_t bcng_pt;
+ nua_handle_t *nh;
+ nua_handle_t *nh2;
+ su_home_t *home;
+ sip_contact_t *contact;
+};
+
+struct callback_t {
+ char *val;
+ switch_size_t len;
+ int matches;
+};
+
+typedef enum {
+ REG_REGISTER,
+ REG_INVITE
+} sofia_regtype_t;
+
+typedef enum {
+ AUTH_OK,
+ AUTH_FORBIDDEN,
+ AUTH_STALE,
+} auth_res_t;
+
+/* Function Prototypes */
+/*************************************************************************************************************************************************************/
+
+
+switch_status_t sofia_glue_activate_rtp(private_object_t * tech_pvt);
+
+void sofia_glue_deactivate_rtp(private_object_t * tech_pvt);
+
+void sofia_glue_set_local_sdp(private_object_t * tech_pvt, char *ip, uint32_t port, char *sr, int force);
+
+void sofia_glue_sofia_glue_tech_set_codecs(private_object_t * tech_pvt);
+
+void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t * profile, private_object_t * tech_pvt, const char *channame);
+
+void sofia_glue_terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line);
+
+switch_status_t sofia_glue_tech_choose_port(private_object_t * tech_pvt);
+
+switch_status_t sofia_glue_do_invite(switch_core_session_t *session);
+
+uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t * sdp);
+
+char *sofia_reg_get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex);
+
+void sofia_presence_establish_presence(sofia_profile_t * profile);
+
+void sofia_handle_sip_i_state(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+
+
+void sofia_handle_sip_i_refer(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]);
+
+void sofia_handle_sip_i_info(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]);
+
+void sofia_handle_sip_i_invite(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+
+void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+
+void sofia_event_callback(nua_event_t event,
+ int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+
+
+void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t * thread, void *obj);
+
+void launch_sofia_profile_thread(sofia_profile_t * profile);
+
+switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint);
+void sofia_glue_tech_absorb_sdp(private_object_t * tech_pvt);
+switch_status_t sofia_glue_tech_media(private_object_t * tech_pvt, char *r_sdp);
+char *sofia_reg_find_reg_url(sofia_profile_t * profile, const char *user, const char *host, char *val, switch_size_t len);
+void event_handler(switch_event_t *event);
+void sofia_presence_event_handler(switch_event_t *event);
+void sofia_presence_cancel(void);
+switch_status_t config_sofia(int reload);
+auth_res_t parse_auth(sofia_profile_t * profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen);
+void sofia_reg_handle_sip_r_challenge(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[]);
+void sofia_reg_handle_sip_r_register(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+void sofia_handle_sip_i_options(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+void sofia_presence_handle_sip_i_publish(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+void sofia_presence_handle_sip_i_message(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+void sofia_presence_handle_sip_r_subscribe(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+void sofia_presence_handle_sip_i_subscribe(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[]);
+
+sofia_profile_t *sofia_glue_find_profile(char *key);
+void sofia_glue_add_profile(char *key, sofia_profile_t * profile);
+void sofia_glue_execute_sql(char *dbname, char *sql, switch_mutex_t * mutex);
+void sofia_reg_check_expire(switch_core_db_t *db, sofia_profile_t * profile, time_t now);
+void sofia_reg_check_gateway(sofia_profile_t * profile, time_t now);
+void sofia_reg_unregister(sofia_profile_t * profile);
+switch_status_t sofia_glue_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool);
+outbound_reg_t *sofia_reg_find_gateway(char *key);
+void sofia_reg_add_gateway(char *key, outbound_reg_t * gateway);
+void sofia_glue_pass_sdp(private_object_t * tech_pvt, char *sdp);
+switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status);
+void sofia_glue_do_xfer_invite(switch_core_session_t *session);
+uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key, uint32_t keylen);
+const switch_endpoint_interface_t sofia_endpoint_interface;
+void sofia_presence_set_chat_hash(private_object_t * tech_pvt, sip_t const *sip);
+switch_status_t sofia_on_hangup(switch_core_session_t *session);
+char *sofia_glue_get_url_from_contact(char *buf, uint8_t to_dup);
+int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames);
+int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames);
+void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip);
Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.vcproj
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.vcproj (original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.vcproj Sat Mar 31 15:01:33 2007
@@ -194,16 +194,19 @@
Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
>
- <File
- RelativePath=".\mod_sofia.c"
- >
- </File>
+ <File RelativePath=".\mod_sofia.c"></File>
+ <File RelativePath=".\sofia_reg.c"></File>
+ <File RelativePath=".\sofia_glue.c"></File>
+ <File RelativePath=".\sofia_presence.c"></File>
+ <File RelativePath=".\sofia.c"></File>
+
</Filter>
<Filter
Name="Header Files"
Filter="h;hpp;hxx;hm;inl;inc;xsd"
UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
>
+ <File RelativePath=".\mod_sofia.h"></File>
</Filter>
<Filter
Name="Resource Files"
Added: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia.c Sat Mar 31 15:01:33 2007
@@ -0,0 +1,1753 @@
+/*
+ * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ * Copyright (C) 2005/2006, Anthony Minessale II <anthmct(a)yahoo.com>
+ *
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
+ *
+ * The Initial Developer of the Original Code is
+ * Anthony Minessale II <anthmct(a)yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct(a)yahoo.com>
+ * Ken Rice, Asteria Solutions Group, Inc <ken(a)asteriasgi.com>
+ * Paul D. Tinsley <pdt at jackhammer.org>
+ * Bret McDanel <trixter AT 0xdecafbad.com>
+ *
+ *
+ * sofia.c -- SOFIA SIP Endpoint
+ *
+ */
+#include "mod_sofia.h"
+extern su_log_t tport_log[];
+
+
+static char reg_sql[] =
+ "CREATE TABLE sip_registrations (\n"
+ " user VARCHAR(255),\n"
+ " host VARCHAR(255),\n"
+ " contact VARCHAR(1024),\n"
+ " status VARCHAR(255),\n"
+ " rpid VARCHAR(255),\n"
+ " expires INTEGER(8)" ");\n";
+
+
+static char sub_sql[] =
+ "CREATE TABLE sip_subscriptions (\n"
+ " proto VARCHAR(255),\n"
+ " user VARCHAR(255),\n"
+ " host VARCHAR(255),\n"
+ " sub_to_user VARCHAR(255),\n"
+ " sub_to_host VARCHAR(255),\n"
+ " event VARCHAR(255),\n"
+ " contact VARCHAR(1024),\n"
+ " call_id VARCHAR(255),\n"
+ " full_from VARCHAR(255),\n"
+ " full_via VARCHAR(255),\n"
+ " expires INTEGER(8)" ");\n";
+
+
+static char auth_sql[] =
+ "CREATE TABLE sip_authentication (\n"
+ " user VARCHAR(255),\n"
+ " host VARCHAR(255),\n"
+ " passwd VARCHAR(255),\n"
+ " nonce VARCHAR(255),\n"
+ " expires INTEGER(8)"
+ ");\n";
+
+
+void sofia_event_callback(nua_event_t event,
+ int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ struct private_object *tech_pvt = NULL;
+ auth_res_t auth_res = AUTH_FORBIDDEN;
+ switch_core_session_t *session = NULL;
+ switch_channel_t *channel = NULL;
+
+ if (sofia_private) {
+ if (!switch_strlen_zero(sofia_private->uuid)) {
+
+ if ((session = switch_core_session_locate(sofia_private->uuid))) {
+ tech_pvt = switch_core_session_get_private(session);
+ channel = switch_core_session_get_channel(tech_pvt->session);
+ if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
+ switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
+ }
+ if (!tech_pvt->call_id && sip && sip->sip_call_id && sip->sip_call_id->i_id) {
+ tech_pvt->call_id = switch_core_session_strdup(session, (char *) sip->sip_call_id->i_id);
+ switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id);
+ }
+ } else {
+ /* too late */
+ return;
+ }
+ }
+ }
+
+
+ if (status != 100 && status != 200) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "event [%s] status [%d][%s] session: %s\n",
+ nua_event_name(event), status, phrase, session ? switch_channel_get_name(channel) : "n/a");
+ }
+
+ if ((profile->pflags & PFLAG_AUTH_ALL) && tech_pvt && tech_pvt->key && sip) {
+ sip_authorization_t const *authorization = NULL;
+
+ if (sip->sip_authorization) {
+ authorization = sip->sip_authorization;
+ } else if (sip->sip_proxy_authorization) {
+ authorization = sip->sip_proxy_authorization;
+ }
+
+ if (authorization) {
+ auth_res = parse_auth(profile, authorization, (char *) sip->sip_request->rq_method_name, tech_pvt->key, strlen(tech_pvt->key));
+ }
+
+ if (auth_res != AUTH_OK) {
+ switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ nua_respond(nh, SIP_401_UNAUTHORIZED, TAG_END());
+ goto done;
+ }
+
+ if (channel) {
+ switch_channel_set_variable(channel, "sip_authorized", "true");
+ }
+ }
+
+ if (sip && (status == 401 || status == 407)) {
+ sofia_reg_handle_sip_r_challenge(status, phrase, nua, profile, nh, session, sip, tags);
+ goto done;
+ }
+
+ switch (event) {
+ case nua_r_shutdown:
+ case nua_r_get_params:
+ case nua_r_invite:
+ case nua_r_unregister:
+ case nua_r_options:
+ case nua_i_fork:
+ case nua_r_info:
+ case nua_r_bye:
+ case nua_i_bye:
+ case nua_r_unsubscribe:
+ case nua_r_publish:
+ case nua_r_message:
+ case nua_r_notify:
+ case nua_i_notify:
+ case nua_i_cancel:
+ case nua_i_error:
+ case nua_i_active:
+ case nua_i_ack:
+ case nua_i_terminated:
+ case nua_r_set_params:
+ break;
+ case nua_r_register:
+ sofia_reg_handle_sip_r_register(status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_i_options:
+ sofia_handle_sip_i_options(status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_i_invite:
+ if (!session) {
+ sofia_handle_sip_i_invite(nua, profile, nh, sofia_private, sip, tags);
+ }
+ break;
+ case nua_i_publish:
+ sofia_presence_handle_sip_i_publish(nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_i_register:
+ sofia_reg_handle_sip_i_register(nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_i_prack:
+ break;
+ case nua_i_state:
+ sofia_handle_sip_i_state(status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_i_message:
+ sofia_presence_handle_sip_i_message(status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_i_info:
+ sofia_handle_sip_i_info(nua, profile, nh, session, sip, tags);
+ break;
+ case nua_r_refer:
+ break;
+ case nua_i_refer:
+ if (session) {
+ sofia_handle_sip_i_refer(nua, profile, nh, session, sip, tags);
+ }
+ break;
+ case nua_r_subscribe:
+ sofia_presence_handle_sip_r_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
+ case nua_i_subscribe:
+ sofia_presence_handle_sip_i_subscribe(status, phrase, nua, profile, nh, sofia_private, sip, tags);
+ break;
+ default:
+ if (status > 100) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: unknown event %d: %03d %s\n", nua_event_name(event), event, status, phrase);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: unknown event %d\n", nua_event_name(event), event);
+ }
+ break;
+ }
+
+ done:
+
+ if (session) {
+ switch_core_session_rwunlock(session);
+ }
+}
+
+
+void event_handler(switch_event_t *event)
+{
+ char *subclass, *sql;
+
+ if ((subclass = switch_event_get_header(event, "orig-event-subclass")) && !strcasecmp(subclass, MY_EVENT_REGISTER)) {
+ char *from_user = switch_event_get_header(event, "orig-from-user");
+ char *from_host = switch_event_get_header(event, "orig-from-host");
+ char *contact_str = switch_event_get_header(event, "orig-contact");
+ char *exp_str = switch_event_get_header(event, "orig-expires");
+ char *rpid = switch_event_get_header(event, "orig-rpid");
+ long expires = (long) time(NULL) + atol(exp_str);
+ char *profile_name = switch_event_get_header(event, "orig-profile-name");
+ sofia_profile_t *profile;
+ char buf[512];
+
+ if (!rpid) {
+ rpid = "unknown";
+ }
+
+ if (!profile_name || !(profile = sofia_glue_find_profile(profile_name))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Profile\n");
+ return;
+ }
+
+
+ if (!sofia_reg_find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
+ sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Regestered', '%q', %ld)",
+ from_user, from_host, contact_str, rpid, expires);
+ } else {
+ sql =
+ switch_mprintf
+ ("update sip_registrations set contact='%q', rpid='%q', expires=%ld where user='%q' and host='%q'",
+ contact_str, rpid, expires, from_user, from_host);
+
+ }
+
+ if (sql) {
+ sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
+ switch_safe_free(sql);
+ sql = NULL;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Propagating registration for %s@%s->%s\n", from_user, from_host, contact_str);
+
+ }
+
+ }
+}
+
+
+
+void *SWITCH_THREAD_FUNC sofia_profile_thread_run(switch_thread_t * thread, void *obj)
+{
+ sofia_profile_t *profile = (sofia_profile_t *) obj;
+ switch_memory_pool_t *pool;
+ sip_alias_node_t *node;
+ uint32_t ireg_loops = 0;
+ uint32_t gateway_loops = 0;
+ switch_core_db_t *db;
+ switch_event_t *s_event;
+
+ profile->s_root = su_root_create(NULL);
+ profile->home = su_home_new(sizeof(*profile->home));
+
+ profile->nua = nua_create(profile->s_root, /* Event loop */
+ sofia_event_callback, /* Callback for processing events */
+ profile, /* Additional data to pass to callback */
+ NUTAG_URL(profile->bindurl), NTATAG_UDP_MTU(65536), TAG_END()); /* Last tag should always finish the sequence */
+
+ nua_set_params(profile->nua,
+ //NUTAG_EARLY_MEDIA(1),
+ NUTAG_AUTOANSWER(0),
+ NUTAG_AUTOALERT(0),
+ NUTAG_ALLOW("REGISTER"),
+ NUTAG_ALLOW("REFER"),
+ NUTAG_ALLOW("INFO"),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("NOTIFY")),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("SUBSCRIBE")),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence")),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW_EVENTS("presence.winfo")),
+ SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END());
+
+
+ for (node = profile->aliases; node; node = node->next) {
+ node->nua = nua_create(profile->s_root, /* Event loop */
+ sofia_event_callback, /* Callback for processing events */
+ profile, /* Additional data to pass to callback */
+ NUTAG_URL(node->url), TAG_END()); /* Last tag should always finish the sequence */
+
+ nua_set_params(node->nua,
+ NUTAG_EARLY_MEDIA(1),
+ NUTAG_AUTOANSWER(0),
+ NUTAG_AUTOALERT(0),
+ NUTAG_ALLOW("REGISTER"),
+ NUTAG_ALLOW("REFER"),
+ NUTAG_ALLOW("INFO"),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ALLOW("PUBLISH")),
+ TAG_IF((profile->pflags & PFLAG_PRESENCE), NUTAG_ENABLEMESSAGE(1)),
+ SIPTAG_SUPPORTED_STR("100rel, precondition"), SIPTAG_USER_AGENT_STR(SOFIA_USER_AGENT), TAG_END());
+
+ }
+
+
+ if ((db = switch_core_db_open_file(profile->dbname))) {
+ switch_core_db_test_reactive(db, "select contact from sip_registrations", reg_sql);
+ switch_core_db_test_reactive(db, "select contact from sip_subscriptions", sub_sql);
+ switch_core_db_test_reactive(db, "select * from sip_authentication", auth_sql);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot Open SQL Database!\n");
+ return NULL;
+ }
+
+
+ switch_mutex_init(&profile->ireg_mutex, SWITCH_MUTEX_NESTED, profile->pool);
+ switch_mutex_init(&profile->gateway_mutex, SWITCH_MUTEX_NESTED, profile->pool);
+
+ ireg_loops = IREG_SECONDS;
+ gateway_loops = GATEWAY_SECONDS;
+
+ if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
+ switch_event_fire(&s_event);
+ }
+
+ if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._tcp");
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
+ switch_event_fire(&s_event);
+ }
+
+ if (switch_event_create(&s_event, SWITCH_EVENT_PUBLISH) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._sctp");
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
+ switch_event_fire(&s_event);
+ }
+
+ sofia_glue_add_profile(profile->name, profile);
+
+ if (profile->pflags & PFLAG_PRESENCE) {
+ sofia_presence_establish_presence(profile);
+ }
+
+ while (globals.running == 1) {
+ if (++ireg_loops >= IREG_SECONDS) {
+ sofia_reg_check_expire(db, profile, time(NULL));
+ ireg_loops = 0;
+ }
+
+ if (++gateway_loops >= GATEWAY_SECONDS) {
+ sofia_reg_check_gateway(profile, time(NULL));
+ gateway_loops = 0;
+ }
+
+ su_root_step(profile->s_root, 1000);
+ }
+
+ switch_core_db_close(db);
+ sofia_reg_unregister(profile);
+ su_home_unref(profile->home);
+
+
+ if (switch_event_create(&s_event, SWITCH_EVENT_UNPUBLISH) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "service", "_sip._udp");
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "port", "%d", profile->sip_port);
+ switch_event_fire(&s_event);
+ }
+
+ su_root_destroy(profile->s_root);
+ pool = profile->pool;
+ switch_core_destroy_memory_pool(&pool);
+ switch_mutex_lock(globals.mutex);
+ globals.running = 0;
+ switch_mutex_unlock(globals.mutex);
+
+ return NULL;
+}
+
+void launch_sofia_profile_thread(sofia_profile_t * profile)
+{
+ switch_thread_t *thread;
+ switch_threadattr_t *thd_attr = NULL;
+
+ switch_threadattr_create(&thd_attr, profile->pool);
+ switch_threadattr_detach_set(thd_attr, 1);
+ switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
+ switch_thread_create(&thread, thd_attr, sofia_profile_thread_run, profile, profile->pool);
+}
+
+static void logger(void *logarg, char const *fmt, va_list ap)
+{
+ char *data = NULL;
+
+ if (fmt) {
+#ifdef HAVE_VASPRINTF
+ int ret;
+ ret = vasprintf(&data, fmt, ap);
+ if ((ret == -1) || !data) {
+ return;
+ }
+#else
+ data = (char *) malloc(2048);
+ if (data) {
+ vsnprintf(data, 2048, fmt, ap);
+ } else {
+ return;
+ }
+#endif
+ }
+ if (data) {
+ switch_log_printf(SWITCH_CHANNEL_LOG_CLEAN, SWITCH_LOG_CONSOLE, (char *) "%s", data);
+ free(data);
+ }
+}
+
+
+switch_status_t config_sofia(int reload)
+{
+ char *cf = "sofia.conf";
+ switch_xml_t cfg, xml = NULL, xprofile, param, settings, profiles, gateway_tag, gateways_tag;
+ switch_status_t status = SWITCH_STATUS_SUCCESS;
+ sofia_profile_t *profile = NULL;
+ char url[512] = "";
+ switch_mutex_lock(globals.mutex);
+ globals.running = 1;
+ switch_mutex_unlock(globals.mutex);
+
+ if (!reload) {
+ su_init();
+ su_log_redirect(NULL, logger, NULL);
+ su_log_redirect(tport_log, logger, NULL);
+ }
+
+ if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "open of %s failed\n", cf);
+ status = SWITCH_STATUS_FALSE;
+ goto done;
+ }
+
+ if ((settings = switch_xml_child(cfg, "global_settings"))) {
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+ if (!strcasecmp(var, "log-level")) {
+ su_log_set_level(NULL, atoi(val));
+ } else if (!strcasecmp(var, "log-level-trace")) {
+ su_log_set_level(tport_log, atoi(val));
+ }
+ }
+ }
+
+ if ((profiles = switch_xml_child(cfg, "profiles"))) {
+ for (xprofile = switch_xml_child(profiles, "profile"); xprofile; xprofile = xprofile->next) {
+ if (!(settings = switch_xml_child(xprofile, "settings"))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Settings, check the new config!\n");
+ } else {
+ char *xprofilename = (char *) switch_xml_attr_soft(xprofile, "name");
+ switch_memory_pool_t *pool = NULL;
+
+
+ /* Setup the pool */
+ if ((status = switch_core_new_memory_pool(&pool)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
+ goto done;
+ }
+
+ if (!(profile = (sofia_profile_t *) switch_core_alloc(pool, sizeof(*profile)))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
+ goto done;
+ }
+
+ if (!xprofilename) {
+ xprofilename = "unnamed";
+ }
+
+ profile->pool = pool;
+
+ profile->name = switch_core_strdup(profile->pool, xprofilename);
+ snprintf(url, sizeof(url), "sofia_reg_%s", xprofilename);
+ profile->dbname = switch_core_strdup(profile->pool, url);
+ switch_core_hash_init(&profile->chat_hash, profile->pool);
+
+ profile->dtmf_duration = 100;
+ profile->codec_ms = 20;
+
+ for (param = switch_xml_child(settings, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "debug")) {
+ profile->debug = atoi(val);
+ } else if (!strcasecmp(var, "use-rtp-timer") && switch_true(val)) {
+ switch_set_flag(profile, TFLAG_TIMER);
+ } else if (!strcasecmp(var, "inbound-no-media") && switch_true(val)) {
+ switch_set_flag(profile, TFLAG_INB_NOMEDIA);
+ } else if (!strcasecmp(var, "inbound-late-negotiation") && switch_true(val)) {
+ switch_set_flag(profile, TFLAG_LATE_NEGOTIATION);
+ } else if (!strcasecmp(var, "rfc2833-pt")) {
+ profile->te = (switch_payload_t) atoi(val);
+ } else if (!strcasecmp(var, "cng-pt")) {
+ profile->cng_pt = (switch_payload_t) atoi(val);
+ } else if (!strcasecmp(var, "sip-port")) {
+ profile->sip_port = atoi(val);
+ } else if (!strcasecmp(var, "vad")) {
+ if (!strcasecmp(val, "in")) {
+ switch_set_flag(profile, TFLAG_VAD_IN);
+ } else if (!strcasecmp(val, "out")) {
+ switch_set_flag(profile, TFLAG_VAD_OUT);
+ } else if (!strcasecmp(val, "both")) {
+ switch_set_flag(profile, TFLAG_VAD_IN);
+ switch_set_flag(profile, TFLAG_VAD_OUT);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invald option %s for VAD\n", val);
+ }
+ } else if (!strcasecmp(var, "ext-rtp-ip")) {
+ profile->extrtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
+ } else if (!strcasecmp(var, "rtp-ip")) {
+ profile->rtpip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
+ } else if (!strcasecmp(var, "sip-ip")) {
+ profile->sipip = switch_core_strdup(profile->pool, strcasecmp(val, "auto") ? val : globals.guess_ip);
+ } else if (!strcasecmp(var, "ext-sip-ip")) {
+ if (!strcasecmp(val, "auto")) {
+ profile->extsipip = switch_core_strdup(profile->pool, globals.guess_ip);
+ } else {
+ char *ip = NULL;
+ switch_port_t port = 0;
+ if (sofia_glue_ext_address_lookup(&ip, &port, val, profile->pool) == SWITCH_STATUS_SUCCESS) {
+
+ if (ip) {
+ profile->extsipip = switch_core_strdup(profile->pool, ip);
+ }
+ }
+ }
+
+ } else if (!strcasecmp(var, "sip-domain")) {
+ profile->sipdomain = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "rtp-timer-name")) {
+ profile->timer_name = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "hold-music")) {
+ profile->hold_music = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "manage-presence")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_PRESENCE;
+ }
+ } else if (!strcasecmp(var, "pass-rfc2833")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_PASS_RFC2833;
+ }
+ } else if (!strcasecmp(var, "disable-transcoding")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_DISABLE_TRANSCODING;
+ }
+ } else if (!strcasecmp(var, "auth-calls")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_AUTH_CALLS;
+ }
+ } else if (!strcasecmp(var, "nonce-ttl")) {
+ profile->nonce_ttl = atoi(val);
+ } else if (!strcasecmp(var, "accept-blind-reg")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_BLIND_REG;
+ }
+ } else if (!strcasecmp(var, "auth-all-packets")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_AUTH_ALL;
+ }
+ } else if (!strcasecmp(var, "full-id-in-dialplan")) {
+ if (switch_true(val)) {
+ profile->pflags |= PFLAG_FULL_ID;
+ }
+ } else if (!strcasecmp(var, "bitpacking")) {
+ if (!strcasecmp(val, "aal2")) {
+ profile->codec_flags = SWITCH_CODEC_FLAG_AAL2;
+ }
+ } else if (!strcasecmp(var, "username")) {
+ profile->username = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "context")) {
+ profile->context = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "alias")) {
+ sip_alias_node_t *node;
+ if ((node = switch_core_alloc(profile->pool, sizeof(*node)))) {
+ if ((node->url = switch_core_strdup(profile->pool, val))) {
+ node->next = profile->aliases;
+ profile->aliases = node;
+ }
+ }
+ } else if (!strcasecmp(var, "dialplan")) {
+ profile->dialplan = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "max-calls")) {
+ profile->max_calls = atoi(val);
+ } else if (!strcasecmp(var, "codec-prefs")) {
+ profile->codec_string = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "codec-ms")) {
+ profile->codec_ms = atoi(val);
+ } else if (!strcasecmp(var, "dtmf-duration")) {
+ int dur = atoi(val);
+ if (dur > 10 && dur < 8000) {
+ profile->dtmf_duration = dur;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Duration out of bounds!\n");
+ }
+ }
+ }
+
+ if (!profile->cng_pt) {
+ profile->cng_pt = SWITCH_RTP_CNG_PAYLOAD;
+ }
+
+ if (!profile->sipip) {
+ profile->sipip = switch_core_strdup(profile->pool, globals.guess_ip);
+ }
+
+ if (!profile->rtpip) {
+ profile->rtpip = switch_core_strdup(profile->pool, globals.guess_ip);
+ }
+
+ if (profile->nonce_ttl < 60) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Setting nonce TTL to 60 seconds\n");
+ profile->nonce_ttl = 60;
+ }
+
+ if (switch_test_flag(profile, TFLAG_TIMER) && !profile->timer_name) {
+ profile->timer_name = switch_core_strdup(profile->pool, "soft");
+ }
+
+ if (!profile->username) {
+ profile->username = switch_core_strdup(profile->pool, "FreeSWITCH");
+ }
+
+ if (!profile->rtpip) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Setting ip to '127.0.0.1'\n");
+ profile->rtpip = switch_core_strdup(profile->pool, "127.0.0.1");
+ }
+
+ if (!profile->sip_port) {
+ profile->sip_port = atoi(SOFIA_DEFAULT_PORT);
+ }
+
+ if (!profile->dialplan) {
+ profile->dialplan = switch_core_strdup(profile->pool, "XML");
+ }
+
+ if (!profile->sipdomain) {
+ profile->sipdomain = switch_core_strdup(profile->pool, profile->sipip);
+ }
+ if (profile->extsipip) {
+ profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->extsipip, profile->sip_port);
+ profile->bindurl = switch_core_sprintf(profile->pool, "%s;maddr=%s", profile->url, profile->sipip);
+ } else {
+ profile->url = switch_core_sprintf(profile->pool, "sip:mod_sofia@%s:%d", profile->sipip, profile->sip_port);
+ profile->bindurl = profile->url;
+ }
+ }
+ if (profile) {
+ if ((gateways_tag = switch_xml_child(xprofile, "registrations"))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT,
+ "The <registrations> syntax has been discontinued, please see the new syntax in the default configuration examples\n");
+ }
+
+ if ((gateways_tag = switch_xml_child(xprofile, "gateways"))) {
+ for (gateway_tag = switch_xml_child(gateways_tag, "gateway"); gateway_tag; gateway_tag = gateway_tag->next) {
+ char *name = (char *) switch_xml_attr_soft(gateway_tag, "name");
+ outbound_reg_t *gateway;
+
+ if (switch_strlen_zero(name)) {
+ name = "anonymous";
+ }
+
+ if ((gateway = switch_core_alloc(profile->pool, sizeof(*gateway)))) {
+ char *scheme = "Digest",
+ *realm = NULL,
+ *username = NULL, *password = NULL, *extension = NULL, *proxy = NULL, *context = "default", *expire_seconds = "3600";
+
+ gateway->pool = profile->pool;
+ gateway->profile = profile;
+ gateway->name = switch_core_strdup(gateway->pool, name);
+ gateway->freq = 0;
+
+
+ for (param = switch_xml_child(gateway_tag, "param"); param; param = param->next) {
+ char *var = (char *) switch_xml_attr_soft(param, "name");
+ char *val = (char *) switch_xml_attr_soft(param, "value");
+
+ if (!strcmp(var, "scheme")) {
+ scheme = val;
+ } else if (!strcmp(var, "realm")) {
+ realm = val;
+ } else if (!strcmp(var, "username")) {
+ username = val;
+ } else if (!strcmp(var, "password")) {
+ password = val;
+ } else if (!strcmp(var, "extension")) {
+ extension = val;
+ } else if (!strcmp(var, "proxy")) {
+ proxy = val;
+ } else if (!strcmp(var, "context")) {
+ context = val;
+ } else if (!strcmp(var, "expire-seconds")) {
+ expire_seconds = val;
+ }
+ }
+
+ if (switch_strlen_zero(realm)) {
+ realm = name;
+ }
+
+ if (switch_strlen_zero(username)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: username param is REQUIRED!\n");
+ switch_xml_free(xml);
+ goto skip;
+ }
+
+ if (switch_strlen_zero(password)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR: password param is REQUIRED!\n");
+ switch_xml_free(xml);
+ goto skip;
+ }
+
+ if (switch_strlen_zero(extension)) {
+ extension = username;
+ }
+
+ if (switch_strlen_zero(proxy)) {
+ proxy = realm;
+ }
+
+ gateway->register_scheme = switch_core_strdup(gateway->pool, scheme);
+ gateway->register_context = switch_core_strdup(gateway->pool, context);
+ gateway->register_realm = switch_core_strdup(gateway->pool, realm);
+ gateway->register_username = switch_core_strdup(gateway->pool, username);
+ gateway->register_password = switch_core_strdup(gateway->pool, password);
+ gateway->register_from = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, realm);
+ gateway->register_contact = switch_core_sprintf(gateway->pool, "sip:%s@%s:%d", extension, profile->sipip, profile->sip_port);
+
+ if (!strncasecmp(proxy, "sip:", 4)) {
+ gateway->register_proxy = switch_core_strdup(gateway->pool, proxy);
+ gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy + 4);
+ } else {
+ gateway->register_proxy = switch_core_sprintf(gateway->pool, "sip:%s", proxy);
+ gateway->register_to = switch_core_sprintf(gateway->pool, "sip:%s@%s", username, proxy);
+ }
+
+ gateway->expires_str = switch_core_strdup(gateway->pool, expire_seconds);
+
+ if ((gateway->freq = atoi(gateway->expires_str)) < 5) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "Invalid Freq: %d. Setting Register-Frequency to 3600\n", gateway->freq);
+ gateway->freq = 3600;
+ }
+ gateway->freq -= 2;
+
+ gateway->next = profile->gateways;
+ profile->gateways = gateway;
+
+ if (sofia_reg_find_gateway(gateway->name)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate gateway '%s'\n", gateway->name);
+ } else if (sofia_reg_find_gateway(gateway->register_from)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate uri '%s'\n", gateway->register_from);
+ } else if (sofia_reg_find_gateway(gateway->register_contact)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Ignoring duplicate contact '%s'\n", gateway->register_from);
+ } else {
+ sofia_reg_add_gateway(gateway->name, gateway);
+ sofia_reg_add_gateway(gateway->register_from, gateway);
+ sofia_reg_add_gateway(gateway->register_contact, gateway);
+ }
+ }
+
+ skip:
+ assert(gateway_tag);
+ }
+ }
+
+ if (profile->sipip) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Started Profile %s [%s]\n", profile->name, url);
+ launch_sofia_profile_thread(profile);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Unable to start Profile %s due to no configured sip-ip\n", profile->name);
+ }
+ profile = NULL;
+ }
+ }
+ }
+ done:
+ if (xml) {
+ switch_xml_free(xml);
+ }
+
+ return status;
+
+}
+
+void sofia_handle_sip_i_state(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ const char *l_sdp = NULL, *r_sdp = NULL;
+ int offer_recv = 0, answer_recv = 0, offer_sent = 0, answer_sent = 0;
+ int ss_state = nua_callstate_init;
+ switch_channel_t *channel = NULL;
+ private_object_t *tech_pvt = NULL;
+ switch_core_session_t *session = NULL;
+ const char *replaces_str = NULL;
+ char *uuid;
+ switch_core_session_t *other_session = NULL;
+ switch_channel_t *other_channel = NULL;
+ char st[80] = "";
+
+
+ if (sofia_private) {
+ if (!switch_strlen_zero(sofia_private->uuid)) {
+ if (!(session = switch_core_session_locate(sofia_private->uuid))) {
+ /* too late */
+ return;
+ }
+ }
+ }
+
+
+ tl_gets(tags,
+ NUTAG_CALLSTATE_REF(ss_state),
+ NUTAG_OFFER_RECV_REF(offer_recv),
+ NUTAG_ANSWER_RECV_REF(answer_recv),
+ NUTAG_OFFER_SENT_REF(offer_sent),
+ NUTAG_ANSWER_SENT_REF(answer_sent),
+ SIPTAG_REPLACES_STR_REF(replaces_str), SOATAG_LOCAL_SDP_STR_REF(l_sdp), SOATAG_REMOTE_SDP_STR_REF(r_sdp), TAG_END());
+
+ if (session) {
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+ assert(tech_pvt->nh != NULL);
+
+ if (switch_channel_test_flag(channel, CF_NOMEDIA)) {
+ switch_set_flag(tech_pvt, TFLAG_NOMEDIA);
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Channel %s entering state [%s]\n",
+ switch_channel_get_name(channel), nua_callstate_name(ss_state));
+
+ 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, r_sdp);
+ switch_channel_set_variable(channel, SWITCH_R_SDP_VARIABLE, r_sdp);
+ sofia_glue_pass_sdp(tech_pvt, (char *) r_sdp);
+
+ }
+ }
+
+ if (status == 988) {
+ goto done;
+ }
+
+ switch ((enum nua_callstate) ss_state) {
+ case nua_callstate_init:
+ break;
+ case nua_callstate_authenticating:
+ break;
+ case nua_callstate_calling:
+ break;
+ case nua_callstate_proceeding:
+ if (channel) {
+ if (status == 180) {
+ switch_channel_mark_ring_ready(channel);
+ if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK)) {
+ if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+ if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+ && (other_session = switch_core_session_locate(uuid))) {
+ switch_core_session_message_t msg;
+ msg.message_id = SWITCH_MESSAGE_INDICATE_RINGING;
+ msg.from = __FILE__;
+ switch_core_session_receive_message(other_session, &msg);
+ switch_core_session_rwunlock(other_session);
+ }
+
+ } else {
+ switch_core_session_queue_indication(session, SWITCH_MESSAGE_INDICATE_RINGING);
+ }
+ }
+ }
+
+ if (r_sdp) {
+ if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+ switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
+ switch_channel_mark_pre_answered(channel);
+ if (!switch_channel_test_flag(channel, CF_GEN_RINGBACK) && (uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+ && (other_session = switch_core_session_locate(uuid))) {
+ other_channel = switch_core_session_get_channel(other_session);
+ if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
+ switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
+ }
+
+ switch_channel_pre_answer(other_channel);
+ switch_core_session_rwunlock(other_session);
+ }
+ goto done;
+ } else {
+ if (switch_test_flag(tech_pvt, TFLAG_LATE_NEGOTIATION)) {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "DELAYED NEGOTIATION");
+ } else {
+ if (sofia_glue_tech_media(tech_pvt, (char *) r_sdp) != SWITCH_STATUS_SUCCESS) {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "CODEC NEGOTIATION ERROR");
+ nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+ }
+ }
+ goto done;
+ }
+ }
+ }
+ break;
+ case nua_callstate_completing:
+ nua_ack(nh, TAG_END());
+ break;
+ case nua_callstate_received:
+
+ if (session && switch_core_session_running(session)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Re-Entering Call State Received!\n");
+ goto done;
+ }
+
+ if (channel) {
+ if (r_sdp) {
+ if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOMEDIA");
+ switch_channel_set_state(channel, CS_INIT);
+ switch_set_flag_locked(tech_pvt, TFLAG_READY);
+ switch_core_session_thread_launch(session);
+ goto done;
+ } 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) {
+ nua_handle_t *bnh;
+ sip_replaces_t *replaces;
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "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_magic(bnh))) {
+ char *br_b = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE);
+ char *br_a = b_private->uuid;
+
+ if (br_b) {
+ switch_ivr_uuid_bridge(br_a, br_b);
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
+ switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER);
+ } else {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
+ switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
+ } else {
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
+ switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
+ }
+ nua_handle_unref(bnh);
+ }
+ goto done;
+ }
+
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
+ nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Invite with no SDP activating no-media-mode\n");
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "RECEIVED_NOSDP");
+
+ switch_set_flag(tech_pvt, TFLAG_LATE_NEGOTIATION);
+ switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+ switch_channel_set_flag(channel, CF_NOMEDIA);
+ switch_channel_set_state(channel, CS_INIT);
+ switch_set_flag_locked(tech_pvt, TFLAG_READY);
+ switch_core_session_thread_launch(session);
+ goto done;
+ }
+ }
+
+ break;
+ case nua_callstate_early:
+ break;
+ case nua_callstate_completed:
+ if (tech_pvt && r_sdp) {
+ if (r_sdp) {
+ if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+ goto done;
+ } 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 (match) {
+ if (sofia_glue_tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
+ goto done;
+ }
+ sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+ switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+ sofia_glue_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 (tech_pvt && 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;
+ if (sofia_glue_tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
+ sofia_glue_activate_rtp(tech_pvt);
+ }
+ goto done;
+ }
+
+ if (channel) {
+ if (switch_test_flag(tech_pvt, TFLAG_EARLY_MEDIA)) {
+ switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+ switch_channel_mark_answered(channel);
+ if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+ && (other_session = switch_core_session_locate(uuid))) {
+ other_channel = switch_core_session_get_channel(other_session);
+ switch_channel_answer(other_channel);
+ switch_core_session_rwunlock(other_session);
+ }
+ goto done;
+ }
+
+ if (!r_sdp) {
+ r_sdp = (const char *) switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE);
+ }
+ if (r_sdp) {
+ if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+ switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+ switch_channel_mark_answered(channel);
+ if ((uuid = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+ && (other_session = switch_core_session_locate(uuid))) {
+ other_channel = switch_core_session_get_channel(other_session);
+ if (!switch_channel_get_variable(other_channel, SWITCH_B_SDP_VARIABLE)) {
+ switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, r_sdp);
+ }
+ switch_channel_answer(other_channel);
+ switch_core_session_rwunlock(other_session);
+ }
+ goto done;
+ } 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) {
+ switch_set_flag_locked(tech_pvt, TFLAG_ANS);
+ if (sofia_glue_tech_choose_port(tech_pvt) == SWITCH_STATUS_SUCCESS) {
+ sofia_glue_activate_rtp(tech_pvt);
+ switch_channel_mark_answered(channel);
+ goto done;
+ }
+ }
+
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "NO CODECS");
+ nua_respond(nh, SIP_488_NOT_ACCEPTABLE, TAG_END());
+ }
+ }
+
+ }
+
+ break;
+ case nua_callstate_terminating:
+ break;
+ case nua_callstate_terminated:
+ if (session) {
+ if (!switch_test_flag(tech_pvt, TFLAG_BYE)) {
+
+ switch_set_flag_locked(tech_pvt, TFLAG_BYE);
+ if (switch_test_flag(tech_pvt, TFLAG_NOHUP)) {
+ switch_clear_flag_locked(tech_pvt, TFLAG_NOHUP);
+ } else {
+ snprintf(st, sizeof(st), "%d", status);
+ switch_channel_set_variable(channel, "sip_term_status", st);
+ sofia_glue_terminate_session(&session, sofia_glue_sip_cause_to_freeswitch(status), __LINE__);
+ }
+ }
+
+ if (tech_pvt->sofia_private) {
+ free(tech_pvt->sofia_private);
+ tech_pvt->sofia_private = NULL;
+ }
+ tech_pvt->nh = NULL;
+ } else if (sofia_private) {
+ free(sofia_private);
+ }
+
+ if (nh) {
+ nua_handle_bind(nh, NULL);
+ nua_handle_destroy(nh);
+ }
+ break;
+ }
+
+ done:
+
+ if (session) {
+ switch_core_session_rwunlock(session);
+ }
+}
+
+
+/*---------------------------------------*/
+void sofia_handle_sip_i_refer(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
+{
+ /* Incoming refer */
+ sip_from_t const *from;
+ sip_to_t const *to;
+ sip_refer_to_t const *refer_to;
+ private_object_t *tech_pvt = 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_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"),
+ NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
+ goto done;
+ }
+
+ from = sip->sip_from;
+ to = sip->sip_to;
+
+ if ((refer_to = sip->sip_refer_to)) {
+ if (profile->pflags & PFLAG_FULL_ID) {
+ exten = switch_mprintf("%s@%s", (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host);
+ } else {
+ exten = (char *) refer_to->r_url->url_user;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Process REFER to [%s@%s]\n", exten, (char *) refer_to->r_url->url_host);
+
+ if (refer_to->r_url->url_headers) {
+ sip_replaces_t *replaces;
+ nua_handle_t *bnh;
+ char *rep;
+
+ if ((rep = strchr(refer_to->r_url->url_headers, '='))) {
+ char *br_a = NULL, *br_b = NULL;
+ char *buf;
+ rep++;
+
+
+
+ if ((buf = switch_core_session_alloc(session, strlen(rep) + 1))) {
+ rep = url_unescape(buf, (const char *) rep);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Replaces: [%s]\n", rep);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
+ goto done;
+ }
+ if ((replaces = sip_replaces_make(tech_pvt->home, rep))
+ && (bnh = nua_handle_by_replaces(nua, replaces))) {
+ sofia_private_t *b_private = NULL;
+ private_object_t *b_tech_pvt = NULL;
+ switch_core_session_t *b_session = NULL;
+
+ switch_channel_set_variable(channel_a, SOFIA_REPLACES_HEADER, rep);
+ if ((b_private = nua_handle_magic(bnh))) {
+ if (!(b_session = switch_core_session_locate(b_private->uuid))) {
+ goto done;
+ }
+ b_tech_pvt = (private_object_t *) switch_core_session_get_private(b_session);
+ channel_b = switch_core_session_get_channel(b_session);
+
+ br_a = switch_channel_get_variable(channel_a, SWITCH_SIGNAL_BOND_VARIABLE);
+ br_b = switch_channel_get_variable(channel_b, SWITCH_SIGNAL_BOND_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, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
+ switch_set_flag_locked(tech_pvt, TFLAG_BYE);
+ switch_set_flag_locked(b_tech_pvt, TFLAG_BYE);
+ nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
+
+ } else {
+ if (!br_a && !br_b) {
+ switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
+ switch_set_flag_locked(b_tech_pvt, TFLAG_XFER);
+ b_tech_pvt->xferto = switch_core_session_strdup(b_session, switch_core_session_get_uuid(session));
+ } else if (!br_a && br_b) {
+ switch_core_session_t *br_b_session;
+
+ if ((br_b_session = switch_core_session_locate(br_b))) {
+ private_object_t *br_b_tech_pvt = switch_core_session_get_private(br_b_session);
+ switch_channel_t *br_b_channel = switch_core_session_get_channel(br_b_session);
+
+ switch_set_flag_locked(tech_pvt, TFLAG_NOHUP);
+
+ switch_channel_clear_state_handler(br_b_channel, NULL);
+ switch_channel_set_state_flag(br_b_channel, CF_TRANSFER);
+ switch_channel_set_state(br_b_channel, CS_TRANSMIT);
+
+ switch_set_flag_locked(tech_pvt, TFLAG_REINVITE);
+ tech_pvt->local_sdp_audio_ip = switch_core_session_strdup(session, b_tech_pvt->local_sdp_audio_ip);
+ tech_pvt->local_sdp_audio_port = b_tech_pvt->local_sdp_audio_port;
+
+ tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, br_b_tech_pvt->remote_sdp_audio_ip);
+ tech_pvt->remote_sdp_audio_port = br_b_tech_pvt->remote_sdp_audio_port;
+ sofia_glue_activate_rtp(tech_pvt);
+
+ br_b_tech_pvt->kick = switch_core_session_strdup(br_b_session, switch_core_session_get_uuid(session));
+
+
+ switch_core_session_rwunlock(br_b_session);
+ }
+
+ switch_channel_hangup(channel_b, SWITCH_CAUSE_ATTENDED_TRANSFER);
+ }
+ switch_set_flag_locked(tech_pvt, TFLAG_BYE);
+ nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
+
+ }
+ if (b_session) {
+ switch_core_session_rwunlock(b_session);
+ }
+ }
+ 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, SWITCH_SIGNAL_BOND_VARIABLE))) {
+ switch_core_session_t *a_session;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ if ((a_session = 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(a_session);
+
+ exten = switch_mprintf("sofia/%s/%s@%s:%s",
+ profile->name,
+ (char *) refer_to->r_url->url_user, (char *) refer_to->r_url->url_host, refer_to->r_url->url_port);
+
+ switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, rep);
+
+ if (switch_ivr_originate(a_session,
+ &tsession, &cause, exten, timeout, &noop_state_handler, NULL, 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"),
+ NUTAG_SUBSTATE(nua_substate_terminated),
+ SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp), TAG_END());
+ goto done;
+ }
+
+ switch_core_session_rwunlock(a_session);
+ tuuid_str = switch_core_session_get_uuid(tsession);
+ switch_ivr_uuid_bridge(br_a, tuuid_str);
+ switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER");
+ switch_set_flag_locked(tech_pvt, TFLAG_BYE);
+ nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"), SIPTAG_EVENT_STR(etmp), TAG_END());
+ } else {
+ goto error;
+ }
+
+ } else {
+ error:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Transfer! [%s]\n", br_a);
+ switch_channel_set_variable(channel_a, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "ATTENDED_TRANSFER_ERROR");
+ nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ NUTAG_SUBSTATE(nua_substate_terminated), SIPTAG_PAYLOAD_STR("SIP/2.0 403 Forbidden"), SIPTAG_EVENT_STR(etmp),
+ TAG_END());
+ }
+ }
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot parse Replaces!\n");
+ }
+ goto done;
+ }
+
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing Refer-To\n");
+ goto done;
+ }
+
+ if (exten) {
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+ char *br;
+
+ if ((br = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))) {
+ switch_core_session_t *b_session;
+
+ if ((b_session = switch_core_session_locate(br))) {
+ switch_channel_set_variable(channel, "TRANSFER_FALLBACK", from->a_user);
+ switch_ivr_session_transfer(b_session, exten, profile->dialplan, profile->context);
+ switch_core_session_rwunlock(b_session);
+ }
+
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "BLIND_TRANSFER");
+
+ /*
+ nua_notify(tech_pvt->nh, SIPTAG_CONTENT_TYPE_STR("message/sipfrag"),
+ NUTAG_SUBSTATE(nua_substate_terminated),
+ SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
+ SIPTAG_EVENT_STR(etmp),
+ TAG_END());
+ */
+ } else {
+ exten = switch_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"),
+ NUTAG_SUBSTATE(nua_substate_terminated),
+ SIPTAG_PAYLOAD_STR("SIP/2.0 200 OK"),
+ SIPTAG_EVENT_STR(etmp),
+ TAG_END());
+ */
+ sofia_glue_do_xfer_invite(session);
+
+ }
+ }
+
+ done:
+ if (exten && strchr(exten, '@')) {
+ switch_safe_free(exten);
+ }
+ if (etmp) {
+ switch_safe_free(etmp);
+ }
+
+
+}
+
+
+void sofia_handle_sip_i_info(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
+{
+
+ //placeholder for string searching
+ char *signal_ptr;
+
+ //Try and find signal information in the payload
+ signal_ptr = strstr(sip->sip_payload->pl_data, "Signal=");
+
+ //See if we found a match
+ if (signal_ptr) {
+ struct private_object *tech_pvt = NULL;
+ switch_channel_t *channel = NULL;
+ char dtmf_digit[2] = { 0, 0 };
+
+ //Get the channel
+ channel = switch_core_session_get_channel(session);
+
+ //Barf if we didn't get it
+ assert(channel != NULL);
+
+ //make sure we have our privates
+ tech_pvt = switch_core_session_get_private(session);
+
+ //Barf if we didn't get it
+ assert(tech_pvt != NULL);
+
+ //move signal_ptr where we need it (right past Signal=)
+ signal_ptr = signal_ptr + 7;
+
+ //put the digit somewhere we can muck with
+ strncpy(dtmf_digit, signal_ptr, 1);
+
+ //queue it up
+ switch_channel_queue_dtmf(channel, dtmf_digit);
+
+ //print debug info
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "INFO DTMF(%s)\n", dtmf_digit);
+
+ } else { //unknown info type
+ sip_from_t const *from;
+
+ from = sip->sip_from;
+
+ //print in the logs if something comes through we don't understand
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Unknown INFO Recieved: %s%s" URL_PRINT_FORMAT "[%s]\n",
+ from->a_display ? from->a_display : "", from->a_display ? " " : "", URL_PRINT_ARGS(from->a_url), sip->sip_payload->pl_data);
+ }
+
+ return;
+}
+
+#define url_set_chanvars(session, url, varprefix) _url_set_chanvars(session, url, #varprefix "_user", #varprefix "_host", #varprefix "_port", #varprefix "_uri")
+const char *_url_set_chanvars(switch_core_session_t *session, url_t * url, const char *user_var,
+ const char *host_var, const char *port_var, const char *uri_var)
+{
+ const char *user = NULL, *host = NULL, *port = NULL;
+ char *uri = NULL;
+ switch_channel_t *channel = switch_core_session_get_channel(session);
+
+ if (url) {
+ user = url->url_user;
+ host = url->url_host;
+ port = url->url_port;
+ }
+
+ if (user) {
+ switch_channel_set_variable(channel, user_var, user);
+ }
+
+ if (!port) {
+ port = SOFIA_DEFAULT_PORT;
+ }
+
+ switch_channel_set_variable(channel, port_var, port);
+ if (host) {
+ if (user) {
+ uri = switch_core_session_sprintf(session, "%s@%s:%s", user, host, port);
+ } else {
+ uri = switch_core_session_sprintf(session, "%s:%s", host, port);
+ }
+ switch_channel_set_variable_nodup(channel, uri_var, uri);
+ switch_channel_set_variable(channel, host_var, host);
+ }
+
+ return uri;
+}
+
+void process_rpid(sip_unknown_t * un, private_object_t * tech_pvt)
+{
+ int argc, x, screen = 1;
+ char *mydata, *argv[10] = { 0 };
+ if (!switch_strlen_zero(un->un_value)) {
+ if ((mydata = strdup(un->un_value))) {
+ argc = switch_separate_string(mydata, ';', argv, (sizeof(argv) / sizeof(argv[0])));
+
+ // Do We really need this at this time
+ // clid_uri = argv[0];
+
+ for (x = 1; x < argc && argv[x]; x++) {
+ // we dont need to do anything with party yet we should only be seeing party=calling here anyway
+ // maybe thats a dangerous assumption bit oh well yell at me later
+ // if (!strncasecmp(argv[x], "party", 5)) {
+ // party = argv[x];
+ // } else
+ if (!strncasecmp(argv[x], "privacy=", 8)) {
+ char *arg = argv[x] + 9;
+
+ if (!strcasecmp(arg, "yes")) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+ } else if (!strcasecmp(arg, "full")) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME | SWITCH_CPF_HIDE_NUMBER);
+ } else if (!strcasecmp(arg, "name")) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME);
+ } else if (!strcasecmp(arg, "number")) {
+ switch_set_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER);
+ } else {
+ switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NAME);
+ switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_HIDE_NUMBER);
+ }
+
+ } else if (!strncasecmp(argv[x], "screen=", 7) && screen > 0) {
+ char *arg = argv[x] + 8;
+ if (!strcasecmp(arg, "no")) {
+ screen = 0;
+ switch_clear_flag(tech_pvt->caller_profile, SWITCH_CPF_SCREEN);
+ }
+ }
+ }
+ free(mydata);
+ }
+ }
+}
+
+void sofia_handle_sip_i_invite(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ switch_core_session_t *session = NULL;
+ char key[128] = "";
+ sip_unknown_t *un;
+ private_object_t *tech_pvt = NULL;
+ switch_channel_t *channel = NULL;
+ const char *channel_name = NULL;
+ const char *displayname = NULL;
+ const char *destination_number = NULL;
+ const char *from_user = NULL, *from_host = NULL;
+ const char *context = NULL;
+ char network_ip[80];
+
+ if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
+ nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ return;
+ }
+
+
+ if (!(sip->sip_contact && sip->sip_contact->m_url)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
+ nua_respond(nh, 400, "Missing Contact Header", TAG_END());
+ return;
+ }
+
+ if ((profile->pflags & PFLAG_AUTH_CALLS)) {
+ if (sofia_reg_handle_register(nua, profile, nh, sip, REG_INVITE, key, sizeof(key))) {
+ return;
+ }
+ }
+
+ if (!(session = switch_core_session_request(&sofia_endpoint_interface, NULL))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Session Alloc Failed!\n");
+ nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
+ return;
+ }
+
+ if (!(tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t)))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Hey where is my memory pool?\n");
+ nua_respond(nh, SIP_503_SERVICE_UNAVAILABLE, TAG_END());
+ sofia_glue_terminate_session(&session, SWITCH_CAUSE_SWITCH_CONGESTION, __LINE__);
+ return;
+ }
+
+ if (!switch_strlen_zero(key)) {
+ tech_pvt->key = switch_core_session_strdup(session, key);
+ }
+
+ get_addr(network_ip, sizeof(network_ip), &((struct sockaddr_in *) msg_addrinfo(nua_current_request(nua))->ai_addr)->sin_addr);
+
+ channel = switch_core_session_get_channel(session);
+
+ if (sip->sip_from && sip->sip_from->a_url) {
+ from_user = sip->sip_from->a_url->url_user;
+ from_host = sip->sip_from->a_url->url_host;
+ channel_name = url_set_chanvars(session, sip->sip_from->a_url, sip_from);
+
+ if (!switch_strlen_zero(from_user)) {
+ if (*from_user == '+') {
+ switch_channel_set_variable(channel, "sip_from_user_stripped", (const char *) (from_user + 1));
+ } else {
+ switch_channel_set_variable(channel, "sip_from_user_stripped", from_user);
+ }
+ }
+
+ if (!switch_strlen_zero(sip->sip_from->a_display)) {
+ char *tmp;
+ tmp = switch_core_session_strdup(session, sip->sip_from->a_display);
+ if (*tmp == '"') {
+ char *p;
+
+ tmp++;
+ if ((p = strchr(tmp, '"'))) {
+ *p = '\0';
+ }
+ }
+ displayname = tmp;
+ } else {
+ displayname = switch_strlen_zero(from_user) ? "unkonwn" : from_user;
+ }
+ }
+
+ if (sip->sip_request->rq_url) {
+ const char *req_uri = url_set_chanvars(session, sip->sip_request->rq_url, sip_req);
+ if (profile->pflags & PFLAG_FULL_ID) {
+ destination_number = req_uri;
+ } else {
+ destination_number = sip->sip_request->rq_url->url_user;
+ }
+ }
+
+ if (sip->sip_to && sip->sip_to->a_url) {
+ url_set_chanvars(session, sip->sip_to->a_url, sip_to);
+ }
+
+ if (sip->sip_contact && sip->sip_contact->m_url) {
+ const char *contact_uri = url_set_chanvars(session, sip->sip_contact->m_url, sip_contact);
+ if (!channel_name) {
+ channel_name = contact_uri;
+ }
+ }
+
+ sofia_glue_attach_private(session, profile, tech_pvt, channel_name);
+ sofia_glue_sofia_glue_tech_set_codecs(tech_pvt);
+
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "INBOUND CALL");
+ sofia_presence_set_chat_hash(tech_pvt, sip);
+
+ if (switch_test_flag(tech_pvt, TFLAG_INB_NOMEDIA)) {
+ switch_set_flag_locked(tech_pvt, TFLAG_NOMEDIA);
+ switch_channel_set_flag(channel, CF_NOMEDIA);
+ }
+
+ if (!tech_pvt->call_id && sip->sip_call_id && sip->sip_call_id->i_id) {
+ tech_pvt->call_id = switch_core_session_strdup(session, sip->sip_call_id->i_id);
+ switch_channel_set_variable(channel, "sip_call_id", tech_pvt->call_id);
+ }
+
+ if (sip->sip_via) {
+ if (sip->sip_via->v_host) {
+ switch_channel_set_variable(channel, "sip_via_host", sip->sip_via->v_host);
+ }
+ if (sip->sip_via->v_port) {
+ switch_channel_set_variable(channel, "sip_via_port", sip->sip_via->v_port);
+ }
+ if (sip->sip_via->v_rport) {
+ switch_channel_set_variable(channel, "sip_via_rport", sip->sip_via->v_rport);
+ }
+ }
+
+ if (sip->sip_max_forwards) {
+ char max_forwards[32];
+ snprintf(max_forwards, sizeof(max_forwards), "%lu", sip->sip_max_forwards->mf_count);
+ switch_channel_set_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE, max_forwards);
+ }
+
+
+ if (sip->sip_request->rq_url) {
+ outbound_reg_t *gateway;
+ char *from_key = switch_core_session_sprintf(session, "sip:%s@%s",
+ (char *) sip->sip_request->rq_url->url_user,
+ (char *) sip->sip_request->rq_url->url_host);
+
+ if ((gateway = sofia_reg_find_gateway(from_key))) {
+ context = gateway->register_context;
+ switch_channel_set_variable(channel, "sip_gateway", gateway->name);
+ }
+ }
+
+
+ if (!context) {
+ if (profile->context && !strcasecmp(profile->context, "_domain_")) {
+ context = from_host;
+ } else {
+ context = profile->context;
+ }
+ }
+
+ tech_pvt->caller_profile = switch_caller_profile_new(switch_core_session_get_pool(session),
+ from_user,
+ profile->dialplan,
+ displayname, from_user, network_ip, NULL, NULL, NULL, modname, context, destination_number);
+
+ if (tech_pvt->caller_profile) {
+
+ /* Loop thru unknown Headers Here so we can do something with them */
+ for (un = sip->sip_unknown; un; un = un->un_next) {
+ if (!strncasecmp(un->un_name, "Alert-Info", 10)) {
+ if (!switch_strlen_zero(un->un_value)) {
+ switch_channel_set_variable(channel, "alert_info", un->un_value);
+ }
+ } else if (!strncasecmp(un->un_name, "Remote-Party-ID", 15)) {
+ process_rpid(un, tech_pvt);
+ } else if (!strncasecmp(un->un_name, "X-", 2)) {
+ if (!switch_strlen_zero(un->un_value)) {
+ char *new_name;
+ if ((new_name = switch_mprintf("%s%s", SOFIA_SIP_HEADER_PREFIX, un->un_name))) {
+ switch_channel_set_variable(channel, new_name, un->un_value);
+ free(new_name);
+ }
+ }
+ }
+ }
+
+ switch_channel_set_caller_profile(channel, tech_pvt->caller_profile);
+ }
+
+ if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) {
+ abort();
+ }
+ memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private));
+ switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid));
+ nua_handle_bind(nh, tech_pvt->sofia_private);
+ tech_pvt->nh = nh;
+}
+
+void sofia_handle_sip_i_options(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ nua_respond(nh, SIP_200_OK,
+ //SOATAG_USER_SDP_STR(tech_pvt->local_sdp_str),
+ //SOATAG_AUDIO_AUX("cn telephone-event"),
+ //NUTAG_INCLUDE_EXTRA_SDP(1),
+ TAG_END());
+}
+
+
+
+
Added: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_glue.c Sat Mar 31 15:01:33 2007
@@ -0,0 +1,1110 @@
+#include "mod_sofia.h"
+
+
+void sofia_glue_set_local_sdp(private_object_t *tech_pvt, char *ip, uint32_t port, char *sr, int force)
+{
+ char buf[2048];
+ switch_time_t now = switch_time_now();
+ int ptime = 0;
+ int rate = 0;
+
+ if (!force && !ip && !sr && switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+ return;
+ }
+
+ if (!ip) {
+ if (!(ip = tech_pvt->adv_sdp_audio_ip)) {
+ ip = tech_pvt->proxy_sdp_audio_ip;
+ }
+ }
+ if (!port) {
+ if (!(port = tech_pvt->adv_sdp_audio_port)) {
+ port = tech_pvt->proxy_sdp_audio_port;
+ }
+ }
+ if (!sr) {
+ sr = "sendrecv";
+ }
+
+ snprintf(buf, sizeof(buf),
+ "v=0\n"
+ "o=FreeSWITCH %d%" SWITCH_TIME_T_FMT " %d%" SWITCH_TIME_T_FMT " IN IP4 %s\n"
+ "s=FreeSWITCH\n" "c=IN IP4 %s\n" "t=0 0\n" "a=%s\n" "m=audio %d RTP/AVP", port, now, port, now, ip, ip, sr, port);
+
+ if (tech_pvt->rm_encoding) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->pt);
+ } else if (tech_pvt->num_codecs) {
+ int i;
+ for (i = 0; i < tech_pvt->num_codecs; i++) {
+ const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", imp->ianacode);
+ if (!ptime) {
+ ptime = imp->microseconds_per_frame / 1000;
+ }
+ }
+ }
+
+ if (tech_pvt->te > 95) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->te);
+ }
+
+ if (tech_pvt->cng_pt) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), " %d", tech_pvt->cng_pt);
+ }
+
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "\n");
+
+ if (tech_pvt->rm_encoding) {
+ rate = tech_pvt->rm_rate;
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%ld\n", tech_pvt->pt, tech_pvt->rm_encoding, tech_pvt->rm_rate);
+ if (tech_pvt->fmtp_out) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", tech_pvt->pt, tech_pvt->fmtp_out);
+ }
+ if (tech_pvt->read_codec.implementation && !ptime) {
+ ptime = tech_pvt->read_codec.implementation->microseconds_per_frame / 1000;
+ }
+
+ } else if (tech_pvt->num_codecs) {
+ int i;
+ for (i = 0; i < tech_pvt->num_codecs; i++) {
+ const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+ uint32_t rfc_3551_sucks = imp->samples_per_second;
+
+ if (!rate) {
+ rate = imp->samples_per_second;
+ }
+ if (ptime && ptime != imp->microseconds_per_frame / 1000) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "ptime %u != advertised ptime %u\n", imp->microseconds_per_frame / 1000, ptime);
+ }
+
+ if (rfc_3551_sucks && imp->ianacode == 9) {
+ rfc_3551_sucks = 8000;
+ }
+
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d %s/%d\n", imp->ianacode, imp->iananame, rfc_3551_sucks);
+ if (imp->fmtp) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=fmtp:%d %s\n", imp->ianacode, imp->fmtp);
+ }
+ }
+ }
+
+ if (tech_pvt->te > 95) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d telephone-event/8000\na=fmtp:%d 0-16\n", tech_pvt->te, tech_pvt->te);
+ }
+ if (tech_pvt->cng_pt) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=rtpmap:%d CN/%d\n", tech_pvt->cng_pt, rate);
+ if (!tech_pvt->rm_encoding) {
+ tech_pvt->cng_pt = 0;
+ }
+ }
+ if (ptime) {
+ snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "a=ptime:%d\n", ptime);
+ }
+
+ tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, buf);
+}
+
+void sofia_glue_sofia_glue_tech_set_codecs(private_object_t * tech_pvt)
+{
+ switch_channel_t *channel;
+ char *abs, *codec_string = NULL;
+ char *ocodec = NULL;
+
+ if (switch_test_flag(tech_pvt, TFLAG_NOMEDIA)) {
+ return;
+ }
+
+ if (tech_pvt->num_codecs) {
+ return;
+ }
+
+ assert(tech_pvt->session != NULL);
+
+ channel = switch_core_session_get_channel(tech_pvt->session);
+ assert(channel != NULL);
+
+
+ if ((abs = switch_channel_get_variable(channel, "absolute_codec_string"))) {
+ codec_string = abs;
+ } else {
+ if (!(codec_string = switch_channel_get_variable(channel, "codec_string"))) {
+ if (tech_pvt->profile->codec_string) {
+ codec_string = tech_pvt->profile->codec_string;
+ }
+ }
+
+ if ((ocodec = switch_channel_get_variable(channel, SWITCH_ORIGINATOR_CODEC_VARIABLE))) {
+ if (!codec_string || (tech_pvt->profile->pflags & PFLAG_DISABLE_TRANSCODING)) {
+ codec_string = ocodec;
+ } else {
+ if (!(codec_string = switch_core_session_sprintf(tech_pvt->session, "%s,%s", ocodec, codec_string))) {
+ codec_string = ocodec;
+ }
+ }
+ }
+ }
+
+ if (codec_string) {
+ char *tmp_codec_string;
+ if ((tmp_codec_string = switch_core_session_strdup(tech_pvt->session, codec_string))) {
+ tech_pvt->codec_order_last = switch_separate_string(tmp_codec_string, ',', tech_pvt->codec_order, SWITCH_MAX_CODECS);
+ tech_pvt->num_codecs =
+ switch_loadable_module_get_codecs_sorted(tech_pvt->codecs, SWITCH_MAX_CODECS, tech_pvt->codec_order, tech_pvt->codec_order_last);
+ }
+ } else {
+ tech_pvt->num_codecs =
+ switch_loadable_module_get_codecs(switch_core_session_get_pool(tech_pvt->session), tech_pvt->codecs,
+ sizeof(tech_pvt->codecs) / sizeof(tech_pvt->codecs[0]));
+ }
+
+}
+
+
+void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t * profile, private_object_t * tech_pvt, const char *channame)
+{
+ switch_channel_t *channel;
+ char name[256];
+
+ assert(session != NULL);
+ assert(profile != NULL);
+ assert(tech_pvt != NULL);
+
+ switch_core_session_add_stream(session, NULL);
+ channel = switch_core_session_get_channel(session);
+
+ //switch_channel_set_flag(channel, CF_ACCEPT_CNG);
+
+ switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
+ switch_mutex_lock(tech_pvt->flag_mutex);
+ tech_pvt->flags = profile->flags;
+ switch_mutex_unlock(tech_pvt->flag_mutex);
+ tech_pvt->profile = profile;
+ if (tech_pvt->bte) {
+ tech_pvt->te = tech_pvt->bte;
+ } else if (!tech_pvt->te) {
+ tech_pvt->te = profile->te;
+ }
+
+ if (tech_pvt->bcng_pt) {
+ tech_pvt->cng_pt = tech_pvt->bcng_pt;
+ } else if (!tech_pvt->cng_pt) {
+ tech_pvt->cng_pt = profile->cng_pt;
+ }
+
+ tech_pvt->session = session;
+ tech_pvt->home = su_home_new(sizeof(*tech_pvt->home));
+
+ switch_core_session_set_private(session, tech_pvt);
+
+
+ snprintf(name, sizeof(name), "sofia/%s/%s", profile->name, channame);
+ switch_channel_set_name(channel, name);
+ //sofia_glue_sofia_glue_tech_set_codecs(tech_pvt);
+
+}
+
+void sofia_glue_terminate_session(switch_core_session_t **session, switch_call_cause_t cause, int line)
+{
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Term called from line: %d\n", line);
+ if (*session) {
+ switch_channel_t *channel = switch_core_session_get_channel(*session);
+ struct private_object *tech_pvt = NULL;
+ unsigned running = switch_core_session_running(*session);
+ tech_pvt = switch_core_session_get_private(*session);
+
+ if (running) {
+ switch_channel_hangup(channel, cause);
+ } else {
+ if (tech_pvt) {
+ sofia_on_hangup(*session);
+ }
+ if (session && *session) {
+ switch_core_session_destroy(session);
+ }
+ }
+ }
+}
+
+
+
+switch_status_t sofia_glue_ext_address_lookup(char **ip, switch_port_t *port, char *sourceip, switch_memory_pool_t *pool)
+{
+ char *error;
+
+ if (!sourceip) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!strncasecmp(sourceip, "stun:", 5)) {
+ char *stun_ip = sourceip + 5;
+ if (!stun_ip) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stun Failed! NO STUN SERVER\n");
+ return SWITCH_STATUS_FALSE;
+ }
+ if (switch_stun_lookup(ip, port, stun_ip, SWITCH_STUN_DEFAULT_PORT, &error, pool) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Stun Failed! %s:%d [%s]\n", stun_ip, SWITCH_STUN_DEFAULT_PORT, error);
+ return SWITCH_STATUS_FALSE;
+ }
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Stun Success [%s]:[%d]\n", *ip, *port);
+ } else {
+ *ip = sourceip;
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t sofia_glue_tech_choose_port(private_object_t * tech_pvt)
+{
+ char *ip = tech_pvt->profile->rtpip;
+ switch_channel_t *channel;
+ switch_port_t sdp_port;
+ char tmp[50];
+
+ channel = switch_core_session_get_channel(tech_pvt->session);
+
+ 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;
+
+ if (tech_pvt->profile->extrtpip) {
+ if (sofia_glue_ext_address_lookup(&ip, &sdp_port, tech_pvt->profile->extrtpip, switch_core_session_get_pool(tech_pvt->session)) !=
+ SWITCH_STATUS_SUCCESS) {
+ sofia_glue_terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ return SWITCH_STATUS_FALSE;
+ }
+ }
+
+ tech_pvt->adv_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, ip);
+ tech_pvt->adv_sdp_audio_port = sdp_port;
+
+ snprintf(tmp, sizeof(tmp), "%d", sdp_port);
+ switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+ switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
+{
+ char rpid[1024] = { 0 };
+ char alert_info[1024] = { 0 };
+ char max_forwards[8] = { 0 };
+ char *alertbuf;
+ char *forwardbuf;
+ int forwardval;
+ private_object_t *tech_pvt;
+ switch_channel_t *channel = NULL;
+ switch_caller_profile_t *caller_profile;
+ char *cid_name, *cid_num;
+ char *e_dest = NULL;
+ const char *holdstr = "";
+ switch_stream_handle_t stream = { 0 };
+ switch_hash_index_t *hi;
+ void *vval;
+ char *extra_headers = NULL;
+ const void *vvar;
+ switch_status_t status = SWITCH_STATUS_FALSE;
+ char *rep;
+
+ channel = switch_core_session_get_channel(session);
+ assert(channel != NULL);
+
+ rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
+
+ tech_pvt = (private_object_t *) switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ caller_profile = switch_channel_get_caller_profile(channel);
+
+ cid_name = (char *) caller_profile->caller_id_name;
+ cid_num = (char *) caller_profile->caller_id_number;
+ sofia_glue_sofia_glue_tech_set_codecs(tech_pvt);
+
+ if (!tech_pvt->from_str) {
+ tech_pvt->from_str = switch_core_session_sprintf(tech_pvt->session, "\"%s\" <sip:%s@%s>",
+ cid_name,
+ cid_num, tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip);
+
+ }
+
+ if (!tech_pvt->from_str) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+
+
+
+ if ((alertbuf = switch_channel_get_variable(channel, "alert_info"))) {
+ snprintf(alert_info, sizeof(alert_info) - 1, "Alert-Info: %s", alertbuf);
+ }
+
+ if ((forwardbuf = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE))) {
+ forwardval = atoi(forwardbuf) - 1;
+ snprintf(max_forwards, sizeof(max_forwards) - 1, "%d", forwardval);
+ }
+
+ if (sofia_glue_tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
+ return status;
+ }
+
+ sofia_glue_set_local_sdp(tech_pvt, NULL, 0, NULL, 0);
+
+ switch_set_flag_locked(tech_pvt, TFLAG_READY);
+
+ // forge a RPID for now KHR -- Should wrap this in an if statement so it can be turned on and off
+ if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
+ const char *priv = "off";
+ const char *screen = "no";
+ if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NAME)) {
+ priv = "name";
+ if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
+ priv = "yes";
+ }
+ } else if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
+ priv = "yes";
+ }
+ if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
+ screen = "yes";
+ }
+
+ snprintf(rpid, sizeof(rpid) - 1, "Remote-Party-ID: %s;party=calling;screen=%s;privacy=%s", tech_pvt->from_str, screen, priv);
+
+ }
+
+ if (!tech_pvt->nh) {
+ char *url = sofia_glue_get_url_from_contact(tech_pvt->dest, 1);
+ tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
+ NUTAG_URL(url),
+ SIPTAG_TO_STR(tech_pvt->dest_to), SIPTAG_FROM_STR(tech_pvt->from_str), SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+ TAG_END());
+ switch_safe_free(url);
+
+ if (!(tech_pvt->sofia_private = malloc(sizeof(*tech_pvt->sofia_private)))) {
+ abort();
+ }
+ memset(tech_pvt->sofia_private, 0, sizeof(*tech_pvt->sofia_private));
+ switch_copy_string(tech_pvt->sofia_private->uuid, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid));
+ nua_handle_bind(tech_pvt->nh, tech_pvt->sofia_private);
+
+ }
+
+
+ if (tech_pvt->e_dest && (e_dest = strdup(tech_pvt->e_dest))) {
+ char *user = e_dest, *host = NULL;
+ char hash_key[256] = "";
+
+ if ((host = strchr(user, '@'))) {
+ *host++ = '\0';
+ }
+ snprintf(hash_key, sizeof(hash_key), "%s%s%s", user, host, cid_num);
+
+ tech_pvt->chat_from = tech_pvt->from_str;
+ tech_pvt->chat_to = tech_pvt->dest;
+ tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
+ switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
+ free(e_dest);
+ }
+
+ holdstr = switch_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? "*" : "";
+
+
+ SWITCH_STANDARD_STREAM(stream);
+ for (hi = switch_channel_variable_first(channel, switch_core_session_get_pool(tech_pvt->session)); hi; hi = switch_hash_next(hi)) {
+ switch_hash_this(hi, &vvar, NULL, &vval);
+ if (vvar && vval) {
+ const char *name = vvar;
+ char *value = (char *) vval;
+
+ if (!strncasecmp(name, SOFIA_SIP_HEADER_PREFIX, strlen(SOFIA_SIP_HEADER_PREFIX))) {
+ const char *hname = name + strlen(SOFIA_SIP_HEADER_PREFIX);
+ stream.write_function(&stream, "%s: %s\r\n", hname, value);
+ }
+ }
+ }
+
+ if (stream.data) {
+ extra_headers = stream.data;
+ }
+
+ nua_invite(tech_pvt->nh,
+ TAG_IF(!switch_strlen_zero(rpid), SIPTAG_HEADER_STR(rpid)),
+ TAG_IF(!switch_strlen_zero(alert_info), SIPTAG_HEADER_STR(alert_info)),
+ TAG_IF(!switch_strlen_zero(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
+ TAG_IF(!switch_strlen_zero(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)),
+ //SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+ 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)), SOATAG_HOLD(holdstr), TAG_END());
+
+ switch_safe_free(stream.data);
+
+ return SWITCH_STATUS_SUCCESS;
+
+}
+
+
+
+void sofia_glue_do_xfer_invite(switch_core_session_t *session)
+{
+ char rpid[1024];
+ 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_session_sprintf(session, "\"%s\" <sip:%s@%s>",
+ (char *) caller_profile->caller_id_name,
+ (char *) caller_profile->caller_id_number,
+ tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : 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());
+
+
+ nua_handle_bind(tech_pvt->nh2, tech_pvt->sofia_private);
+
+ nua_invite(tech_pvt->nh2,
+ TAG_IF(rpid, SIPTAG_HEADER_STR(rpid)),
+ SIPTAG_CONTACT_STR(tech_pvt->profile->url),
+ 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");
+ }
+
+}
+
+void sofia_glue_tech_absorb_sdp(private_object_t * tech_pvt)
+{
+ switch_channel_t *channel;
+ char *sdp_str;
+
+ channel = switch_core_session_get_channel(tech_pvt->session);
+ assert(channel != NULL);
+
+ if ((sdp_str = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE))) {
+ sdp_parser_t *parser;
+ sdp_session_t *sdp;
+ sdp_media_t *m;
+ sdp_connection_t *connection;
+
+ if ((parser = sdp_parse(tech_pvt->home, sdp_str, (int) strlen(sdp_str), 0))) {
+ if ((sdp = sdp_session(parser))) {
+ for (m = sdp->sdp_media; m; m = m->m_next) {
+ if (m->m_type != sdp_media_audio) {
+ continue;
+ }
+
+ connection = sdp->sdp_connection;
+ if (m->m_connections) {
+ connection = m->m_connections;
+ }
+
+ if (connection) {
+ tech_pvt->proxy_sdp_audio_ip = switch_core_session_strdup(tech_pvt->session, connection->c_address);
+ }
+ tech_pvt->proxy_sdp_audio_port = (switch_port_t) m->m_port;
+ if (tech_pvt->proxy_sdp_audio_ip && tech_pvt->proxy_sdp_audio_port) {
+ break;
+ }
+ }
+ }
+ sdp_parser_free(parser);
+ }
+ tech_pvt->local_sdp_str = switch_core_session_strdup(tech_pvt->session, sdp_str);
+ }
+}
+
+void sofia_glue_deactivate_rtp(private_object_t * tech_pvt)
+{
+ int loops = 0; //, sock = -1;
+ if (switch_rtp_ready(tech_pvt->rtp_session)) {
+ while (loops < 10 && (switch_test_flag(tech_pvt, TFLAG_READING) || switch_test_flag(tech_pvt, TFLAG_WRITING))) {
+ switch_yield(10000);
+ loops++;
+ }
+ switch_rtp_destroy(&tech_pvt->rtp_session);
+ }
+}
+
+switch_status_t sofia_glue_tech_set_codec(private_object_t * tech_pvt, int force)
+{
+ switch_channel_t *channel;
+
+ if (tech_pvt->read_codec.implementation) {
+ if (!force) {
+ return SWITCH_STATUS_SUCCESS;
+ }
+ if (strcasecmp(tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding) ||
+ tech_pvt->read_codec.implementation->samples_per_second != tech_pvt->rm_rate) {
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Changing Codec from %s to %s\n",
+ tech_pvt->read_codec.implementation->iananame, tech_pvt->rm_encoding);
+ switch_core_codec_destroy(&tech_pvt->read_codec);
+ switch_core_codec_destroy(&tech_pvt->write_codec);
+ switch_core_session_reset(tech_pvt->session);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Already using %s\n", tech_pvt->read_codec.implementation->iananame);
+ return SWITCH_STATUS_SUCCESS;
+ }
+ }
+
+ channel = switch_core_session_get_channel(tech_pvt->session);
+ assert(channel != NULL);
+
+ if (!tech_pvt->rm_encoding) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec with no name?\n");
+ sofia_glue_terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (switch_core_codec_init(&tech_pvt->read_codec,
+ tech_pvt->rm_encoding,
+ tech_pvt->rm_fmtp,
+ tech_pvt->rm_rate,
+ tech_pvt->codec_ms,
+ 1,
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
+ NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+ sofia_glue_terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ return SWITCH_STATUS_FALSE;
+ } else {
+ if (switch_core_codec_init(&tech_pvt->write_codec,
+ tech_pvt->rm_encoding,
+ tech_pvt->rm_fmtp,
+ tech_pvt->rm_rate,
+ tech_pvt->codec_ms,
+ 1,
+ SWITCH_CODEC_FLAG_ENCODE | SWITCH_CODEC_FLAG_DECODE | tech_pvt->profile->codec_flags,
+ NULL, switch_core_session_get_pool(tech_pvt->session)) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't load codec?\n");
+ sofia_glue_terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ return SWITCH_STATUS_FALSE;
+ } else {
+ int ms;
+ tech_pvt->read_frame.rate = tech_pvt->rm_rate;
+ ms = tech_pvt->write_codec.implementation->microseconds_per_frame / 1000;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set Codec %s %s/%ld %d ms\n",
+ switch_channel_get_name(channel), tech_pvt->rm_encoding, tech_pvt->rm_rate, tech_pvt->codec_ms);
+ tech_pvt->read_frame.codec = &tech_pvt->read_codec;
+
+ switch_core_session_set_read_codec(tech_pvt->session, &tech_pvt->read_codec);
+ switch_core_session_set_write_codec(tech_pvt->session, &tech_pvt->write_codec);
+ tech_pvt->fmtp_out = switch_core_session_strdup(tech_pvt->session, tech_pvt->write_codec.fmtp_out);
+ }
+ }
+ return SWITCH_STATUS_SUCCESS;
+}
+
+
+switch_status_t sofia_glue_activate_rtp(private_object_t * tech_pvt)
+{
+ int bw, ms;
+ switch_channel_t *channel;
+ const char *err = NULL;
+ char *val = NULL;
+ switch_rtp_flag_t flags;
+ switch_status_t status;
+ char tmp[50];
+ assert(tech_pvt != NULL);
+
+ 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;
+ }
+
+ if ((status = sofia_glue_tech_set_codec(tech_pvt, 0)) != SWITCH_STATUS_SUCCESS) {
+ return status;
+ }
+
+ bw = tech_pvt->read_codec.implementation->bits_per_second;
+ ms = tech_pvt->read_codec.implementation->microseconds_per_frame;
+
+ flags = (switch_rtp_flag_t) (SWITCH_RTP_FLAG_RAW_WRITE | SWITCH_RTP_FLAG_AUTOADJ | SWITCH_RTP_FLAG_DATAWAIT);
+
+ if (switch_test_flag(tech_pvt, TFLAG_BUGGY_2833)) {
+ flags |= SWITCH_RTP_FLAG_BUGGY_2833;
+ }
+
+ if ((tech_pvt->profile->pflags & PFLAG_PASS_RFC2833)
+ || ((val = switch_channel_get_variable(channel, "pass_rfc2833")) && switch_true(val))) {
+ flags |= SWITCH_RTP_FLAG_PASS_RFC2833;
+ }
+
+ if (tech_pvt->cng_pt) {
+ flags |= SWITCH_RTP_FLAG_AUTO_CNG;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "RTP [%s] %s:%d->%s:%d codec: %u ms: %d\n",
+ switch_channel_get_name(channel),
+ tech_pvt->local_sdp_audio_ip,
+ tech_pvt->local_sdp_audio_port,
+ tech_pvt->remote_sdp_audio_ip,
+ tech_pvt->remote_sdp_audio_port, tech_pvt->agreed_pt, tech_pvt->read_codec.implementation->microseconds_per_frame / 1000);
+
+ snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+ switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_IP_VARIABLE, tech_pvt->adv_sdp_audio_ip);
+ switch_channel_set_variable(channel, SWITCH_LOCAL_MEDIA_PORT_VARIABLE, tmp);
+
+ if (tech_pvt->rtp_session && switch_test_flag(tech_pvt, TFLAG_REINVITE)) {
+ switch_clear_flag_locked(tech_pvt, TFLAG_REINVITE);
+
+ if (switch_rtp_set_remote_address(tech_pvt->rtp_session, tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port, &err) !=
+ SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP CHANGING DEST TO: [%s:%d]\n",
+ tech_pvt->remote_sdp_audio_ip, tech_pvt->remote_sdp_audio_port);
+ /* Reactivate the NAT buster flag. */
+ switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTOADJ);
+ }
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ tech_pvt->rtp_session = switch_rtp_new(tech_pvt->local_sdp_audio_ip,
+ tech_pvt->local_sdp_audio_port,
+ tech_pvt->remote_sdp_audio_ip,
+ tech_pvt->remote_sdp_audio_port,
+ tech_pvt->agreed_pt,
+ tech_pvt->read_codec.implementation->samples_per_frame,
+ tech_pvt->codec_ms * 1000,
+ (switch_rtp_flag_t) flags,
+ NULL, tech_pvt->profile->timer_name, &err, switch_core_session_get_pool(tech_pvt->session));
+
+ if (switch_rtp_ready(tech_pvt->rtp_session)) {
+ uint8_t vad_in = switch_test_flag(tech_pvt, TFLAG_VAD_IN) ? 1 : 0;
+ uint8_t vad_out = switch_test_flag(tech_pvt, TFLAG_VAD_OUT) ? 1 : 0;
+ uint8_t inb = switch_test_flag(tech_pvt, TFLAG_OUTBOUND) ? 0 : 1;
+
+ tech_pvt->ssrc = switch_rtp_get_ssrc(tech_pvt->rtp_session);
+ switch_set_flag_locked(tech_pvt, TFLAG_RTP);
+ switch_set_flag_locked(tech_pvt, TFLAG_IO);
+
+ if ((vad_in && inb) || (vad_out && !inb)) {
+ switch_rtp_enable_vad(tech_pvt->rtp_session, tech_pvt->session, &tech_pvt->read_codec, SWITCH_VAD_FLAG_TALKING);
+ switch_set_flag_locked(tech_pvt, TFLAG_VAD);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "RTP Engage VAD for %s ( %s %s )\n",
+ switch_channel_get_name(switch_core_session_get_channel(tech_pvt->session)), vad_in ? "in" : "", vad_out ? "out" : "");
+ }
+
+ if (tech_pvt->te) {
+ switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
+ }
+ if (tech_pvt->cng_pt) {
+ switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
+ }
+
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "RTP REPORTS ERROR: [%s]\n", err);
+ sofia_glue_terminate_session(&tech_pvt->session, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER, __LINE__);
+ switch_clear_flag_locked(tech_pvt, TFLAG_IO);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch_set_flag_locked(tech_pvt, TFLAG_IO);
+ return SWITCH_STATUS_SUCCESS;
+}
+
+switch_status_t sofia_glue_tech_media(private_object_t * tech_pvt, char *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;
+ switch_channel_t *channel = switch_core_session_get_channel(tech_pvt->session);
+
+ assert(tech_pvt != NULL);
+
+ if (switch_strlen_zero(r_sdp)) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (tech_pvt->num_codecs) {
+ if ((sdp = sdp_session(parser))) {
+ match = negotiate_sdp(tech_pvt->session, sdp);
+ }
+ }
+
+ if (parser) {
+ sdp_parser_free(parser);
+ }
+
+ if (match) {
+ if (sofia_glue_tech_choose_port(tech_pvt) != SWITCH_STATUS_SUCCESS) {
+ return SWITCH_STATUS_FALSE;
+ }
+ sofia_glue_activate_rtp(tech_pvt);
+ switch_channel_set_variable(channel, SWITCH_ENDPOINT_DISPOSITION_VARIABLE, "EARLY MEDIA");
+ switch_set_flag_locked(tech_pvt, TFLAG_EARLY_MEDIA);
+ switch_channel_mark_pre_answered(channel);
+ return SWITCH_STATUS_SUCCESS;
+ }
+
+ return SWITCH_STATUS_FALSE;
+}
+
+
+
+uint8_t negotiate_sdp(switch_core_session_t *session, sdp_session_t * sdp)
+{
+ uint8_t match = 0;
+ switch_payload_t te = 0, cng_pt = 0;
+ private_object_t *tech_pvt;
+ sdp_media_t *m;
+ sdp_attribute_t *a;
+ switch_channel_t *channel;
+ int ptime = 0, dptime = 0;
+
+ tech_pvt = switch_core_session_get_private(session);
+ assert(tech_pvt != NULL);
+
+ channel = switch_core_session_get_channel(session);
+
+ if ((tech_pvt->origin = switch_core_session_strdup(session, (char *) sdp->sdp_origin->o_username))) {
+ if (strstr(tech_pvt->origin, "CiscoSystemsSIP-GW-UserAgent")) {
+ switch_set_flag_locked(tech_pvt, TFLAG_BUGGY_2833);
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Activate Buggy RFC2833 Mode!\n");
+ }
+ }
+
+ for (a = sdp->sdp_attributes; a; a = a->a_next) {
+ if (switch_strlen_zero(a->a_name)) {
+ continue;
+ }
+ if (!strcasecmp(a->a_name, "sendonly")) {
+ if (!switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+ char *stream;
+
+ switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ switch_channel_set_flag(channel, CF_HOLD);
+ if (!(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+ stream = tech_pvt->profile->hold_music;
+ }
+ if (stream) {
+ switch_ivr_broadcast(switch_core_session_get_uuid(tech_pvt->session), stream, SMF_ECHO_BLEG | SMF_LOOP);
+ }
+ }
+ } else if (!strcasecmp(a->a_name, "sendrecv")) {
+ if (switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+ switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ switch_channel_clear_flag(channel, CF_HOLD);
+ switch_channel_clear_flag_partner(channel, CF_BROADCAST);
+ switch_channel_set_flag_partner(channel, CF_BREAK);
+ }
+ } else if (!strcasecmp(a->a_name, "ptime")) {
+ dptime = atoi(a->a_value);
+ }
+ }
+
+ for (m = sdp->sdp_media; m; m = m->m_next) {
+ sdp_connection_t *connection;
+
+ ptime = dptime;
+ for (a = m->m_attributes; a; a = a->a_next) {
+ if (!strcasecmp(a->a_name, "ptime") && a->a_value) {
+ ptime = atoi(a->a_value);
+ }
+ }
+
+ if (m->m_type == sdp_media_audio) {
+ sdp_rtpmap_t *map;
+
+ connection = sdp->sdp_connection;
+ if (m->m_connections) {
+ connection = m->m_connections;
+ }
+
+ if (!connection) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find a c= line in the sdp at media or session level!\n");
+ match = 0;
+ break;
+ }
+
+ for (map = m->m_rtpmaps; map; map = map->rm_next) {
+ int32_t i;
+ const switch_codec_implementation_t *mimp = NULL, *near_match = NULL;
+ const char *rm_encoding;
+
+
+ if (!(rm_encoding = map->rm_encoding)) {
+ rm_encoding = "";
+ }
+
+ if (!te && !strcasecmp(rm_encoding, "telephone-event")) {
+ te = tech_pvt->te = (switch_payload_t) map->rm_pt;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set 2833 dtmf payload to %u\n", te);
+ if (tech_pvt->rtp_session) {
+ switch_rtp_set_telephony_event(tech_pvt->rtp_session, tech_pvt->te);
+ }
+ }
+
+ if (!cng_pt && !strcasecmp(rm_encoding, "CN")) {
+ cng_pt = tech_pvt->cng_pt = (switch_payload_t) map->rm_pt;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Set comfort noise payload to %u\n", cng_pt);
+ if (tech_pvt->rtp_session) {
+ switch_rtp_set_cng_pt(tech_pvt->rtp_session, tech_pvt->cng_pt);
+ switch_rtp_set_flag(tech_pvt->rtp_session, SWITCH_RTP_FLAG_AUTO_CNG);
+ }
+ }
+
+ if (match) {
+ if (te && cng_pt) {
+ break;
+ }
+ continue;
+ }
+
+ for (i = 0; i < tech_pvt->num_codecs; i++) {
+ const switch_codec_implementation_t *imp = tech_pvt->codecs[i];
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Codec Compare [%s:%d]/[%s:%d]\n",
+ rm_encoding, map->rm_pt, imp->iananame, imp->ianacode);
+ if (map->rm_pt < 96) {
+ match = (map->rm_pt == imp->ianacode) ? 1 : 0;
+ } else {
+ match = strcasecmp(rm_encoding, imp->iananame) ? 0 : 1;
+ }
+
+ if (match && (map->rm_rate == imp->samples_per_second)) {
+ if (ptime && ptime * 1000 != imp->microseconds_per_frame) {
+ near_match = imp;
+ match = 0;
+ continue;
+ }
+ mimp = imp;
+ break;
+ } else {
+ match = 0;
+ }
+ }
+
+ if (!match && near_match) {
+ const switch_codec_implementation_t *search[1];
+ char *prefs[1];
+ char tmp[80];
+ int num;
+
+ snprintf(tmp, sizeof(tmp), "%s@%uk@%ui", near_match->iananame, near_match->samples_per_second, ptime);
+
+ prefs[0] = tmp;
+ num = switch_loadable_module_get_codecs_sorted(search, 1, prefs, 1);
+
+ if (num) {
+ mimp = search[0];
+ } else {
+ mimp = near_match;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Substituting codec %s@%ums\n",
+ mimp->iananame, mimp->microseconds_per_frame / 1000);
+ match = 1;
+ }
+
+ if (mimp) {
+ if ((tech_pvt->rm_encoding = switch_core_session_strdup(session, (char *) rm_encoding))) {
+ char tmp[50];
+ tech_pvt->pt = (switch_payload_t) map->rm_pt;
+ tech_pvt->rm_rate = map->rm_rate;
+ tech_pvt->codec_ms = mimp->microseconds_per_frame / 1000;
+ tech_pvt->remote_sdp_audio_ip = switch_core_session_strdup(session, (char *) connection->c_address);
+ tech_pvt->rm_fmtp = switch_core_session_strdup(session, (char *) map->rm_fmtp);
+ tech_pvt->remote_sdp_audio_port = (switch_port_t) m->m_port;
+ tech_pvt->agreed_pt = (switch_payload_t) map->rm_pt;
+ snprintf(tmp, sizeof(tmp), "%d", tech_pvt->remote_sdp_audio_port);
+ switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_IP_VARIABLE, tech_pvt->remote_sdp_audio_ip);
+ switch_channel_set_variable(channel, SWITCH_REMOTE_MEDIA_PORT_VARIABLE, tmp);
+ } else {
+ match = 0;
+ }
+ }
+
+ if (match) {
+ if (sofia_glue_tech_set_codec(tech_pvt, 1) != SWITCH_STATUS_SUCCESS) {
+ match = 0;
+ }
+ }
+ }
+ }
+ }
+
+ return match;
+}
+
+// map sip responses to QSIG cause codes ala RFC4497 section 8.4.4
+switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status)
+{
+ switch (status) {
+ case 200:
+ return SWITCH_CAUSE_NORMAL_CLEARING;
+ case 401:
+ case 402:
+ case 403:
+ case 407:
+ case 603:
+ return SWITCH_CAUSE_CALL_REJECTED;
+ case 404:
+ case 485:
+ case 604:
+ return SWITCH_CAUSE_NO_ROUTE_DESTINATION;
+ case 408:
+ case 504:
+ return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
+ case 410:
+ return SWITCH_CAUSE_NUMBER_CHANGED;
+ case 413:
+ case 414:
+ case 416:
+ case 420:
+ case 421:
+ case 423:
+ case 505:
+ case 513:
+ return SWITCH_CAUSE_INTERWORKING;
+ case 480:
+ return SWITCH_CAUSE_NO_USER_RESPONSE;
+ case 400:
+ case 481:
+ case 500:
+ case 503:
+ return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE;
+ case 486:
+ case 600:
+ return SWITCH_CAUSE_USER_BUSY;
+ case 484:
+ return SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
+ case 488:
+ case 606:
+ return SWITCH_CAUSE_BEARERCAPABILITY_NOTIMPL;
+ case 502:
+ return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
+ case 405:
+ return SWITCH_CAUSE_SERVICE_UNAVAILABLE;
+ case 406:
+ case 415:
+ case 501:
+ return SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED;
+ case 482:
+ case 483:
+ return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR;
+ case 487:
+ return SWITCH_CAUSE_ORIGINATOR_CANCEL;
+
+ default:
+ return SWITCH_CAUSE_NORMAL_UNSPECIFIED;
+
+ }
+}
+
+
+void sofia_glue_pass_sdp(private_object_t * tech_pvt, char *sdp)
+{
+ char *val;
+ switch_channel_t *channel;
+ switch_core_session_t *other_session;
+ switch_channel_t *other_channel;
+
+ channel = switch_core_session_get_channel(tech_pvt->session);
+ assert(channel != NULL);
+
+ if ((val = switch_channel_get_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE))
+ && (other_session = switch_core_session_locate(val))) {
+ other_channel = switch_core_session_get_channel(other_session);
+ assert(other_channel != NULL);
+ switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp);
+
+ if (!switch_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) && (switch_channel_test_flag(other_channel, CF_OUTBOUND) &&
+ //switch_channel_test_flag(other_channel, CF_NOMEDIA) &&
+ switch_channel_test_flag(channel, CF_OUTBOUND) &&
+ switch_channel_test_flag(channel, CF_NOMEDIA))) {
+ switch_ivr_nomedia(val, SMF_FORCE);
+ switch_set_flag_locked(tech_pvt, TFLAG_CHANGE_MEDIA);
+ }
+
+ switch_core_session_rwunlock(other_session);
+ }
+}
+
+
+char *sofia_glue_get_url_from_contact(char *buf, uint8_t to_dup)
+{
+ char *url = NULL, *e;
+
+ if ((url = strchr(buf, '<')) && (e = strchr(url, '>'))) {
+ url++;
+ if (to_dup) {
+ url = strdup(url);
+ e = strchr(url, '>');
+ }
+
+ *e = '\0';
+ }
+
+ return url;
+}
+
+
+sofia_profile_t *sofia_glue_find_profile(char *key)
+{
+ sofia_profile_t *profile;
+
+ switch_mutex_lock(globals.hash_mutex);
+ profile = (sofia_profile_t *) switch_core_hash_find(globals.profile_hash, key);
+ switch_mutex_unlock(globals.hash_mutex);
+
+ return profile;
+}
+
+void sofia_glue_add_profile(char *key, sofia_profile_t * profile)
+{
+ switch_mutex_lock(globals.hash_mutex);
+ switch_core_hash_insert(globals.profile_hash, key, profile);
+ switch_mutex_unlock(globals.hash_mutex);
+}
+
+void sofia_glue_execute_sql(char *dbname, char *sql, switch_mutex_t * mutex)
+{
+ switch_core_db_t *db;
+
+ if (mutex) {
+ switch_mutex_lock(mutex);
+ }
+
+ if (!(db = switch_core_db_open_file(dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname);
+ goto end;
+ }
+ switch_core_db_persistant_execute(db, sql, 25);
+ switch_core_db_close(db);
+
+ end:
+ if (mutex) {
+ switch_mutex_unlock(mutex);
+ }
+}
+
+
+
Added: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_presence.c Sat Mar 31 15:01:33 2007
@@ -0,0 +1,909 @@
+#include "mod_sofia.h"
+
+
+switch_status_t sofia_presence_chat_send(char *proto, char *from, char *to, char *subject, char *body, char *hint)
+{
+ char buf[256];
+ char *user, *host;
+ sofia_profile_t *profile;
+ char *ffrom = NULL;
+ nua_handle_t *msg_nh;
+ char *contact;
+
+ if (to && (user = strdup(to))) {
+ if ((host = strchr(user, '@'))) {
+ *host++ = '\0';
+ }
+
+ if (!host || !(profile = sofia_glue_find_profile(host))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
+ "Chat proto [%s]\nfrom [%s]\nto [%s]\n%s\nInvalid Profile %s\n", proto, from, to,
+ body ? body : "[no body]", host ? host : "NULL");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!sofia_reg_find_reg_url(profile, user, host, buf, sizeof(buf))) {
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if (!strcmp(proto, SOFIA_CHAT_PROTO)) {
+ from = hint;
+ } else {
+ char *fp, *p, *fu = NULL;
+
+ if (!(fp = strdup(from))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n");
+ return SWITCH_STATUS_FALSE;
+ }
+
+ if ((p = strchr(fp, '@'))) {
+ *p = '\0';
+ fu = strdup(fp);
+ *p = '+';
+ }
+
+ ffrom = switch_mprintf("\"%s\" <sip:%s+%s@%s>", fu, proto, fp, profile->name);
+ from = ffrom;
+ switch_safe_free(fu);
+ switch_safe_free(fp);
+ }
+
+ contact = sofia_glue_get_url_from_contact(buf, 1);
+ msg_nh = nua_handle(profile->nua, NULL, SIPTAG_FROM_STR(from), NUTAG_URL(contact), SIPTAG_TO_STR(buf), // if this cries, add contact here too, change the 1 to 0 and omit the safe_free
+ SIPTAG_CONTACT_STR(profile->url), TAG_END());
+
+ switch_safe_free(contact);
+
+
+ nua_message(msg_nh, SIPTAG_CONTENT_TYPE_STR("text/html"), SIPTAG_PAYLOAD_STR(body), TAG_END());
+
+
+ switch_safe_free(ffrom);
+ free(user);
+ }
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+void sofia_presence_cancel(void)
+{
+ char *sql, *errmsg = NULL;
+ switch_core_db_t *db;
+ sofia_profile_t *profile;
+ switch_hash_index_t *hi;
+ void *val;
+
+ if ((sql = switch_mprintf("select 0,'unavailable','unavailable',* from sip_subscriptions where event='presence'"))) {
+ switch_mutex_lock(globals.hash_mutex);
+ for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+ switch_hash_this(hi, NULL, NULL, &val);
+ profile = (sofia_profile_t *) val;
+ if (!(profile->pflags & PFLAG_PRESENCE)) {
+ continue;
+ }
+
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ continue;
+ }
+ switch_mutex_lock(profile->ireg_mutex);
+ switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg);
+ switch_mutex_unlock(profile->ireg_mutex);
+ switch_core_db_close(db);
+ }
+ switch_safe_free(sql);
+ }
+ switch_mutex_unlock(globals.hash_mutex);
+}
+
+void sofia_presence_establish_presence(sofia_profile_t * profile)
+{
+ char *sql, *errmsg = NULL;
+ switch_core_db_t *db;
+
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ return;
+ }
+
+ if ((sql = switch_mprintf("select user,host,'Registered','unknown','' from sofia_handle_sip_registrations"))) {
+ switch_mutex_lock(profile->ireg_mutex);
+ switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg);
+ switch_mutex_unlock(profile->ireg_mutex);
+ switch_safe_free(sql);
+ }
+
+ if ((sql = switch_mprintf("select sub_to_user,sub_to_host,'Online','unknown',proto from sip_subscriptions "
+ "where proto='ext' or proto='user' or proto='conf'"))) {
+ switch_mutex_lock(profile->ireg_mutex);
+ switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg);
+ switch_mutex_unlock(profile->ireg_mutex);
+ switch_safe_free(sql);
+ }
+
+ switch_core_db_close(db);
+
+}
+
+
+
+char *sofia_presence_translate_rpid(char *in, char *ext)
+{
+ char *r = NULL;
+
+ if (in && (strstr(in, "null") || strstr(in, "NULL"))) {
+ in = NULL;
+ }
+
+ if (!in) {
+ in = ext;
+ }
+
+ if (!in) {
+ return NULL;
+ }
+
+ if (!strcasecmp(in, "dnd")) {
+ r = "busy";
+ }
+
+ if (ext && !strcasecmp(ext, "away")) {
+ r = "idle";
+ }
+
+ return r;
+}
+
+void sofia_presence_event_handler(switch_event_t *event)
+{
+ sofia_profile_t *profile;
+ switch_hash_index_t *hi;
+ void *val;
+ char *from = switch_event_get_header(event, "from");
+ char *proto = switch_event_get_header(event, "proto");
+ char *rpid = switch_event_get_header(event, "rpid");
+ char *status = switch_event_get_header(event, "status");
+ char *event_type = switch_event_get_header(event, "event_type");
+ //char *event_subtype = switch_event_get_header(event, "event_subtype");
+ char *sql = NULL;
+ char *euser = NULL, *user = NULL, *host = NULL;
+ char *errmsg;
+ switch_core_db_t *db;
+
+
+ if (rpid && !strcasecmp(rpid, "n/a")) {
+ rpid = NULL;
+ }
+
+ if (status && !strcasecmp(status, "n/a")) {
+ status = NULL;
+ }
+
+ if (rpid) {
+ rpid = sofia_presence_translate_rpid(rpid, status);
+ }
+
+ if (!status) {
+ status = "Available";
+
+ if (rpid) {
+ if (!strcasecmp(rpid, "busy")) {
+ status = "Busy";
+ } else if (!strcasecmp(rpid, "unavailable")) {
+ status = "Idle";
+ } else if (!strcasecmp(rpid, "away")) {
+ status = "Idle";
+ }
+ }
+ }
+
+ if (!rpid) {
+ rpid = "unknown";
+ }
+
+ if (event->event_id == SWITCH_EVENT_ROSTER) {
+
+ if (from) {
+ sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence' and full_from like '%%%q%%'", status, rpid, from);
+ } else {
+ sql = switch_mprintf("select 1,'%q','%q',* from sip_subscriptions where event='presence'", status, rpid);
+ }
+
+ switch_mutex_lock(globals.hash_mutex);
+ for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+ switch_hash_this(hi, NULL, NULL, &val);
+ profile = (sofia_profile_t *) val;
+ if (!(profile->pflags & PFLAG_PRESENCE)) {
+ continue;
+ }
+
+ if (sql) {
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ continue;
+ }
+ switch_mutex_lock(profile->ireg_mutex);
+ switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg);
+ switch_mutex_unlock(profile->ireg_mutex);
+ switch_core_db_close(db);
+ }
+
+ }
+ switch_mutex_unlock(globals.hash_mutex);
+
+ return;
+ }
+
+ if (switch_strlen_zero(event_type)) {
+ event_type = "presence";
+ }
+
+ if ((user = strdup(from))) {
+ if ((host = strchr(user, '@'))) {
+ char *p;
+ *host++ = '\0';
+ if ((p = strchr(host, '/'))) {
+ *p = '\0';
+ }
+ } else {
+ switch_safe_free(user);
+ return;
+ }
+ if ((euser = strchr(user, '+'))) {
+ euser++;
+ } else {
+ euser = user;
+ }
+
+ } else {
+ return;
+ }
+
+
+ switch (event->event_id) {
+ case SWITCH_EVENT_PRESENCE_PROBE:
+ if (proto) {
+ switch_core_db_t *db = NULL;
+ char *to = switch_event_get_header(event, "to");
+ char *user, *euser, *host, *p;
+
+ if (!to || !(user = strdup(to))) {
+ return;
+ }
+
+ if ((host = strchr(user, '@'))) {
+ *host++ = '\0';
+ }
+ euser = user;
+ if ((p = strchr(euser, '+'))) {
+ euser = (p + 1);
+ }
+
+ if (euser && host &&
+ (sql =
+ switch_mprintf("select user,host,status,rpid,'' from sofia_handle_sip_registrations where user='%q' and host='%q'",
+ euser, host)) && (profile = sofia_glue_find_profile(host))) {
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ switch_safe_free(user);
+ switch_safe_free(sql);
+ return;
+ }
+
+ switch_mutex_lock(profile->ireg_mutex);
+ switch_core_db_exec(db, sql, sofia_presence_resub_callback, profile, &errmsg);
+ switch_mutex_unlock(profile->ireg_mutex);
+ switch_safe_free(sql);
+ }
+ switch_safe_free(user);
+ switch_core_db_close(db);
+ }
+ return;
+ case SWITCH_EVENT_PRESENCE_IN:
+ sql =
+ switch_mprintf
+ ("select 1,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'",
+ status, rpid, proto, event_type, euser, host);
+ break;
+ case SWITCH_EVENT_PRESENCE_OUT:
+ sql =
+ switch_mprintf
+ ("select 0,'%q','%q',* from sip_subscriptions where proto='%q' and event='%q' and sub_to_user='%q' and sub_to_host='%q'",
+ status, rpid, proto, event_type, euser, host);
+ break;
+ default:
+ break;
+ }
+
+ switch_mutex_lock(globals.hash_mutex);
+ for (hi = switch_hash_first(switch_hash_pool_get(globals.profile_hash), globals.profile_hash); hi; hi = switch_hash_next(hi)) {
+ switch_hash_this(hi, NULL, NULL, &val);
+ profile = (sofia_profile_t *) val;
+ if (!(profile->pflags & PFLAG_PRESENCE)) {
+ continue;
+ }
+
+ if (sql) {
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ continue;
+ }
+ switch_mutex_lock(profile->ireg_mutex);
+ switch_core_db_exec(db, sql, sofia_presence_sub_callback, profile, &errmsg);
+ switch_mutex_unlock(profile->ireg_mutex);
+
+ switch_core_db_close(db);
+ }
+ }
+ switch_mutex_unlock(globals.hash_mutex);
+
+ switch_safe_free(sql);
+ switch_safe_free(user);
+}
+
+int sofia_presence_sub_reg_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ sofia_profile_t *profile = (sofia_profile_t *) pArg;
+ //char *proto = argv[0];
+ char *user = argv[1];
+ char *host = argv[2];
+ switch_event_t *event;
+ char *status = NULL;
+ if (switch_strlen_zero(status)) {
+ status = "Available";
+ }
+ if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_subtype", "probe");
+ switch_event_fire(&event);
+ }
+
+ return 0;
+}
+
+int sofia_presence_resub_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ sofia_profile_t *profile = (sofia_profile_t *) pArg;
+ char *user = argv[0];
+ char *host = argv[1];
+ char *status = argv[2];
+ char *rpid = argv[3];
+ char *proto = argv[4];
+ switch_event_t *event;
+
+ if (switch_strlen_zero(proto)) {
+ proto = NULL;
+ }
+
+ if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "%s", proto ? proto : SOFIA_CHAT_PROTO);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", user, host);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", status);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+ switch_event_fire(&event);
+ }
+
+ return 0;
+}
+
+int sofia_presence_sub_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ sofia_profile_t *profile = (sofia_profile_t *) pArg;
+ char *pl;
+ char *id, *note;
+ uint32_t in = atoi(argv[0]);
+ char *status = argv[1];
+ char *rpid = argv[2];
+ char *proto = argv[3];
+ char *user = argv[4];
+ char *host = argv[5];
+ char *sub_to_user = argv[6];
+ char *sub_to_host = argv[7];
+ char *event = argv[8];
+ char *contact = argv[9];
+ char *callid = argv[10];
+ char *full_from = argv[11];
+ char *full_via = argv[12];
+ nua_handle_t *nh;
+ char *to;
+ char *open;
+ char *tmp;
+
+ if (!rpid) {
+ rpid = "unknown";
+ }
+
+ if (in) {
+ note = switch_mprintf("<dm:note>%s</dm:note>", status);
+ open = "open";
+ } else {
+ note = NULL;
+ open = "closed";
+ }
+
+ if (!strcasecmp(sub_to_host, host)) {
+ /* same host */
+ id = switch_mprintf("sip:%s+%s@%s", proto, sub_to_user, sub_to_host);
+ } else if (strcasecmp(proto, SOFIA_CHAT_PROTO)) {
+ /*encapsulate */
+ id = switch_mprintf("sip:%s+%s+%s@%s", proto, sub_to_user, sub_to_host, host);
+ } else {
+ id = switch_mprintf("sip:%s@%s", sub_to_user, sub_to_host);
+ }
+
+ to = switch_mprintf("sip:%s@%s", user, host);
+ pl = switch_mprintf("<?xml version='1.0' encoding='UTF-8'?>\r\n"
+ "<presence xmlns='urn:ietf:params:xml:ns:pidf'\r\n"
+ "xmlns:dm='urn:ietf:params:xml:ns:pidf:data-model'\r\n"
+ "xmlns:rpid='urn:ietf:params:xml:ns:pidf:rpid'\r\n"
+ "xmlns:c='urn:ietf:params:xml:ns:pidf:cipid'\r\n"
+ "entity='pres:%s'>\r\n"
+ "<tuple id='t6a5ed77e'>\r\n"
+ "<status>\r\n"
+ "<basic>%s</basic>\r\n"
+ "</status>\r\n"
+ "</tuple>\r\n"
+ "<dm:person id='p06360c4a'>\r\n"
+ "<rpid:activities>\r\n" "<rpid:%s/>\r\n" "</rpid:activities>%s</dm:person>\r\n" "</presence>", id, open, rpid, note);
+
+
+
+ nh = nua_handle(profile->nua, NULL, TAG_END());
+ tmp = contact;
+ contact = sofia_glue_get_url_from_contact(tmp, 0);
+
+ nua_notify(nh,
+ NUTAG_URL(contact),
+ SIPTAG_TO_STR(full_from),
+ SIPTAG_FROM_STR(id),
+ SIPTAG_CONTACT_STR(profile->url),
+ SIPTAG_CALL_ID_STR(callid),
+ SIPTAG_VIA_STR(full_via),
+ SIPTAG_SUBSCRIPTION_STATE_STR("active;expires=3600"),
+ SIPTAG_EVENT_STR(event), SIPTAG_CONTENT_TYPE_STR("application/pidf+xml"), SIPTAG_PAYLOAD_STR(pl), TAG_END());
+
+ switch_safe_free(id);
+ switch_safe_free(note);
+ switch_safe_free(pl);
+ switch_safe_free(to);
+
+ return 0;
+}
+
+void sofia_presence_handle_sip_i_subscribe(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ if (sip) {
+ long exp, exp_raw;
+ sip_to_t const *to = sip->sip_to;
+ sip_from_t const *from = sip->sip_from;
+ sip_contact_t const *contact = sip->sip_contact;
+ char *from_user = NULL;
+ char *from_host = NULL;
+ char *to_user = NULL;
+ char *to_host = NULL;
+ char *sql, *event = NULL;
+ char *proto = "sip";
+ char *d_user = NULL;
+ char *contact_str = "";
+ char *call_id = NULL;
+ char *to_str = NULL;
+ char *full_from = NULL;
+ char *full_via = NULL;
+ switch_core_db_t *db;
+ char *errmsg;
+ char *sstr;
+ const char *display = "\"user\"";
+ switch_event_t *sevent;
+
+ if (contact) {
+ char *port = (char *) contact->m_url->url_port;
+
+ display = contact->m_display;
+
+ if (switch_strlen_zero(display)) {
+ if (from) {
+ display = from->a_display;
+ if (switch_strlen_zero(display)) {
+ display = "\"user\"";
+ }
+ }
+ } else {
+ display = "\"user\"";
+ }
+
+ if (!port) {
+ port = SOFIA_DEFAULT_PORT;
+ }
+
+ if (contact->m_url->url_params) {
+ contact_str = switch_mprintf("%s <sip:%s@%s:%s;%s>",
+ display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params);
+ } else {
+ contact_str = switch_mprintf("%s <sip:%s@%s:%s>", display, contact->m_url->url_user, contact->m_url->url_host, port);
+ }
+ }
+
+ if (to) {
+ to_str = switch_mprintf("sip:%s@%s", to->a_url->url_user, to->a_url->url_host); //, to->a_url->url_port);
+ }
+
+ if (to) {
+ to_user = (char *) to->a_url->url_user;
+ to_host = (char *) to->a_url->url_host;
+ }
+
+
+ if (strstr(to_user, "ext+") || strstr(to_user, "user+") || strstr(to_user, "conf+")) {
+ char proto[80];
+ char *p;
+
+ switch_copy_string(proto, to_user, sizeof(proto));
+ if ((p = strchr(proto, '+'))) {
+ *p = '\0';
+ }
+
+ if (switch_event_create(&sevent, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+ switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "login", "%s", profile->name);
+ switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "from", "%s@%s", to_user, to_host);
+ switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "rpid", "unknown");
+ switch_event_add_header(sevent, SWITCH_STACK_BOTTOM, "status", "Click To Call");
+ switch_event_fire(&sevent);
+ }
+ }
+
+ if (strchr(to_user, '+')) {
+ char *h;
+ if ((proto = (d_user = strdup(to_user)))) {
+ if ((to_user = strchr(d_user, '+'))) {
+ *to_user++ = '\0';
+ if ((h = strchr(to_user, '+')) || (h = strchr(to_user, '@'))) {
+ *h++ = '\0';
+ to_host = h;
+ }
+ }
+ }
+
+ if (!(proto && to_user && to_host)) {
+ nua_respond(nh, SIP_404_NOT_FOUND, NUTAG_WITH_THIS(nua), TAG_END());
+ goto end;
+ }
+ }
+
+ call_id = sip_header_as_string(profile->home, (void *) sip->sip_call_id);
+ event = sip_header_as_string(profile->home, (void *) sip->sip_event);
+ full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
+ full_via = sip_header_as_string(profile->home, (void *) sip->sip_via);
+
+ exp_raw = (sip->sip_expires ? sip->sip_expires->ex_delta : 3600);
+ exp = (long) time(NULL) + exp_raw;
+
+ if (sip && sip->sip_from) {
+ from_user = (char *) sip->sip_from->a_url->url_user;
+ from_host = (char *) sip->sip_from->a_url->url_host;
+ } else {
+ from_user = "n/a";
+ from_host = "n/a";
+ }
+
+ if ((sql = switch_mprintf("delete from sip_subscriptions where "
+ "proto='%q' and user='%q' and host='%q' and sub_to_user='%q' and sub_to_host='%q' and event='%q';\n"
+ "insert into sip_subscriptions values ('%q','%q','%q','%q','%q','%q','%q','%q','%q','%q',%ld)",
+ proto,
+ from_user,
+ from_host,
+ to_user,
+ to_host, event, proto, from_user, from_host, to_user, to_host, event, contact_str, call_id, full_from, full_via, exp))) {
+ sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
+ switch_safe_free(sql);
+ }
+
+ sstr = switch_mprintf("active;expires=%ld", exp_raw);
+
+ nua_respond(nh, SIP_202_ACCEPTED,
+ NUTAG_WITH_THIS(nua),
+ SIPTAG_SUBSCRIPTION_STATE_STR(sstr), SIPTAG_FROM(sip->sip_to), SIPTAG_TO(sip->sip_from), SIPTAG_CONTACT_STR(to_str), TAG_END());
+
+
+
+ switch_safe_free(sstr);
+
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ goto end;
+ }
+ if ((sql = switch_mprintf("select * from sip_subscriptions where user='%q' and host='%q'", to_user, to_host, to_user, to_host))) {
+ switch_mutex_lock(profile->ireg_mutex);
+ switch_core_db_exec(db, sql, sofia_presence_sub_reg_callback, profile, &errmsg);
+ switch_mutex_unlock(profile->ireg_mutex);
+ switch_safe_free(sql);
+ }
+ switch_core_db_close(db);
+ end:
+
+ if (event) {
+ su_free(profile->home, event);
+ }
+ if (call_id) {
+ su_free(profile->home, call_id);
+ }
+ if (full_from) {
+ su_free(profile->home, full_from);
+ }
+ if (full_via) {
+ su_free(profile->home, full_via);
+ }
+
+ switch_safe_free(d_user);
+ switch_safe_free(to_str);
+ switch_safe_free(contact_str);
+ }
+}
+
+void sofia_presence_handle_sip_r_subscribe(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+
+}
+
+void sofia_presence_handle_sip_i_publish(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ if (sip) {
+ sip_from_t const *from = sip->sip_from;
+ char *from_user = NULL;
+ char *from_host = NULL;
+ char *rpid = "unknown";
+ sip_payload_t *payload = sip->sip_payload;
+ char *event_type;
+
+ if (from) {
+ from_user = (char *) from->a_url->url_user;
+ from_host = (char *) from->a_url->url_host;
+ }
+
+ if (payload) {
+ switch_xml_t xml, note, person, tuple, status, basic, act;
+ switch_event_t *event;
+ uint8_t in = 0;
+ char *sql;
+
+ if ((xml = switch_xml_parse_str(payload->pl_data, strlen(payload->pl_data)))) {
+ char *status_txt = "", *note_txt = "";
+
+ if ((tuple = switch_xml_child(xml, "tuple")) && (status = switch_xml_child(tuple, "status"))
+ && (basic = switch_xml_child(status, "basic"))) {
+ status_txt = basic->txt;
+ }
+
+ if ((person = switch_xml_child(xml, "dm:person")) && (note = switch_xml_child(person, "dm:note"))) {
+ note_txt = note->txt;
+ }
+
+ if (person && (act = switch_xml_child(person, "rpid:activities"))) {
+ if ((rpid = strchr(act->child->name, ':'))) {
+ rpid++;
+ } else {
+ rpid = act->child->name;
+ }
+ }
+
+ if (!strcasecmp(status_txt, "open")) {
+ if (switch_strlen_zero(note_txt)) {
+ note_txt = "Available";
+ }
+ in = 1;
+ } else if (!strcasecmp(status_txt, "closed")) {
+ if (switch_strlen_zero(note_txt)) {
+ note_txt = "Unavailable";
+ }
+ }
+
+ if ((sql =
+ switch_mprintf("update sofia_handle_sip_registrations set status='%q',rpid='%q' where user='%q' and host='%q'",
+ note_txt, rpid, from_user, from_host))) {
+ sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
+ switch_safe_free(sql);
+ }
+
+ event_type = sip_header_as_string(profile->home, (void *) sip->sip_event);
+
+ if (in) {
+ if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
+
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "%s", note_txt);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type);
+ switch_event_fire(&event);
+ }
+ } else {
+ if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
+
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "%s", event_type);
+ switch_event_fire(&event);
+ }
+ }
+
+ if (event_type) {
+ su_free(profile->home, event_type);
+ }
+
+ switch_xml_free(xml);
+ }
+
+ }
+
+ }
+
+ nua_respond(nh, SIP_200_OK, NUTAG_WITH_THIS(nua), TAG_END());
+
+}
+
+void sofia_presence_set_hash_key(char *hash_key, int32_t len, sip_t const *sip)
+{
+
+ snprintf(hash_key, len, "%s%s%s", (char *) sip->sip_from->a_url->url_user, (char *) sip->sip_from->a_url->url_host,
+ (char *) sip->sip_to->a_url->url_user);
+
+
+#if 0
+ /* nicer one we cant use in both directions >=0 */
+ snprintf(hash_key, len, "%s%s%s%s%s%s",
+ (char *) sip->sip_to->a_url->url_user,
+ (char *) sip->sip_to->a_url->url_host,
+ (char *) sip->sip_to->a_url->url_params,
+ (char *) sip->sip_from->a_url->url_user, (char *) sip->sip_from->a_url->url_host, (char *) sip->sip_from->a_url->url_params);
+#endif
+
+}
+
+
+void sofia_presence_handle_sip_i_message(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ if (sip) {
+ sip_from_t const *from = sip->sip_from;
+ char *from_user = NULL;
+ char *from_host = NULL;
+ sip_to_t const *to = sip->sip_to;
+ char *to_user = NULL;
+ char *to_host = NULL;
+ sip_subject_t const *sip_subject = sip->sip_subject;
+ sip_payload_t *payload = sip->sip_payload;
+ const char *subject = "n/a";
+ char *msg = NULL;
+
+ if (sip->sip_content_type) {
+ if (strstr((char *) sip->sip_content_type->c_subtype, "composing")) {
+ return;
+ }
+ }
+
+ if (from) {
+ from_user = (char *) from->a_url->url_user;
+ from_host = (char *) from->a_url->url_host;
+ }
+
+ if (to) {
+ to_user = (char *) to->a_url->url_user;
+ to_host = (char *) to->a_url->url_host;
+ }
+
+
+ if (!to_user) {
+ return;
+ }
+
+ if (payload) {
+ msg = payload->pl_data;
+ }
+
+ if (sip_subject) {
+ subject = sip_subject->g_value;
+ }
+
+ if (nh) {
+ char hash_key[512];
+ private_object_t *tech_pvt;
+ switch_channel_t *channel;
+ switch_event_t *event;
+ char *to_addr;
+ char *from_addr;
+ char *p;
+ char *full_from;
+ char proto[512] = SOFIA_CHAT_PROTO;
+
+ full_from = sip_header_as_string(profile->home, (void *) sip->sip_from);
+
+ if ((p = strchr(to_user, '+'))) {
+ switch_copy_string(proto, to_user, sizeof(proto));
+ p = strchr(proto, '+');
+ *p++ = '\0';
+
+ if ((to_addr = strdup(p))) {
+ if ((p = strchr(to_addr, '+'))) {
+ *p = '@';
+ }
+ }
+
+ } else {
+ to_addr = switch_mprintf("%s@%s", to_user, to_host);
+ }
+
+ from_addr = switch_mprintf("%s@%s", from_user, from_host);
+
+
+ sofia_presence_set_hash_key(hash_key, sizeof(hash_key), sip);
+ if ((tech_pvt = (private_object_t *) switch_core_hash_find(profile->chat_hash, hash_key))) {
+ channel = switch_core_session_get_channel(tech_pvt->session);
+ if (switch_event_create(&event, SWITCH_EVENT_MESSAGE) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", SOFIA_CHAT_PROTO);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s", tech_pvt->hash_key);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "to", "%s", to_addr);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "subject", "SIMPLE MESSAGE");
+ if (msg) {
+ switch_event_add_body(event, "%s", msg);
+ }
+ if (switch_core_session_queue_event(tech_pvt->session, &event) != SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "delivery-failure", "true");
+ switch_event_fire(&event);
+ }
+ }
+ } else {
+ switch_chat_interface_t *ci;
+
+ if ((ci = switch_loadable_module_get_chat_interface(proto))) {
+ ci->chat_send(SOFIA_CHAT_PROTO, from_addr, to_addr, "", msg, full_from);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Chat Interface [%s]!\n", proto ? proto : "(none)");
+ }
+
+ }
+ switch_safe_free(to_addr);
+ switch_safe_free(from_addr);
+ if (full_from) {
+ su_free(profile->home, full_from);
+ }
+ }
+
+ }
+}
+
+void sofia_presence_set_chat_hash(private_object_t * tech_pvt, sip_t const *sip)
+{
+ char hash_key[256] = "";
+ char buf[512];
+
+ if (tech_pvt->hash_key || !sip || !sip->sip_from || !sip->sip_from->a_url || !sip->sip_from->a_url->url_user || !sip->sip_from->a_url->url_host) {
+ return;
+ }
+
+ if (sofia_reg_find_reg_url(tech_pvt->profile, sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host, buf, sizeof(buf))) {
+ tech_pvt->chat_from = sip_header_as_string(tech_pvt->home, (const sip_header_t *) sip->sip_to);
+ tech_pvt->chat_to = switch_core_session_strdup(tech_pvt->session, buf);
+ sofia_presence_set_hash_key(hash_key, sizeof(hash_key), sip);
+ } else {
+ return;
+ }
+
+ tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
+ switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
+
+}
Added: freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_reg.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/sofia_reg.c Sat Mar 31 15:01:33 2007
@@ -0,0 +1,790 @@
+#include "mod_sofia.h"
+
+
+void sofia_reg_unregister(sofia_profile_t * profile)
+{
+ outbound_reg_t *gateway_ptr;
+ for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+ if (gateway_ptr->sofia_private) {
+ free(gateway_ptr->sofia_private);
+ nua_handle_bind(gateway_ptr->nh, NULL);
+ gateway_ptr->sofia_private = NULL;
+ }
+ nua_handle_destroy(gateway_ptr->nh);
+ }
+}
+
+void sofia_reg_check_gateway(sofia_profile_t * profile, time_t now)
+{
+ outbound_reg_t *gateway_ptr;
+ for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+ int ss_state = nua_callstate_authenticating;
+ reg_state_t ostate = gateway_ptr->state;
+
+ switch (ostate) {
+ case REG_STATE_REGISTER:
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "registered %s\n", gateway_ptr->name);
+ gateway_ptr->expires = now + gateway_ptr->freq;
+ gateway_ptr->state = REG_STATE_REGED;
+ break;
+ case REG_STATE_UNREGED:
+ if ((gateway_ptr->nh = nua_handle(gateway_ptr->profile->nua, NULL,
+ NUTAG_URL(gateway_ptr->register_proxy),
+ SIPTAG_TO_STR(gateway_ptr->register_to),
+ NUTAG_CALLSTATE_REF(ss_state), SIPTAG_FROM_STR(gateway_ptr->register_from), TAG_END()))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "registering %s\n", gateway_ptr->name);
+
+ if (!(gateway_ptr->sofia_private = malloc(sizeof(*gateway_ptr->sofia_private)))) {
+ abort();
+ }
+ memset(gateway_ptr->sofia_private, 0, sizeof(*gateway_ptr->sofia_private));
+
+ gateway_ptr->sofia_private->gateway = gateway_ptr;
+ nua_handle_bind(gateway_ptr->nh, gateway_ptr->sofia_private);
+
+ nua_register(gateway_ptr->nh,
+ SIPTAG_FROM_STR(gateway_ptr->register_from),
+ SIPTAG_CONTACT_STR(gateway_ptr->register_contact),
+ SIPTAG_EXPIRES_STR(gateway_ptr->expires_str),
+ NUTAG_REGISTRAR(gateway_ptr->register_proxy),
+ NUTAG_OUTBOUND("no-options-keepalive"), NUTAG_OUTBOUND("no-validate"), NUTAG_KEEPALIVE(0), TAG_NULL());
+ gateway_ptr->retry = now + 10;
+ gateway_ptr->state = REG_STATE_TRYING;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error registering %s\n", gateway_ptr->name);
+ gateway_ptr->state = REG_STATE_FAILED;
+ }
+ break;
+
+ case REG_STATE_TRYING:
+ if (gateway_ptr->retry && now >= gateway_ptr->retry) {
+ gateway_ptr->state = REG_STATE_UNREGED;
+ gateway_ptr->retry = 0;
+ }
+ break;
+ default:
+ if (now >= gateway_ptr->expires) {
+ gateway_ptr->state = REG_STATE_UNREGED;
+ }
+ break;
+ }
+ }
+
+}
+
+
+int sofia_reg_find_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ struct callback_t *cbt = (struct callback_t *) pArg;
+
+ switch_copy_string(cbt->val, argv[0], cbt->len);
+ cbt->matches++;
+ return 0;
+}
+
+int sofia_reg_del_callback(void *pArg, int argc, char **argv, char **columnNames)
+{
+ switch_event_t *s_event;
+
+ if (argc >= 3) {
+ if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_EXPIRE) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", argv[0]);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "user", "%s", argv[1]);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "host", "%s", argv[2]);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", argv[3]);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%s", argv[4]);
+ switch_event_fire(&s_event);
+ }
+ }
+ return 0;
+}
+
+void sofia_reg_check_expire(switch_core_db_t *db, sofia_profile_t * profile, time_t now)
+{
+ char sql[1024];
+ char *errmsg;
+
+ if (!db) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ return;
+ }
+
+ switch_mutex_lock(profile->ireg_mutex);
+ snprintf(sql, sizeof(sql), "select '%s',* from sip_registrations where expires > 0 and expires < %ld", profile->name, (long) now);
+ switch_core_db_exec(db, sql, sofia_reg_del_callback, NULL, &errmsg);
+
+ if (errmsg) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", sql, errmsg);
+ switch_safe_free(errmsg);
+ errmsg = NULL;
+ }
+
+ snprintf(sql, sizeof(sql), "delete from sip_registrations where expires > 0 and expires < %ld", (long) now);
+ switch_core_db_persistant_execute(db, sql, 1000);
+ snprintf(sql, sizeof(sql), "delete from sip_authentication where expires > 0 and expires < %ld", (long) now);
+ switch_core_db_persistant_execute(db, sql, 1000);
+ snprintf(sql, sizeof(sql), "delete from sip_subscriptions where expires > 0 and expires < %ld", (long) now);
+ switch_core_db_persistant_execute(db, sql, 1000);
+
+ switch_mutex_unlock(profile->ireg_mutex);
+
+}
+
+char *sofia_reg_find_reg_url(sofia_profile_t * profile, const char *user, const char *host, char *val, switch_size_t len)
+{
+ char *errmsg;
+ struct callback_t cbt = { 0 };
+ switch_core_db_t *db;
+
+ if (!user) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Called with null user!\n");
+ return NULL;
+ }
+
+ if (!(db = switch_core_db_open_file(profile->dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", profile->dbname);
+ return NULL;
+ }
+
+ cbt.val = val;
+ cbt.len = len;
+ switch_mutex_lock(profile->ireg_mutex);
+ if (host) {
+ snprintf(val, len, "select contact from sip_registrations where user='%s' and host='%s'", user, host);
+ } else {
+ snprintf(val, len, "select contact from sip_registrations where user='%s'", user);
+ }
+
+ switch_core_db_exec(db, val, sofia_reg_find_callback, &cbt, &errmsg);
+
+ if (errmsg) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR [%s][%s]\n", val, errmsg);
+ switch_safe_free(errmsg);
+ errmsg = NULL;
+ }
+
+ switch_mutex_unlock(profile->ireg_mutex);
+
+ switch_core_db_close(db);
+ if (cbt.matches) {
+ return val;
+ } else {
+ return NULL;
+ }
+}
+
+char *sofia_reg_get_auth_data(char *dbname, char *nonce, char *npassword, size_t len, switch_mutex_t * mutex)
+{
+ switch_core_db_t *db;
+ switch_core_db_stmt_t *stmt;
+ char *sql = NULL, *ret = NULL;
+
+ if (mutex) {
+ switch_mutex_lock(mutex);
+ }
+
+ if (!dbname) {
+ goto end;
+ }
+
+ if (!(db = switch_core_db_open_file(dbname))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB %s\n", dbname);
+ goto end;
+ }
+
+ sql = switch_mprintf("select passwd from sip_authentication where nonce='%q'", nonce);
+ if (switch_core_db_prepare(db, sql, -1, &stmt, 0)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Statement Error!\n");
+ goto fail;
+ } else {
+ int running = 1;
+ int colcount;
+
+ while (running < 5000) {
+ int result = switch_core_db_step(stmt);
+
+ if (result == SWITCH_CORE_DB_ROW) {
+ if ((colcount = switch_core_db_column_count(stmt))) {
+ switch_copy_string(npassword, (char *) switch_core_db_column_text(stmt, 0), len);
+ ret = npassword;
+ }
+ break;
+ } else if (result == SWITCH_CORE_DB_BUSY) {
+ running++;
+ switch_yield(1000);
+ continue;
+ }
+ break;
+ }
+
+ switch_core_db_finalize(stmt);
+ }
+
+
+ fail:
+
+ switch_core_db_close(db);
+
+ end:
+ if (mutex) {
+ switch_mutex_unlock(mutex);
+ }
+
+ if (sql) {
+ switch_safe_free(sql);
+ }
+
+ return ret;
+}
+
+
+
+uint8_t sofia_reg_handle_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sip_t const *sip, sofia_regtype_t regtype, char *key,
+ uint32_t keylen)
+{
+ sip_from_t const *from = NULL;
+ sip_expires_t const *expires = NULL;
+ sip_authorization_t const *authorization = NULL;
+ sip_contact_t const *contact = NULL;
+ switch_xml_t domain, xml, user, param, xparams;
+ char params[1024] = "";
+ char *sql;
+ switch_event_t *s_event;
+ const char *from_user = NULL;
+ const char *from_host = NULL;
+ char contact_str[1024] = "";
+ char buf[512];
+ const char *passwd = NULL;
+ const char *a1_hash = NULL;
+ uint8_t stale = 0, ret = 0, forbidden = 0;
+ auth_res_t auth_res;
+ long exptime = 60;
+ switch_event_t *event;
+ const char *rpid = "unknown";
+ const char *display = "\"user\"";
+
+ /* all callers must confirm that sip, sip->sip_request and sip->sip_contact are not NULL */
+ assert(sip != NULL && sip->sip_contact != NULL && sip->sip_request != NULL);
+
+ expires = sip->sip_expires;
+ authorization = sip->sip_authorization;
+ contact = sip->sip_contact;
+ from = sip->sip_from;
+
+ if (from) {
+ from_user = from->a_url->url_user;
+ from_host = from->a_url->url_host;
+ }
+
+ if (!from_user || !from_host) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can not do authorization without a complete from header\n");
+ nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ return 1;
+ }
+
+ if (contact->m_url) {
+ const char *port = contact->m_url->url_port;
+ display = contact->m_display;
+
+ if (switch_strlen_zero(display)) {
+ if (from) {
+ display = from->a_display;
+ if (switch_strlen_zero(display)) {
+ display = "\"user\"";
+ }
+ }
+ }
+
+ if (!port) {
+ port = SOFIA_DEFAULT_PORT;
+ }
+
+ if (contact->m_url->url_params) {
+ snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s;%s>",
+ display, contact->m_url->url_user, contact->m_url->url_host, port, contact->m_url->url_params);
+ } else {
+ snprintf(contact_str, sizeof(contact_str), "%s <sip:%s@%s:%s>", display, contact->m_url->url_user, contact->m_url->url_host, port);
+ }
+ }
+
+ if (expires) {
+ exptime = expires->ex_delta;
+ } else if (contact->m_expires) {
+ exptime = atol(contact->m_expires);
+ }
+
+ if (regtype == REG_REGISTER) {
+ authorization = sip->sip_authorization;
+ } else if (regtype == REG_INVITE) {
+ authorization = sip->sip_proxy_authorization;
+ }
+
+ if ((profile->pflags & PFLAG_BLIND_REG)) {
+ goto reg;
+ }
+
+ if (authorization) {
+ if ((auth_res = parse_auth(profile, authorization, sip->sip_request->rq_method_name, key, keylen)) == AUTH_STALE) {
+ stale = 1;
+ }
+
+ if (auth_res != AUTH_OK && !stale) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "send %s for [%s@%s]\n", forbidden ? "forbidden" : "challange", from_user, from_host);
+ if (auth_res == AUTH_FORBIDDEN) {
+ nua_respond(nh, SIP_403_FORBIDDEN, NUTAG_WITH_THIS(nua), TAG_END());
+ } else {
+ nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), TAG_END());
+ }
+ return 1;
+ }
+ }
+
+ if (!authorization || stale) {
+ snprintf(params, sizeof(params), "from_user=%s&from_host=%s&contact=%s", from_user, from_host, contact_str);
+
+
+ if (switch_xml_locate("directory", "domain", "name", from_host, &xml, &domain, params) != SWITCH_STATUS_SUCCESS) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "can't find domain for [%s@%s]\n", from_user, from_host);
+ nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
+ return 1;
+ }
+
+ if (!(user = switch_xml_find_child(domain, "user", "id", from_user))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find user [%s@%s]\n", from_user, from_host);
+ nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
+ switch_xml_free(xml);
+ return 1;
+ }
+
+ if (!(xparams = switch_xml_child(user, "params"))) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "can't find params for user [%s@%s]\n", from_user, from_host);
+ nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_CONTACT(contact), TAG_END());
+ switch_xml_free(xml);
+ return 1;
+ }
+
+
+ for (param = switch_xml_child(xparams, "param"); param; param = param->next) {
+ const char *var = switch_xml_attr_soft(param, "name");
+ const char *val = switch_xml_attr_soft(param, "value");
+
+ if (!strcasecmp(var, "password")) {
+ passwd = val;
+ }
+
+ if (!strcasecmp(var, "a1-hash")) {
+ a1_hash = val;
+ }
+ }
+
+ if (passwd || a1_hash) {
+ switch_uuid_t uuid;
+ char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
+ char *sql, *auth_str;
+
+ su_md5_t ctx;
+ char hexdigest[2 * SU_MD5_DIGEST_SIZE + 1];
+ char *input;
+
+ if (!a1_hash) {
+ input = switch_mprintf("%s:%s:%s", from_user, from_host, passwd);
+ su_md5_init(&ctx);
+ su_md5_strupdate(&ctx, input);
+ su_md5_hexdigest(&ctx, hexdigest);
+ su_md5_deinit(&ctx);
+ switch_safe_free(input);
+
+ switch_uuid_get(&uuid);
+ switch_uuid_format(uuid_str, &uuid);
+ a1_hash = hexdigest;
+ }
+
+ sql = switch_mprintf("delete from sip_authentication where user='%q' and host='%q';\n"
+ "insert into sip_authentication values('%q','%q','%q','%q', %ld)",
+ from_user, from_host, from_user, from_host, a1_hash, uuid_str, time(NULL) + profile->nonce_ttl);
+ auth_str =
+ switch_mprintf("Digest realm=\"%q\", nonce=\"%q\",%s algorithm=MD5, qop=\"auth\"", from_host, uuid_str, stale ? " stale=\"true\"," : "");
+
+
+ if (regtype == REG_REGISTER) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Requesting Registration from: [%s@%s]\n", from_user, from_host);
+ nua_respond(nh, SIP_401_UNAUTHORIZED, NUTAG_WITH_THIS(nua), SIPTAG_WWW_AUTHENTICATE_STR(auth_str), TAG_END());
+ } else if (regtype == REG_INVITE) {
+ nua_respond(nh, SIP_407_PROXY_AUTH_REQUIRED, NUTAG_WITH_THIS(nua), SIPTAG_PROXY_AUTHENTICATE_STR(auth_str), TAG_END());
+
+ }
+
+ sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
+ switch_safe_free(sql);
+ switch_safe_free(auth_str);
+ ret = 1;
+ } else {
+ ret = 0;
+ }
+
+ switch_xml_free(xml);
+
+ if (ret) {
+ return ret;
+ }
+ }
+ reg:
+
+ if (exptime) {
+ if (!sofia_reg_find_reg_url(profile, from_user, from_host, buf, sizeof(buf))) {
+ sql = switch_mprintf("insert into sip_registrations values ('%q','%q','%q','Registered', '%q', %ld)",
+ from_user, from_host, contact_str, rpid, (long) time(NULL) + (long) exptime * 2);
+
+ } else {
+ sql =
+ switch_mprintf
+ ("update sip_registrations set contact='%q', expires=%ld, rpid='%q' where user='%q' and host='%q'",
+ contact_str, (long) time(NULL) + (long) exptime * 2, rpid, from_user, from_host);
+
+ }
+
+ if (switch_event_create_subclass(&s_event, SWITCH_EVENT_CUSTOM, MY_EVENT_REGISTER) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "profile-name", "%s", profile->name);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-user", "%s", from_user);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "from-host", "%s", from_host);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "contact", "%s", contact_str);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
+ switch_event_add_header(s_event, SWITCH_STACK_BOTTOM, "expires", "%ld", (long) exptime);
+ switch_event_fire(&s_event);
+ }
+
+ if (sql) {
+ sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
+ switch_safe_free(sql);
+ sql = NULL;
+ }
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
+ "Register:\nFrom: [%s@%s]\nContact: [%s]\nExpires: [%ld]\n", from_user, from_host, contact_str, (long) exptime);
+
+
+ if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_IN) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
+
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "Registered");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+ switch_event_fire(&event);
+ }
+ } else {
+ if ((sql = switch_mprintf("delete from sip_subscriptions where user='%q' and host='%q'", from_user, from_host))) {
+ sofia_glue_execute_sql(profile->dbname, sql, profile->ireg_mutex);
+ switch_safe_free(sql);
+ sql = NULL;
+ }
+ if (switch_event_create(&event, SWITCH_EVENT_PRESENCE_OUT) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "login", "%s", profile->url);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s+%s@%s", SOFIA_CHAT_PROTO, from_user, from_host);
+
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "status", "unavailable");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "rpid", "%s", rpid);
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "event_type", "presence");
+ switch_event_fire(&event);
+ }
+ }
+
+
+ if (switch_event_create(&event, SWITCH_EVENT_ROSTER) == SWITCH_STATUS_SUCCESS) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "proto", "sip");
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "from", "%s@%s", from_user, from_host);
+ switch_event_fire(&event);
+ }
+
+ if (regtype == REG_REGISTER) {
+ nua_respond(nh, SIP_200_OK, SIPTAG_CONTACT(contact), NUTAG_WITH_THIS(nua), TAG_END());
+ return 1;
+ }
+
+ return 0;
+}
+
+
+
+void sofia_reg_handle_sip_i_register(nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ char key[128] = "";
+
+ if (!sip || !sip->sip_request || !sip->sip_request->rq_method_name) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received an invalid packet!\n");
+ nua_respond(nh, SIP_500_INTERNAL_SERVER_ERROR, TAG_END());
+ return;
+ }
+
+ if (!(sip->sip_contact && sip->sip_contact->m_url)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NO CONTACT!\n");
+ nua_respond(nh, 400, "Missing Contact Header", TAG_END());
+ return;
+ }
+
+ sofia_reg_handle_register(nua, profile, nh, sip, REG_REGISTER, key, sizeof(key));
+}
+
+
+void sofia_reg_handle_sip_r_register(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, sofia_private_t * sofia_private, sip_t const *sip, tagi_t tags[])
+{
+ if (sofia_private && sofia_private->gateway) {
+ switch (status) {
+ case 200:
+ if (sip && sip->sip_contact && sip->sip_contact->m_expires) {
+ char *new_expires = (char *) sip->sip_contact->m_expires;
+ uint32_t expi = (uint32_t) atoi(new_expires);
+
+ if (expi != sofia_private->gateway->freq) {
+ sofia_private->gateway->freq = expi;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE,
+ "Changing expire time to %d by request of proxy %s\n", expi, sofia_private->gateway->register_proxy);
+ }
+
+ }
+ sofia_private->gateway->state = REG_STATE_REGISTER;
+ break;
+ case 100:
+ break;
+ default:
+ sofia_private->gateway->state = REG_STATE_FAILED;
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Registration Failed with status %d\n", status);
+ break;
+ }
+ }
+}
+
+void sofia_reg_handle_sip_r_challenge(int status,
+ char const *phrase,
+ nua_t * nua, sofia_profile_t * profile, nua_handle_t * nh, switch_core_session_t *session, sip_t const *sip, tagi_t tags[])
+{
+ outbound_reg_t *gateway = NULL;
+ sip_www_authenticate_t const *authenticate = NULL;
+ char const *realm = NULL;
+ char *p = NULL, *duprealm = NULL, *qrealm = NULL;
+ char const *scheme = NULL;
+ int indexnum;
+ char *cur;
+ char authentication[256] = "";
+ int ss_state;
+
+ if (session) {
+ private_object_t *tech_pvt;
+ 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");
+ return;
+ }
+ }
+
+
+ if (sip->sip_www_authenticate) {
+ authenticate = sip->sip_www_authenticate;
+ } else if (sip->sip_proxy_authenticate) {
+ authenticate = sip->sip_proxy_authenticate;
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Missing Authenticate Header!\n");
+ return;
+ }
+ scheme = (char const *) authenticate->au_scheme;
+ if (authenticate->au_params) {
+ for (indexnum = 0; (cur = (char *) authenticate->au_params[indexnum]); indexnum++) {
+ if ((realm = strstr(cur, "realm="))) {
+ realm += 6;
+ break;
+ }
+ }
+ }
+
+ if (!(scheme && realm)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No scheme and realm!\n");
+ return;
+ }
+
+ if (profile) {
+ outbound_reg_t *gateway_ptr;
+
+ if ((duprealm = strdup(realm))) {
+ qrealm = duprealm;
+
+ while (*qrealm && *qrealm == '"') {
+ qrealm++;
+ }
+
+ if ((p = strchr(qrealm, '"'))) {
+ *p = '\0';
+ }
+
+ if (sip->sip_from) {
+ char *from_key = switch_mprintf("sip:%s@%s",
+ (char *) sip->sip_from->a_url->url_user,
+ (char *) sip->sip_from->a_url->url_host);
+
+ if (!(gateway = sofia_reg_find_gateway(from_key))) {
+ gateway = sofia_reg_find_gateway(qrealm);
+ }
+
+ switch_safe_free(from_key);
+ }
+
+ if (!gateway) {
+ for (gateway_ptr = profile->gateways; gateway_ptr; gateway_ptr = gateway_ptr->next) {
+ if (scheme && qrealm && !strcasecmp(gateway_ptr->register_scheme, scheme)
+ && !strcasecmp(gateway_ptr->register_realm, qrealm)) {
+ gateway = gateway_ptr;
+ break;
+ }
+ }
+ }
+
+ if (!gateway) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No Match for Scheme [%s] Realm [%s]\n", scheme, qrealm);
+ return;
+ }
+ switch_safe_free(duprealm);
+ } else {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n");
+ return;
+ }
+ }
+
+ snprintf(authentication, sizeof(authentication), "%s:%s:%s:%s", scheme, realm, gateway->register_username, gateway->register_password);
+
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Authenticating '%s' with '%s'.\n", profile->username, authentication);
+
+
+ ss_state = nua_callstate_authenticating;
+
+ tl_gets(tags, NUTAG_CALLSTATE_REF(ss_state), SIPTAG_WWW_AUTHENTICATE_REF(authenticate), TAG_END());
+
+ nua_authenticate(nh, SIPTAG_EXPIRES_STR(gateway->expires_str), NUTAG_AUTH(authentication), TAG_END());
+
+}
+
+auth_res_t parse_auth(sofia_profile_t * profile, sip_authorization_t const *authorization, const char *regstr, char *np, size_t nplen)
+{
+ int indexnum;
+ const char *cur;
+ su_md5_t ctx;
+ char uridigest[2 * SU_MD5_DIGEST_SIZE + 1];
+ char bigdigest[2 * SU_MD5_DIGEST_SIZE + 1];
+ char *nonce, *uri, *qop, *cnonce, *nc, *response, *input = NULL, *input2 = NULL;
+ auth_res_t ret = AUTH_FORBIDDEN;
+ char *npassword = NULL;
+ int cnt = 0;
+ nonce = uri = qop = cnonce = nc = response = NULL;
+
+ if (authorization->au_params) {
+ for (indexnum = 0; (cur = authorization->au_params[indexnum]); indexnum++) {
+ char *var, *val, *p, *work;
+ var = val = work = NULL;
+ if ((work = strdup(cur))) {
+ var = work;
+ if ((val = strchr(var, '='))) {
+ *val++ = '\0';
+ while (*val == '"') {
+ *val++ = '\0';
+ }
+ if ((p = strchr(val, '"'))) {
+ *p = '\0';
+ }
+
+ if (!strcasecmp(var, "nonce")) {
+ nonce = strdup(val);
+ cnt++;
+ } else if (!strcasecmp(var, "uri")) {
+ uri = strdup(val);
+ cnt++;
+ } else if (!strcasecmp(var, "qop")) {
+ qop = strdup(val);
+ cnt++;
+ } else if (!strcasecmp(var, "cnonce")) {
+ cnonce = strdup(val);
+ cnt++;
+ } else if (!strcasecmp(var, "response")) {
+ response = strdup(val);
+ cnt++;
+ } else if (!strcasecmp(var, "nc")) {
+ nc = strdup(val);
+ cnt++;
+ }
+ }
+
+ free(work);
+ }
+ }
+ }
+
+ if (cnt != 6) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid Authorization header!\n");
+ goto end;
+ }
+
+ if (switch_strlen_zero(np)) {
+ if (!sofia_reg_get_auth_data(profile->dbname, nonce, np, nplen, profile->ireg_mutex)) {
+ ret = AUTH_STALE;
+ goto end;
+ }
+ }
+
+ npassword = np;
+
+ if ((input = switch_mprintf("%s:%q", regstr, uri))) {
+ su_md5_init(&ctx);
+ su_md5_strupdate(&ctx, input);
+ su_md5_hexdigest(&ctx, uridigest);
+ su_md5_deinit(&ctx);
+ }
+
+ if ((input2 = switch_mprintf("%q:%q:%q:%q:%q:%q", npassword, nonce, nc, cnonce, qop, uridigest))) {
+ memset(&ctx, 0, sizeof(ctx));
+ su_md5_init(&ctx);
+ su_md5_strupdate(&ctx, input2);
+ su_md5_hexdigest(&ctx, bigdigest);
+ su_md5_deinit(&ctx);
+
+ if (!strcasecmp(bigdigest, response)) {
+ ret = AUTH_OK;
+ } else {
+ ret = AUTH_FORBIDDEN;
+ }
+ }
+
+ end:
+ switch_safe_free(input);
+ switch_safe_free(input2);
+ switch_safe_free(nonce);
+ switch_safe_free(uri);
+ switch_safe_free(qop);
+ switch_safe_free(cnonce);
+ switch_safe_free(nc);
+ switch_safe_free(response);
+
+ return ret;
+
+}
+
+
+outbound_reg_t *sofia_reg_find_gateway(char *key)
+{
+ outbound_reg_t *gateway;
+
+ switch_mutex_lock(globals.hash_mutex);
+ gateway = (outbound_reg_t *) switch_core_hash_find(globals.gateway_hash, key);
+ switch_mutex_unlock(globals.hash_mutex);
+
+ return gateway;
+}
+
+void sofia_reg_add_gateway(char *key, outbound_reg_t * gateway)
+{
+ switch_mutex_lock(globals.hash_mutex);
+ switch_core_hash_insert(globals.gateway_hash, key, gateway);
+ switch_mutex_unlock(globals.hash_mutex);
+}
+
+
+
1
0
Author: brian
Date: Sat Mar 31 13:25:10 2007
New Revision: 4818
Modified:
freeswitch/trunk/bootstrap.sh
Log:
fix err when version only has 2 dots
Modified: freeswitch/trunk/bootstrap.sh
==============================================================================
--- freeswitch/trunk/bootstrap.sh (original)
+++ freeswitch/trunk/bootstrap.sh Sat Mar 31 13:25:10 2007
@@ -68,8 +68,12 @@
IFS=.; set $lt_version; IFS=' '
lt_status="good"
-if test "$1" -lt "2"; then
- if test "$2" -lt "5" -o "$2" = "5" -a "$3" -lt "14" ; then
+a=$[$1+0]
+b=$[$2+0]
+c=$[$3+0]
+
+if test "$a" -lt "2"; then
+ if test "$b" -lt "5" -o "$b" = "5" -a "$c" -lt "14" ; then
lt_status="bad"
fi
else
@@ -85,7 +89,6 @@
exit 1
fi
-
echo "Entering directory ${LIBDIR}/apr"
cd ${LIBDIR}/apr
1
0
Author: brian
Date: Sat Mar 31 11:13:28 2007
New Revision: 4817
Added:
freeswitch/trunk/build/fixautomake.sh
Log:
add
Added: freeswitch/trunk/build/fixautomake.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/build/fixautomake.sh Sat Mar 31 11:13:28 2007
@@ -0,0 +1,12 @@
+cd /tmp
+mkdir fix_automake
+cd fix_automake
+wget http://mirrors.kernel.org/gnu/automake/automake-1.9.tar.gz
+tar -zxvf automake-1.9.tar.gz
+cd automake-1.9
+./configure --prefix=/usr
+make
+make install
+cd /tmp
+rm -fr fix_automake
+
1
0
[commit] r4816 - in freeswitch/trunk/src: . include mod/endpoints/mod_sofia
by Freeswitch SVN 30 Mar '07
by Freeswitch SVN 30 Mar '07
30 Mar '07
Author: anthm
Date: Fri Mar 30 18:13:19 2007
New Revision: 4816
Modified:
freeswitch/trunk/src/include/switch_channel.h
freeswitch/trunk/src/include/switch_types.h
freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c
freeswitch/trunk/src/switch_channel.c
freeswitch/trunk/src/switch_core_session.c
freeswitch/trunk/src/switch_ivr.c
freeswitch/trunk/src/switch_ivr_async.c
freeswitch/trunk/src/switch_ivr_bridge.c
Log:
hold stuff
Modified: freeswitch/trunk/src/include/switch_channel.h
==============================================================================
--- freeswitch/trunk/src/include/switch_channel.h (original)
+++ freeswitch/trunk/src/include/switch_channel.h Fri Mar 30 18:13:19 2007
@@ -259,6 +259,22 @@
SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_channel_flag_t flags);
/*!
+ \brief Set given flag(s) on a given channel's bridge partner
+ \param channel channel to derive the partner channel to set flag(s) on
+ \param flags or'd list of flags to set
+ \return true if the flag was set
+*/
+SWITCH_DECLARE(switch_bool_t) switch_channel_set_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags);
+
+/*!
+ \brief Clears given flag(s) on a given channel's bridge partner
+ \param channel channel to derive the partner channel to clear flag(s) from
+ \param flags the flags to clear
+ \return true if the flag was cleared
+*/
+SWITCH_DECLARE(switch_bool_t) switch_channel_clear_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags);
+
+/*!
\brief Set given flag(s) on a given channel to be applied on the next state change
\param channel channel on which to set flag(s)
\param flags or'd list of flags to set
Modified: freeswitch/trunk/src/include/switch_types.h
==============================================================================
--- freeswitch/trunk/src/include/switch_types.h (original)
+++ freeswitch/trunk/src/include/switch_types.h Fri Mar 30 18:13:19 2007
@@ -96,6 +96,7 @@
#endif
#define SWITCH_URL_SEPARATOR "://"
#define SWITCH_ENDPOINT_DISPOSITION_VARIABLE "endpoint_disposition"
+#define SWITCH_HOLD_MUSIC_VARIABLE "hold_music"
#define SWITCH_EXPORT_VARS_VARIABLE "export_vars"
#define SWITCH_R_SDP_VARIABLE "switch_r_sdp"
#define SWITCH_L_SDP_VARIABLE "switch_l_sdp"
@@ -168,6 +169,7 @@
SMF_ECHO_ALEG = (1 << 1),
SMF_ECHO_BLEG = (1 << 2),
SMF_FORCE = (1 << 3),
+ SMF_LOOP = (1 << 4)
} switch_media_flag_t;
typedef enum {
@@ -529,6 +531,8 @@
CF_REPEAT_STATE = (1 << 16) - Tell the state machine to repeat a state
CF_GEN_RINGBACK = (1 << 17) - Channel is generating it's own ringback
CF_RING_READY = (1 << 18) - Channel is ready to send ringback
+CF_BREAK = (1 << 19) - Channel should stop what it's doing
+CF_BROADCAST = (1 << 20) - Channel is broadcasting
</pre>
*/
@@ -551,7 +555,9 @@
CF_EVENT_PARSE = (1 << 15),
CF_REPEAT_STATE = (1 << 16),
CF_GEN_RINGBACK = (1 << 17),
- CF_RING_READY = (1 << 18)
+ CF_RING_READY = (1 << 18),
+ CF_BREAK = (1 << 19),
+ CF_BROADCAST = (1 << 20)
} switch_channel_flag_t;
Modified: freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c
==============================================================================
--- freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c (original)
+++ freeswitch/trunk/src/mod/endpoints/mod_sofia/mod_sofia.c Fri Mar 30 18:13:19 2007
@@ -90,7 +90,10 @@
"CREATE TABLE sip_registrations (\n"
" user VARCHAR(255),\n"
" host VARCHAR(255),\n"
- " contact VARCHAR(1024),\n" " status VARCHAR(255),\n" " rpid VARCHAR(255),\n" " expires INTEGER(8)" ");\n";
+ " contact VARCHAR(1024),\n"
+ " status VARCHAR(255),\n"
+ " rpid VARCHAR(255),\n"
+ " expires INTEGER(8)" ");\n";
static char sub_sql[] =
@@ -102,13 +105,19 @@
" sub_to_host VARCHAR(255),\n"
" event VARCHAR(255),\n"
" contact VARCHAR(1024),\n"
- " call_id VARCHAR(255),\n" " full_from VARCHAR(255),\n" " full_via VARCHAR(255),\n" " expires INTEGER(8)" ");\n";
+ " call_id VARCHAR(255),\n"
+ " full_from VARCHAR(255),\n"
+ " full_via VARCHAR(255),\n"
+ " expires INTEGER(8)" ");\n";
static char auth_sql[] =
"CREATE TABLE sip_authentication (\n"
" user VARCHAR(255),\n"
- " host VARCHAR(255),\n" " passwd VARCHAR(255),\n" " nonce VARCHAR(255),\n" " expires INTEGER(8)"
+ " host VARCHAR(255),\n"
+ " passwd VARCHAR(255),\n"
+ " nonce VARCHAR(255),\n"
+ " expires INTEGER(8)"
");\n";
static const char modname[] = "mod_sofia";
@@ -231,6 +240,7 @@
char *bindurl;
char *sipdomain;
char *timer_name;
+ char *hold_music;
int sip_port;
char *codec_string;
int running;
@@ -1024,7 +1034,7 @@
return SWITCH_STATUS_FALSE;
}
-
+
if ((alertbuf = switch_channel_get_variable(channel, "alert_info"))) {
@@ -2418,10 +2428,29 @@
}
for (a = sdp->sdp_attributes; a; a = a->a_next) {
+ if (switch_strlen_zero(a->a_name)) {
+ continue;
+ }
if (!strcasecmp(a->a_name, "sendonly")) {
- switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ if (!switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+ char *stream;
+
+ switch_set_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ switch_channel_set_flag(channel, CF_HOLD);
+ if (!(stream = switch_channel_get_variable(channel, SWITCH_HOLD_MUSIC_VARIABLE))) {
+ stream = tech_pvt->profile->hold_music;
+ }
+ if (stream) {
+ switch_ivr_broadcast(switch_core_session_get_uuid(tech_pvt->session), stream, SMF_ECHO_BLEG | SMF_LOOP);
+ }
+ }
} else if (!strcasecmp(a->a_name, "sendrecv")) {
- switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ if (switch_test_flag(tech_pvt, TFLAG_SIP_HOLD)) {
+ switch_clear_flag_locked(tech_pvt, TFLAG_SIP_HOLD);
+ switch_channel_clear_flag(channel, CF_HOLD);
+ switch_channel_clear_flag_partner(channel, CF_BROADCAST);
+ switch_channel_set_flag_partner(channel, CF_BREAK);
+ }
} else if (!strcasecmp(a->a_name, "ptime")) {
dptime = atoi(a->a_value);
}
@@ -5135,6 +5164,8 @@
profile->sipdomain = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "rtp-timer-name")) {
profile->timer_name = switch_core_strdup(profile->pool, val);
+ } else if (!strcasecmp(var, "hold-music")) {
+ profile->hold_music = switch_core_strdup(profile->pool, val);
} else if (!strcasecmp(var, "manage-presence")) {
if (switch_true(val)) {
profile->pflags |= PFLAG_PRESENCE;
Modified: freeswitch/trunk/src/switch_channel.c
==============================================================================
--- freeswitch/trunk/src/switch_channel.c (original)
+++ freeswitch/trunk/src/switch_channel.c Fri Mar 30 18:13:19 2007
@@ -396,6 +396,42 @@
return switch_test_flag(channel, flags) ? 1 : 0;
}
+SWITCH_DECLARE(switch_bool_t) switch_channel_set_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags)
+{
+ char *uuid;
+
+ assert(channel != NULL);
+
+ if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) {
+ switch_core_session_t *session;
+ if ((session = switch_core_session_locate(uuid))) {
+ switch_channel_set_flag(switch_core_session_get_channel(session), flags);
+ switch_core_session_rwunlock(session);
+ return SWITCH_TRUE;
+ }
+ }
+
+ return SWITCH_FALSE;
+}
+
+SWITCH_DECLARE(switch_bool_t) switch_channel_clear_flag_partner(switch_channel_t *channel, switch_channel_flag_t flags)
+{
+ char *uuid;
+
+ assert(channel != NULL);
+
+ if ((uuid = switch_channel_get_variable(channel, SWITCH_BRIDGE_VARIABLE))) {
+ switch_core_session_t *session;
+ if ((session = switch_core_session_locate(uuid))) {
+ switch_channel_clear_flag(switch_core_session_get_channel(session), flags);
+ switch_core_session_rwunlock(session);
+ return SWITCH_TRUE;
+ }
+ }
+
+ return SWITCH_FALSE;
+}
+
SWITCH_DECLARE(void) switch_channel_set_flag(switch_channel_t *channel, switch_channel_flag_t flags)
{
assert(channel != NULL);
@@ -431,9 +467,20 @@
SWITCH_DECLARE(uint8_t) switch_channel_ready(switch_channel_t *channel)
{
+ uint8_t ret = 0;
+
assert(channel != NULL);
+
+ if (!channel->hangup_cause && channel->state > CS_RING && channel->state < CS_HANGUP && !switch_test_flag(channel, CF_TRANSFER)) {
+ ret++;
+ }
+
+ if (switch_test_flag(channel, CF_BREAK)) {
+ switch_clear_flag_locked(channel, CF_BREAK);
+ ret = (uint8_t) 0;
+ }
- return (!channel->hangup_cause && channel->state > CS_RING && channel->state < CS_HANGUP && !switch_test_flag(channel, CF_TRANSFER)) ? 1 : 0;
+ return ret;
}
static const char *state_names[] = {
Modified: freeswitch/trunk/src/switch_core_session.c
==============================================================================
--- freeswitch/trunk/src/switch_core_session.c (original)
+++ freeswitch/trunk/src/switch_core_session.c Fri Mar 30 18:13:19 2007
@@ -599,6 +599,7 @@
switch_channel_dequeue_dtmf(channel, buf, sizeof(buf));
}
+ switch_channel_clear_flag(channel, CF_BREAK);
}
Modified: freeswitch/trunk/src/switch_ivr.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr.c (original)
+++ freeswitch/trunk/src/switch_ivr.c Fri Mar 30 18:13:19 2007
@@ -108,11 +108,25 @@
const switch_application_interface_t *application_interface;
char *app_name = switch_event_get_header(event, "execute-app-name");
char *app_arg = switch_event_get_header(event, "execute-app-arg");
+ char *loop_h = switch_event_get_header(event, "loops");
+ int loops = 0;
+
+ if (loop_h) {
+ loops = atoi(loop_h);
+ }
if (app_name && app_arg) {
if ((application_interface = switch_loadable_module_get_application_interface(app_name))) {
if (application_interface->application_function) {
- application_interface->application_function(session, app_arg);
+ int x;
+ switch_channel_set_flag(channel, CF_BROADCAST);
+ for (x = 0; x < loops || loops < 0; x++) {
+ application_interface->application_function(session, app_arg);
+ if (!switch_channel_test_flag(channel, CF_BROADCAST)) {
+ break;
+ }
+ }
+ switch_channel_clear_flag(channel, CF_BROADCAST);
}
}
}
Modified: freeswitch/trunk/src/switch_ivr_async.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr_async.c (original)
+++ freeswitch/trunk/src/switch_ivr_async.c Fri Mar 30 18:13:19 2007
@@ -737,8 +737,13 @@
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", app);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path);
+ if ((flags & SMF_LOOP)) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1);
+ }
+
switch_core_session_queue_private_event(other_session, &event);
}
+
switch_core_session_rwunlock(other_session);
master = other_session;
other_session = NULL;
@@ -749,6 +754,9 @@
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "call-command", "execute");
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-name", "%s", app);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "execute-app-arg", "%s", path);
+ if ((flags & SMF_LOOP)) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "loops", "%d", -1);
+ }
switch_core_session_queue_private_event(session, &event);
}
master = session;
Modified: freeswitch/trunk/src/switch_ivr_bridge.c
==============================================================================
--- freeswitch/trunk/src/switch_ivr_bridge.c (original)
+++ freeswitch/trunk/src/switch_ivr_bridge.c Fri Mar 30 18:13:19 2007
@@ -81,11 +81,22 @@
switch_channel_set_flag(chan_a, CF_BRIDGED);
- while (switch_channel_ready(chan_a) && data->running > 0 && his_thread->running > 0) {
- switch_channel_state_t b_state = switch_channel_get_state(chan_b);
+ for (;;) {
+ switch_channel_state_t b_state;
switch_status_t status;
switch_event_t *event;
+ if (!(data->running > 0 && his_thread->running > 0)) {
+ break;
+ }
+
+ /* if you really want to make sure it's not ready, test it twice because it might be just a break */
+ if (!switch_channel_ready(chan_a) && !switch_channel_ready(chan_a)) {
+ break;
+ }
+
+ b_state = switch_channel_get_state(chan_b);
+
switch (b_state) {
case CS_HANGUP:
case CS_DONE:
1
0
Author: anthm
Date: Fri Mar 30 16:24:37 2007
New Revision: 4815
Added:
freeswitch/trunk/build/turbo_build.sh (contents, props changed)
Log:
turbo_build.sh
Added: freeswitch/trunk/build/turbo_build.sh
==============================================================================
--- (empty file)
+++ freeswitch/trunk/build/turbo_build.sh Fri Mar 30 16:24:37 2007
@@ -0,0 +1,54 @@
+arg=$1 ; shift
+switch_srcdir=`pwd`
+if [ -z $MAKE ] ; then
+ MAKE=make
+fi
+
+if [ -z $arg ] ; then
+ $MAKE -j8 core
+ MODS=`cat modules.conf | grep -v \#`
+ for i in $MODS ; do
+ MOD_NAME=`echo $i | sed -e 's|^.*/||'`
+ MOD_DIR=`if test -d $switch_srcdir/src/mod/$i ; then echo $switch_srcdir/src/mod/$i ; else echo $i ; fi;`
+ touch /tmp/$MOD_NAME.tmp
+ $0 $MOD_NAME $MOD_DIR
+ done
+ while [ 1 = 1 ] ; do
+ x=0
+ for i in $MODS ; do
+ if [ -f /tmp/$MOD_NAME.tmp ] ; then
+ x=$[$x+1];
+ fi
+ done
+ if [ $x = 0 ] ; then
+ sleep 1
+ echo done
+ exit;
+ fi
+ sleep 1
+ done
+
+ exit
+fi
+
+if [ ! $arg = "bg" ] ; then
+ $0 bg $arg $@ &
+ exit
+fi
+
+
+MOD_NAME=$1 ; shift
+MOD_DIR=$1 ; shift
+
+echo "Making module in $MOD_NAME"
+if [ -f $MOD_DIR/Makefile ] ; then
+ cd $MOD_DIR && BASE=$switch_srcdir $MAKE
+else
+ cd $MOD_DIR && BASE=$switch_srcdir $MAKE -f $switch_srcdir/build/modmake.rules
+fi
+
+echo "Finished making module in $MOD_NAME"
+sleep 1
+rm /tmp/$MOD_NAME.tmp
+
+
1
0
Author: mikej
Date: Fri Mar 30 16:22:38 2007
New Revision: 4814
Modified:
freeswitch/trunk/Makefile.am
freeswitch/trunk/build/modmake.rules.in
freeswitch/trunk/configure.in
freeswitch/trunk/src/mod/Makefile.am
Log:
some cleanup in the Makefiles
Modified: freeswitch/trunk/Makefile.am
==============================================================================
--- freeswitch/trunk/Makefile.am (original)
+++ freeswitch/trunk/Makefile.am Fri Mar 30 16:22:38 2007
@@ -10,13 +10,6 @@
BASE = $(switch_srcdir)
OSARCH=`uname -s`
-LIBTOOL=`if test -z "$(VERBOSE)" ; then echo $(SHELL) $(switch_builddir)/quiet_libtool ;else echo $(switch_builddir)/libtool; fi;`
-#LIBS+=> core.log || error="yes";if test -n "$(VERBOSE)" -o "$$error" = "yes";then cat core.log;fi;if test "$$error" = "yes";then exit 1;fi
-
-LTINSTALL = $(LIBTOOL) --mode=install $(INSTALL)
-TOUCH_TARGET=if test -f "$@" ; then touch "$@" ; fi ;
-AM_MAKEFLAGS=`test -n "$(VERBOSE)" || echo -s`
-
if CRASHPROT
AM_CFLAGS += -DCRASH_PROT
endif
Modified: freeswitch/trunk/build/modmake.rules.in
==============================================================================
--- freeswitch/trunk/build/modmake.rules.in (original)
+++ freeswitch/trunk/build/modmake.rules.in Fri Mar 30 16:22:38 2007
@@ -9,7 +9,7 @@
SHELL=@SHELL@
INSTALL=@INSTALL@
GETLIB=@GETLIB@
-LIBTOOL=$(switch_builddir)/libtool
+LIBTOOL=@LIBTOOL@
LTINSTALL=$(LIBTOOL) --mode=install $(INSTALL)
LTUNINSTALL=$(LIBTOOL) --mode=uninstall rm -f
CCLD = $(CC)
@@ -46,7 +46,7 @@
CSOURCEFILE=$(MODNAME).c
CXXSOURCEFILE=$(MODNAME).cpp
-TOUCH_TARGET=if test -f "$@" ; then touch "$@" ; fi ;
+TOUCH_TARGET=@TOUCH_TARGET@
#MAKE_OPTS = `if test -z "$(VERBOSE)" ; then $(MAKE) --help | grep silent | grep "\-s" 2>&1 >/dev/null && echo -s;fi`
MAKE_OPTS = `test -n "$(VERBOSE)" || echo -s`
Modified: freeswitch/trunk/configure.in
==============================================================================
--- freeswitch/trunk/configure.in (original)
+++ freeswitch/trunk/configure.in Fri Mar 30 16:22:38 2007
@@ -327,6 +327,15 @@
AM_CONDITIONAL(ISMAC, [test `uname -s` = Darwin])
AM_CONDITIONAL(IS64BITLINUX, [test `uname -m` = x86_64])
+#some vars to sub into the Makefile.am's
+#LIBS+=> core.log || error="yes";if test -n "$(VERBOSE)" -o "$$error" = "yes";then cat core.log;fi;if test "$$error" = "yes";then exit 1;fi
+LIBTOOL='`if test -z "$(VERBOSE)" ; then echo $(SHELL) $(switch_builddir)/quiet_libtool ;else echo $(switch_builddir)/libtool; fi;`'
+TOUCH_TARGET='if test -f "$@";then touch "$@";fi;'
+AM_MAKEFLAGS='`test -n "$(VERBOSE)" || echo -s`'
+AC_SUBST(LIBTOOL)
+AC_SUBST(TOUCH_TARGET)
+AC_SUBST(AM_MAKEFLAGS)
+
# Run configure in all the subdirs
AC_CONFIG_SUBDIRS(libs/srtp)
AC_CONFIG_SUBDIRS(libs/sqlite)
Modified: freeswitch/trunk/src/mod/Makefile.am
==============================================================================
--- freeswitch/trunk/src/mod/Makefile.am (original)
+++ freeswitch/trunk/src/mod/Makefile.am Fri Mar 30 16:22:38 2007
@@ -6,8 +6,6 @@
else our_clean_modules="$(MODULES)" ; fi ;
MOD_NAME=`echo $$i | sed -e 's|^.*/||'`
MOD_DIR=`if test -d $(switch_srcdir)/src/mod/$$i ; then echo $(switch_srcdir)/src/mod/$$i ; else echo $$i ; fi;`
-AM_MAKEFLAGS = `test -n "$(VERBOSE)" || echo -s`
-#AM_MAKEFLAGS = `if test -z "$(VERBOSE)" ; then $(MAKE) --help | grep silent | grep "\-s" 2>&1 >/dev/null && echo -s;fi`
all:
@$(CONF_MODULES) \
1
0
Author: anthm
Date: Fri Mar 30 13:31:47 2007
New Revision: 4812
Modified:
freeswitch/trunk/libs/libdingaling/src/libdingaling.c
freeswitch/trunk/libs/libdingaling/src/libdingaling.h
Log:
doh
Modified: freeswitch/trunk/libs/libdingaling/src/libdingaling.c
==============================================================================
--- freeswitch/trunk/libs/libdingaling/src/libdingaling.c (original)
+++ freeswitch/trunk/libs/libdingaling/src/libdingaling.c Fri Mar 30 13:31:47 2007
@@ -761,6 +761,11 @@
from = buf;
}
+ if (ldl_test_flag(handle, LDL_FLAG_COMPONENT) && ldl_jid_domcmp(from, to)) {
+ globals.logger(DL_LOG_ERR, "Refusal to send presence from and to the same domain in component mode [%s][%s]\n", from, to);
+ return;
+ }
+
if ((pres = iks_new("presence"))) {
iks_insert_attrib(pres, "xmlns", "jabber:client");
if (from) {
Modified: freeswitch/trunk/libs/libdingaling/src/libdingaling.h
==============================================================================
--- freeswitch/trunk/libs/libdingaling/src/libdingaling.h (original)
+++ freeswitch/trunk/libs/libdingaling/src/libdingaling.h Fri Mar 30 13:31:47 2007
@@ -180,6 +180,55 @@
#define ldl_yield(ms) apr_sleep(ms * 10); apr_thread_yield();
/*!
+ \brief Test for a common domain in 2 jid
+ \param id_a the first id
+ \param id_b the second id
+ \return 1 if the domains match 0 if they dont or -1 if either id is invalid
+ \note the id may or may not contain a user and/or resource
+*/
+static inline int ldl_jid_domcmp(char *id_a, char *id_b)
+{
+ char *id_a_host, *id_b_host, *id_a_r, *id_b_r;
+
+ if ((id_a_host = strchr(id_a, '@'))) {
+ id_a_host++;
+ } else {
+ id_a_host = id_a;
+ }
+
+ if ((id_b_host = strchr(id_b, '@'))) {
+ id_b_host++;
+ } else {
+ id_b_host = id_b;
+ }
+
+ if (id_a_host && id_b_host) {
+ int id_a_len = 0, id_b_len = 0, len = 0;
+
+ if ((id_a_r = strchr(id_a_host, '/'))) {
+ id_a_len = id_a_r - id_a_host;
+ } else {
+ id_a_len = strlen(id_a_host);
+ }
+
+ if ((id_b_r = strchr(id_b_host, '/'))) {
+ id_b_len = id_b_r - id_b_host;
+ } else {
+ id_b_len = strlen(id_b_host);
+ }
+
+ if (id_a_len > id_b_len) {
+ len = id_b_len;
+ } else {
+ len = id_a_len;
+ }
+ printf("[%s][%s][%d]\n", id_a_host, id_b_host, len);
+ return strncasecmp(id_a_host, id_b_host, len) ? 0 : 1;
+ }
+ return -1;
+}
+
+/*!
\brief Test for the existance of a flag on an arbitary object
\param obj the object to test
\param flag the or'd list of flags to test
1
0
Author: anthm
Date: Fri Mar 30 13:31:21 2007
New Revision: 4811
Modified:
freeswitch/trunk/Makefile.am
Log:
no more .noversion because it breaks things
Modified: freeswitch/trunk/Makefile.am
==============================================================================
--- freeswitch/trunk/Makefile.am (original)
+++ freeswitch/trunk/Makefile.am Fri Mar 30 13:31:21 2007
@@ -147,15 +147,13 @@
touch .version
src/include/switch_version.h: $(top_srcdir)/src/include/switch_version.h.in .version $(libfreeswitch_la_SOURCES) $(library_include_HEADERS)
- @if test ! -f .noversion ; then \
- force=0 ; \
- version=`svnversion . -n || echo hacked` ; \
- oldversion=`cat .version 2>/dev/null || echo "0"` ; \
- test ! -f src/include/switch_version.h || grep "@SVN_VERSION@" src/include/switch_version.h && force=1 ; \
- if test "$$oldversion" != "$$version" || test $$force = 1 ; then \
- cat src/include/switch_version.h.in | sed "s/@SVN_VERSION@/$$version/g" > src/include/switch_version.h ; \
- echo $$version > .version ; \
- fi ; \
+ @force=0 ; \
+ version=`svnversion . -n || echo hacked` ; \
+ oldversion=`cat .version 2>/dev/null || echo "0"` ; \
+ test ! -f src/include/switch_version.h || grep "@SVN_VERSION@" src/include/switch_version.h && force=1 ; \
+ if test "$$oldversion" != "$$version" || test $$force = 1 ; then \
+ cat src/include/switch_version.h.in | sed "s/@SVN_VERSION@/$$version/g" > src/include/switch_version.h ; \
+ echo $$version > .version ; \
fi ;
update:
1
0
Author: anthm
Date: Fri Mar 30 13:25:48 2007
New Revision: 4810
Modified:
freeswitch/trunk/src/switch_core.c
freeswitch/trunk/src/switch_core_sqldb.c
freeswitch/trunk/src/switch_event.c
Log:
fix race
Modified: freeswitch/trunk/src/switch_core.c
==============================================================================
--- freeswitch/trunk/src/switch_core.c (original)
+++ freeswitch/trunk/src/switch_core.c Fri Mar 30 13:25:48 2007
@@ -482,6 +482,7 @@
assert(runtime.memory_pool != NULL);
switch_log_init(runtime.memory_pool);
switch_event_init(runtime.memory_pool);
+
switch_core_sqldb_start(runtime.memory_pool);
switch_rtp_init(runtime.memory_pool);
runtime.running = 1;
Modified: freeswitch/trunk/src/switch_core_sqldb.c
==============================================================================
--- freeswitch/trunk/src/switch_core_sqldb.c (original)
+++ freeswitch/trunk/src/switch_core_sqldb.c Fri Mar 30 13:25:48 2007
@@ -39,6 +39,7 @@
switch_core_db_t *event_db;
switch_queue_t *sql_queue;
switch_memory_pool_t *memory_pool;
+ int thread_running;
} runtime;
static switch_status_t switch_core_db_persistant_execute_trans(switch_core_db_t *db, char *sql, uint32_t retries)
@@ -159,9 +160,8 @@
if (!runtime.event_db) {
runtime.event_db = switch_core_db_handle();
}
- switch_queue_create(&runtime.sql_queue, SWITCH_SQL_QUEUE_LEN, runtime.memory_pool);
-
+ runtime.thread_running = 1;
for (;;) {
if (switch_queue_trypop(runtime.sql_queue, &pop) == SWITCH_STATUS_SUCCESS) {
@@ -398,11 +398,15 @@
}
}
+ switch_queue_create(&runtime.sql_queue, SWITCH_SQL_QUEUE_LEN, runtime.memory_pool);
+
switch_threadattr_create(&thd_attr, runtime.memory_pool);
switch_threadattr_detach_set(thd_attr, 1);
switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE);
switch_thread_create(&thread, thd_attr, switch_core_sql_thread, NULL, runtime.memory_pool);
-
+ while (!runtime.thread_running) {
+ switch_yield(10000);
+ }
}
void switch_core_sqldb_stop(void)
Modified: freeswitch/trunk/src/switch_event.c
==============================================================================
--- freeswitch/trunk/src/switch_event.c (original)
+++ freeswitch/trunk/src/switch_event.c Fri Mar 30 13:25:48 2007
@@ -398,13 +398,14 @@
switch_threadattr_detach_set(thd_attr, 1);
assert(pool != NULL);
- RUNTIME_POOL = pool;
-
+ THRUNTIME_POOL = RUNTIME_POOL = pool;
+ /*
if (switch_core_new_memory_pool(&THRUNTIME_POOL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Could not allocate memory pool\n");
return SWITCH_STATUS_MEMERR;
}
+ */
/*
if (switch_core_new_memory_pool(&BPOOL) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Could not allocate memory pool\n");
1
0
Author: mikej
Date: Fri Mar 30 13:14:28 2007
New Revision: 4809
Modified:
freeswitch/trunk/src/mod/say/mod_say_en/mod_say_en.c
Log:
I was told that the rules for spanish are the same as for english. So for now, I will add an interface using the same module and functions for "es". If there are changes to be made in the future, we can split this up into multiple modules.
Modified: freeswitch/trunk/src/mod/say/mod_say_en/mod_say_en.c
==============================================================================
--- freeswitch/trunk/src/mod/say/mod_say_en/mod_say_en.c (original)
+++ freeswitch/trunk/src/mod/say/mod_say_en/mod_say_en.c Fri Mar 30 13:14:28 2007
@@ -510,9 +510,15 @@
return SWITCH_STATUS_FALSE;
}
+static const switch_say_interface_t es_say_interface = {
+ /*.name */ "es",
+ /*.say_function */ en_say,
+};
+
static const switch_say_interface_t en_say_interface = {
/*.name */ "en",
/*.say_function */ en_say,
+ /*.next */ &es_say_interface
};
static switch_loadable_module_interface_t say_en_module_interface = {
1
0