1 /*
2  * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
3  * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
4  *
5  * Version: MPL 1.1
6  *
7  * The contents of this file are subject to the Mozilla Public License Version
8  * 1.1 (the "License"); you may not use this file except in compliance with
9  * the License. You may obtain a copy of the License at
10  * http://www.mozilla.org/MPL/
11  *
12  * Software distributed under the License is distributed on an "AS IS" basis,
13  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14  * for the specific language governing rights and limitations under the
15  * License.
16  *
17  * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18  *
19  * The Initial Developer of the Original Code is
20  * Anthony Minessale II <anthm@freeswitch.org>
21  * Portions created by the Initial Developer are Copyright (C)
22  * the Initial Developer. All Rights Reserved.
23  *
24  * Contributor(s):
25  *
26  * Anthony Minessale II <anthm@freeswitch.org>
27  * Ken Rice <krice@freeswitch.org>
28  * Paul D. Tinsley <pdt at jackhammer.org>
29  * Bret McDanel <trixter AT 0xdecafbad.com>
30  * Eliot Gable <egable AT.AT broadvox.com>
31  *
32  *
33  * sofia_glue.c -- SOFIA SIP Endpoint (code to tie sofia to freeswitch)
34  *
35  */
36 #include "mod_sofia.h"
37 #include <switch_stun.h>
38 
39 switch_cache_db_handle_t *_sofia_glue_get_db_handle(sofia_profile_t *profile, const char *file, const char *func, int line);
40 #define sofia_glue_get_db_handle(_p) _sofia_glue_get_db_handle(_p, __FILE__, __SWITCH_FUNC__, __LINE__)
41 
42 
sofia_glue_check_nat(sofia_profile_t * profile,const char * network_ip)43 int sofia_glue_check_nat(sofia_profile_t *profile, const char *network_ip)
44 {
45 	switch_assert(network_ip);
46 
47 	return (profile->extsipip &&
48 			!switch_check_network_list_ip(network_ip, "loopback.auto") &&
49 			!switch_check_network_list_ip(network_ip, profile->local_network));
50 }
51 
sofia_glue_new_pvt(switch_core_session_t * session)52 private_object_t *sofia_glue_new_pvt(switch_core_session_t *session)
53 {
54 	private_object_t *tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t));
55 	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
56 	switch_mutex_init(&tech_pvt->sofia_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
57 	return tech_pvt;
58 }
59 
sofia_glue_set_name(private_object_t * tech_pvt,const char * channame)60 void sofia_glue_set_name(private_object_t *tech_pvt, const char *channame)
61 {
62 	char name[256];
63 	char *p;
64 
65 	switch_snprintf(name, sizeof(name), "sofia/%s/%s", tech_pvt->profile->name, channame);
66 	if ((p = strchr(name, ';'))) {
67 		*p = '\0';
68 	}
69 	switch_channel_set_name(tech_pvt->channel, name);
70 }
71 
sofia_glue_attach_private(switch_core_session_t * session,sofia_profile_t * profile,private_object_t * tech_pvt,const char * channame)72 void sofia_glue_attach_private(switch_core_session_t *session, sofia_profile_t *profile, private_object_t *tech_pvt, const char *channame)
73 {
74 
75 	unsigned int x, i;
76 
77 	switch_assert(session != NULL);
78 	switch_assert(profile != NULL);
79 	switch_assert(tech_pvt != NULL);
80 
81 	switch_core_session_add_stream(session, NULL);
82 
83 	switch_mutex_lock(tech_pvt->flag_mutex);
84 	switch_mutex_lock(profile->flag_mutex);
85 
86 	/* copy flags from profile to the sofia private */
87 	for (x = 0; x < TFLAG_MAX; x++) {
88 		tech_pvt->flags[x] = profile->flags[x];
89 	}
90 
91 	tech_pvt->x_freeswitch_support_local = FREESWITCH_SUPPORT;
92 
93 	tech_pvt->profile = profile;
94 
95 	if (!zstr(profile->rtpip[profile->rtpip_next])) {
96 		tech_pvt->mparams.rtpip4 = switch_core_session_strdup(session, profile->rtpip[profile->rtpip_next++]);
97 		tech_pvt->mparams.rtpip = tech_pvt->mparams.rtpip4;
98 
99 		if (profile->rtpip_next >= profile->rtpip_index) {
100 			profile->rtpip_next = 0;
101 		}
102 	}
103 
104 	if (!zstr(profile->rtpip6[profile->rtpip_next6])) {
105 		tech_pvt->mparams.rtpip6 = switch_core_session_strdup(session, profile->rtpip6[profile->rtpip_next6++]);
106 
107 		if (zstr(tech_pvt->mparams.rtpip)) {
108 			tech_pvt->mparams.rtpip = tech_pvt->mparams.rtpip6;
109 		}
110 
111 		if (profile->rtpip_next6 >= profile->rtpip_index6) {
112 			profile->rtpip_next6 = 0;
113 		}
114 	}
115 
116 	profile->inuse++;
117 	switch_mutex_unlock(profile->flag_mutex);
118 	switch_mutex_unlock(tech_pvt->flag_mutex);
119 
120 	if (tech_pvt->bte) {
121 		tech_pvt->recv_te = tech_pvt->te = tech_pvt->bte;
122 	} else if (!tech_pvt->te) {
123 		tech_pvt->mparams.recv_te = tech_pvt->mparams.te = profile->te;
124 	}
125 
126 	tech_pvt->mparams.dtmf_type = tech_pvt->profile->dtmf_type;
127 
128 	if (!sofia_test_media_flag(tech_pvt->profile, SCMF_SUPPRESS_CNG)) {
129 		if (tech_pvt->bcng_pt) {
130 			tech_pvt->cng_pt = tech_pvt->bcng_pt;
131 		} else if (!tech_pvt->cng_pt) {
132 			tech_pvt->cng_pt = profile->cng_pt;
133 		}
134 	}
135 
136 	tech_pvt->session = session;
137 	tech_pvt->channel = switch_core_session_get_channel(session);
138 
139 	if (sofia_test_pflag(profile, PFLAG_TRACK_CALLS)) {
140 		switch_channel_set_flag(tech_pvt->channel, CF_TRACKABLE);
141 	}
142 
143 
144 	if (profile->flags[PFLAG_PASS_RFC2833]) {
145 		switch_channel_set_flag(tech_pvt->channel, CF_PASS_RFC2833);
146 	}
147 
148 	if (sofia_test_pflag(tech_pvt->profile, PFLAG_RTP_NOTIMER_DURING_BRIDGE)) {
149 		switch_channel_set_flag(tech_pvt->channel, CF_RTP_NOTIMER_DURING_BRIDGE);
150 	}
151 
152 	if (sofia_test_pflag(tech_pvt->profile, PFLAG_T38_PASSTHRU)) {
153 		switch_channel_set_flag(tech_pvt->channel, CF_T38_PASSTHRU);
154 	}
155 
156 	switch_channel_set_cap(tech_pvt->channel, CC_MEDIA_ACK);
157 	switch_channel_set_cap(tech_pvt->channel, CC_BYPASS_MEDIA);
158 	switch_channel_set_cap(tech_pvt->channel, CC_PROXY_MEDIA);
159 	switch_channel_set_cap(tech_pvt->channel, CC_JITTERBUFFER);
160 	switch_channel_set_cap(tech_pvt->channel, CC_FS_RTP);
161 	switch_channel_set_cap(tech_pvt->channel, CC_RTP_RTT);
162 	switch_channel_set_cap(tech_pvt->channel, CC_MSRP);
163 	switch_channel_set_cap(tech_pvt->channel, CC_QUEUEABLE_DTMF_DELAY);
164 
165 
166 
167 	tech_pvt->mparams.ndlb = tech_pvt->profile->mndlb;
168 	tech_pvt->mparams.inbound_codec_string = profile->inbound_codec_string;
169 	tech_pvt->mparams.outbound_codec_string = profile->outbound_codec_string;
170 	tech_pvt->mparams.auto_rtp_bugs = profile->auto_rtp_bugs;
171 	tech_pvt->mparams.timer_name = profile->timer_name;
172 	tech_pvt->mparams.vflags = profile->vflags;
173 	tech_pvt->mparams.manual_rtp_bugs = profile->manual_rtp_bugs;
174 	tech_pvt->mparams.manual_video_rtp_bugs = profile->manual_video_rtp_bugs;
175 	tech_pvt->mparams.extsipip = profile->extsipip;
176 	tech_pvt->mparams.extrtpip = profile->extrtpip;
177 	tech_pvt->mparams.local_network = profile->local_network;
178 	tech_pvt->mparams.sipip = profile->sipip;
179 	tech_pvt->mparams.jb_msec = profile->jb_msec;
180 	tech_pvt->mparams.rtcp_audio_interval_msec = profile->rtcp_audio_interval_msec;
181 	tech_pvt->mparams.rtcp_video_interval_msec = profile->rtcp_video_interval_msec;
182 	tech_pvt->mparams.sdp_username = profile->sdp_username;
183 	tech_pvt->mparams.cng_pt = tech_pvt->cng_pt;
184 	tech_pvt->mparams.rtp_timeout_sec = profile->rtp_timeout_sec;
185 	tech_pvt->mparams.rtp_hold_timeout_sec = profile->rtp_hold_timeout_sec;
186 
187 	if (profile->rtp_digit_delay) {
188 		tech_pvt->mparams.dtmf_delay = profile->rtp_digit_delay;
189 	}
190 
191 	switch_media_handle_create(&tech_pvt->media_handle, session, &tech_pvt->mparams);
192 	switch_media_handle_set_media_flags(tech_pvt->media_handle, tech_pvt->profile->media_flags);
193 
194 	switch_core_media_check_dtmf_type(session);
195 
196 	for(i = 0; i < profile->cand_acl_count; i++) {
197 		switch_core_media_add_ice_acl(session, SWITCH_MEDIA_TYPE_AUDIO, profile->cand_acl[i]);
198 		switch_core_media_add_ice_acl(session, SWITCH_MEDIA_TYPE_VIDEO, profile->cand_acl[i]);
199 	}
200 
201 
202 	switch_core_session_set_private(session, tech_pvt);
203 
204 	if (channame) {
205 		sofia_glue_set_name(tech_pvt, channame);
206 	}
207 
208 }
209 
210 
211 
212 
sofia_glue_ext_address_lookup(sofia_profile_t * profile,char ** ip,switch_port_t * port,const char * sourceip,switch_memory_pool_t * pool)213 switch_status_t sofia_glue_ext_address_lookup(sofia_profile_t *profile, char **ip, switch_port_t *port,
214 											  const char *sourceip, switch_memory_pool_t *pool)
215 {
216 	char *error = "";
217 	switch_status_t status = SWITCH_STATUS_FALSE;
218 	int x;
219 	switch_port_t stun_port = SWITCH_STUN_DEFAULT_PORT;
220 	char *stun_ip = NULL;
221 
222 	if (!sourceip) {
223 		return status;
224 	}
225 
226 	if (!strncasecmp(sourceip, "host:", 5)) {
227 		status = (*ip = switch_stun_host_lookup(sourceip + 5, pool)) ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
228 	} else if (!strncasecmp(sourceip, "stun:", 5)) {
229 		char *p;
230 
231 		stun_ip = strdup(sourceip + 5);
232 
233 		switch_assert(stun_ip);
234 
235 		if ((p = strchr(stun_ip, ':'))) {
236 			int iport;
237 			*p++ = '\0';
238 			iport = atoi(p);
239 			if (iport > 0 && iport < 0xFFFF) {
240 				stun_port = (switch_port_t) iport;
241 			}
242 		}
243 
244 		if (zstr(stun_ip)) {
245 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STUN Failed! NO STUN SERVER\n");
246 			goto out;
247 		}
248 
249 
250         for (x = 0; x < 5; x++) {
251             if ((status = switch_stun_lookup(ip, port, stun_ip, stun_port, &error, pool)) != SWITCH_STATUS_SUCCESS) {
252                 switch_yield(100000);
253             } else {
254 				break;
255             }
256         }
257 
258 		if (!*ip) {
259 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "STUN Failed! No IP returned\n");
260 			goto out;
261 		}
262 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "STUN Success [%s]:[%d]\n", *ip, *port);
263 		status = SWITCH_STATUS_SUCCESS;
264 	} else {
265 		*ip = (char *) sourceip;
266 		status = SWITCH_STATUS_SUCCESS;
267 	}
268 
269  out:
270 
271 	switch_safe_free(stun_ip);
272 
273 	return status;
274 }
275 
276 
sofia_glue_get_unknown_header(sip_t const * sip,const char * name)277 const char *sofia_glue_get_unknown_header(sip_t const *sip, const char *name)
278 {
279 	sip_unknown_t *un;
280 	for (un = sip->sip_unknown; un; un = un->un_next) {
281 		if (!strcasecmp(un->un_name, name)) {
282 			if (!zstr(un->un_value)) {
283 				return un->un_value;
284 			}
285 		}
286 	}
287 	return NULL;
288 }
289 
sofia_glue_str2transport(const char * str)290 sofia_transport_t sofia_glue_str2transport(const char *str)
291 {
292 	if (!strncasecmp(str, "udp", 3)) {
293 		return SOFIA_TRANSPORT_UDP;
294 	} else if (!strncasecmp(str, "tcp", 3)) {
295 		return SOFIA_TRANSPORT_TCP;
296 	} else if (!strncasecmp(str, "sctp", 4)) {
297 		return SOFIA_TRANSPORT_SCTP;
298 	} else if (!strncasecmp(str, "tls", 3)) {
299 		return SOFIA_TRANSPORT_TCP_TLS;
300 	}
301 
302 	return SOFIA_TRANSPORT_UNKNOWN;
303 }
304 
sofia_glue_str2tls_verify_policy(const char * str)305 enum tport_tls_verify_policy sofia_glue_str2tls_verify_policy(const char * str){
306 	char *ptr_next;
307 	int len;
308 	enum tport_tls_verify_policy ret;
309 	char *ptr_cur = (char *) str;
310 	ret = TPTLS_VERIFY_NONE;
311 
312 	while (ptr_cur) {
313 		if ((ptr_next = strchr(ptr_cur, '|'))) {
314 			len = (int)(ptr_next++ - ptr_cur);
315 		} else {
316 			len = (int)strlen(ptr_cur);
317 		}
318 		if (!strncasecmp(ptr_cur, "in",len)) {
319 			ret |= TPTLS_VERIFY_IN;
320 		} else if (!strncasecmp(ptr_cur, "none",len)) {
321 			ret = TPTLS_VERIFY_NONE;
322 			break;
323 		} else if (!strncasecmp(ptr_cur, "out",len)) {
324 			ret |= TPTLS_VERIFY_OUT;
325 		} else if (!strncasecmp(ptr_cur, "all",len)) {
326 			ret |= TPTLS_VERIFY_ALL;
327 		} else if (!strncasecmp(ptr_cur, "subjects_in",len)) {
328 			ret |= TPTLS_VERIFY_SUBJECTS_IN;
329 		} else if (!strncasecmp(ptr_cur, "subjects_out",len)) {
330 			ret |= TPTLS_VERIFY_SUBJECTS_OUT;
331 		} else if (!strncasecmp(ptr_cur, "subjects_all",len)) {
332 			ret |= TPTLS_VERIFY_SUBJECTS_ALL;
333 		} else {
334 			char el[32] = {0};
335 			strncpy(el, ptr_cur, len < sizeof(el) ? len : sizeof(el) - 1);
336 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid tls-verify-policy value: %s\n", el);
337 		}
338 		ptr_cur = ptr_next;
339 	}
340 	return ret;
341 }
342 
343 /* create "local-uuid" */
sofia_glue_is_valid_session_uuid(const char * session_uuid)344 int sofia_glue_is_valid_session_uuid(const char *session_uuid)
345 {
346 	int i;
347 	if (zstr(session_uuid) || strlen(session_uuid) != RFC7989_SESSION_UUID_LEN) {
348 		return 0;
349 	}
350 	for (i = 0; i < RFC7989_SESSION_UUID_LEN; i++) {
351 		char c = session_uuid[i];
352 		if ((c < '0' || c > '9') && (c < 'a' || c > 'f')) {
353 			return 0;
354 		}
355 	}
356 	return 1;
357 }
358 
359 /* NIL session-uuid: 00000000000000000000000000000000 */
sofia_glue_is_nil_session_uuid(const char * session_uuid)360 int sofia_glue_is_nil_session_uuid(const char *session_uuid)
361 {
362 	if (zstr(session_uuid)) {
363 		return 0;
364 	}
365 	if (!memcmp(session_uuid, RFC7989_SESSION_UUID_NULL, RFC7989_SESSION_UUID_LEN)) {
366 		return 1;
367 	}
368 	return 0;
369 }
370 
sofia_glue_uuid_to_session_uuid(switch_memory_pool_t * pool,const char * uuid)371 const char *sofia_glue_uuid_to_session_uuid(switch_memory_pool_t *pool, const char *uuid)
372 {
373 	char *session_uuid = NULL; /*"local-uuid", per rfc7989*/
374 	if (zstr(uuid) || strlen(uuid) != 36) return NULL;
375 
376 	session_uuid = switch_core_alloc(pool, RFC7989_SESSION_UUID_LEN + 1);
377 	memcpy(session_uuid, uuid, 8);
378 	memcpy(session_uuid + 8, uuid + 9, 4);
379 	memcpy(session_uuid + 12, uuid + 14, 4);
380 	memcpy(session_uuid + 16, uuid + 19, 4);
381 	memcpy(session_uuid + 20, uuid + 24, 12);
382 
383 	if (!sofia_glue_is_valid_session_uuid(session_uuid)) return NULL;
384 
385 	return session_uuid;
386 }
387 
388 /* rfc7989 generic params, return 0 if param is disabled from config or invalid. ALL params allowed by default. */
389 /* save updated generic params list in chan var. */
sofia_glue_check_filter_generic_params(switch_core_session_t * session,sofia_profile_t * profile,char * param)390 int sofia_glue_check_filter_generic_params(switch_core_session_t *session, sofia_profile_t *profile, char *param)
391 {
392 
393 	char *tmp = NULL;
394 	switch_channel_t *channel = switch_core_session_get_channel(session);
395 
396 	if (zstr(param)) {
397 		return 0;
398 	}
399 	if (profile->rfc7989_filter) {
400 		char *found = NULL; char *end = NULL;
401 		char *token_array[100] = { 0 };
402 		int tokens = switch_separate_string(profile->rfc7989_filter, ',', token_array, (sizeof(token_array) / sizeof(token_array[0])));
403 		tmp = switch_core_session_strdup(session, param);
404 		if (tokens) {
405 			int i;
406 			for (i = 0; i < tokens && token_array[i]; i++) {
407 				while ((found = strstr(tmp, token_array[i]))) {
408 					end = strchr(found, ';');
409 					if (!end) end = strchr(found, '\0');
410 					*found = '\0';
411 					strcat(tmp, found + (end - found));
412 					switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING,
413 						"Session-ID: Dropped generic param: %s\n", token_array[i]);
414 				}
415 			}
416 		}
417 	}
418 
419 	if (tmp) {
420 		switch_channel_set_variable(channel, SWITCH_RFC7989_GENERIC_PARAM_VARIABLE, tmp);
421 	} else {
422 		switch_channel_set_variable(channel, SWITCH_RFC7989_GENERIC_PARAM_VARIABLE, param);
423 	}
424 
425 	return 1;
426 }
427 /* check and store Session-ID header. */
428 /* retrieve "local-uuid" and "remote-uuid" of the remote party. */
sofia_glue_store_session_id(switch_core_session_t * session,sofia_profile_t * profile,sip_t const * sip,switch_bool_t is_reply)429 void sofia_glue_store_session_id(switch_core_session_t *session, sofia_profile_t *profile, sip_t const *sip, switch_bool_t is_reply)
430 {
431 	char *a_id, *b_id, *duped, *p, *remote_param;
432 	const char *header = sofia_glue_get_unknown_header(sip, "Session-ID");
433 	switch_channel_t *channel = switch_core_session_get_channel(session);
434 
435 	if (!sofia_test_pflag(profile, PFLAG_RFC7989_SESSION_ID)) return;
436 
437 	if (!header) {
438 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Session-ID: missing header.");
439 		return;
440 	}
441 
442 	duped = switch_core_session_strdup(session, header);
443 
444 	if (zstr(duped)) return;
445 
446 	a_id = switch_strip_whitespace(duped);
447 
448 	if (zstr(a_id)) return;
449 
450 	p = strchr(a_id, ';');
451 	if (p) *p = '\0';
452 
453 	if (!sofia_glue_is_valid_session_uuid(a_id)) {
454 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Session-ID: Ignoring \"%s\" parsed as \"%s\"\n", header, a_id);
455 		return;
456 	}
457 
458 	/* RFC7329 compatibility */
459 	if (is_reply) {
460 		const char *temp_id = switch_channel_get_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE);
461 		if (!zstr(temp_id) && !memcmp(a_id, temp_id, RFC7989_SESSION_UUID_LEN) ) {
462 			/* 'If a SIP response only contains the "local-uuid" that was sent
463 			 *  originally, this comes from a pre-standard implementation and MUST
464 			 *  NOT be discarded for removing the nil "remote-uuid". In this
465 			 *  case, all future transactions within this dialog MUST contain only
466 			 *  the UUID received in the first SIP response" */
467 			switch_channel_set_flag(channel, CF_RFC7329_COMPAT);
468 			switch_channel_set_flag_partner(channel, CF_RFC7329_COMPAT);
469 		}
470 	}
471 
472 	/* "local-uuid" field retrieved from remote party will become
473 	 * SWITCH_RFC7989_APP_SESSION_ID_VARIABLE in a b2bua role. */
474 	if (!zstr(a_id)) {
475 		struct private_object *tech_pvt = switch_core_session_get_private(session);
476 		switch_channel_set_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE, a_id);
477 		if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) {
478 			tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id);
479 		}
480 	}
481 
482 	if (!p) {
483 		switch_channel_set_flag(channel, CF_RFC7329_COMPAT);
484 		switch_channel_set_flag_partner(channel, CF_RFC7329_COMPAT);
485 		return;
486 	}
487 	p++;
488 	remote_param = strstr(p, "remote=");
489 	if (!remote_param) {
490 		switch_channel_set_flag(channel, CF_RFC7329_COMPAT);
491 		switch_channel_set_flag_partner(channel, CF_RFC7329_COMPAT);
492 		sofia_glue_check_filter_generic_params(session, profile, p);
493 		return;
494 	}
495 	b_id = remote_param + 7;
496 	if (!zstr(b_id) && strlen(b_id) == RFC7989_SESSION_UUID_LEN /*32*/) {
497 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session-ID: Set remote-uuid: %s\n", b_id);
498 		/*using chan var as placeholder only when UAS or when answer() was called in the dialplan */
499 		switch_channel_set_variable(channel, SWITCH_RFC7989_REMOTE_SESSION_ID_VARIABLE, b_id);
500 		switch_channel_set_variable_partner(channel, SWITCH_RFC7989_REMOTE_SESSION_ID_VARIABLE, b_id);
501 
502 	} else {
503 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Session-ID: invalid uuid, ignored.\n");
504 	}
505 }
506 
507 /* add "Session-ID:" header */
sofia_glue_session_id_header(switch_core_session_t * session,sofia_profile_t * profile)508 char *sofia_glue_session_id_header(switch_core_session_t *session, sofia_profile_t *profile)
509 {
510 	switch_channel_t *channel;
511 	const char *b_id = NULL;
512 	const char *a_id = NULL;
513 	const char *temp_id = NULL;
514 	const char *generic = NULL;
515 
516 	if (!session) return NULL;
517 
518 	if (!profile) return NULL;
519 
520 	if (!sofia_test_pflag(profile, PFLAG_RFC7989_SESSION_ID)) return NULL;
521 
522 	channel = switch_core_session_get_channel(session);
523 
524 	a_id = switch_channel_get_variable_partner(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE);
525 
526 	if (zstr(a_id)) {
527 		a_id = switch_channel_get_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE);
528 		if (!zstr(a_id) && strlen(a_id) == 36) {
529 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Reformatting app Session-ID: %s\n", a_id);
530 			a_id = sofia_glue_uuid_to_session_uuid(switch_core_session_get_pool(session), a_id);
531 			if (!zstr(a_id)) {
532 				struct private_object *tech_pvt = switch_core_session_get_private(session);
533 				switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id);
534 				if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) {
535 					tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id);
536 				}
537 			}
538 		}
539 	}
540 
541 	if (zstr(a_id)) {
542 		const char *partner_uuid = switch_channel_get_partner_uuid(channel);
543 		if (!zstr(partner_uuid)) {
544 			const char *partner_session_id = sofia_glue_uuid_to_session_uuid(switch_core_session_get_pool(session), partner_uuid);
545 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Setting \"Session-ID: %s\" from partner leg\n", partner_session_id);
546 			switch_channel_set_variable_partner(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE, partner_session_id);
547 			a_id = partner_session_id;
548 		}
549 	}
550 
551 	if (((switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) && zstr(a_id) &&
552 				switch_channel_get_state(channel) == CS_INIT) && switch_channel_test_flag(channel, CF_ORIGINATING)) {
553 		/*outbound initial request*/
554 		char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
555 
556 		switch_uuid_str(uuid_str, sizeof(uuid_str));
557 		a_id = sofia_glue_uuid_to_session_uuid(switch_core_session_get_pool(session), uuid_str);
558 		if (!zstr(a_id)) {
559 			struct private_object *tech_pvt = switch_core_session_get_private(session);
560 			switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id);
561 			if (tech_pvt && tech_pvt->sofia_private && !tech_pvt->sofia_private->rfc7989_uuid) {
562 				tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id);
563 			}
564 		}
565 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
566 				"Session-ID: Outbound initial request. local-uuid: %s", a_id);
567 		if (sofia_test_pflag(profile, PFLAG_RFC7989_FORCE_OLD)) {
568 			/*for old (and obsolete) Session-ID RFC7329 */
569 			return switch_core_session_sprintf(session, "Session-ID: %s", a_id);
570 		}
571 
572 		b_id = RFC7989_SESSION_UUID_NULL;
573 		return switch_core_session_sprintf(session, "Session-ID: %s;remote=%s", a_id, b_id);
574 	}
575 
576 	temp_id = switch_channel_get_variable(channel, SWITCH_RFC7989_REMOTE_SESSION_ID_VARIABLE);
577 	if ((switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) &&
578 			((switch_channel_get_state(channel) == CS_INIT) || (switch_channel_get_state(channel) == CS_EXECUTE)) &&
579 			zstr(temp_id)) {
580 		/* fallback to RFC7329 - "old". */
581 		/* inbound initial request, no "remote" param. section 11 of RFC7989. */
582 		a_id = switch_channel_get_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE);
583 		if (zstr(a_id)) {
584 			a_id = RFC7989_SESSION_UUID_NULL;
585 		} else {
586 			switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id);
587 		}
588 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Session-ID: Fallback to RFC7329");
589 		switch_channel_set_flag(channel, CF_RFC7329_COMPAT);
590 		return switch_core_session_sprintf(session, "Session-ID: %s", a_id);
591 	}
592 	if ((switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) &&
593 			((switch_channel_get_state(channel) == CS_INIT) || (switch_channel_get_state(channel) == CS_EXECUTE)) &&
594 			sofia_glue_is_nil_session_uuid(temp_id)) {
595 		/*inbound initial request*/
596 		char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1];
597 
598 		switch_uuid_str(uuid_str, sizeof(uuid_str));
599 		a_id = sofia_glue_uuid_to_session_uuid(switch_core_session_get_pool(session), uuid_str);
600 		if (!zstr(a_id)) {
601 			struct private_object *tech_pvt = switch_core_session_get_private(session);
602 			switch_channel_set_variable(channel, SWITCH_RFC7989_APP_SESSION_ID_VARIABLE, a_id);
603 			if (tech_pvt && tech_pvt->sofia_private) {
604 				tech_pvt->sofia_private->rfc7989_uuid = su_strdup(tech_pvt->nh->nh_home, a_id);
605 			}
606 		}
607 		b_id = switch_channel_get_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE);
608 		if (zstr(b_id)) {
609 			b_id = RFC7989_SESSION_UUID_NULL;
610 		}
611 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,
612 				"Session-ID: Inbound initial request. local-uuid: %s", a_id);
613 		return switch_core_session_sprintf(session, "Session-ID: %s;remote=%s", a_id, b_id);
614 	}
615 
616 	if (zstr(a_id)) {
617 		struct private_object *tech_pvt = switch_core_session_get_private(session);
618 		/* setting NIL local-uuid should never happen,
619 		 * but in case we don't get to set it properly by here, just set it to NIL */
620 		if (tech_pvt && tech_pvt->sofia_private && tech_pvt->sofia_private->rfc7989_uuid) {
621 			/* handle BYE after REFER or other cases where the channel is destroyed already and we can't get the chan var */
622 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session-ID: retrieved local-uuid ");
623 			a_id = tech_pvt->sofia_private->rfc7989_uuid;
624 		} else {
625 			a_id = RFC7989_SESSION_UUID_NULL;
626 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session-ID: NIL local-uuid ");
627 		}
628 	}
629 
630 	b_id = switch_channel_get_variable(channel, SWITCH_RFC7989_SESSION_ID_VARIABLE);
631 
632 	if (zstr(b_id) && switch_channel_test_flag(channel, CF_RFC7329_COMPAT)) {
633 		/* fallback to RFC7329 , only one uuid*/
634 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING ,"Session-ID: Fallback to RFC7329, use one uuid");
635 		return switch_core_session_sprintf(session, "Session-ID: %s", a_id);
636 	} else if (zstr(b_id)) {
637 		b_id = RFC7989_SESSION_UUID_NULL;
638 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Session-ID: set NIL remote-uuid");
639 	}
640 
641 	/* B2B: handle generic params*/
642 	generic = switch_channel_get_variable_partner(channel, SWITCH_RFC7989_GENERIC_PARAM_VARIABLE);
643 	if (!zstr(generic)) {
644 		/* copy generic param (name and val) */
645 		return switch_core_session_sprintf(session, "Session-ID: %s;%s", a_id, generic);
646 	}
647 	if (switch_channel_test_flag(channel, CF_RFC7329_COMPAT)) {
648 		return switch_core_session_sprintf(session, "Session-ID: %s", a_id);
649 	}
650 	return switch_core_session_sprintf(session, "Session-ID: %s;remote=%s", a_id, b_id);
651 }
652 
sofia_glue_find_parameter_value(switch_core_session_t * session,const char * str,const char * param)653 char *sofia_glue_find_parameter_value(switch_core_session_t *session, const char *str, const char *param)
654 {
655 	const char *param_ptr;
656 	char *param_value;
657 	char *tmp;
658 	switch_size_t param_len;
659 
660 	if (zstr(str) || zstr(param) || !session) return NULL;
661 
662 	if (end_of(param) != '=') {
663 		param = switch_core_session_sprintf(session, "%s=", param);
664 		if (zstr(param)) return NULL;
665 	}
666 
667 	param_len = strlen(param);
668 	param_ptr = sofia_glue_find_parameter(str, param);
669 
670 	if (zstr(param_ptr)) return NULL;
671 
672 	param_value = switch_core_session_strdup(session, param_ptr + param_len);
673 
674 	if (zstr(param_value)) return NULL;
675 
676 	if ((tmp = strchr(param_value, ';'))) *tmp = '\0';
677 
678 	return param_value;
679 }
680 
sofia_glue_find_parameter(const char * str,const char * param)681 char *sofia_glue_find_parameter(const char *str, const char *param)
682 {
683 	char *ptr = NULL;
684 
685 	ptr = (char *) str;
686 	while (ptr) {
687 		if (!strncasecmp(ptr, param, strlen(param)))
688 			return ptr;
689 
690 		if ((ptr = strchr(ptr, ';')))
691 			ptr++;
692 	}
693 
694 	return NULL;
695 }
696 
sofia_glue_url2transport(const url_t * url)697 sofia_transport_t sofia_glue_url2transport(const url_t *url)
698 {
699 	char *ptr = NULL;
700 	int tls = 0;
701 
702 	if (!url)
703 		return SOFIA_TRANSPORT_UNKNOWN;
704 
705 	if (url->url_scheme && !strcasecmp(url->url_scheme, "sips")) {
706 		tls++;
707 	}
708 
709 	if ((ptr = sofia_glue_find_parameter(url->url_params, "transport="))) {
710 		return sofia_glue_str2transport(ptr + 10);
711 	}
712 
713 	return (tls) ? SOFIA_TRANSPORT_TCP_TLS : SOFIA_TRANSPORT_UDP;
714 }
715 
sofia_glue_via2transport(const sip_via_t * via)716 sofia_transport_t sofia_glue_via2transport(const sip_via_t * via)
717 {
718 	char *ptr = NULL;
719 
720 	if (!via || !via->v_protocol)
721 		return SOFIA_TRANSPORT_UNKNOWN;
722 
723 	if ((ptr = strrchr(via->v_protocol, '/'))) {
724 		ptr++;
725 
726 		if (!strncasecmp(ptr, "udp", 3)) {
727 			return SOFIA_TRANSPORT_UDP;
728 		} else if (!strncasecmp(ptr, "tcp", 3)) {
729 			return SOFIA_TRANSPORT_TCP;
730 		} else if (!strncasecmp(ptr, "tls", 3)) {
731 			return SOFIA_TRANSPORT_TCP_TLS;
732 		} else if (!strncasecmp(ptr, "sctp", 4)) {
733 			return SOFIA_TRANSPORT_SCTP;
734 		} else if (!strncasecmp(ptr, "wss", 3)) {
735 			return SOFIA_TRANSPORT_WSS;
736 		} else if (!strncasecmp(ptr, "ws", 2)) {
737 			return SOFIA_TRANSPORT_WS;
738 		}
739 	}
740 
741 	return SOFIA_TRANSPORT_UNKNOWN;
742 }
743 
sofia_glue_transport2str(const sofia_transport_t tp)744 const char *sofia_glue_transport2str(const sofia_transport_t tp)
745 {
746 	switch (tp) {
747 	case SOFIA_TRANSPORT_TCP:
748 		return "tcp";
749 
750 	case SOFIA_TRANSPORT_TCP_TLS:
751 		return "tls";
752 
753 	case SOFIA_TRANSPORT_SCTP:
754 		return "sctp";
755 
756 	case SOFIA_TRANSPORT_WS:
757 		return "ws";
758 
759 	case SOFIA_TRANSPORT_WSS:
760 		return "wss";
761 
762 	default:
763 		return "udp";
764 	}
765 }
766 
sofia_glue_create_external_via(switch_core_session_t * session,sofia_profile_t * profile,sofia_transport_t transport)767 char *sofia_glue_create_external_via(switch_core_session_t *session, sofia_profile_t *profile, sofia_transport_t transport)
768 {
769 	return sofia_glue_create_via(session, profile->extsipip, (sofia_glue_transport_has_tls(transport))
770 								 ? profile->tls_sip_port : profile->extsipport, transport);
771 }
772 
sofia_glue_create_via(switch_core_session_t * session,const char * ip,switch_port_t port,sofia_transport_t transport)773 char *sofia_glue_create_via(switch_core_session_t *session, const char *ip, switch_port_t port, sofia_transport_t transport)
774 {
775 	char *ipv6 = strchr(ip, ':');
776 	if (port && port != 5060) {
777 		if (session) {
778 			return switch_core_session_sprintf(session, "SIP/2.0/%s %s%s%s:%d;rport", sofia_glue_transport2str(transport), ipv6 ? "[" : "", ip, ipv6 ? "]" : "", port);
779 		} else {
780 			return switch_mprintf("SIP/2.0/%s %s%s%s:%d;rport", sofia_glue_transport2str(transport), ipv6 ? "[" : "", ip, ipv6 ? "]" : "", port);
781 		}
782 	} else {
783 		if (session) {
784 			return switch_core_session_sprintf(session, "SIP/2.0/%s %s%s%s;rport", sofia_glue_transport2str(transport), ipv6 ? "[" : "", ip, ipv6 ? "]" : "");
785 		} else {
786 			return switch_mprintf("SIP/2.0/%s %s%s%s;rport", sofia_glue_transport2str(transport), ipv6 ? "[" : "", ip, ipv6 ? "]" : "");
787 		}
788 	}
789 }
790 
sofia_glue_strip_uri(const char * str)791 char *sofia_glue_strip_uri(const char *str)
792 {
793 	char *p;
794 	char *r;
795 
796 	if ((p = strchr(str, '<'))) {
797 		p++;
798 		r = strdup(p);
799 		switch_assert(r);
800 		if ((p = strchr(r, '>'))) {
801 			*p = '\0';
802 		}
803 	} else {
804 		r = strdup(str);
805 		switch_assert(r);
806 	}
807 
808 	return r;
809 }
810 
811 
812 
sofia_glue_transport_has_tls(const sofia_transport_t tp)813 int sofia_glue_transport_has_tls(const sofia_transport_t tp)
814 {
815 	switch (tp) {
816 	case SOFIA_TRANSPORT_TCP_TLS:
817 		return 1;
818 
819 	default:
820 		return 0;
821 	}
822 }
823 
sofia_glue_get_addr(msg_t * msg,char * buf,size_t buflen,int * port)824 void sofia_glue_get_addr(msg_t *msg, char *buf, size_t buflen, int *port)
825 {
826 	su_addrinfo_t *addrinfo = msg_addrinfo(msg);
827 	if (!addrinfo) {
828 		return;
829 	}
830 
831 	if (buf) {
832 		get_addr(buf, buflen, addrinfo->ai_addr, (socklen_t)addrinfo->ai_addrlen);
833 	}
834 
835 	if (port) {
836 		*port = get_port(addrinfo->ai_addr);
837 	}
838 }
839 
sofia_overcome_sip_uri_weakness(switch_core_session_t * session,const char * uri,const sofia_transport_t transport,switch_bool_t uri_only,const char * params,const char * invite_tel_params)840 char *sofia_overcome_sip_uri_weakness(switch_core_session_t *session, const char *uri, const sofia_transport_t transport, switch_bool_t uri_only,
841 									  const char *params, const char *invite_tel_params)
842 {
843 	char *stripped = switch_core_session_strdup(session, uri);
844 	char *new_uri = NULL;
845 	char *p;
846 	const char *url_params = NULL;
847 
848 	if (!zstr(params) && *params == '~') {
849 		url_params = params + 1;
850 		params = NULL;
851 	}
852 
853 	stripped = sofia_glue_get_url_from_contact(stripped, 0);
854 
855 	/* remove our params so we don't make any whiny moronic device piss its pants and forget who it is for a half-hour */
856 	if ((p = (char *) switch_stristr(";fs_", stripped))) {
857 		*p = '\0';
858 	}
859 
860 	if (transport && transport != SOFIA_TRANSPORT_UDP) {
861 
862 		if (switch_stristr("port=", stripped)) {
863 			new_uri = switch_core_session_sprintf(session, "%s%s%s", uri_only ? "" : "<", stripped, uri_only ? "" : ">");
864 		} else {
865 			if (params) {
866 				new_uri = switch_core_session_sprintf(session, "%s%s;transport=%s;%s%s",
867 													  uri_only ? "" : "<", stripped, sofia_glue_transport2str(transport), params, uri_only ? "" : ">");
868 			} else {
869 				new_uri = switch_core_session_sprintf(session, "%s%s;transport=%s%s",
870 													  uri_only ? "" : "<", stripped, sofia_glue_transport2str(transport), uri_only ? "" : ">");
871 			}
872 		}
873 	} else {
874 		if (params) {
875 			new_uri = switch_core_session_sprintf(session, "%s%s;%s%s", uri_only ? "" : "<", stripped, params, uri_only ? "" : ">");
876 		} else {
877 			if (uri_only) {
878 				new_uri = stripped;
879 			} else {
880 				new_uri = switch_core_session_sprintf(session, "<%s>", stripped);
881 			}
882 		}
883 	}
884 
885 	if (url_params && !uri_only) {
886 		new_uri = switch_core_session_sprintf(session, "%s;%s", new_uri, url_params);
887 	}
888 
889 	if (!zstr(invite_tel_params)) {
890 		char *lhs, *rhs = strchr(new_uri, '@');
891 
892 		if (!zstr(rhs)) {
893 			*rhs++ = '\0';
894 			lhs = new_uri;
895 			new_uri = switch_core_session_sprintf(session, "%s;%s@%s", lhs, invite_tel_params, rhs);
896 		}
897 	}
898 
899 	return new_uri;
900 }
901 
sofia_glue_get_extra_headers(switch_channel_t * channel,const char * prefix)902 char *sofia_glue_get_extra_headers(switch_channel_t *channel, const char *prefix)
903 {
904 	char *extra_headers = NULL;
905 	switch_stream_handle_t stream = { 0 };
906 	switch_event_header_t *hi = NULL;
907 	const char *exclude_regex = NULL;
908 	switch_regex_t *re = NULL;
909 	int ovector[30] = {0};
910 	int proceed;
911 
912 	exclude_regex = switch_channel_get_variable(channel, "exclude_outgoing_extra_header");
913 	SWITCH_STANDARD_STREAM(stream);
914 	if ((hi = switch_channel_variable_first(channel))) {
915 		for (; hi; hi = hi->next) {
916 			const char *name = (char *) hi->name;
917 			char *value = (char *) hi->value;
918 
919 			if (!strcasecmp(name, "sip_geolocation")) {
920 				stream.write_function(&stream, "Geolocation: %s\r\n", value);
921 			}
922 
923 			if (!strncasecmp(name, prefix, strlen(prefix))) {
924 				if ( !exclude_regex || !(proceed = switch_regex_perform(name, exclude_regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0])))) {
925 					const char *hname = name + strlen(prefix);
926 					stream.write_function(&stream, "%s: %s\r\n", hname, value);
927 					switch_regex_safe_free(re);
928 				} else {
929 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Ignoring Extra Header [%s] , matches exclude_outgoing_extra_header [%s]\n", name, exclude_regex);
930 				}
931 			}
932 		}
933 		switch_channel_variable_last(channel);
934 	}
935 
936 	if (!zstr((char *) stream.data)) {
937 		extra_headers = stream.data;
938 	} else {
939 		switch_safe_free(stream.data);
940 	}
941 
942 	return extra_headers;
943 }
944 
sofia_glue_set_extra_headers(switch_core_session_t * session,sip_t const * sip,const char * prefix)945 void sofia_glue_set_extra_headers(switch_core_session_t *session, sip_t const *sip, const char *prefix)
946 {
947 	sip_unknown_t *un;
948 	char name[512] = "";
949 	switch_channel_t *channel = switch_core_session_get_channel(session);
950 	char pstr[32];
951 
952 
953 	if (!sip || !channel) {
954 		return;
955 	}
956 
957 	for (un = sip->sip_unknown; un; un = un->un_next) {
958 		if (sofia_test_extra_headers(un->un_name)) {
959 			if (!zstr(un->un_value)) {
960 				switch_snprintf(name, sizeof(name), "%s%s", prefix, un->un_name);
961 				switch_channel_set_variable(channel, name, un->un_value);
962 			}
963 		}
964 	}
965 
966 	switch_snprintf(pstr, sizeof(pstr), "execute_on_%sprefix", prefix);
967 	switch_channel_execute_on(channel, pstr);
968 	switch_channel_api_on(channel, pstr);
969 
970 	switch_channel_execute_on(channel, "execute_on_sip_extra_headers");
971 	switch_channel_api_on(channel, "api_on_sip_extra_headers");
972 }
973 
sofia_glue_get_extra_headers_from_event(switch_event_t * event,const char * prefix)974 char *sofia_glue_get_extra_headers_from_event(switch_event_t *event, const char *prefix)
975 {
976 	char *extra_headers = NULL;
977 	switch_stream_handle_t stream = { 0 };
978 	switch_event_header_t *hp;
979 
980 	SWITCH_STANDARD_STREAM(stream);
981 	for (hp = event->headers; hp; hp = hp->next) {
982 		if (!zstr(hp->name) && !zstr(hp->value) && !strncasecmp(hp->name, prefix, strlen(prefix))) {
983 			char *name = strdup(hp->name);
984 			const char *hname;
985 			switch_assert(name);
986 			hname = name + strlen(prefix);
987 			stream.write_function(&stream, "%s: %s\r\n", hname, (char *)hp->value);
988 			free(name);
989 		}
990 	}
991 
992 	if (!zstr((char *) stream.data)) {
993 		extra_headers = stream.data;
994 	} else {
995 		switch_safe_free(stream.data);
996 	}
997 
998 	return extra_headers;
999 }
1000 
sofia_glue_get_non_extra_unknown_headers(sip_t const * sip)1001 char *sofia_glue_get_non_extra_unknown_headers(sip_t const *sip)
1002 {
1003 	char *unknown = NULL;
1004 	switch_stream_handle_t stream = { 0 };
1005 	sip_unknown_t *un;
1006 
1007 	if (!sip) {
1008 		return NULL;
1009 	}
1010 
1011 	SWITCH_STANDARD_STREAM(stream);
1012 	for (un = sip->sip_unknown; un; un = un->un_next) {
1013 		if (!sofia_test_extra_headers(un->un_name)) {
1014 			if (!zstr(un->un_value)) {
1015 				stream.write_function(&stream, "%s: %s\r\n",un->un_name,un->un_value);
1016 			}
1017 		}
1018 	}
1019 	if (!zstr((char *) stream.data)) {
1020 		unknown = stream.data;
1021 	} else {
1022 		switch_safe_free(stream.data);
1023 	}
1024 
1025 	return unknown;
1026 }
1027 
sofia_glue_do_invite(switch_core_session_t * session)1028 switch_status_t sofia_glue_do_invite(switch_core_session_t *session)
1029 {
1030 	char *alert_info = NULL;
1031 	const char *max_forwards = NULL;
1032 	const char *alertbuf;
1033 	private_object_t *tech_pvt = switch_core_session_get_private(session);
1034 	switch_channel_t *channel = switch_core_session_get_channel(session);
1035 	switch_caller_profile_t *caller_profile;
1036 	const char *cid_name, *cid_num;
1037 	char *e_dest = NULL;
1038 	const char *holdstr = "";
1039 	char *extra_headers = NULL;
1040 	switch_status_t status = SWITCH_STATUS_FALSE;
1041 	uint32_t session_timeout = tech_pvt->profile->session_timeout;
1042 	const char *val;
1043 	const char *rep;
1044 	const char *call_id = NULL;
1045 	char *route = NULL;
1046 	char *route_uri = NULL;
1047 	sofia_destination_t *dst = NULL;
1048 	sofia_cid_type_t cid_type = tech_pvt->profile->cid_type;
1049 	sip_cseq_t *cseq = NULL;
1050 	const char *invite_record_route = switch_channel_get_variable(tech_pvt->channel, "sip_invite_record_route");
1051 	const char *invite_route_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_route_uri");
1052 	const char *invite_full_from = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_from");
1053 	const char *invite_full_to = switch_channel_get_variable(tech_pvt->channel, "sip_invite_full_to");
1054 	const char *handle_full_from = switch_channel_get_variable(tech_pvt->channel, "sip_handle_full_from");
1055 	const char *handle_full_to = switch_channel_get_variable(tech_pvt->channel, "sip_handle_full_to");
1056 	const char *force_full_from = switch_channel_get_variable(tech_pvt->channel, "sip_force_full_from");
1057 	const char *force_full_to = switch_channel_get_variable(tech_pvt->channel, "sip_force_full_to");
1058 	const char *content_encoding = switch_channel_get_variable(tech_pvt->channel, "sip_content_encoding");
1059 	char *mp = NULL, *mp_type = NULL;
1060 	char *record_route = NULL;
1061 	const char *recover_via = NULL;
1062 	int require_timer = 1;
1063 	uint8_t is_t38 = 0;
1064 	const char *hold_char = "*";
1065 	const char *session_id_header = sofia_glue_session_id_header(session, tech_pvt->profile);
1066 
1067 
1068 	if (sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD_INACTIVE) ||
1069 		switch_true(switch_channel_get_variable_dup(tech_pvt->channel, "sofia_hold_inactive", SWITCH_FALSE, -1))) {
1070 		hold_char = "#";
1071 	}
1072 
1073 	if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) {
1074 		const char *recover_contact = switch_channel_get_variable(tech_pvt->channel, "sip_recover_contact");
1075 		recover_via = switch_channel_get_variable(tech_pvt->channel, "sip_recover_via");
1076 
1077 		if (!zstr(invite_record_route)) {
1078 			record_route = switch_core_session_sprintf(session, "Record-Route: %s", invite_record_route);
1079 		}
1080 
1081 		if (recover_contact) {
1082 			char *tmp = switch_core_session_strdup(session, recover_contact);
1083 			tech_pvt->redirected = sofia_glue_get_url_from_contact(tmp, 0);
1084 		}
1085 	}
1086 
1087 
1088 	if ((rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER))) {
1089 		switch_channel_set_variable(channel, SOFIA_REPLACES_HEADER, NULL);
1090 	}
1091 
1092 	switch_assert(tech_pvt != NULL);
1093 
1094 	sofia_clear_flag_locked(tech_pvt, TFLAG_SDP);
1095 
1096 	caller_profile = switch_channel_get_caller_profile(channel);
1097 
1098 	if (!caller_profile) {
1099 		switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
1100 		switch_goto_status(SWITCH_STATUS_FALSE, end);
1101 	}
1102 
1103 
1104 	if ((val = switch_channel_get_variable_dup(channel, "sip_require_timer", SWITCH_FALSE, -1)) && switch_false(val)) {
1105 		require_timer = 0;
1106 	}
1107 
1108 
1109 	cid_name = caller_profile->caller_id_name;
1110 	cid_num = caller_profile->caller_id_number;
1111 
1112 	if (!tech_pvt->sent_invites && !switch_channel_test_flag(channel, CF_ANSWERED)) {
1113 		switch_core_media_prepare_codecs(tech_pvt->session, SWITCH_FALSE);
1114 		switch_core_media_check_video_codecs(tech_pvt->session);
1115 	}
1116 
1117 	check_decode(cid_name, session);
1118 	check_decode(cid_num, session);
1119 
1120 
1121 	if ((alertbuf = switch_channel_get_variable(channel, "alert_info"))) {
1122 		alert_info = switch_core_session_sprintf(tech_pvt->session, "Alert-Info: %s", alertbuf);
1123 	}
1124 
1125 	max_forwards = switch_channel_get_variable(channel, SWITCH_MAX_FORWARDS_VARIABLE);
1126 
1127 	if ((status = switch_core_media_choose_port(tech_pvt->session, SWITCH_MEDIA_TYPE_AUDIO, 0)) != SWITCH_STATUS_SUCCESS) {
1128 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Port Error!\n");
1129 		goto end;
1130 	}
1131 
1132 	if (!switch_channel_get_private(tech_pvt->channel, "t38_options") || zstr(tech_pvt->mparams.local_sdp_str)) {
1133 		switch_core_media_gen_local_sdp(session, SDP_TYPE_REQUEST, NULL, 0, NULL, 0);
1134 	}
1135 
1136 	sofia_set_flag_locked(tech_pvt, TFLAG_READY);
1137 
1138 	if (!tech_pvt->nh) {
1139 		char *d_url = NULL, *url = NULL, *url_str = NULL;
1140 		sofia_private_t *sofia_private;
1141 		char *invite_contact = NULL, *to_str, *use_from_str, *from_str;
1142 		const char *t_var;
1143 		char *rpid_domain = NULL, *p;
1144 		const char *priv = "off";
1145 		const char *screen = "no";
1146 		const char *invite_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_params");
1147 		const char *invite_to_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_to_params");
1148 		const char *invite_tel_params = switch_channel_get_variable(switch_core_session_get_channel(session), "sip_invite_tel_params");
1149 		const char *invite_to_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_to_uri");
1150 		const char *invite_from_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_from_uri");
1151 		const char *invite_contact_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_contact_params");
1152 		const char *invite_from_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_from_params");
1153 		const char *invite_pid_params = switch_channel_get_variable(tech_pvt->channel, "sip_invite_pid_params");
1154 		const char *from_var = switch_channel_get_variable(tech_pvt->channel, "sip_from_uri");
1155 		const char *from_display = switch_channel_get_variable(tech_pvt->channel, "sip_from_display");
1156 		const char *invite_req_uri = switch_channel_get_variable(tech_pvt->channel, "sip_invite_req_uri");
1157 		const char *invite_domain = switch_channel_get_variable(tech_pvt->channel, "sip_invite_domain");
1158 
1159 		const char *use_name, *use_number;
1160 
1161 		if (zstr(tech_pvt->dest)) {
1162 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "URL Error!\n");
1163 			switch_goto_status(SWITCH_STATUS_FALSE, end);
1164 		}
1165 
1166 		if ((d_url = sofia_glue_get_url_from_contact(tech_pvt->dest, 1))) {
1167 			url = d_url;
1168 		} else {
1169 			url = tech_pvt->dest;
1170 		}
1171 
1172 		if (!tech_pvt->from_str) {
1173 			const char *sipip;
1174 			const char *format;
1175 			char *use_cid_num = switch_core_session_url_encode(tech_pvt->session, cid_num);
1176 
1177 			sipip = tech_pvt->profile->sipip;
1178 
1179 			if (!zstr(tech_pvt->mparams.remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->mparams.remote_ip)) {
1180 				sipip = tech_pvt->profile->extsipip;
1181 			}
1182 
1183 			if (!zstr(invite_domain)) {
1184 				sipip = invite_domain;
1185 			}
1186 
1187 			format = strchr(sipip, ':') ? "\"%s\" <sip:%s%s[%s]>" : "\"%s\" <sip:%s%s%s>";
1188 
1189 			tech_pvt->from_str = switch_core_session_sprintf(tech_pvt->session, format, cid_name, use_cid_num, !zstr(cid_num) ? "@" : "", sipip);
1190 		}
1191 
1192 		if (from_var) {
1193 			if (strncasecmp(from_var, "sip:", 4) || strncasecmp(from_var, "sips:", 5)) {
1194 				use_from_str = switch_core_session_strdup(tech_pvt->session, from_var);
1195 			} else {
1196 				use_from_str = switch_core_session_sprintf(tech_pvt->session, "sip:%s", from_var);
1197 			}
1198 		} else if (!zstr(tech_pvt->gateway_from_str)) {
1199 			use_from_str = tech_pvt->gateway_from_str;
1200 		} else {
1201 			use_from_str = tech_pvt->from_str;
1202 		}
1203 
1204 		if (!zstr(tech_pvt->gateway_from_str)) {
1205 			rpid_domain = switch_core_session_strdup(session, tech_pvt->gateway_from_str);
1206 		} else if (!zstr(tech_pvt->from_str)) {
1207 			rpid_domain = switch_core_session_strdup(session, use_from_str);
1208 		}
1209 
1210 		sofia_glue_get_url_from_contact(rpid_domain, 0);
1211 		if ((rpid_domain = strrchr(rpid_domain, '@'))) {
1212 			rpid_domain++;
1213 			if ((p = strchr(rpid_domain, ';'))) {
1214 				*p = '\0';
1215 			}
1216 		}
1217 
1218 		if (sofia_test_pflag(tech_pvt->profile, PFLAG_AUTO_NAT)) {
1219 			if (!zstr(tech_pvt->mparams.remote_ip) && !zstr(tech_pvt->profile->extsipip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->mparams.remote_ip)) {
1220 				rpid_domain = tech_pvt->profile->extsipip;
1221 			} else {
1222 				rpid_domain = tech_pvt->profile->sipip;
1223 			}
1224 		}
1225 
1226 		if (!zstr(invite_domain)) {
1227 			rpid_domain = (char *)invite_domain;
1228 		}
1229 
1230 		if (zstr(rpid_domain)) {
1231 			rpid_domain = "cluecon.com";
1232 		}
1233 
1234 		if (!zstr(tech_pvt->dest)) {
1235 			dst = sofia_glue_get_destination(tech_pvt->dest);
1236 		}
1237 
1238 		/*
1239 		 * Ignore transport chanvar and uri parameter for gateway connections
1240 		 * since all of them have been already taken care of in mod_sofia.c:sofia_outgoing_channel()
1241 		 */
1242 		if (tech_pvt->transport == SOFIA_TRANSPORT_UNKNOWN && zstr(tech_pvt->gateway_name)) {
1243 			if (dst && dst->route_uri) {
1244 				p = dst->route_uri;
1245 			} else {
1246 				p = url;
1247 			}
1248 			if ((p = (char *) switch_stristr("port=", p))) {
1249 				p += 5;
1250 				tech_pvt->transport = sofia_glue_str2transport(p);
1251 			} else {
1252 				if ((t_var = switch_channel_get_variable(channel, "sip_transport"))) {
1253 					tech_pvt->transport = sofia_glue_str2transport(t_var);
1254 				}
1255 			}
1256 
1257 			if (tech_pvt->transport == SOFIA_TRANSPORT_UNKNOWN) {
1258 				tech_pvt->transport = SOFIA_TRANSPORT_UDP;
1259 			}
1260 		}
1261 
1262 		if (!zstr(tech_pvt->mparams.remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->mparams.remote_ip)) {
1263 			tech_pvt->user_via = sofia_glue_create_external_via(session, tech_pvt->profile, tech_pvt->transport);
1264 		}
1265 
1266 		if (!sofia_test_pflag(tech_pvt->profile, PFLAG_TLS) && sofia_glue_transport_has_tls(tech_pvt->transport)) {
1267 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "TLS not supported by profile\n");
1268 			switch_goto_status(SWITCH_STATUS_FALSE, end);
1269 		}
1270 
1271 		if (zstr(tech_pvt->invite_contact)) {
1272 			const char *contact;
1273 			if ((contact = switch_channel_get_variable(channel, "sip_contact_user"))) {
1274 				char *ip_addr = tech_pvt->profile->sipip;
1275 				char *ipv6;
1276 
1277 				if ( !zstr(tech_pvt->mparams.remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->mparams.remote_ip ) ) {
1278 					ip_addr = tech_pvt->profile->extsipip;
1279 				}
1280 
1281 				ipv6 = strchr(ip_addr, ':');
1282 
1283 				if (sofia_glue_transport_has_tls(tech_pvt->transport)) {
1284 					tech_pvt->invite_contact = switch_core_session_sprintf(session, "sip:%s@%s%s%s:%d", contact,
1285 																		   ipv6 ? "[" : "", ip_addr, ipv6 ? "]" : "", tech_pvt->profile->tls_sip_port);
1286 				} else {
1287 					tech_pvt->invite_contact = switch_core_session_sprintf(session, "sip:%s@%s%s%s:%d", contact,
1288 																		   ipv6 ? "[" : "", ip_addr, ipv6 ? "]" : "", tech_pvt->profile->extsipport);
1289 				}
1290 			} else {
1291 				tech_pvt->invite_contact = sofia_glue_get_profile_url(tech_pvt->profile, tech_pvt->mparams.remote_ip, tech_pvt->transport);
1292 			}
1293 		}
1294 
1295 		url_str = sofia_overcome_sip_uri_weakness(session, url, tech_pvt->transport, SWITCH_TRUE, invite_params, invite_tel_params);
1296 		invite_contact = sofia_overcome_sip_uri_weakness(session, tech_pvt->invite_contact, tech_pvt->transport, SWITCH_FALSE, invite_contact_params, NULL);
1297 		from_str = sofia_overcome_sip_uri_weakness(session, invite_from_uri ? invite_from_uri : use_from_str, 0, SWITCH_TRUE, invite_from_params, NULL);
1298 		to_str = sofia_overcome_sip_uri_weakness(session, invite_to_uri ? invite_to_uri : tech_pvt->dest_to, 0, SWITCH_FALSE, invite_to_params, NULL);
1299 
1300 		switch_channel_set_variable(channel, "sip_outgoing_contact_uri", invite_contact);
1301 
1302 		/*
1303 		  Does the "genius" who wanted SIP to be "text-based" so it was "easier to read" even use it now,
1304 		  or did he just suggest it to make our lives miserable?
1305 		*/
1306 		use_from_str = from_str;
1307 
1308 		if (!switch_stristr("sip:", use_from_str)) {
1309 			use_from_str = switch_core_session_sprintf(session, "sip:%s", use_from_str);
1310 		}
1311 
1312 		if (!from_display && (!strcasecmp(tech_pvt->caller_profile->caller_id_name, "_undef_") || zstr(tech_pvt->caller_profile->caller_id_name))) {
1313 			from_str = switch_core_session_sprintf(session, "<%s>", use_from_str);
1314 		} else {
1315 			char *name = switch_core_session_strdup(session, from_display ? from_display : tech_pvt->caller_profile->caller_id_name);
1316 			check_decode(name, session);
1317 			from_str = switch_core_session_sprintf(session, "\"%s\" <%s>", name, use_from_str);
1318 		}
1319 
1320 		if (!(call_id = switch_channel_get_variable(channel, "sip_invite_call_id"))) {
1321 			if (sofia_test_pflag(tech_pvt->profile, PFLAG_UUID_AS_CALLID)) {
1322 				call_id = switch_core_session_get_uuid(session);
1323 			}
1324 		}
1325 
1326 		if (handle_full_from) {
1327 			from_str = (char *) handle_full_from;
1328 		}
1329 
1330 		if (handle_full_to) {
1331 			to_str = (char *) handle_full_to;
1332 		}
1333 
1334 
1335 		if (force_full_from) {
1336 			from_str = (char *) force_full_from;
1337 		}
1338 
1339 		if (force_full_to) {
1340 			to_str = (char *) force_full_to;
1341 		}
1342 
1343 
1344 		if (invite_req_uri) {
1345 			url_str = (char *) invite_req_uri;
1346 		}
1347 
1348 		if (url_str) {
1349 			char *s = NULL;
1350 			if (!strncasecmp(url_str, "sip:", 4)) {
1351 				s = url_str + 4;
1352 			}
1353 			if (!strncasecmp(url_str, "sips:", 5)) {
1354 				s = url_str + 5;
1355 			}
1356 
1357 			/* tel: patch from jaybinks, added by MC
1358                It compiles but I don't have a way to test it
1359 			*/
1360 			if (!strncasecmp(url_str, "tel:", 4)) {
1361 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session),
1362 								  SWITCH_LOG_ERROR, "URL Error! tel: uri's not supported at this time\n");
1363 				switch_goto_status(SWITCH_STATUS_FALSE, end);
1364 			}
1365 			if (!s) {
1366 				s = url_str;
1367 			}
1368 			switch_channel_set_variable(channel, "sip_req_uri", s);
1369 		}
1370 
1371 		switch_channel_set_variable(channel, "sip_to_host", sofia_glue_get_host(to_str, switch_core_session_get_pool(session)));
1372 		switch_channel_set_variable(channel, "sip_from_host", sofia_glue_get_host(from_str, switch_core_session_get_pool(session)));
1373 
1374 		if (!(tech_pvt->nh = nua_handle(tech_pvt->profile->nua, NULL,
1375 										NUTAG_URL(url_str),
1376 										TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
1377 										TAG_IF(!zstr(record_route), SIPTAG_HEADER_STR(record_route)),
1378 										SIPTAG_TO_STR(to_str), SIPTAG_FROM_STR(from_str), SIPTAG_CONTACT_STR(invite_contact), TAG_END()))) {
1379 
1380 			switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT,
1381 							  "Error creating HANDLE!\nurl_str=[%s]\ncall_id=[%s]\nto_str=[%s]\nfrom_str=[%s]\ninvite_contact=[%s]\n",
1382 							  url_str,
1383 							  call_id ? call_id : "N/A",
1384 							  to_str,
1385 							  from_str,
1386 							  invite_contact);
1387 
1388 			switch_safe_free(d_url);
1389 			switch_goto_status(SWITCH_STATUS_FALSE, end);
1390 		}
1391 
1392 		if (tech_pvt->dest && (strstr(tech_pvt->dest, ";fs_nat") || strstr(tech_pvt->dest, ";received")
1393 							   || ((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val)))) {
1394 			sofia_set_flag(tech_pvt, TFLAG_NAT);
1395 			tech_pvt->record_route = switch_core_session_strdup(tech_pvt->session, url_str);
1396 			if (!dst || !dst->route_uri) {
1397 				route_uri = tech_pvt->record_route;
1398 			}
1399 			session_timeout = SOFIA_NAT_SESSION_TIMEOUT;
1400 			switch_channel_set_variable(channel, "sip_nat_detected", "true");
1401 		}
1402 
1403 		if ((val = switch_channel_get_variable(channel, "sip_cid_type"))) {
1404 			cid_type = sofia_cid_name2type(val);
1405 		}
1406 
1407 		if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING) && switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_INBOUND) {
1408 			if (zstr((use_name = switch_channel_get_variable(tech_pvt->channel, "effective_callee_id_name"))) &&
1409 				zstr((use_name = switch_channel_get_variable(tech_pvt->channel, "sip_callee_id_name")))) {
1410 				if (!(use_name = switch_channel_get_variable(tech_pvt->channel, "sip_to_display"))) {
1411 					use_name = switch_channel_get_variable(tech_pvt->channel, "sip_to_user");
1412 				}
1413 			}
1414 
1415 			if (zstr((use_number = switch_channel_get_variable(tech_pvt->channel, "effective_callee_id_number"))) &&
1416 				zstr((use_number = switch_channel_get_variable(tech_pvt->channel, "sip_callee_id_number")))) {
1417 				use_number = switch_channel_get_variable(tech_pvt->channel, "sip_to_user");
1418 			}
1419 
1420 			if (zstr(use_name) && zstr(use_name = tech_pvt->caller_profile->callee_id_name)) {
1421 				use_name = tech_pvt->caller_profile->caller_id_name;
1422 			}
1423 
1424 			if (zstr(use_number) && zstr(use_number = tech_pvt->caller_profile->callee_id_number)) {
1425 				use_number = tech_pvt->caller_profile->caller_id_number;
1426 			}
1427 		} else {
1428 			use_name = tech_pvt->caller_profile->caller_id_name;
1429 			use_number = tech_pvt->caller_profile->caller_id_number;
1430 		}
1431 
1432 		check_decode(use_name, session);
1433 
1434 		switch (cid_type) {
1435 		case CID_TYPE_PID:
1436 			if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
1437 				if (zstr(tech_pvt->caller_profile->caller_id_name) || !strcasecmp(tech_pvt->caller_profile->caller_id_name, "_undef_")) {
1438 					tech_pvt->asserted_id = switch_core_session_sprintf(tech_pvt->session, "<sip:%s@%s%s%s>",
1439 																		use_number, rpid_domain,
1440 																		invite_pid_params ? ";" : "",
1441 																		invite_pid_params ? invite_pid_params : "");
1442 				} else {
1443 					tech_pvt->asserted_id = switch_core_session_sprintf(tech_pvt->session, "\"%s\" <sip:%s@%s%s%s>",
1444 																		use_name, use_number, rpid_domain,
1445 																		invite_pid_params ? ";" : "",
1446 																		invite_pid_params ? invite_pid_params : "");
1447 				}
1448 			} else {
1449 				if (zstr(tech_pvt->caller_profile->caller_id_name) || !strcasecmp(tech_pvt->caller_profile->caller_id_name, "_undef_")) {
1450 					tech_pvt->preferred_id = switch_core_session_sprintf(tech_pvt->session, "<sip:%s@%s%s%s>",
1451 																		 tech_pvt->caller_profile->caller_id_number, rpid_domain,
1452 																		 invite_pid_params ? ";" : "",
1453 																		 invite_pid_params ? invite_pid_params : "");
1454 				} else {
1455 					tech_pvt->preferred_id = switch_core_session_sprintf(tech_pvt->session, "\"%s\" <sip:%s@%s%s%s>",
1456 																		 tech_pvt->caller_profile->caller_id_name,
1457 																		 tech_pvt->caller_profile->caller_id_number, rpid_domain,
1458 																		 invite_pid_params ? ";" : "",
1459 																		 invite_pid_params ? invite_pid_params : "");
1460 				}
1461 			}
1462 
1463 			if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
1464 				tech_pvt->privacy = "id";
1465 			} else {
1466 				if (!(val = switch_channel_get_variable(channel, "sip_cid_suppress_privacy_none")) || !switch_true(val)) {
1467 					tech_pvt->privacy = "none";
1468 				}
1469 			}
1470 
1471 			break;
1472 		case CID_TYPE_RPID:
1473 			{
1474 				if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NAME)) {
1475 					priv = "name";
1476 					if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
1477 						priv = "full";
1478 					}
1479 				} else if (switch_test_flag(caller_profile, SWITCH_CPF_HIDE_NUMBER)) {
1480 					priv = "full";
1481 				}
1482 
1483 				if (switch_test_flag(caller_profile, SWITCH_CPF_SCREEN)) {
1484 					screen = "yes";
1485 				}
1486 
1487 				if (zstr(tech_pvt->caller_profile->caller_id_name) || !strcasecmp(tech_pvt->caller_profile->caller_id_name, "_undef_")) {
1488 					tech_pvt->rpid = switch_core_session_sprintf(tech_pvt->session, "<sip:%s@%s>;party=calling;screen=%s;privacy=%s",
1489 																 use_number, rpid_domain, screen, priv);
1490 				} else {
1491 					tech_pvt->rpid = switch_core_session_sprintf(tech_pvt->session, "\"%s\"<sip:%s@%s>;party=calling;screen=%s;privacy=%s",
1492 																 use_name, use_number, rpid_domain, screen, priv);
1493 				}
1494 			}
1495 			break;
1496 		default:
1497 			break;
1498 		}
1499 
1500 
1501 		switch_safe_free(d_url);
1502 
1503 		if (!(sofia_private = su_alloc(tech_pvt->nh->nh_home, sizeof(*sofia_private)))) {
1504 			abort();
1505 		}
1506 
1507 		memset(sofia_private, 0, sizeof(*sofia_private));
1508 		sofia_private->is_call = 2;
1509 		sofia_private->is_static++;
1510 
1511 		if (switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING)) {
1512 			sofia_private->is_call++;
1513 		}
1514 
1515 		tech_pvt->sofia_private = sofia_private;
1516 		switch_copy_string(tech_pvt->sofia_private->uuid_str, switch_core_session_get_uuid(session), sizeof(tech_pvt->sofia_private->uuid_str));
1517 		tech_pvt->sofia_private->uuid = tech_pvt->sofia_private->uuid_str;
1518 		nua_handle_bind(tech_pvt->nh, tech_pvt->sofia_private);
1519 	}
1520 
1521 	if (tech_pvt->e_dest && sofia_test_pflag(tech_pvt->profile, PFLAG_IN_DIALOG_CHAT)) {
1522 		char *user = NULL, *host = NULL;
1523 		char hash_key[256] = "";
1524 
1525 		e_dest = strdup(tech_pvt->e_dest);
1526 		switch_assert(e_dest != NULL);
1527 		user = e_dest;
1528 
1529 		if ((host = strchr(user, '@'))) {
1530 			*host++ = '\0';
1531 		}
1532 		switch_snprintf(hash_key, sizeof(hash_key), "%s%s%s", user, host, cid_num);
1533 
1534 		tech_pvt->chat_from = tech_pvt->from_str;
1535 		tech_pvt->chat_to = tech_pvt->dest;
1536 		if (tech_pvt->profile->pres_type) {
1537 			tech_pvt->hash_key = switch_core_session_strdup(tech_pvt->session, hash_key);
1538 			switch_mutex_lock(tech_pvt->profile->flag_mutex);
1539 			switch_core_hash_insert(tech_pvt->profile->chat_hash, tech_pvt->hash_key, tech_pvt);
1540 			switch_mutex_unlock(tech_pvt->profile->flag_mutex);
1541 		}
1542 		free(e_dest);
1543 	}
1544 
1545 	holdstr = sofia_test_flag(tech_pvt, TFLAG_SIP_HOLD) ? hold_char : "";
1546 
1547 	if (!switch_channel_get_variable(channel, "sofia_profile_name")) {
1548 		switch_channel_set_variable(channel, "sofia_profile_name", tech_pvt->profile->name);
1549 		switch_channel_set_variable(channel, "recovery_profile_name", tech_pvt->profile->name);
1550 		switch_channel_set_variable(channel, "sofia_profile_url", tech_pvt->profile->url);
1551 	}
1552 
1553 	extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_HEADER_PREFIX);
1554 
1555 	if ((val = switch_channel_get_variable(channel, SOFIA_SESSION_TIMEOUT))) {
1556 		int v_session_timeout = atoi(val);
1557 		if (v_session_timeout >= 0) {
1558 			session_timeout = v_session_timeout;
1559 		}
1560 	}
1561 
1562 	if (switch_channel_test_flag(channel, CF_PROXY_MEDIA)) {
1563 		switch_core_media_proxy_remote_addr(session, NULL);
1564 		switch_core_media_patch_sdp(tech_pvt->session);
1565 	}
1566 
1567 	if (!zstr(tech_pvt->dest)) {
1568 		if (!dst) {
1569 			dst = sofia_glue_get_destination(tech_pvt->dest);
1570 		}
1571 
1572 		if (dst->route_uri) {
1573 			route_uri = sofia_overcome_sip_uri_weakness(tech_pvt->session, dst->route_uri, tech_pvt->transport, SWITCH_TRUE, NULL, NULL);
1574 		}
1575 
1576 		if (dst->route) {
1577 			route = dst->route;
1578 		}
1579 	}
1580 
1581 	if ((val = switch_channel_get_variable(channel, "sip_route_uri"))) {
1582 		route_uri = switch_core_session_strdup(session, val);
1583 		route = NULL;
1584 	}
1585 
1586 	if (route_uri) {
1587 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s Setting proxy route to %s\n", route_uri,
1588 						  switch_channel_get_name(channel));
1589 		tech_pvt->route_uri = switch_core_session_strdup(tech_pvt->session, route_uri);
1590 	}
1591 
1592 
1593 	if ((val = switch_channel_get_variable(tech_pvt->channel, "sip_invite_cseq"))) {
1594 		uint32_t callsequence = (uint32_t) strtoul(val, NULL, 10);
1595 		cseq = sip_cseq_create(tech_pvt->nh->nh_home, callsequence, SIP_METHOD_INVITE);
1596 	}
1597 
1598 
1599 	switch_channel_clear_flag(channel, CF_MEDIA_ACK);
1600 
1601 	if (handle_full_from) {
1602 		tech_pvt->nh->nh_has_invite = 1;
1603 	}
1604 
1605 	if ((mp = sofia_media_get_multipart(session, "sip_multipart", tech_pvt->mparams.local_sdp_str, &mp_type))) {
1606 		sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
1607 	}
1608 
1609 	if ((tech_pvt->session_timeout = session_timeout)) {
1610 		tech_pvt->session_refresher = switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND ? nua_local_refresher : nua_remote_refresher;
1611 		if (sofia_test_pflag(tech_pvt->profile, PFLAG_UPDATE_REFRESHER) || switch_channel_var_true(tech_pvt->channel, "sip_update_refresher")) {
1612 			tech_pvt->update_refresher = 1;
1613 		}
1614 	} else {
1615 		tech_pvt->session_refresher = nua_no_refresher;
1616 	}
1617 
1618 	switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_DEBUG, "%s sending invite version: %s\nLocal SDP:\n%s\n",
1619 					  switch_channel_get_name(tech_pvt->channel), switch_version_full_human(),
1620 					  tech_pvt->mparams.local_sdp_str ? tech_pvt->mparams.local_sdp_str : "NO SDP PRESENT\n");
1621 
1622 
1623 
1624 	if ((switch_channel_get_private(tech_pvt->channel, "t38_options")) ||
1625 		((switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE) ||
1626 		  switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MEDIA) )
1627 			&& switch_stristr("m=image", tech_pvt->mparams.local_sdp_str))) {
1628 		sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
1629 		is_t38 = 1;
1630     }
1631 
1632 
1633 	if (sofia_use_soa(tech_pvt)) {
1634 		nua_invite(tech_pvt->nh,
1635 				   NUTAG_AUTOANSWER(0),
1636 				   //TAG_IF(zstr(tech_pvt->mparams.local_sdp_str), NUTAG_AUTOACK(0)),
1637 				   //TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), NUTAG_AUTOACK(1)),
1638 				   // The code above is breaking things...... grrr WE need this because we handle our own acks and there are 3pcc cases in there too
1639 				   NUTAG_AUTOACK(0),
1640 				   NUTAG_SESSION_TIMER(tech_pvt->session_timeout),
1641 				   NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher),
1642 				   NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher),
1643 				   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1644 				   TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)),
1645 				   TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)),
1646 				   TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)),
1647 				   TAG_IF(tech_pvt->redirected, NUTAG_URL(tech_pvt->redirected)),
1648 				   TAG_IF(!zstr(recover_via), SIPTAG_VIA_STR(recover_via)),
1649 				   TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
1650 				   TAG_IF(!zstr(tech_pvt->rpid), SIPTAG_REMOTE_PARTY_ID_STR(tech_pvt->rpid)),
1651 				   TAG_IF(!zstr(tech_pvt->preferred_id), SIPTAG_P_PREFERRED_IDENTITY_STR(tech_pvt->preferred_id)),
1652 				   TAG_IF(!zstr(tech_pvt->asserted_id), SIPTAG_P_ASSERTED_IDENTITY_STR(tech_pvt->asserted_id)),
1653 				   TAG_IF(!zstr(tech_pvt->privacy), SIPTAG_PRIVACY_STR(tech_pvt->privacy)),
1654 				   TAG_IF(!zstr(alert_info), SIPTAG_HEADER_STR(alert_info)),
1655 				   TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
1656 				   TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID), SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)),
1657 				   TAG_IF(!zstr(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)),
1658 				   TAG_IF(!zstr(route_uri), NUTAG_PROXY(route_uri)),
1659 				   TAG_IF(!zstr(invite_route_uri), NUTAG_INITIAL_ROUTE_STR(invite_route_uri)),
1660 				   TAG_IF(!zstr(route), SIPTAG_ROUTE_STR(route)),
1661 				   TAG_IF(tech_pvt->profile->minimum_session_expires, NUTAG_MIN_SE(tech_pvt->profile->minimum_session_expires)),
1662 				   TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
1663 				   TAG_IF(content_encoding, SIPTAG_CONTENT_ENCODING_STR(content_encoding)),
1664 				   TAG_IF(zstr(tech_pvt->mparams.local_sdp_str), SIPTAG_PAYLOAD_STR("")),
1665 				   TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_ADDRESS(tech_pvt->mparams.adv_sdp_audio_ip)),
1666 				   TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str)),
1667 				   TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_REUSE_REJECTED(1)),
1668 				   TAG_IF(is_t38, SOATAG_ORDERED_USER(1)),
1669 				   TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE)),
1670 				   TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL)),
1671 				   TAG_IF(rep, SIPTAG_REPLACES_STR(rep)),
1672 				   TAG_IF(!require_timer, NUTAG_TIMER_AUTOREQUIRE(0)),
1673 				   TAG_IF(!zstr(tech_pvt->mparams.local_sdp_str), SOATAG_HOLD(holdstr)), TAG_END());
1674 	} else {
1675 		nua_invite(tech_pvt->nh,
1676 				   NUTAG_AUTOANSWER(0),
1677 				   NUTAG_AUTOACK(0),
1678 				   NUTAG_SESSION_TIMER(tech_pvt->session_timeout),
1679 				   NUTAG_SESSION_REFRESHER(tech_pvt->session_refresher),
1680 				   NUTAG_UPDATE_REFRESH(tech_pvt->update_refresher),
1681 				   TAG_IF(!zstr(session_id_header), SIPTAG_HEADER_STR(session_id_header)),
1682 				   TAG_IF(sofia_test_flag(tech_pvt, TFLAG_RECOVERED), NUTAG_INVITE_TIMER(UINT_MAX)),
1683 				   TAG_IF(invite_full_from, SIPTAG_FROM_STR(invite_full_from)),
1684 				   TAG_IF(invite_full_to, SIPTAG_TO_STR(invite_full_to)),
1685 				   TAG_IF(tech_pvt->redirected, NUTAG_URL(tech_pvt->redirected)),
1686 				   TAG_IF(!zstr(recover_via), SIPTAG_VIA_STR(recover_via)),
1687 				   TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
1688 				   TAG_IF(!zstr(tech_pvt->rpid), SIPTAG_REMOTE_PARTY_ID_STR(tech_pvt->rpid)),
1689 				   TAG_IF(!zstr(tech_pvt->preferred_id), SIPTAG_P_PREFERRED_IDENTITY_STR(tech_pvt->preferred_id)),
1690 				   TAG_IF(!zstr(tech_pvt->asserted_id), SIPTAG_P_ASSERTED_IDENTITY_STR(tech_pvt->asserted_id)),
1691 				   TAG_IF(!zstr(tech_pvt->privacy), SIPTAG_PRIVACY_STR(tech_pvt->privacy)),
1692 				   TAG_IF(!zstr(alert_info), SIPTAG_HEADER_STR(alert_info)),
1693 				   TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
1694 				   TAG_IF(sofia_test_pflag(tech_pvt->profile, PFLAG_PASS_CALLEE_ID), SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)),
1695 				   TAG_IF(!zstr(max_forwards), SIPTAG_MAX_FORWARDS_STR(max_forwards)),
1696 				   TAG_IF(!zstr(route_uri), NUTAG_PROXY(route_uri)),
1697 				   TAG_IF(!zstr(route), SIPTAG_ROUTE_STR(route)),
1698 				   TAG_IF(!zstr(invite_route_uri), NUTAG_INITIAL_ROUTE_STR(invite_route_uri)),
1699 				   TAG_IF(tech_pvt->profile->minimum_session_expires, NUTAG_MIN_SE(tech_pvt->profile->minimum_session_expires)),
1700 				   TAG_IF(!require_timer, NUTAG_TIMER_AUTOREQUIRE(0)),
1701 				   TAG_IF(cseq, SIPTAG_CSEQ(cseq)),
1702 				   TAG_IF(content_encoding, SIPTAG_CONTENT_ENCODING_STR(content_encoding)),
1703 				   NUTAG_MEDIA_ENABLE(0),
1704 				   SIPTAG_CONTENT_TYPE_STR(mp_type ? mp_type : "application/sdp"),
1705 				   SIPTAG_PAYLOAD_STR(mp ? mp : tech_pvt->mparams.local_sdp_str), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), SOATAG_HOLD(holdstr), TAG_END());
1706 	}
1707 
1708 	switch_safe_free(extra_headers);
1709 	switch_safe_free(mp);
1710 	tech_pvt->redirected = NULL;
1711 
1712 	status = SWITCH_STATUS_SUCCESS;
1713 
1714 end:
1715 
1716 	if (dst) {
1717 		sofia_glue_free_destination(dst);
1718 	}
1719 
1720 	return status;
1721 }
1722 
sofia_glue_do_xfer_invite(switch_core_session_t * session)1723 void sofia_glue_do_xfer_invite(switch_core_session_t *session)
1724 {
1725 	private_object_t *tech_pvt = switch_core_session_get_private(session);
1726 	switch_channel_t *channel = switch_core_session_get_channel(session);
1727 	switch_caller_profile_t *caller_profile;
1728 	const char *sipip, *format, *contact_url;
1729 
1730 	switch_assert(tech_pvt != NULL);
1731 	switch_mutex_lock(tech_pvt->sofia_mutex);
1732 	caller_profile = switch_channel_get_caller_profile(channel);
1733 
1734 	if (!zstr(tech_pvt->mparams.remote_ip) && sofia_glue_check_nat(tech_pvt->profile, tech_pvt->mparams.remote_ip)) {
1735 		sipip = tech_pvt->profile->extsipip;
1736 		contact_url = tech_pvt->profile->public_url;
1737 	} else {
1738 		sipip = tech_pvt->profile->extsipip ? tech_pvt->profile->extsipip : tech_pvt->profile->sipip;
1739 		contact_url = tech_pvt->profile->url;
1740 	}
1741 
1742 	format = strchr(sipip, ':') ? "\"%s\" <sip:%s@[%s]>" : "\"%s\" <sip:%s@%s>";
1743 
1744 	if ((tech_pvt->from_str = switch_core_session_sprintf(session, format, caller_profile->caller_id_name, caller_profile->caller_id_number, sipip))) {
1745 
1746 		const char *rep = switch_channel_get_variable(channel, SOFIA_REPLACES_HEADER);
1747 
1748 		tech_pvt->nh2 = nua_handle(tech_pvt->profile->nua, NULL,
1749 								   SIPTAG_TO_STR(tech_pvt->dest), SIPTAG_FROM_STR(tech_pvt->from_str), SIPTAG_CONTACT_STR(contact_url), TAG_END());
1750 
1751 		nua_handle_bind(tech_pvt->nh2, tech_pvt->sofia_private);
1752 
1753 		nua_invite(tech_pvt->nh2,
1754 				   SIPTAG_CONTACT_STR(contact_url),
1755 				   TAG_IF(!zstr(tech_pvt->user_via), SIPTAG_VIA_STR(tech_pvt->user_via)),
1756 				   SOATAG_ADDRESS(tech_pvt->mparams.adv_sdp_audio_ip),
1757 				   SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
1758 				   SOATAG_REUSE_REJECTED(1),
1759 				   SOATAG_RTP_SORT(SOA_RTP_SORT_REMOTE), SOATAG_RTP_SELECT(SOA_RTP_SELECT_ALL), TAG_IF(rep, SIPTAG_REPLACES_STR(rep)), TAG_END());
1760 	} else {
1761 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(tech_pvt->session), SWITCH_LOG_ERROR, "Memory Error!\n");
1762 	}
1763 	switch_mutex_unlock(tech_pvt->sofia_mutex);
1764 }
1765 
1766 
1767 /* map sip responses to QSIG cause codes ala RFC4497 section 8.4.4 */
sofia_glue_sip_cause_to_freeswitch(int status)1768 switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status)
1769 {
1770 	switch (status) {
1771 	case 200:
1772 		return SWITCH_CAUSE_NORMAL_CLEARING;
1773 	case 401:
1774 	case 402:
1775 	case 403:
1776 	case 407:
1777 	case 603:
1778 	case 607:
1779 		return SWITCH_CAUSE_CALL_REJECTED;
1780 	case 404:
1781 		return SWITCH_CAUSE_UNALLOCATED_NUMBER;
1782 	case 485:
1783 	case 604:
1784 		return SWITCH_CAUSE_NO_ROUTE_DESTINATION;
1785 	case 408:
1786 	case 504:
1787 		return SWITCH_CAUSE_RECOVERY_ON_TIMER_EXPIRE;
1788 	case 410:
1789 		return SWITCH_CAUSE_NUMBER_CHANGED;
1790 	case 413:
1791 	case 414:
1792 	case 416:
1793 	case 420:
1794 	case 421:
1795 	case 423:
1796 	case 505:
1797 	case 513:
1798 		return SWITCH_CAUSE_INTERWORKING;
1799 	case 480:
1800 		return SWITCH_CAUSE_NO_USER_RESPONSE;
1801 	case 400:
1802 	case 481:
1803 	case 500:
1804 	case 503:
1805 		return SWITCH_CAUSE_NORMAL_TEMPORARY_FAILURE;
1806 	case 486:
1807 	case 600:
1808 		return SWITCH_CAUSE_USER_BUSY;
1809 	case 484:
1810 		return SWITCH_CAUSE_INVALID_NUMBER_FORMAT;
1811 	case 488:
1812 	case 606:
1813 		return SWITCH_CAUSE_INCOMPATIBLE_DESTINATION;
1814 	case 502:
1815 		return SWITCH_CAUSE_NETWORK_OUT_OF_ORDER;
1816 	case 405:
1817 		return SWITCH_CAUSE_SERVICE_UNAVAILABLE;
1818 	case 406:
1819 	case 415:
1820 	case 501:
1821 		return SWITCH_CAUSE_SERVICE_NOT_IMPLEMENTED;
1822 	case 482:
1823 	case 483:
1824 		return SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR;
1825 	case 487:
1826 		return SWITCH_CAUSE_ORIGINATOR_CANCEL;
1827 	default:
1828 		return SWITCH_CAUSE_NORMAL_UNSPECIFIED;
1829 	}
1830 }
1831 
sofia_glue_pass_sdp(private_object_t * tech_pvt,char * sdp)1832 void sofia_glue_pass_sdp(private_object_t *tech_pvt, char *sdp)
1833 {
1834 	const char *val;
1835 	switch_core_session_t *other_session;
1836 	switch_channel_t *other_channel;
1837 
1838 	if ((val = switch_channel_get_partner_uuid(tech_pvt->channel))
1839 		&& (other_session = switch_core_session_locate(val))) {
1840 		other_channel = switch_core_session_get_channel(other_session);
1841 		switch_channel_set_variable(other_channel, SWITCH_B_SDP_VARIABLE, sdp);
1842 
1843 #if 0
1844 		if (!sofia_test_flag(tech_pvt, TFLAG_CHANGE_MEDIA) && !switch_channel_test_flag(tech_pvt->channel, CF_RECOVERING) &&
1845 			(switch_channel_direction(other_channel) == SWITCH_CALL_DIRECTION_OUTBOUND &&
1846 			 switch_channel_direction(tech_pvt->channel) == SWITCH_CALL_DIRECTION_OUTBOUND && switch_channel_test_flag(tech_pvt->channel, CF_PROXY_MODE))) {
1847 			switch_ivr_nomedia(val, SMF_FORCE);
1848 			sofia_set_flag_locked(tech_pvt, TFLAG_CHANGE_MEDIA);
1849 		}
1850 #endif
1851 
1852 		switch_core_session_rwunlock(other_session);
1853 	}
1854 }
1855 
sofia_glue_get_path_from_contact(char * buf)1856 char *sofia_glue_get_path_from_contact(char *buf)
1857 {
1858 	char *p, *e, *path = NULL, *contact = NULL;
1859 
1860 	if (!buf) return NULL;
1861 
1862 	contact = sofia_glue_get_url_from_contact(buf, SWITCH_TRUE);
1863 
1864 	if (!contact) return NULL;
1865 
1866 	if ((p = strstr(contact, "fs_path="))) {
1867 		p += 8;
1868 
1869 		if (!zstr(p)) {
1870 			path = strdup(p);
1871 		}
1872 	}
1873 
1874 	if (!path) {
1875 		free(contact);
1876 		return NULL;
1877 	}
1878 
1879 	if ((e = strrchr(path, ';'))) {
1880 		*e = '\0';
1881 	}
1882 
1883 	switch_url_decode(path);
1884 
1885 	free(contact);
1886 
1887 	return path;
1888 }
1889 
sofia_glue_get_url_from_contact(char * buf,uint8_t to_dup)1890 char *sofia_glue_get_url_from_contact(char *buf, uint8_t to_dup)
1891 {
1892 	char *url = NULL, *e;
1893 
1894 	switch_assert(buf);
1895 
1896 	while(*buf == ' ') {
1897 		buf++;
1898 	}
1899 
1900 	if (*buf == '"') {
1901 		buf++;
1902 		if((e = strchr(buf, '"'))) {
1903 			buf = e+1;
1904 		}
1905 	}
1906 
1907 	while(*buf == ' ') {
1908 		buf++;
1909 	}
1910 
1911 	url = strchr(buf, '<');
1912 
1913 	if (url && (e = switch_find_end_paren(url, '<', '>'))) {
1914 		url++;
1915 		if (to_dup) {
1916 			url = strdup(url);
1917 			switch_assert(url);
1918 			e = strchr(url, '>');
1919 		}
1920 
1921 		*e = '\0';
1922 	} else {
1923 		if (url) buf++;
1924 
1925 		if (to_dup) {
1926 			url = strdup(buf);
1927 		} else {
1928 			url = buf;
1929 		}
1930 	}
1931 	return url;
1932 }
1933 
sofia_glue_profile_rdlock__(const char * file,const char * func,int line,sofia_profile_t * profile)1934 switch_status_t sofia_glue_profile_rdlock__(const char *file, const char *func, int line, sofia_profile_t *profile)
1935 {
1936 	switch_status_t status = switch_thread_rwlock_tryrdlock(profile->rwlock);
1937 	if (status != SWITCH_STATUS_SUCCESS) {
1938 		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is locked\n", profile->name);
1939 		return status;
1940 	}
1941 #ifdef SOFIA_DEBUG_RWLOCKS
1942 	switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX LOCK %s\n", profile->name);
1943 #endif
1944 	return status;
1945 }
1946 
sofia_glue_profile_exists(const char * key)1947 switch_bool_t sofia_glue_profile_exists(const char *key)
1948 {
1949 	switch_bool_t tf = SWITCH_FALSE;
1950 
1951 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
1952 	if (switch_core_hash_find(mod_sofia_globals.profile_hash, key)) {
1953 		tf = SWITCH_TRUE;
1954 	}
1955 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
1956 
1957 	return tf;
1958 }
1959 
sofia_glue_find_profile__(const char * file,const char * func,int line,const char * key)1960 sofia_profile_t *sofia_glue_find_profile__(const char *file, const char *func, int line, const char *key)
1961 {
1962 	sofia_profile_t *profile;
1963 
1964 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
1965 	if ((profile = (sofia_profile_t *) switch_core_hash_find(mod_sofia_globals.profile_hash, key))) {
1966 		if (!sofia_test_pflag(profile, PFLAG_RUNNING)) {
1967 #ifdef SOFIA_DEBUG_RWLOCKS
1968 			switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is not running\n", profile->name);
1969 #endif
1970 			profile = NULL;
1971 			goto done;
1972 		}
1973 		if (sofia_glue_profile_rdlock__(file, func, line, profile) != SWITCH_STATUS_SUCCESS) {
1974 			profile = NULL;
1975 		}
1976 	} else {
1977 #ifdef SOFIA_DEBUG_RWLOCKS
1978 		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "Profile %s is not in the hash\n", key);
1979 #endif
1980 	}
1981 
1982  done:
1983 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
1984 
1985 	return profile;
1986 }
1987 
sofia_glue_release_profile__(const char * file,const char * func,int line,sofia_profile_t * profile)1988 void sofia_glue_release_profile__(const char *file, const char *func, int line, sofia_profile_t *profile)
1989 {
1990 	if (profile) {
1991 #ifdef SOFIA_DEBUG_RWLOCKS
1992 		switch_log_printf(SWITCH_CHANNEL_ID_LOG, file, func, line, NULL, SWITCH_LOG_ERROR, "XXXXXXXXXXXXXX UNLOCK %s\n", profile->name);
1993 #endif
1994 		switch_thread_rwlock_unlock(profile->rwlock);
1995 	}
1996 }
1997 
sofia_glue_add_profile(char * key,sofia_profile_t * profile)1998 switch_status_t sofia_glue_add_profile(char *key, sofia_profile_t *profile)
1999 {
2000 	switch_status_t status = SWITCH_STATUS_FALSE;
2001 
2002 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
2003 	if (!switch_core_hash_find(mod_sofia_globals.profile_hash, key)) {
2004 		status = switch_core_hash_insert(mod_sofia_globals.profile_hash, key, profile);
2005 	}
2006 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2007 
2008 	return status;
2009 }
2010 
2011 
sofia_glue_del_every_gateway(sofia_profile_t * profile)2012 void sofia_glue_del_every_gateway(sofia_profile_t *profile)
2013 {
2014 	sofia_gateway_t *gp = NULL;
2015 
2016 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
2017 	for (gp = profile->gateways; gp; gp = gp->next) {
2018 		sofia_glue_del_gateway(gp);
2019 	}
2020 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2021 }
2022 
2023 
sofia_glue_gateway_list(sofia_profile_t * profile,switch_stream_handle_t * stream,int up)2024 void sofia_glue_gateway_list(sofia_profile_t *profile, switch_stream_handle_t *stream, int up)
2025 {
2026 	sofia_gateway_t *gp = NULL;
2027 
2028 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
2029 	for (gp = profile->gateways; gp; gp = gp->next) {
2030 		int reged = (gp->status == SOFIA_GATEWAY_UP);
2031 
2032 		if (up ? reged : !reged) {
2033 			stream->write_function(stream, "%s ", gp->name);
2034 		}
2035 	}
2036 
2037 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2038 }
2039 
2040 
sofia_glue_del_gateway(sofia_gateway_t * gp)2041 void sofia_glue_del_gateway(sofia_gateway_t *gp)
2042 {
2043 	if (!gp->deleted) {
2044 		if (gp->state != REG_STATE_NOREG) {
2045 			gp->retry = 0;
2046 			gp->state = REG_STATE_UNREGISTER;
2047 		}
2048 
2049 		gp->deleted = 1;
2050 	}
2051 }
2052 
sofia_glue_restart_all_profiles(void)2053 void sofia_glue_restart_all_profiles(void)
2054 {
2055 	switch_hash_index_t *hi;
2056 	const void *var;
2057 	void *val;
2058 	sofia_profile_t *pptr;
2059 	switch_xml_t xml_root;
2060 	const char *err;
2061 
2062 	if ((xml_root = switch_xml_open_root(1, &err))) {
2063 		switch_xml_free(xml_root);
2064 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Reload XML [%s]\n", err);
2065 	}
2066 
2067 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
2068 	if (mod_sofia_globals.profile_hash) {
2069 		for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2070 			switch_core_hash_this(hi, &var, NULL, &val);
2071 			if ((pptr = (sofia_profile_t *) val)) {
2072 				int rsec = 10;
2073 				int diff = (int) (switch_epoch_time_now(NULL) - pptr->started);
2074 				int remain = rsec - diff;
2075 				if (sofia_test_pflag(pptr, PFLAG_RESPAWN) || !sofia_test_pflag(pptr, PFLAG_RUNNING)) {
2076 					continue;
2077 				}
2078 
2079 				if (diff < rsec) {
2080 					switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,
2081 									  "Profile %s must be up for at least %d seconds to stop/restart.\nPlease wait %d second%s\n",
2082 									  pptr->name, rsec, remain, remain == 1 ? "" : "s");
2083 					continue;
2084 				}
2085 				sofia_set_pflag_locked(pptr, PFLAG_RESPAWN);
2086 				sofia_clear_pflag_locked(pptr, PFLAG_RUNNING);
2087 			}
2088 		}
2089 	}
2090 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2091 
2092 }
2093 
2094 
sofia_glue_global_siptrace(switch_bool_t on)2095 void sofia_glue_global_siptrace(switch_bool_t on)
2096 {
2097 	switch_hash_index_t *hi;
2098 	const void *var;
2099 	void *val;
2100 	sofia_profile_t *pptr;
2101 
2102 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
2103 	if (mod_sofia_globals.profile_hash) {
2104 		for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2105 			switch_core_hash_this(hi, &var, NULL, &val);
2106 			if ((pptr = (sofia_profile_t *) val)) {
2107 				nua_set_params(pptr->nua, TPTAG_LOG(on), TAG_END());
2108 			}
2109 		}
2110 	}
2111 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2112 
2113 }
2114 
sofia_glue_global_standby(switch_bool_t on)2115 void sofia_glue_global_standby(switch_bool_t on)
2116 {
2117 	switch_hash_index_t *hi;
2118 	const void *var;
2119 	void *val;
2120 	sofia_profile_t *pptr;
2121 
2122 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
2123 	if (mod_sofia_globals.profile_hash) {
2124 		for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2125 			switch_core_hash_this(hi, &var, NULL, &val);
2126 			if ((pptr = (sofia_profile_t *) val)) {
2127 				if (on) {
2128 					sofia_set_pflag_locked(pptr, PFLAG_STANDBY);
2129 				} else {
2130 					sofia_clear_pflag_locked(pptr, PFLAG_STANDBY);
2131 				}
2132 			}
2133 		}
2134 	}
2135 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2136 
2137 }
2138 
sofia_glue_global_capture(switch_bool_t on)2139 void sofia_glue_global_capture(switch_bool_t on)
2140 {
2141        switch_hash_index_t *hi;
2142        const void *var;
2143        void *val;
2144        sofia_profile_t *pptr;
2145 
2146        switch_mutex_lock(mod_sofia_globals.hash_mutex);
2147        if (mod_sofia_globals.profile_hash) {
2148                for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2149                        switch_core_hash_this(hi, &var, NULL, &val);
2150                        if ((pptr = (sofia_profile_t *) val)) {
2151                                nua_set_params(pptr->nua, TPTAG_CAPT(on ? mod_sofia_globals.capture_server : NULL), TAG_END());
2152                        }
2153                }
2154        }
2155        switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2156 
2157 }
2158 
2159 
sofia_glue_global_watchdog(switch_bool_t on)2160 void sofia_glue_global_watchdog(switch_bool_t on)
2161 {
2162 	switch_hash_index_t *hi;
2163 	const void *var;
2164 	void *val;
2165 	sofia_profile_t *pptr;
2166 
2167 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
2168 	if (mod_sofia_globals.profile_hash) {
2169 		for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2170 			switch_core_hash_this(hi, &var, NULL, &val);
2171 			if ((pptr = (sofia_profile_t *) val)) {
2172 				pptr->watchdog_enabled = (on ? 1 : 0);
2173 			}
2174 		}
2175 	}
2176 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2177 
2178 }
2179 
sofia_glue_del_profile(sofia_profile_t * profile)2180 void sofia_glue_del_profile(sofia_profile_t *profile)
2181 {
2182 	sofia_gateway_t *gp;
2183 	char *aliases[512];
2184 	int i = 0, j = 0;
2185 	switch_hash_index_t *hi;
2186 	const void *var;
2187 	void *val;
2188 	sofia_profile_t *pptr;
2189 
2190 	switch_mutex_lock(mod_sofia_globals.hash_mutex);
2191 	if (mod_sofia_globals.profile_hash) {
2192 		for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) {
2193 			switch_core_hash_this(hi, &var, NULL, &val);
2194 			if ((pptr = (sofia_profile_t *) val) && pptr == profile) {
2195 				aliases[i++] = strdup((char *) var);
2196 				if (i == 512) {
2197 					abort();
2198 				}
2199 			}
2200 		}
2201 
2202 		for (j = 0; j < i && j < 512; j++) {
2203 			switch_core_hash_delete(mod_sofia_globals.profile_hash, aliases[j]);
2204 			free(aliases[j]);
2205 		}
2206 
2207 		for (gp = profile->gateways; gp; gp = gp->next) {
2208 			char *pkey = switch_mprintf("%s::%s", profile->name, gp->name);
2209 
2210 			switch_core_hash_delete(mod_sofia_globals.gateway_hash, gp->name);
2211 			switch_core_hash_delete(mod_sofia_globals.gateway_hash, pkey);
2212 			switch_safe_free(pkey);
2213 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "deleted gateway %s from profile %s\n", gp->name, profile->name);
2214 		}
2215 		profile->gateways = NULL;
2216 	}
2217 	switch_mutex_unlock(mod_sofia_globals.hash_mutex);
2218 }
2219 
sofia_recover_callback(switch_core_session_t * session)2220 int sofia_recover_callback(switch_core_session_t *session)
2221 {
2222 
2223 	switch_channel_t *channel = switch_core_session_get_channel(session);
2224 	private_object_t *tech_pvt = NULL;
2225 	sofia_profile_t *profile = NULL;
2226 	const char *tmp;
2227 	const char *rr;
2228 	int r = 0;
2229 	const char *profile_name = switch_channel_get_variable_dup(channel, "recovery_profile_name", SWITCH_FALSE, -1);
2230 
2231 
2232 	if (zstr(profile_name)) {
2233 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Missing profile\n");
2234 		return 0;
2235 	}
2236 
2237 	if (!(profile = sofia_glue_find_profile(profile_name))) {
2238 		switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Invalid profile %s\n", profile_name);
2239 		return 0;
2240 	}
2241 
2242 
2243 	tech_pvt = (private_object_t *) switch_core_session_alloc(session, sizeof(private_object_t));
2244 	tech_pvt->channel = channel;
2245 
2246 	switch_mutex_init(&tech_pvt->flag_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
2247 	switch_mutex_init(&tech_pvt->sofia_mutex, SWITCH_MUTEX_NESTED, switch_core_session_get_pool(session));
2248 
2249 	tech_pvt->mparams.remote_ip = (char *) switch_channel_get_variable(channel, "sip_network_ip");
2250 	tech_pvt->mparams.remote_port = atoi(switch_str_nil(switch_channel_get_variable(channel, "sip_network_port")));
2251 	tech_pvt->caller_profile = switch_channel_get_caller_profile(channel);
2252 
2253 	if ((tmp = switch_channel_get_variable(tech_pvt->channel, "rtp_2833_send_payload"))) {
2254 		int te = atoi(tmp);
2255 		if (te > 64) {
2256 			tech_pvt->te = (switch_payload_t)te;
2257 		}
2258 	}
2259 
2260 	if ((tmp = switch_channel_get_variable(tech_pvt->channel, "rtp_2833_recv_payload"))) {
2261 		int te = atoi(tmp);
2262 		if (te > 64) {
2263 			tech_pvt->recv_te = (switch_payload_t)te;
2264 		}
2265 	}
2266 
2267 	rr = switch_channel_get_variable(channel, "sip_invite_record_route");
2268 
2269 	if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) {
2270 		int break_rfc = switch_true(switch_channel_get_variable(channel, "sip_recovery_break_rfc"));
2271 		tech_pvt->dest = switch_core_session_sprintf(session, "sip:%s", switch_channel_get_variable(channel, "sip_req_uri"));
2272 		switch_channel_set_variable(channel, "sip_handle_full_from", switch_channel_get_variable(channel, break_rfc ? "sip_full_to" : "sip_full_from"));
2273 		switch_channel_set_variable(channel, "sip_handle_full_to", switch_channel_get_variable(channel, break_rfc ? "sip_full_from" : "sip_full_to"));
2274 	} else {
2275 		const char *contact_params = switch_channel_get_variable(channel, "sip_contact_params");
2276 		const char *contact_uri = switch_channel_get_variable(channel, "sip_contact_uri");
2277 		tech_pvt->redirected = switch_core_session_sprintf(session, "sip:%s%s%s", contact_uri, contact_params ? ";" : "", switch_str_nil(contact_params));
2278 
2279 		if (zstr(rr)) {
2280 			switch_channel_set_variable_printf(channel, "sip_invite_route_uri", "<sip:%s@%s:%s;transport=%s>",
2281 											   switch_channel_get_variable(channel, "sip_from_user"),
2282 											   switch_channel_get_variable(channel, "sip_network_ip"),
2283 											   switch_channel_get_variable(channel, "sip_network_port"),
2284 											   switch_channel_get_variable(channel,"sip_via_protocol")
2285 											   );
2286 
2287 		}
2288 
2289 		tech_pvt->dest = switch_core_session_sprintf(session, "sip:%s", switch_channel_get_variable(channel, "sip_from_uri"));
2290 
2291 		if (!switch_channel_get_variable_dup(channel, "sip_handle_full_from", SWITCH_FALSE, -1)) {
2292 			switch_channel_set_variable(channel, "sip_handle_full_from", switch_channel_get_variable(channel, "sip_full_to"));
2293 		}
2294 
2295 		if (!switch_channel_get_variable_dup(channel, "sip_handle_full_to", SWITCH_FALSE, -1)) {
2296 			switch_channel_set_variable(channel, "sip_handle_full_to", switch_channel_get_variable(channel, "sip_full_from"));
2297 		}
2298 	}
2299 
2300 	if (rr && !switch_channel_get_variable(channel, "sip_invite_route_uri")) {
2301 		switch_channel_set_variable(channel, "sip_invite_route_uri", rr);
2302 	}
2303 
2304 	tech_pvt->dest_to = tech_pvt->dest;
2305 
2306 	sofia_glue_attach_private(session, profile, tech_pvt, NULL);
2307 	switch_channel_set_name(tech_pvt->channel, switch_channel_get_variable(channel, "channel_name"));
2308 
2309 
2310 	switch_channel_set_variable(channel, "sip_invite_call_id", switch_channel_get_variable(channel, "sip_call_id"));
2311 
2312 	if (switch_true(switch_channel_get_variable(channel, "sip_nat_detected"))) {
2313 		switch_channel_set_variable_printf(channel, "sip_route_uri", "sip:%s@%s:%s",
2314 										   switch_channel_get_variable(channel, "sip_req_user"),
2315 										   switch_channel_get_variable(channel, "sip_network_ip"), switch_channel_get_variable(channel, "sip_network_port")
2316 										   );
2317 	}
2318 
2319 	if (session) {
2320 		const char *use_uuid;
2321 
2322 		if ((use_uuid = switch_channel_get_variable(channel, "origination_uuid"))) {
2323 			if (switch_core_session_set_uuid(session, use_uuid) == SWITCH_STATUS_SUCCESS) {
2324 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s set UUID=%s\n", switch_channel_get_name(channel),
2325 								  use_uuid);
2326 			} else {
2327 				switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "%s set UUID=%s FAILED\n",
2328 								  switch_channel_get_name(channel), use_uuid);
2329 			}
2330 		}
2331 	}
2332 
2333 	r++;
2334 
2335 	sofia_glue_release_profile(profile);
2336 
2337 
2338 	return r;
2339 
2340 }
2341 
2342 
2343 
sofia_glue_recover(switch_bool_t flush)2344 int sofia_glue_recover(switch_bool_t flush)
2345 {
2346 	sofia_profile_t *profile;
2347 	int r = 0;
2348 	switch_console_callback_match_t *matches;
2349 
2350 
2351 	if (list_profiles_full(NULL, NULL, &matches, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
2352 		switch_console_callback_match_node_t *m;
2353 		for (m = matches->head; m; m = m->next) {
2354 			if ((profile = sofia_glue_find_profile(m->val))) {
2355 				r += sofia_glue_profile_recover(profile, flush);
2356 				sofia_glue_release_profile(profile);
2357 			}
2358 		}
2359 		switch_console_free_matches(&matches);
2360 	}
2361 	return r;
2362 }
2363 
sofia_glue_profile_recover(sofia_profile_t * profile,switch_bool_t flush)2364 int sofia_glue_profile_recover(sofia_profile_t *profile, switch_bool_t flush)
2365 {
2366 	int r = 0;
2367 
2368 	if (profile) {
2369 		sofia_clear_pflag_locked(profile, PFLAG_STANDBY);
2370 
2371 		if (flush) {
2372 			switch_core_recovery_flush(SOFIA_RECOVER, profile->name);
2373 		} else {
2374 			r = switch_core_recovery_recover(SOFIA_RECOVER, profile->name);
2375 		}
2376 	}
2377 
2378 	return r;
2379 }
2380 
2381 
sofia_glue_init_sql(sofia_profile_t * profile)2382 int sofia_glue_init_sql(sofia_profile_t *profile)
2383 {
2384 	char *test_sql = NULL;
2385 
2386 	char reg_sql[] =
2387 		"CREATE TABLE sip_registrations (\n"
2388 		"   call_id          VARCHAR(255),\n"
2389 		"   sip_user         VARCHAR(255),\n"
2390 		"   sip_host         VARCHAR(255),\n"
2391 		"   presence_hosts   VARCHAR(255),\n"
2392 		"   contact          VARCHAR(1024),\n"
2393 		"   status           VARCHAR(255),\n"
2394 		"   ping_status      VARCHAR(255),\n"
2395 		"   ping_count       INTEGER,\n"
2396 		"   ping_time        BIGINT,\n"
2397 		"   force_ping       INTEGER,\n"
2398 		"   rpid             VARCHAR(255),\n"
2399 		"   expires          BIGINT,\n"
2400 		"   ping_expires     INTEGER not null default 0,\n"
2401 		"   user_agent       VARCHAR(255),\n"
2402 		"   server_user      VARCHAR(255),\n"
2403 		"   server_host      VARCHAR(255),\n"
2404 		"   profile_name     VARCHAR(255),\n"
2405 		"   hostname         VARCHAR(255),\n"
2406 		"   network_ip       VARCHAR(255),\n"
2407 		"   network_port     VARCHAR(6),\n"
2408 		"   sip_username     VARCHAR(255),\n"
2409 		"   sip_realm        VARCHAR(255),\n"
2410 		"   mwi_user         VARCHAR(255),\n"
2411 		"   mwi_host         VARCHAR(255),\n"
2412 		"   orig_server_host VARCHAR(255),\n"
2413 		"   orig_hostname    VARCHAR(255),\n"
2414 		"   sub_host         VARCHAR(255)\n"
2415 		");\n";
2416 
2417 	char pres_sql[] =
2418 		"CREATE TABLE sip_presence (\n"
2419 		"   sip_user        VARCHAR(255),\n"
2420 		"   sip_host        VARCHAR(255),\n"
2421 		"   status          VARCHAR(255),\n"
2422 		"   rpid            VARCHAR(255),\n"
2423 		"   expires         BIGINT,\n"
2424 		"   user_agent      VARCHAR(255),\n"
2425 		"   profile_name    VARCHAR(255),\n"
2426 		"   hostname        VARCHAR(255),\n"
2427 		"   network_ip      VARCHAR(255),\n"
2428 		"   network_port    VARCHAR(6),\n"
2429 		"   open_closed     VARCHAR(255)\n"
2430 		");\n";
2431 
2432 	char dialog_sql[] =
2433 		"CREATE TABLE sip_dialogs (\n"
2434 		"   call_id         VARCHAR(255),\n"
2435 		"   uuid            VARCHAR(255),\n"
2436 		"   sip_to_user     VARCHAR(255),\n"
2437 		"   sip_to_host     VARCHAR(255),\n"
2438 		"   sip_from_user   VARCHAR(255),\n"
2439 		"   sip_from_host   VARCHAR(255),\n"
2440 		"   contact_user    VARCHAR(255),\n"
2441 		"   contact_host    VARCHAR(255),\n"
2442 		"   state           VARCHAR(255),\n"
2443 		"   direction       VARCHAR(255),\n"
2444 		"   user_agent      VARCHAR(255),\n"
2445 		"   profile_name    VARCHAR(255),\n"
2446 		"   hostname        VARCHAR(255),\n"
2447 		"   contact         VARCHAR(255),\n"
2448 		"   presence_id     VARCHAR(255),\n"
2449 		"   presence_data   VARCHAR(255),\n"
2450 		"   call_info       VARCHAR(255),\n"
2451 		"   call_info_state VARCHAR(255) default '',\n"
2452 		"   expires         BIGINT default 0,\n"
2453 		"   status          VARCHAR(255),\n"
2454 		"   rpid            VARCHAR(255),\n"
2455 		"   sip_to_tag      VARCHAR(255),\n"
2456 		"   sip_from_tag    VARCHAR(255),\n"
2457 		"   rcd             INTEGER not null default 0\n"
2458 		");\n";
2459 
2460 	char sub_sql[] =
2461 		"CREATE TABLE sip_subscriptions (\n"
2462 		"   proto           VARCHAR(255),\n"
2463 		"   sip_user        VARCHAR(255),\n"
2464 		"   sip_host        VARCHAR(255),\n"
2465 		"   sub_to_user     VARCHAR(255),\n"
2466 		"   sub_to_host     VARCHAR(255),\n"
2467 		"   presence_hosts  VARCHAR(255),\n"
2468 		"   event           VARCHAR(255),\n"
2469 		"   contact         VARCHAR(1024),\n"
2470 		"   call_id         VARCHAR(255),\n"
2471 		"   full_from       VARCHAR(255),\n"
2472 		"   full_via        VARCHAR(255),\n"
2473 		"   expires         BIGINT,\n"
2474 		"   user_agent      VARCHAR(255),\n"
2475 		"   accept          VARCHAR(255),\n"
2476 		"   profile_name    VARCHAR(255),\n"
2477 		"   hostname        VARCHAR(255),\n"
2478 		"   network_port    VARCHAR(6),\n"
2479 		"   network_ip      VARCHAR(255),\n"
2480 		"   version         INTEGER DEFAULT 0 NOT NULL,\n"
2481 		"   orig_proto      VARCHAR(255),\n"
2482 		"   full_to         VARCHAR(255)\n"
2483 		");\n";
2484 
2485 	char auth_sql[] =
2486 		"CREATE TABLE sip_authentication (\n"
2487 		"   nonce           VARCHAR(255),\n"
2488 		"   expires         BIGINT,"
2489 		"   profile_name    VARCHAR(255),\n"
2490 		"   hostname        VARCHAR(255),\n"
2491 		"   last_nc         INTEGER\n"
2492 		");\n";
2493 
2494 	/* should we move this glue to sofia_sla or keep it here where all db init happens? XXX MTK */
2495 	char shared_appearance_sql[] =
2496 		"CREATE TABLE sip_shared_appearance_subscriptions (\n"
2497 		"   subscriber        VARCHAR(255),\n"
2498 		"   call_id           VARCHAR(255),\n"
2499 		"   aor               VARCHAR(255),\n"
2500 		"   profile_name      VARCHAR(255),\n"
2501 		"   hostname          VARCHAR(255),\n"
2502 		"   contact_str       VARCHAR(255),\n"
2503 		"   network_ip        VARCHAR(255)\n"
2504 		");\n";
2505 
2506 	char shared_appearance_dialogs_sql[] =
2507 		"CREATE TABLE sip_shared_appearance_dialogs (\n"
2508 		"   profile_name      VARCHAR(255),\n"
2509 		"   hostname          VARCHAR(255),\n"
2510 		"   contact_str       VARCHAR(255),\n"
2511 		"   call_id           VARCHAR(255),\n"
2512 		"   network_ip        VARCHAR(255),\n"
2513 		"   expires           BIGINT\n"
2514 		");\n";
2515 
2516 
2517 	int x;
2518 	char *indexes[] = {
2519 		"create index sr_call_id on sip_registrations (call_id)",
2520 		"create index sr_sip_user on sip_registrations (sip_user)",
2521 		"create index sr_sip_host on sip_registrations (sip_host)",
2522 		"create index sr_sub_host on sip_registrations (sub_host)",
2523 		"create index sr_mwi_user on sip_registrations (mwi_user)",
2524 		"create index sr_mwi_host on sip_registrations (mwi_host)",
2525 		"create index sr_profile_name on sip_registrations (profile_name)",
2526 		"create index sr_presence_hosts on sip_registrations (presence_hosts)",
2527 		"create index sr_contact on sip_registrations (contact)",
2528 		"create index sr_expires on sip_registrations (expires)",
2529 		"create index sr_ping_expires on sip_registrations (ping_expires)",
2530 		"create index sr_hostname on sip_registrations (hostname)",
2531 		"create index sr_status on sip_registrations (status)",
2532 		"create index sr_ping_status on sip_registrations (ping_status)",
2533 		"create index sr_network_ip on sip_registrations (network_ip)",
2534 		"create index sr_network_port on sip_registrations (network_port)",
2535 		"create index sr_sip_username on sip_registrations (sip_username)",
2536 		"create index sr_sip_realm on sip_registrations (sip_realm)",
2537 		"create index sr_orig_server_host on sip_registrations (orig_server_host)",
2538 		"create index sr_orig_hostname on sip_registrations (orig_hostname)",
2539 		"create index ss_call_id on sip_subscriptions (call_id)",
2540 		"create index ss_multi on sip_subscriptions (call_id, profile_name, hostname)",
2541 		"create index ss_hostname on sip_subscriptions (hostname)",
2542 		"create index ss_network_ip on sip_subscriptions (network_ip)",
2543 		"create index ss_sip_user on sip_subscriptions (sip_user)",
2544 		"create index ss_sip_host on sip_subscriptions (sip_host)",
2545 		"create index ss_presence_hosts on sip_subscriptions (presence_hosts)",
2546 		"create index ss_event on sip_subscriptions (event)",
2547 		"create index ss_proto on sip_subscriptions (proto)",
2548 		"create index ss_sub_to_user on sip_subscriptions (sub_to_user)",
2549 		"create index ss_sub_to_host on sip_subscriptions (sub_to_host)",
2550 		"create index ss_expires on sip_subscriptions (expires)",
2551 		"create index ss_orig_proto on sip_subscriptions (orig_proto)",
2552 		"create index ss_network_port on sip_subscriptions (network_port)",
2553 		"create index ss_profile_name on sip_subscriptions (profile_name)",
2554 		"create index ss_version on sip_subscriptions (version)",
2555 		"create index ss_full_from on sip_subscriptions (full_from)",
2556 		"create index ss_contact on sip_subscriptions (contact)",
2557 		"create index sd_uuid on sip_dialogs (uuid)",
2558 		"create index sd_hostname on sip_dialogs (hostname)",
2559 		"create index sd_presence_data on sip_dialogs (presence_data)",
2560 		"create index sd_call_info on sip_dialogs (call_info)",
2561 		"create index sd_call_info_state on sip_dialogs (call_info_state)",
2562 		"create index sd_expires on sip_dialogs (expires)",
2563 		"create index sd_rcd on sip_dialogs (rcd)",
2564 		"create index sd_sip_to_tag on sip_dialogs (sip_to_tag)",
2565 		"create index sd_sip_from_user on sip_dialogs (sip_from_user)",
2566 		"create index sd_sip_from_host on sip_dialogs (sip_from_host)",
2567 		"create index sd_sip_to_host on sip_dialogs (sip_to_host)",
2568 		"create index sd_presence_id on sip_dialogs (presence_id)",
2569 		"create index sd_call_id on sip_dialogs (call_id)",
2570 		"create index sd_sip_from_tag on sip_dialogs (sip_from_tag)",
2571 		"create index sp_hostname on sip_presence (hostname)",
2572 		"create index sp_open_closed on sip_presence (open_closed)",
2573 		"create index sp_sip_user on sip_presence (sip_user)",
2574 		"create index sp_sip_host on sip_presence (sip_host)",
2575 		"create index sp_profile_name on sip_presence (profile_name)",
2576 		"create index sp_expires on sip_presence (expires)",
2577 		"create index sa_nonce on sip_authentication (nonce)",
2578 		"create index sa_hostname on sip_authentication (hostname)",
2579 		"create index sa_expires on sip_authentication (expires)",
2580 		"create index sa_last_nc on sip_authentication (last_nc)",
2581 		"create index ssa_hostname on sip_shared_appearance_subscriptions (hostname)",
2582 		"create index ssa_network_ip on sip_shared_appearance_subscriptions (network_ip)",
2583 		"create index ssa_subscriber on sip_shared_appearance_subscriptions (subscriber)",
2584 		"create index ssa_profile_name on sip_shared_appearance_subscriptions (profile_name)",
2585 		"create index ssa_aor on sip_shared_appearance_subscriptions (aor)",
2586 		"create index ssd_profile_name on sip_shared_appearance_dialogs (profile_name)",
2587 		"create index ssd_hostname on sip_shared_appearance_dialogs (hostname)",
2588 		"create index ssd_contact_str on sip_shared_appearance_dialogs (contact_str)",
2589 		"create index ssd_call_id on sip_shared_appearance_dialogs (call_id)",
2590 		"create index ssd_expires on sip_shared_appearance_dialogs (expires)",
2591 		NULL
2592 	};
2593 
2594 	switch_cache_db_handle_t *dbh = sofia_glue_get_db_handle(profile);
2595 	char *test2;
2596 	char *err;
2597 
2598 	if (!dbh) {
2599 		return 0;
2600 	}
2601 
2602 
2603 	test_sql = switch_mprintf("delete from sip_registrations where sub_host is null "
2604 							  "and hostname='%q' "
2605 							  "and network_ip like '%%' and network_port like '%%' and sip_username "
2606 							  "like '%%' and mwi_user  like '%%' and mwi_host like '%%' "
2607 							  "and orig_server_host like '%%' and orig_hostname like '%%'", mod_sofia_globals.hostname);
2608 
2609 
2610 	switch_cache_db_test_reactive(dbh, test_sql, "drop table sip_registrations", reg_sql);
2611 
2612 	switch_cache_db_test_reactive(dbh, "select ping_count from sip_registrations", NULL, "alter table sip_registrations add column ping_count INTEGER default 0");
2613 	switch_cache_db_test_reactive(dbh, "select ping_status from sip_registrations", NULL, "alter table sip_registrations add column ping_status VARCHAR(255) default 'Reachable'");
2614 	switch_cache_db_test_reactive(dbh, "select ping_expires from sip_registrations", NULL, "alter table sip_registrations add column ping_expires INTEGER not null default 0");
2615 	switch_cache_db_test_reactive(dbh, "select ping_time from sip_registrations", NULL, "alter table sip_registrations add column ping_time BIGINT not null default 0");
2616 	switch_cache_db_test_reactive(dbh, "select force_ping from sip_registrations", NULL, "alter table sip_registrations add column force_ping INTEGER not null default 0");
2617 
2618 	test2 = switch_mprintf("%s;%s", test_sql, test_sql);
2619 
2620 	if (switch_cache_db_execute_sql(dbh, test2, &err) != SWITCH_STATUS_SUCCESS) {
2621 
2622 		if (switch_stristr("read-only", err)) {
2623 			free(err);
2624 		} else {
2625 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "GREAT SCOTT!!! Cannot execute batched statements! [%s]\n"
2626 							  "If you are using mysql, make sure you are using MYODBC 3.51.18 or higher and enable FLAG_MULTI_STATEMENTS\n", err);
2627 
2628 			switch_cache_db_release_db_handle(&dbh);
2629 			free(test2);
2630 			free(test_sql);
2631 			free(err);
2632 			return 0;
2633 		}
2634 	}
2635 
2636 	free(test2);
2637 
2638 
2639 	free(test_sql);
2640 
2641 	test_sql = switch_mprintf("delete from sip_subscriptions where hostname='%q' and full_to='XXX'", mod_sofia_globals.hostname);
2642 
2643 	switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_subscriptions", sub_sql);
2644 
2645 	free(test_sql);
2646 	test_sql = switch_mprintf("delete from sip_dialogs where hostname='%q' and (expires <> -9999 or rpid='' or sip_from_tag='' or rcd > 0)",
2647 							  mod_sofia_globals.hostname);
2648 
2649 
2650 	switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_dialogs", dialog_sql);
2651 
2652 	free(test_sql);
2653 	test_sql = switch_mprintf("delete from sip_presence where hostname='%q' or open_closed=''", mod_sofia_globals.hostname);
2654 
2655 	switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_presence", pres_sql);
2656 
2657 	free(test_sql);
2658 	test_sql = switch_mprintf("delete from sip_authentication where hostname='%q' or last_nc >= 0", mod_sofia_globals.hostname);
2659 
2660 	switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_authentication", auth_sql);
2661 
2662 	free(test_sql);
2663 	test_sql = switch_mprintf("delete from sip_shared_appearance_subscriptions where contact_str='' or hostname='%q' and network_ip like '%%'",
2664 							  mod_sofia_globals.hostname);
2665 
2666 	switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_shared_appearance_subscriptions", shared_appearance_sql);
2667 
2668 	free(test_sql);
2669 	test_sql = switch_mprintf("delete from sip_shared_appearance_dialogs where contact_str='' or hostname='%q' and network_ip like '%%'",
2670 							  mod_sofia_globals.hostname);
2671 
2672 	switch_cache_db_test_reactive(dbh, test_sql, "DROP TABLE sip_shared_appearance_dialogs", shared_appearance_dialogs_sql);
2673 
2674 	free(test_sql);
2675 
2676 	for (x = 0; indexes[x]; x++) {
2677 		switch_cache_db_create_schema(dbh, indexes[x], NULL);
2678 	}
2679 
2680 	switch_cache_db_release_db_handle(&dbh);
2681 
2682 	return 1;
2683 
2684 }
2685 
sofia_glue_execute_sql(sofia_profile_t * profile,char ** sqlp,switch_bool_t sql_already_dynamic)2686 void sofia_glue_execute_sql(sofia_profile_t *profile, char **sqlp, switch_bool_t sql_already_dynamic)
2687 {
2688 	char *sql;
2689 
2690 	switch_assert(sqlp && *sqlp);
2691 	sql = *sqlp;
2692 
2693 	switch_sql_queue_manager_push(profile->qm, sql, 1, !sql_already_dynamic);
2694 
2695 	if (sql_already_dynamic) {
2696 		*sqlp = NULL;
2697 	}
2698 }
2699 
2700 
sofia_glue_execute_sql_now(sofia_profile_t * profile,char ** sqlp,switch_bool_t sql_already_dynamic)2701 void sofia_glue_execute_sql_now(sofia_profile_t *profile, char **sqlp, switch_bool_t sql_already_dynamic)
2702 {
2703 	char *sql;
2704 
2705 	switch_assert(sqlp && *sqlp);
2706 	sql = *sqlp;
2707 
2708 	switch_mutex_lock(profile->dbh_mutex);
2709 	switch_sql_queue_manager_push_confirm(profile->qm, sql, 0, !sql_already_dynamic);
2710 	switch_mutex_unlock(profile->dbh_mutex);
2711 
2712 	if (sql_already_dynamic) {
2713 		*sqlp = NULL;
2714 	}
2715 }
2716 
sofia_glue_execute_sql_soon(sofia_profile_t * profile,char ** sqlp,switch_bool_t sql_already_dynamic)2717 void sofia_glue_execute_sql_soon(sofia_profile_t *profile, char **sqlp, switch_bool_t sql_already_dynamic)
2718 {
2719 	char *sql;
2720 
2721 	switch_assert(sqlp && *sqlp);
2722 	sql = *sqlp;
2723 
2724 	switch_sql_queue_manager_push(profile->qm, sql, 0, !sql_already_dynamic);
2725 
2726 	if (sql_already_dynamic) {
2727 		*sqlp = NULL;
2728 	}
2729 }
2730 
2731 
_sofia_glue_get_db_handle(sofia_profile_t * profile,const char * file,const char * func,int line)2732 switch_cache_db_handle_t *_sofia_glue_get_db_handle(sofia_profile_t *profile, const char *file, const char *func, int line)
2733 {
2734 	switch_cache_db_handle_t *dbh = NULL;
2735 	char *dsn;
2736 
2737 	if (!zstr(profile->odbc_dsn)) {
2738 		dsn = profile->odbc_dsn;
2739 	} else {
2740 		dsn = profile->dbname;
2741 	}
2742 
2743 	if (_switch_cache_db_get_db_handle_dsn(&dbh, dsn, file, func, line) != SWITCH_STATUS_SUCCESS) {
2744 		dbh = NULL;
2745 	}
2746 
2747 	return dbh;
2748 }
2749 
sofia_glue_actually_execute_sql_trans(sofia_profile_t * profile,char * sql,switch_mutex_t * mutex)2750 void sofia_glue_actually_execute_sql_trans(sofia_profile_t *profile, char *sql, switch_mutex_t *mutex)
2751 {
2752 	switch_cache_db_handle_t *dbh = NULL;
2753 
2754 	if (mutex) {
2755 		switch_mutex_lock(mutex);
2756 	}
2757 
2758 
2759 	if (!(dbh = sofia_glue_get_db_handle(profile))) {
2760 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
2761 
2762 		goto end;
2763 	}
2764 
2765 	switch_cache_db_persistant_execute_trans_full(dbh, sql, 1,
2766 												  profile->pre_trans_execute,
2767 												  profile->post_trans_execute,
2768 												  profile->inner_pre_trans_execute,
2769 												  profile->inner_post_trans_execute
2770 												  );
2771 
2772 	switch_cache_db_release_db_handle(&dbh);
2773 
2774  end:
2775 
2776 	if (mutex) {
2777 		switch_mutex_unlock(mutex);
2778 	}
2779 }
2780 
sofia_glue_actually_execute_sql(sofia_profile_t * profile,char * sql,switch_mutex_t * mutex)2781 void sofia_glue_actually_execute_sql(sofia_profile_t *profile, char *sql, switch_mutex_t *mutex)
2782 {
2783 	switch_cache_db_handle_t *dbh = NULL;
2784 	char *err = NULL;
2785 
2786 	if (mutex) {
2787 		switch_mutex_lock(mutex);
2788 	}
2789 
2790 	if (!(dbh = sofia_glue_get_db_handle(profile))) {
2791 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
2792 
2793 		if (mutex) {
2794 			switch_mutex_unlock(mutex);
2795 		}
2796 
2797 		return;
2798 	}
2799 
2800 	switch_cache_db_execute_sql(dbh, sql, &err);
2801 
2802 	if (mutex) {
2803 		switch_mutex_unlock(mutex);
2804 	}
2805 
2806 	if (err) {
2807 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s]\n%s\n", err, sql);
2808 		free(err);
2809 	}
2810 
2811 	switch_cache_db_release_db_handle(&dbh);
2812 }
2813 
sofia_glue_execute_sql_callback(sofia_profile_t * profile,switch_mutex_t * mutex,char * sql,switch_core_db_callback_func_t callback,void * pdata)2814 switch_bool_t sofia_glue_execute_sql_callback(sofia_profile_t *profile,
2815 											  switch_mutex_t *mutex, char *sql, switch_core_db_callback_func_t callback, void *pdata)
2816 {
2817 	switch_bool_t ret = SWITCH_FALSE;
2818 	char *errmsg = NULL;
2819 	switch_cache_db_handle_t *dbh = NULL;
2820 
2821 	if (mutex) {
2822 		switch_mutex_lock(mutex);
2823 	}
2824 
2825 	if (!(dbh = sofia_glue_get_db_handle(profile))) {
2826 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
2827 
2828 		if (mutex) {
2829 			switch_mutex_unlock(mutex);
2830 		}
2831 
2832 		return ret;
2833 	}
2834 
2835 	switch_cache_db_execute_sql_callback(dbh, sql, callback, pdata, &errmsg);
2836 
2837 	if (mutex) {
2838 		switch_mutex_unlock(mutex);
2839 	}
2840 
2841 	if (errmsg) {
2842 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s] %s\n", sql, errmsg);
2843 		free(errmsg);
2844 	}
2845 
2846 	switch_cache_db_release_db_handle(&dbh);
2847 
2848 	return ret;
2849 }
2850 
sofia_glue_execute_sql2str(sofia_profile_t * profile,switch_mutex_t * mutex,char * sql,char * resbuf,size_t len)2851 char *sofia_glue_execute_sql2str(sofia_profile_t *profile, switch_mutex_t *mutex, char *sql, char *resbuf, size_t len)
2852 {
2853 	char *ret = NULL;
2854 	char *err = NULL;
2855 	switch_cache_db_handle_t *dbh = NULL;
2856 
2857 	if (mutex) {
2858 		switch_mutex_lock(mutex);
2859 	}
2860 
2861 	if (!(dbh = sofia_glue_get_db_handle(profile))) {
2862 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB\n");
2863 
2864 		if (mutex) {
2865 			switch_mutex_unlock(mutex);
2866 		}
2867 
2868 		return NULL;
2869 	}
2870 
2871 	ret = switch_cache_db_execute_sql2str(dbh, sql, resbuf, len, &err);
2872 
2873 	if (mutex) {
2874 		switch_mutex_unlock(mutex);
2875 	}
2876 
2877 	if (err) {
2878 		switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "SQL ERR: [%s]\n%s\n", err, sql);
2879 		free(err);
2880 	}
2881 
2882 	switch_cache_db_release_db_handle(&dbh);
2883 
2884 	return ret;
2885 }
2886 
sofia_glue_get_register_host(const char * uri)2887 char *sofia_glue_get_register_host(const char *uri)
2888 {
2889 	char *register_host = NULL;
2890 	const char *s;
2891 	char *p = NULL;
2892 
2893 	if (zstr(uri)) {
2894 		return NULL;
2895 	}
2896 
2897 	if ((s = switch_stristr("sip:", uri))) {
2898 		s += 4;
2899 	} else if ((s = switch_stristr("sips:", uri))) {
2900 		s += 5;
2901 	}
2902 
2903 	if (!s) {
2904 		return NULL;
2905 	}
2906 
2907 	register_host = strdup(s);
2908 
2909 	switch_assert(register_host);
2910 
2911 	/* remove port for register_host for testing nat acl take into account
2912 	   ipv6 addresses which are required to have brackets around the addr
2913 	*/
2914 
2915 	if ((p = strchr(register_host, ']'))) {
2916 		if (*(p + 1) == ':') {
2917 			*(p + 1) = '\0';
2918 		}
2919 	} else {
2920 		if ((p = strrchr(register_host, ':'))) {
2921 			*p = '\0';
2922 		}
2923 	}
2924 
2925 	/* register_proxy should always start with "sip:" or "sips:" */
2926 	assert(register_host);
2927 
2928 	return register_host;
2929 }
2930 
sofia_glue_strip_proto(const char * uri)2931 const char *sofia_glue_strip_proto(const char *uri)
2932 {
2933 	char *p;
2934 
2935 	if ((p = strchr(uri, ':'))) {
2936 		return p + 1;
2937 	}
2938 
2939 	return uri;
2940 }
2941 
sofia_cid_name2type(const char * name)2942 sofia_cid_type_t sofia_cid_name2type(const char *name)
2943 {
2944 	if (!strcasecmp(name, "rpid")) {
2945 		return CID_TYPE_RPID;
2946 	}
2947 
2948 	if (!strcasecmp(name, "pid")) {
2949 		return CID_TYPE_PID;
2950 	}
2951 
2952 	return CID_TYPE_NONE;
2953 
2954 }
2955 
2956 /* all the values of the structure are initialized to NULL  */
2957 /* in case of failure the function returns NULL */
2958 /* sofia_destination->route can be NULL */
sofia_glue_get_destination(char * data)2959 sofia_destination_t *sofia_glue_get_destination(char *data)
2960 {
2961 	sofia_destination_t *dst = NULL;
2962 	char *to = NULL;
2963 	char *contact = NULL;
2964 	char *route = NULL;
2965 	char *route_uri = NULL;
2966 	char *eoc = NULL;
2967 	char *p = NULL;
2968 
2969 	if (zstr(data)) {
2970 		return NULL;
2971 	}
2972 
2973 	if (!(dst = (sofia_destination_t *) malloc(sizeof(sofia_destination_t)))) {
2974 		return NULL;
2975 	}
2976 
2977 	/* return a copy of what is in the buffer between the first < and > */
2978 	if (!(contact = sofia_glue_get_url_from_contact(data, 1))) {
2979 		goto mem_fail;
2980 	}
2981 
2982 	if ((eoc = strstr(contact, ";fs_path="))) {
2983 		*eoc = '\0';
2984 
2985 		if (!(route = strdup(eoc + 9))) {
2986 			goto mem_fail;
2987 		}
2988 
2989 		for (p = route; p && *p; p++) {
2990 			if (*p == '>' || *p == ';') {
2991 				*p = '\0';
2992 				break;
2993 			}
2994 		}
2995 
2996 		switch_url_decode(route);
2997 
2998 		if (!(route_uri = strdup(route))) {
2999 			goto mem_fail;
3000 		}
3001 		if ((p = strchr(route_uri, ','))) {
3002 			do {
3003 				*p = '\0';
3004 			} while ((--p > route_uri) && *p == ' ');
3005 		}
3006 	}
3007 
3008 	if (!(to = strdup(data))) {
3009 		goto mem_fail;
3010 	}
3011 
3012 	if ((eoc = strstr(to, ";fs_path="))) {
3013 		*eoc++ = '>';
3014 		*eoc = '\0';
3015 	}
3016 
3017 	if ((p = strstr(contact, ";fs_"))) {
3018 		*p = '\0';
3019 	}
3020 
3021 	dst->contact = contact;
3022 	dst->to = to;
3023 	dst->route = route;
3024 	dst->route_uri = route_uri;
3025 	return dst;
3026 
3027  mem_fail:
3028 	switch_safe_free(contact);
3029 	switch_safe_free(to);
3030 	switch_safe_free(route);
3031 	switch_safe_free(route_uri);
3032 	switch_safe_free(dst);
3033 	return NULL;
3034 }
3035 
sofia_glue_free_destination(sofia_destination_t * dst)3036 void sofia_glue_free_destination(sofia_destination_t *dst)
3037 {
3038 	if (dst) {
3039 		switch_safe_free(dst->contact);
3040 		switch_safe_free(dst->route);
3041 		switch_safe_free(dst->route_uri);
3042 		switch_safe_free(dst->to);
3043 		switch_safe_free(dst);
3044 	}
3045 }
3046 
sofia_glue_send_notify(sofia_profile_t * profile,const char * user,const char * host,const char * event,const char * contenttype,const char * body,const char * o_contact,const char * network_ip,const char * call_id)3047 switch_status_t sofia_glue_send_notify(sofia_profile_t *profile, const char *user, const char *host, const char *event, const char *contenttype,
3048 									   const char *body, const char *o_contact, const char *network_ip, const char *call_id)
3049 {
3050 	char *id = NULL;
3051 	nua_handle_t *nh;
3052 	sofia_destination_t *dst = NULL;
3053 	char *contact_str, *contact, *user_via = NULL;
3054 	char *route_uri = NULL, *p;
3055 	char *ptr;
3056 
3057 	contact = sofia_glue_get_url_from_contact((char *) o_contact, 1);
3058 
3059 	if ((p = strstr(contact, ";fs_"))) {
3060 		*p = '\0';
3061 	}
3062 
3063 	if (!zstr(network_ip) && sofia_glue_check_nat(profile, network_ip)) {
3064 		id = switch_mprintf("sip:%s@%s", user, profile->extsipip);
3065 		switch_assert(id);
3066 
3067 		if ((ptr = sofia_glue_find_parameter(o_contact, "transport="))) {
3068 			sofia_transport_t transport = sofia_glue_str2transport( ptr + 10 );
3069 
3070 			switch (transport) {
3071 			case SOFIA_TRANSPORT_TCP:
3072 				contact_str = profile->tcp_public_contact;
3073 				break;
3074 			case SOFIA_TRANSPORT_TCP_TLS:
3075 				contact_str = sofia_test_pflag(profile, PFLAG_TLS) ?
3076 					profile->tls_public_contact : profile->tcp_public_contact;
3077 				break;
3078 			default:
3079 				contact_str = profile->public_url;
3080 				break;
3081 			}
3082 			user_via = sofia_glue_create_external_via(NULL, profile, transport);
3083 		} else {
3084 			user_via = sofia_glue_create_external_via(NULL, profile, SOFIA_TRANSPORT_UDP);
3085 			contact_str = profile->public_url;
3086 		}
3087 	} else {
3088 		id = switch_mprintf("sip:%s@%s", user, host);
3089 		switch_assert(id);
3090 
3091 		if ((ptr = sofia_glue_find_parameter(o_contact, "transport="))) {
3092 			sofia_transport_t transport = sofia_glue_str2transport( ptr + 10 );
3093 
3094 			switch (transport) {
3095 			case SOFIA_TRANSPORT_TCP:
3096 				contact_str = profile->tcp_contact;
3097 				break;
3098 			case SOFIA_TRANSPORT_TCP_TLS:
3099 				contact_str = sofia_test_pflag(profile, PFLAG_TLS) ?
3100 					profile->tls_contact : profile->tcp_contact;
3101 				break;
3102 			default:
3103 				contact_str = profile->url;
3104 				break;
3105 			}
3106 		} else {
3107 			contact_str = profile->url;
3108 		}
3109 	}
3110 
3111 	dst = sofia_glue_get_destination((char *) o_contact);
3112 	switch_assert(dst);
3113 
3114 	if (dst->route_uri) {
3115 		route_uri = sofia_glue_strip_uri(dst->route_uri);
3116 	}
3117 
3118 	nh = nua_handle(profile->nua, NULL, NUTAG_URL(contact), SIPTAG_FROM_STR(id), SIPTAG_TO_STR(id), SIPTAG_CONTACT_STR(contact_str), TAG_END());
3119 	nua_handle_bind(nh, &mod_sofia_globals.destroy_private);
3120 
3121 	nua_notify(nh,
3122 			   NUTAG_NEWSUB(1),
3123 			   TAG_IF(dst->route_uri, NUTAG_PROXY(route_uri)), TAG_IF(dst->route, SIPTAG_ROUTE_STR(dst->route)),
3124 			   TAG_IF(user_via, SIPTAG_VIA_STR(user_via)),
3125 			   SIPTAG_SUBSCRIPTION_STATE_STR("terminated;reason=noresource"),
3126 			   TAG_IF(event, SIPTAG_EVENT_STR(event)),
3127 			   TAG_IF(call_id, SIPTAG_CALL_ID_STR(call_id)),
3128 			   TAG_IF(contenttype, SIPTAG_CONTENT_TYPE_STR(contenttype)), TAG_IF(body, SIPTAG_PAYLOAD_STR(body)), TAG_END());
3129 
3130 	switch_safe_free(contact);
3131 	switch_safe_free(route_uri);
3132 	switch_safe_free(id);
3133 	sofia_glue_free_destination(dst);
3134 	switch_safe_free(user_via);
3135 
3136 	return SWITCH_STATUS_SUCCESS;
3137 }
3138 
3139 
sofia_glue_tech_simplify(private_object_t * tech_pvt)3140 int sofia_glue_tech_simplify(private_object_t *tech_pvt)
3141 {
3142 	const char *uuid, *network_addr_a = NULL, *network_addr_b = NULL, *simplify, *simplify_other_channel;
3143 	switch_channel_t *other_channel = NULL, *inbound_channel = NULL;
3144 	switch_core_session_t *other_session = NULL, *inbound_session = NULL;
3145 	uint8_t did_simplify = 0;
3146 	int r = 0;
3147 
3148 	if (!switch_channel_test_flag(tech_pvt->channel, CF_ANSWERED) || switch_channel_test_flag(tech_pvt->channel, CF_SIMPLIFY)) {
3149 		goto end;
3150 	}
3151 
3152 	if (switch_channel_test_flag(tech_pvt->channel, CF_BRIDGED) &&
3153 		(uuid = switch_channel_get_partner_uuid(tech_pvt->channel)) && (other_session = switch_core_session_locate(uuid))) {
3154 
3155 		other_channel = switch_core_session_get_channel(other_session);
3156 
3157 		if (switch_channel_test_flag(other_channel, CF_ANSWERED)) {	/* Check if the other channel is answered */
3158 			simplify = switch_channel_get_variable(tech_pvt->channel, "sip_auto_simplify");
3159 			simplify_other_channel = switch_channel_get_variable(other_channel, "sip_auto_simplify");
3160 
3161 			r = 1;
3162 
3163 			if (switch_true(simplify) && !switch_channel_test_flag(tech_pvt->channel, CF_BRIDGE_ORIGINATOR)) {
3164 				network_addr_a = switch_channel_get_variable(tech_pvt->channel, "network_addr");
3165 				network_addr_b = switch_channel_get_variable(other_channel, "network_addr");
3166 				inbound_session = other_session;
3167 				inbound_channel = other_channel;
3168 			} else if (switch_true(simplify_other_channel) && !switch_channel_test_flag(other_channel, CF_BRIDGE_ORIGINATOR)) {
3169 				network_addr_a = switch_channel_get_variable(other_channel, "network_addr");
3170 				network_addr_b = switch_channel_get_variable(tech_pvt->channel, "network_addr");
3171 				inbound_session = tech_pvt->session;
3172 				inbound_channel = tech_pvt->channel;
3173 			}
3174 
3175 			if (inbound_channel && inbound_session && !zstr(network_addr_a) && !zstr(network_addr_b) && !strcmp(network_addr_a, network_addr_b)) {
3176 				if (strcmp(network_addr_a, switch_str_nil(tech_pvt->profile->sipip))
3177 					&& strcmp(network_addr_a, switch_str_nil(tech_pvt->profile->extsipip))) {
3178 
3179 					switch_core_session_message_t *msg;
3180 
3181 					switch_log_printf(SWITCH_CHANNEL_ID_LOG, __FILE__, __SWITCH_FUNC__, __LINE__, switch_channel_get_uuid(inbound_channel),
3182 									  SWITCH_LOG_NOTICE, "Will simplify channel [%s]\n", switch_channel_get_name(inbound_channel));
3183 
3184 					msg = switch_core_session_alloc(inbound_session, sizeof(*msg));
3185 					MESSAGE_STAMP_FFL(msg);
3186 					msg->message_id = SWITCH_MESSAGE_INDICATE_SIMPLIFY;
3187 					msg->from = __FILE__;
3188 					switch_core_session_receive_message(inbound_session, msg);
3189 
3190 					did_simplify = 1;
3191 
3192 					switch_core_recovery_track(inbound_session);
3193 
3194 					switch_channel_set_flag(inbound_channel, CF_SIMPLIFY);
3195 
3196 				}
3197 			}
3198 
3199 			if (!did_simplify && inbound_channel) {
3200 				switch_log_printf(SWITCH_CHANNEL_ID_LOG, __FILE__, __SWITCH_FUNC__, __LINE__, switch_channel_get_uuid(inbound_channel), SWITCH_LOG_NOTICE,
3201 								  "Could not simplify channel [%s]\n", switch_channel_get_name(inbound_channel));
3202 			}
3203 		}
3204 
3205 		switch_core_session_rwunlock(other_session);
3206 	}
3207 
3208 
3209  end:
3210 
3211 	return r;
3212 }
3213 
sofia_glue_pause_jitterbuffer(switch_core_session_t * session,switch_bool_t on)3214 void sofia_glue_pause_jitterbuffer(switch_core_session_t *session, switch_bool_t on)
3215 {
3216 	switch_core_session_message_t *msg;
3217 	msg = switch_core_session_alloc(session, sizeof(*msg));
3218 	MESSAGE_STAMP_FFL(msg);
3219 	msg->message_id = SWITCH_MESSAGE_INDICATE_JITTER_BUFFER;
3220 	msg->string_arg = switch_core_session_strdup(session, on ? "pause" : "resume");
3221 	msg->from = __FILE__;
3222 
3223 	switch_core_session_queue_message(session, msg);
3224 }
3225 
3226 
sofia_glue_build_vid_refresh_message(switch_core_session_t * session,const char * pl)3227 void sofia_glue_build_vid_refresh_message(switch_core_session_t *session, const char *pl)
3228 {
3229 	switch_core_session_message_t *msg;
3230 	msg = switch_core_session_alloc(session, sizeof(*msg));
3231 	MESSAGE_STAMP_FFL(msg);
3232 	msg->message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
3233 	if (pl) {
3234 		msg->string_arg = switch_core_session_strdup(session, pl);
3235 	}
3236 	msg->from = __FILE__;
3237 
3238 	switch_core_session_queue_message(session, msg);
3239 }
3240 
3241 
sofia_glue_gen_contact_str(sofia_profile_t * profile,sip_t const * sip,nua_handle_t * nh,sofia_dispatch_event_t * de,sofia_nat_parse_t * np)3242 char *sofia_glue_gen_contact_str(sofia_profile_t *profile, sip_t const *sip, nua_handle_t *nh, sofia_dispatch_event_t *de, sofia_nat_parse_t *np)
3243 {
3244 	char *contact_str = NULL;
3245 	const char *contact_host;//, *contact_user;
3246 	sip_contact_t const *contact;
3247 	char *port;
3248 	const char *display = "\"user\"";
3249 	char new_port[25] = "";
3250 	sofia_nat_parse_t lnp = { { 0 } };
3251 	const char *ipv6;
3252 	sip_from_t const *from;
3253 
3254 	if (!sip || !sip->sip_contact) {
3255 		return NULL;
3256 	}
3257 
3258 	from = sip->sip_from;
3259 	contact = sip->sip_contact;
3260 
3261 	if (!np) {
3262 		np = &lnp;
3263 	}
3264 
3265 	sofia_glue_get_addr(de->data->e_msg, np->network_ip, sizeof(np->network_ip), &np->network_port);
3266 
3267 	if (sofia_glue_check_nat(profile, np->network_ip)) {
3268 		np->is_auto_nat = 1;
3269 	}
3270 
3271 	port = (char *) contact->m_url->url_port;
3272 	contact_host = sip->sip_contact->m_url->url_host;
3273 	//contact_user = sip->sip_contact->m_url->url_user;
3274 
3275 	display = contact->m_display;
3276 
3277 
3278 	if (zstr(display)) {
3279 		if (from) {
3280 			display = from->a_display;
3281 			if (zstr(display)) {
3282 				display = "\"user\"";
3283 			}
3284 		}
3285 	} else {
3286 		display = "\"user\"";
3287 	}
3288 
3289 	if (sofia_test_pflag(profile, PFLAG_AGGRESSIVE_NAT_DETECTION)) {
3290 		if (sip->sip_via) {
3291 			const char *v_port = sip->sip_via->v_port;
3292 			const char *v_host = sip->sip_via->v_host;
3293 
3294 			if (v_host && sip->sip_via->v_received) {
3295 				np->is_nat = "via received";
3296 			} else if (v_host && strcmp(np->network_ip, v_host)) {
3297 				np->is_nat = "via host";
3298 			} else if (v_port && atoi(v_port) != np->network_port) {
3299 				np->is_nat = "via port";
3300 			}
3301 		}
3302 	}
3303 
3304 	if (!np->is_nat && sip->sip_via && sip->sip_via->v_port &&
3305 		atoi(sip->sip_via->v_port) == 5060 && np->network_port != 5060 ) {
3306 		np->is_nat = "via port";
3307 	}
3308 
3309 	if (!np->is_nat && profile->nat_acl_count) {
3310 		uint32_t x = 0;
3311 		int ok = 1;
3312 		char *last_acl = NULL;
3313 
3314 		if (!zstr(contact_host)) {
3315 			for (x = 0; x < profile->nat_acl_count; x++) {
3316 				last_acl = profile->nat_acl[x];
3317 				if (!(ok = switch_check_network_list_ip(contact_host, last_acl))) {
3318 					break;
3319 				}
3320 			}
3321 
3322 			if (ok) {
3323 				np->is_nat = last_acl;
3324 			}
3325 		}
3326 	}
3327 
3328 	if (np->is_nat && profile->local_network && switch_check_network_list_ip(np->network_ip, profile->local_network)) {
3329 		if (profile->debug) {
3330 			switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s is on local network, not seting NAT mode.\n", np->network_ip);
3331 		}
3332 		np->is_nat = NULL;
3333 	}
3334 
3335 	if (sip->sip_record_route) {
3336 		char *full_contact = sip_header_as_string(nh->nh_home, (void *) contact);
3337 		char *route = sofia_glue_strip_uri(sip_header_as_string(nh->nh_home, (void *) sip->sip_record_route));
3338 		char *full_contact_dup;
3339 		char *route_encoded;
3340 		int route_encoded_len;
3341 		full_contact_dup = sofia_glue_get_url_from_contact(full_contact, 1);
3342 		route_encoded_len = (int)(strlen(route) * 3) + 1;
3343 		switch_zmalloc(route_encoded, route_encoded_len);
3344 		switch_url_encode(route, route_encoded, route_encoded_len);
3345 		contact_str = switch_mprintf("%s <%s;fs_path=%s>", display, full_contact_dup, route_encoded);
3346 		free(route);
3347 		free(full_contact_dup);
3348 		free(route_encoded);
3349 	}
3350 	else if (np->is_nat && np->fs_path) {
3351 		char *full_contact = sip_header_as_string(nh->nh_home, (void *) contact);
3352 		char *full_contact_dup;
3353 		char *path_encoded;
3354 		int path_encoded_len;
3355 		char *path_val;
3356 		const char *tp;
3357 
3358 		full_contact_dup = sofia_glue_get_url_from_contact(full_contact, 1);
3359 
3360 		if ((tp = switch_stristr("transport=", full_contact_dup))) {
3361 			tp += 10;
3362 		}
3363 
3364 		if (zstr(tp)) {
3365 			tp = "udp";
3366 		}
3367 
3368 		path_val = switch_mprintf("sip:%s:%d;transport=%s", np->network_ip, np->network_port, tp);
3369 		path_encoded_len = (int)(strlen(path_val) * 3) + 1;
3370 
3371 		switch_zmalloc(path_encoded, path_encoded_len);
3372 		switch_copy_string(path_encoded, ";fs_path=", 10);
3373 		switch_url_encode(path_val, path_encoded + 9, path_encoded_len - 9);
3374 
3375 		contact_str = switch_mprintf("%s <%s;fs_nat=yes%s>", display, full_contact_dup, path_encoded);
3376 
3377 		free(full_contact_dup);
3378 		free(path_encoded);
3379 		free(path_val);
3380 
3381 	} else {
3382 
3383 		if (zstr(contact_host)) {
3384 			np->is_nat = "No contact host";
3385 		}
3386 
3387 		if (np->is_nat) {
3388 			contact_host = np->network_ip;
3389 			switch_snprintf(new_port, sizeof(new_port), ":%d", np->network_port);
3390 			port = NULL;
3391 		}
3392 
3393 
3394 		if (port) {
3395 			switch_snprintf(new_port, sizeof(new_port), ":%s", port);
3396 		}
3397 
3398 		ipv6 = strchr(contact_host, ':');
3399 
3400 
3401 		if (contact->m_url->url_params) {
3402 			contact_str = switch_mprintf("%s <sip:%s%s%s%s%s%s;%s>%s",
3403 										 display, contact->m_url->url_user,
3404 										 contact->m_url->url_user ? "@" : "",
3405 										 ipv6 ? "[" : "",
3406 										 contact_host, ipv6 ? "]" : "", new_port, contact->m_url->url_params, np->is_nat ? ";fs_nat=yes" : "");
3407 		} else {
3408 			contact_str = switch_mprintf("%s <sip:%s%s%s%s%s%s>%s",
3409 										 display,
3410 										 contact->m_url->url_user,
3411 										 contact->m_url->url_user ? "@" : "",
3412 										 ipv6 ? "[" : "", contact_host, ipv6 ? "]" : "", new_port, np->is_nat ? ";fs_nat=yes" : "");
3413 		}
3414 	}
3415 
3416 	return contact_str;
3417 }
3418 
sofia_glue_get_host(const char * str,switch_memory_pool_t * pool)3419 char *sofia_glue_get_host(const char *str, switch_memory_pool_t *pool)
3420 {
3421 	char *s, *p;
3422 
3423 	if ((p = strchr(str, '@'))) {
3424 		p++;
3425 	} else {
3426 		return NULL;
3427 	}
3428 
3429 	if (pool) {
3430 		s = switch_core_strdup(pool, p);
3431 	} else {
3432 		s = strdup(p);
3433 	}
3434 
3435 	for (p = s; p && *p; p++) {
3436 		if ((*p == ';') || (*p == '>')) {
3437 			*p = '\0';
3438 			break;
3439 		}
3440 	}
3441 
3442 	return s;
3443 }
3444 
sofia_glue_fire_events(sofia_profile_t * profile)3445 void sofia_glue_fire_events(sofia_profile_t *profile)
3446 {
3447 	void *pop = NULL;
3448 
3449 	while (profile->event_queue && switch_queue_trypop(profile->event_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) {
3450 		switch_event_t *event = (switch_event_t *) pop;
3451 		switch_event_fire(&event);
3452 	}
3453 
3454 }
3455 
sofia_event_fire(sofia_profile_t * profile,switch_event_t ** event)3456 void sofia_event_fire(sofia_profile_t *profile, switch_event_t **event)
3457 {
3458 	switch_queue_push(profile->event_queue, *event);
3459 	*event = NULL;
3460 }
3461 
sofia_glue_clear_soa(switch_core_session_t * session,switch_bool_t partner)3462 void sofia_glue_clear_soa(switch_core_session_t *session, switch_bool_t partner)
3463 {
3464 	switch_core_session_t *other_session;
3465 	struct private_object *tech_pvt = switch_core_session_get_private(session);
3466 
3467 	sofia_clear_flag(tech_pvt, TFLAG_ENABLE_SOA);
3468 
3469 	if (partner && switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
3470 		if (switch_core_session_compare(session, other_session)) {
3471 			struct private_object *other_tech_pvt = switch_core_session_get_private(other_session);
3472 
3473 			sofia_clear_flag(other_tech_pvt, TFLAG_ENABLE_SOA);
3474 		}
3475 		switch_core_session_rwunlock(other_session);
3476 	}
3477 
3478 }
3479 
sofia_glue_get_profile_url(sofia_profile_t * profile,char * remote_ip,const sofia_transport_t transport)3480 char *sofia_glue_get_profile_url(sofia_profile_t *profile, char *remote_ip, const sofia_transport_t transport)
3481 {
3482 	char *url = NULL;
3483 	int check_nat = 0;
3484 
3485 	if (!zstr(remote_ip) && sofia_glue_check_nat(profile, remote_ip)) {
3486 		check_nat = 1;
3487 	}
3488 
3489 	if (sofia_glue_transport_has_tls(transport)) {
3490 		if (check_nat && profile->tls_public_url) {
3491 			url = profile->tls_public_url;
3492 		} else {
3493 			url = profile->tls_url;
3494 		}
3495 	} else {
3496 		if (check_nat && profile->public_url) {
3497 			url = profile->public_url;
3498 		} else {
3499 			url = profile->url;
3500 		}
3501 	}
3502 
3503 	if (!url) url = profile->url;
3504 
3505 	return url;
3506 }
3507 
3508 /* For Emacs:
3509  * Local Variables:
3510  * mode:c
3511  * indent-tabs-mode:t
3512  * tab-width:4
3513  * c-basic-offset:4
3514  * End:
3515  * For VIM:
3516  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
3517  */
3518