[Freeswitch-svn] [commit] r4819 - freeswitch/trunk/src/mod/endpoints/mod_sofia
Freeswitch SVN
mikej at freeswitch.org
Sat Mar 31 15:01:34 EDT 2007
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 at 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 at yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct at yahoo.com>
+ * Ken Rice, Asteria Solutions Group, Inc <ken at 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 at 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 at yahoo.com>
+ * Portions created by the Initial Developer are Copyright (C)
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Anthony Minessale II <anthmct at yahoo.com>
+ * Ken Rice, Asteria Solutions Group, Inc <ken at 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);
+}
+
+
+
More information about the Freeswitch-svn
mailing list