static int tsip_dialog_invite_ice_create_ctx(tsip_dialog_invite_t * self, tmedia_type_t media_type)
{
	int32_t transport_idx;
	int ret = 0;
	if(!self){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
	transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default;
	if (!self->ice.ctx_audio && (media_type & tmedia_audio)) {
		self->ice.ctx_audio = tnet_ice_ctx_create(self->ice.is_jingle, TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), 
					self->use_rtcp, tsk_false, tsip_dialog_invite_ice_audio_callback, self);
		if (!self->ice.ctx_audio) {
			TSK_DEBUG_ERROR("Failed to create ICE audio context");
			return -2;
		}
		ret = tnet_ice_ctx_set_stun(self->ice.ctx_audio, TSIP_DIALOG_GET_SS(self)->media.stun.hostname, TSIP_DIALOG_GET_SS(self)->media.stun.port, kStunSoftware, TSIP_DIALOG_GET_SS(self)->media.stun.username, TSIP_DIALOG_GET_SS(self)->media.stun.password);
		ret = tnet_ice_ctx_set_stun_enabled(self->ice.ctx_audio, TSIP_DIALOG_GET_SS(self)->media.enable_icestun);
		ret = tnet_ice_ctx_set_turn_enabled(self->ice.ctx_audio, TSIP_DIALOG_GET_SS(self)->media.enable_iceturn);
		ret = tnet_ice_ctx_set_rtcpmux(self->ice.ctx_audio, self->use_rtcpmux);
	}
	if (!self->ice.ctx_video && (media_type & tmedia_video)) {
		self->ice.ctx_video = tnet_ice_ctx_create(self->ice.is_jingle, TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), 
					self->use_rtcp, tsk_true, tsip_dialog_invite_ice_video_callback, self);
		if (!self->ice.ctx_video) {
			TSK_DEBUG_ERROR("Failed to create ICE video context");
			return -2;
		}
		ret = tnet_ice_ctx_set_stun(self->ice.ctx_video, TSIP_DIALOG_GET_SS(self)->media.stun.hostname, TSIP_DIALOG_GET_SS(self)->media.stun.port, kStunSoftware, TSIP_DIALOG_GET_SS(self)->media.stun.username, TSIP_DIALOG_GET_SS(self)->media.stun.password);
		ret = tnet_ice_ctx_set_stun_enabled(self->ice.ctx_video, TSIP_DIALOG_GET_SS(self)->media.enable_icestun);
		ret = tnet_ice_ctx_set_turn_enabled(self->ice.ctx_video, TSIP_DIALOG_GET_SS(self)->media.enable_iceturn);
		ret = tnet_ice_ctx_set_rtcpmux(self->ice.ctx_video, self->use_rtcpmux);
	}

	// set media type
	ret = tsip_dialog_invite_ice_set_media_type(self, media_type);

	// update session manager with the right ICE contexts
	if (self->msession_mgr) {
		ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video);
	}

	return ret;
}
Example #2
0
//=================================================================================================
//	SOCKET object definition
//
static tsk_object_t* tnet_socket_ctor(tsk_object_t * self, va_list * app)
{
	tnet_socket_t *sock = self;
	if(sock){
		int status;
		tsk_bool_t nonblocking;
		tsk_bool_t bindsocket;
		tsk_istr_t port;
		struct addrinfo *result = 0;
		struct addrinfo *ptr = 0;
		struct addrinfo hints;
		tnet_host_t local_hostname;

		const char *host = va_arg(*app, const char*);
#if defined(__GNUC__)
		sock->port = (tnet_port_t)va_arg(*app, unsigned);
#else
		sock->port = va_arg(*app, tnet_port_t);
#endif
		tsk_itoa(sock->port, &port);
		sock->type = va_arg(*app, tnet_socket_type_t);
		nonblocking = va_arg(*app, tsk_bool_t);
		bindsocket = va_arg(*app, tsk_bool_t);

		memset(local_hostname, 0, sizeof(local_hostname));

		/* Get the local host name */
		if(host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){
			memcpy(local_hostname, host, tsk_strlen(host)>sizeof(local_hostname)-1 ? sizeof(local_hostname)-1 : tsk_strlen(host));
		}
		else{
			if(TNET_SOCKET_TYPE_IS_IPV6(sock->type)){
				memcpy(local_hostname, "::", 2);
			}
			else{
				memcpy(local_hostname, "0.0.0.0", 7);
			}
			//if((status = tnet_gethostname(&local_hostname)))
			//{
			//	TNET_PRINT_LAST_ERROR("gethostname have failed.");
			//	goto bail;
			//}
		}

		/* hints address info structure */
		memset(&hints, 0, sizeof(hints));
		hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET);
		hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM;
		hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP;
		hints.ai_flags = AI_PASSIVE
#if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600
			| AI_ADDRCONFIG
#endif
			;

		/* Performs getaddrinfo */
		if((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))){
			TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]", 
				hints.ai_family, local_hostname, port, tnet_gai_strerror(status));
			goto bail;
		}
		
		/* Find our address. */
		for(ptr = result; ptr; ptr = ptr->ai_next){
			sock->fd = tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
			if(ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
				continue;
			}
			
			if(bindsocket){
				/* Bind the socket */
				if((status = bind(sock->fd, ptr->ai_addr, ptr->ai_addrlen))){
					TNET_PRINT_LAST_ERROR("bind have failed.");
					tnet_socket_close(sock);
					continue;
				}

				/* Get local IP string. */
				if(status = tnet_get_ip_n_port(sock->fd , &sock->ip, &sock->port)) /* % */
				//if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST)))
				{
					TNET_PRINT_LAST_ERROR("Failed to get local IP and port.");
					tnet_socket_close(sock);
					continue;
				}
//				else{
//#if TNET_UNDER_WINDOWS
//					int index;
//					if((index = tsk_strindexOf(sock->ip, tsk_strlen(sock->ip), "%")) > 0){
//						*(sock->ip + index) = '\0';
//					}
//#endif
//				}
			}

			/* sets the real socket type (if ipv46) */
			if(ptr->ai_family == AF_INET6) {
				TNET_SOCKET_TYPE_SET_IPV6Only(sock->type);
			}
			else{
				TNET_SOCKET_TYPE_SET_IPV4Only(sock->type);
			}
			break;
		}
		
		/* Check socket validity. */
		if(!TNET_SOCKET_IS_VALID(sock)) {
			TNET_PRINT_LAST_ERROR("Invalid socket.");
			goto bail;
		}		

		/* To avoid "Address already in use" error */
		{
#if defined(SOLARIS)
			char yes = '1';
#else
			int yes = 1;
#endif
			if(setsockopt(sock->fd, SOL_SOCKET, SO_REUSEADDR, (char*)&yes, sizeof(int))){
				TNET_PRINT_LAST_ERROR("setsockopt(SO_REUSEADDR) have failed.");
			}
		}

		/* Sets the socket to nonblocking mode */
		if(nonblocking){
			if((status = tnet_sockfd_set_nonblocking(sock->fd))){
				goto bail;
			}
		}

bail:
		/* Free addrinfo */
		tnet_freeaddrinfo(result);

		/* Close socket if failed. */
		if(status && TNET_SOCKET_IS_VALID(sock)){
			tnet_socket_close(sock);
		}

	}
	return self;
}
Example #3
0
/**@ingroup tnet_socket_group
* Creates a new socket.
* To check that the returned socket is valid use @ref TNET_SOCKET_IS_VALID function.
* @param host FQDN (e.g. www.doubango.org) or IPv4/IPv6 IP string.
* @param port The local/remote port used to receive/send data. Set the port value to @ref TNET_SOCKET_PORT_ANY to bind to a random port.
* @param type The type of the socket. See @ref tnet_socket_type_t.
* @param nonblocking Indicates whether to create non-blocking socket.
* @param bindsocket Indicates whether to bind the newly created socket or not.
* @retval @ref tnet_socket_t object.
* @sa @ref tnet_socket_create.
*/
tnet_socket_t* tnet_socket_create_2(const char* host, tnet_port_t port_, tnet_socket_type_t type, tsk_bool_t nonblocking, tsk_bool_t bindsocket)
{
	tnet_socket_t *sock;
	if ((sock = tsk_object_new(tnet_socket_def_t))) {
		int status;
		tsk_istr_t port;
		struct addrinfo *result = tsk_null;
		struct addrinfo *ptr = tsk_null;
		struct addrinfo hints;
		tnet_host_t local_hostname;

		sock->port = port_;
		tsk_itoa(sock->port, &port);
		sock->type = type;

		memset(local_hostname, 0, sizeof(local_hostname));

		/* Get the local host name */
		if (host != TNET_SOCKET_HOST_ANY && !tsk_strempty(host)){
			memcpy(local_hostname, host, tsk_strlen(host) > sizeof(local_hostname) - 1 ? sizeof(local_hostname) - 1 : tsk_strlen(host));
		}
		else{
			if (TNET_SOCKET_TYPE_IS_IPV6(sock->type)){
				memcpy(local_hostname, "::", 2);
			}
			else {
				memcpy(local_hostname, "0.0.0.0", 7);
			}
		}

		/* hints address info structure */
		memset(&hints, 0, sizeof(hints));
		hints.ai_family = TNET_SOCKET_TYPE_IS_IPV46(sock->type) ? AF_UNSPEC : (TNET_SOCKET_TYPE_IS_IPV6(sock->type) ? AF_INET6 : AF_INET);
		hints.ai_socktype = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? SOCK_STREAM : SOCK_DGRAM;
		hints.ai_protocol = TNET_SOCKET_TYPE_IS_STREAM(sock->type) ? IPPROTO_TCP : IPPROTO_UDP;
		hints.ai_flags = AI_PASSIVE
#if !TNET_UNDER_WINDOWS || _WIN32_WINNT>=0x600
			| AI_ADDRCONFIG
#endif
			;

		/* Performs getaddrinfo */
		if ((status = tnet_getaddrinfo(local_hostname, port, &hints, &result))) {
			TNET_PRINT_LAST_ERROR("tnet_getaddrinfo(family=%d, hostname=%s and port=%s) failed: [%s]",
				hints.ai_family, local_hostname, port, tnet_gai_strerror(status));
			goto bail;
	}

		/* Find our address. */
		for (ptr = result; ptr; ptr = ptr->ai_next){
			sock->fd = (tnet_fd_t)tnet_soccket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol);
			if (ptr->ai_family != AF_INET6 && ptr->ai_family != AF_INET){
				continue;
			}
			/* To avoid "Address already in use" error
			* Check issue 368 (https://code.google.com/p/doubango/issues/detail?id=368) to understand why it's not used for UDP/DTLS.
			*/
			//
			if (TNET_SOCKET_TYPE_IS_STREAM(sock->type)) {
				if ((status = tnet_sockfd_reuseaddr(sock->fd, 1))) {
					// do not break...continue
				}
			}

			if (bindsocket){
				/* Bind the socket */
				if ((status = bind(sock->fd, ptr->ai_addr, (int)ptr->ai_addrlen))){
					TNET_PRINT_LAST_ERROR("bind to [%s:%s]have failed", local_hostname, port);
					tnet_socket_close(sock);
					continue;
				}

				/* Get local IP string. */
				if ((status = tnet_get_ip_n_port(sock->fd, tsk_true/*local*/, &sock->ip, &sock->port))) /* % */
					//if((status = tnet_getnameinfo(ptr->ai_addr, ptr->ai_addrlen, sock->ip, sizeof(sock->ip), 0, 0, NI_NUMERICHOST)))
				{
					TNET_PRINT_LAST_ERROR("Failed to get local IP and port.");
					tnet_socket_close(sock);
					continue;
				}
			}

			/* sets the real socket type (if ipv46) */
			if (ptr->ai_family == AF_INET6) {
				TNET_SOCKET_TYPE_SET_IPV6Only(sock->type);
			}
			else {
				TNET_SOCKET_TYPE_SET_IPV4Only(sock->type);
			}
			break;
		}

		/* Check socket validity. */
		if (!TNET_SOCKET_IS_VALID(sock)) {
			TNET_PRINT_LAST_ERROR("Invalid socket.");
			goto bail;
		}

#if TNET_UNDER_IPHONE || TNET_UNDER_IPHONE_SIMULATOR
		/* disable SIGPIPE signal */
		{
			int yes = 1;
			if (setsockopt(sock->fd, SOL_SOCKET, SO_NOSIGPIPE, (char*)&yes, sizeof(int))){
				TNET_PRINT_LAST_ERROR("setsockopt(SO_NOSIGPIPE) have failed.");
			}
		}
#endif /* TNET_UNDER_IPHONE */

		/* Sets the socket to nonblocking mode */
		if(nonblocking){
			if((status = tnet_sockfd_set_nonblocking(sock->fd))){
				goto bail;
			}
		}

	bail:
		/* Free addrinfo */
		tnet_freeaddrinfo(result);

		/* Close socket if failed. */
		if (status){
			if (TNET_SOCKET_IS_VALID(sock)){
				tnet_socket_close(sock);
			}
			return tsk_null;
		}
}

	return sock;
}
/* Started -> (oINVITE) -> Outgoing
*/
int c0000_Started_2_Outgoing_X_oINVITE(va_list *app)
{
	int ret;
	tsip_dialog_invite_t *self;
	const tsip_action_t* action;

	self = va_arg(*app, tsip_dialog_invite_t *);
	va_arg(*app, const tsip_message_t *);
	action = va_arg(*app, const tsip_action_t *);
	
	/* This is the first FSM transaction when you try to make an audio/video/msrp call */
	if(!self->msession_mgr){
		int32_t transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default;
		self->msession_mgr = tmedia_session_mgr_create(action ? action->media.type : tmedia_all,
			TSIP_DIALOG_GET_STACK(self)->network.local_ip[transport_idx], TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), tsk_true);
		if(TSIP_DIALOG_GET_STACK(self)->natt.ctx){
			ret = tmedia_session_mgr_set_natt_ctx(self->msession_mgr, TSIP_DIALOG_GET_STACK(self)->natt.ctx, TSIP_DIALOG_GET_STACK(self)->network.aor.ip[transport_idx]);
		}
		
		ret = tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video);
		ret = tsip_dialog_invite_msession_configure(self);
	}

	/* We are the client */
	self->is_client = tsk_true;
	/* Whether it's a client dialog for call transfer */
	self->is_transf = (TSIP_DIALOG_GET_SS(self)->id_parent != TSIP_SSESSION_INVALID_ID);

	/* Get Media type from the action */
	TSIP_DIALOG_GET_SS(self)->media.type = action->media.type;
	/* Appy media params received from the user */
	if(!TSK_LIST_IS_EMPTY(action->media.params)){
		tmedia_session_mgr_set_3(self->msession_mgr, action->media.params);
	}

	/*  RFC 4028 - 7.1. Generating an Initial Session Refresh Request

		A UAC MAY include a Session-Expires header field in an initial
		session refresh request if it wants a session timer applied to the
		session.  The value of this header field indicates the session
		interval desired by the UAC.  If a Min-SE header is included in the
		initial session refresh request, the value of the Session-Expires
		MUST be greater than or equal to the value in Min-SE.

		The UAC MAY include the refresher parameter with value 'uac' if it
		wants to perform the refreshes.  However, it is RECOMMENDED that the
		parameter be omitted so that it can be selected by the negotiation
		mechanisms described below.
	*/
	if(TSIP_DIALOG_GET_SS(self)->media.timers.timeout){
		self->stimers.timer.timeout = TSIP_DIALOG_GET_SS(self)->media.timers.timeout;
		tsk_strupdate(&self->stimers.refresher, TSIP_DIALOG_GET_SS(self)->media.timers.refresher);
		self->stimers.is_refresher = tsk_striequals(self->stimers.refresher, "uac");
		self->supported.timer = tsk_true;
	}
	
	/* QoS
	* One Voice Profile - 5.4.1 SIP Precondition Considerations
	* The UE shall use the Supported header, and not the Require header, to indicate the support of precondition in
	* accordance with Section 5.1.3.1 of 3GPP TS 24.229.
	*/
	self->qos.type = TSIP_DIALOG_GET_SS(self)->media.qos.type;
	self->qos.strength = TSIP_DIALOG_GET_SS(self)->media.qos.strength;
	tmedia_session_mgr_set_qos(self->msession_mgr, self->qos.type, self->qos.strength);
	self->supported.precondition = (self->qos.strength == tmedia_qos_strength_optional);
	self->required.precondition = (self->qos.strength == tmedia_qos_strength_mandatory);

	/* send the request */
	ret = send_INVITE(self, tsk_false);

	/* alert the user */
	TSIP_DIALOG_SIGNAL(self, tsip_event_code_dialog_connecting, "Dialog connecting");

	return ret;
}
Example #5
0
static int tsip_dialog_invite_ice_create_ctx(tsip_dialog_invite_t * self, tmedia_type_t media_type)
{
	int32_t transport_idx;
	if(!self){
		TSK_DEBUG_ERROR("Invalid parameter");
		return -1;
	}
	transport_idx = TSIP_DIALOG_GET_STACK(self)->network.transport_idx_default;
	if(!self->ice.ctx_audio && (media_type & tmedia_audio)){
		self->ice.ctx_audio = tnet_ice_ctx_create(self->ice.is_jingle, TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), 
					self->use_rtcp, tsk_false, tsip_dialog_invite_ice_audio_callback, self);
		if(!self->ice.ctx_audio){
			TSK_DEBUG_ERROR("Failed to create ICE audio context");
			return -2;
		}
		tnet_ice_ctx_set_stun(self->ice.ctx_audio, "stun.l.google.com", 19302, "Doubango", "*****@*****.**", "stun-password"); //FIXME
		tnet_ice_ctx_set_rtcpmux(self->ice.ctx_audio, self->use_rtcpmux);
	}
	if(!self->ice.ctx_video && (media_type & tmedia_video)){
		self->ice.ctx_video = tnet_ice_ctx_create(self->ice.is_jingle, TNET_SOCKET_TYPE_IS_IPV6(TSIP_DIALOG_GET_STACK(self)->network.proxy_cscf_type[transport_idx]), 
					self->use_rtcp, tsk_true, tsip_dialog_invite_ice_video_callback, self);
		if(!self->ice.ctx_video){
			TSK_DEBUG_ERROR("Failed to create ICE video context");
			return -2;
		}
		tnet_ice_ctx_set_stun(self->ice.ctx_video, "stun.l.google.com", 19302, "Doubango", "*****@*****.**", "stun-password"); // FIXME
		tnet_ice_ctx_set_rtcpmux(self->ice.ctx_video, self->use_rtcpmux);
	}

	// "none" comparison is used to exclude the "first call"
	if(self->ice.media_type != tmedia_none && self->ice.media_type != media_type){
		// cancels contexts associated to old medias
		if(self->ice.ctx_audio && !(media_type & tmedia_audio)){
			tnet_ice_ctx_cancel(self->ice.ctx_audio);
		}
		if(self->ice.ctx_video && !(media_type & tmedia_video)){
			tnet_ice_ctx_cancel(self->ice.ctx_video);
		}
		// cancels contexts associated to new medias (e.g. session "remove" then "add")
		// cancel() on newly created contexts don't have any effect
		if(self->ice.ctx_audio && (!(media_type & tmedia_audio) && (self->ice.media_type & tmedia_audio))){
			//tnet_ice_ctx_cancel(self->ice.ctx_audio);
		}
		if(self->ice.ctx_video && (!(media_type & tmedia_video) && (self->ice.media_type & tmedia_video))){
			//tnet_ice_ctx_cancel(self->ice.ctx_video);
		}
	}

	self->ice.media_type = media_type;
	

	// For now disable timers until both parties get candidates
	// (RECV ACK) or RECV (200 OK)
	tsip_dialog_invite_ice_timers_set(self, -1);

	// update session manager with the right ICE contexts
	if(self->msession_mgr){
		tmedia_session_mgr_set_ice_ctx(self->msession_mgr, self->ice.ctx_audio, self->ice.ctx_video);
	}

	return 0;
}