示例#1
0
void UDT_transport_set_rtp_session(UDT_transport *udt,RtpSession *session){
	char *local_port = ortp_strdup_printf("%d", session->rtp.loc_port);

	udt->rtp_session = session;
	udt->ortp_transport.session = session;

	if (0 != getaddrinfo(NULL, local_port, &udt->hints, &udt->local)){
		ms_message("incorrect network address.");
		return;
	}

	udt->udt_socket = UDT::socket(udt->local->ai_family,
		udt->local->ai_socktype,
		udt->local->ai_protocol);

	/*设置传输参数*/
	UDT::setsockopt(udt->udt_socket, 0, UDT_MSS, new int(ms_get_payload_max_size()), sizeof(int)); //MTU size
	UDT::setsockopt(udt->udt_socket, 0, UDT_RCVSYN, new bool(true), sizeof(bool));
	UDT::setsockopt(udt->udt_socket, 0, UDT_SNDSYN, new bool(true), sizeof(bool)); //非阻塞模式
	UDT::setsockopt(udt->udt_socket, 0, UDT_SNDBUF, new int(1024000), sizeof(int)); //接受缓冲
	UDT::setsockopt(udt->udt_socket, 0, UDT_RCVBUF, new int(1024000), sizeof(int)); //发送缓冲
	UDT::setsockopt(udt->udt_socket, 0, UDT_RCVTIMEO, new int(1), sizeof(int)); //阻塞模式超时设置
	UDT::setsockopt(udt->udt_socket, 0, UDT_SNDTIMEO, new int(1), sizeof(int)); //阻塞模式超时设置


	UDT::setsockopt(udt->udt_socket, 0, UDT_RENDEZVOUS, new bool(true), sizeof(bool));

	if (UDT::ERROR == UDT::bind(udt->udt_socket, rtp_session_get_rtp_socket(udt->rtp_session))){
		ms_error("bind: %s",UDT::getlasterror().getErrorMessage());
	}

	ms_free(local_port);
}
示例#2
0
void VodWnd::active_rtp_sock()
{
    if (!rtp_) return;

    int sock = rtp_session_get_rtp_socket(rtp_);
    send_something(sock, server_ip_.c_str(), server_rtp_port_);
}
示例#3
0
void SinkBase::RunOnce()
{
	// FIXME: 不处理 rtcp 数据了

	// FIXME: 此时简单的发送 rtp, rtcp 激活包,更好的方式应该是受到 rtp, rtcp 包之后,就不再发送了 
	active_sock(rtp_session_get_rtp_socket(rtp_), mcu_ip_.c_str(), mcu_rtp_port_);
	active_sock(rtp_session_get_rtcp_socket(rtp_), mcu_ip_.c_str(), mcu_rtcp_port_);
}
RtpSession * create_duplex_rtpsession(int loc_rtp_port, int loc_rtcp_port, bool_t ipv6) {
	RtpSession *rtpr;

	rtpr = rtp_session_new(RTP_SESSION_SENDRECV);
	rtp_session_set_recv_buf_size(rtpr, MAX(ms_get_mtu() , MS_MINIMAL_MTU));
	rtp_session_set_scheduling_mode(rtpr, 0);
	rtp_session_set_blocking_mode(rtpr, 0);
	rtp_session_enable_adaptive_jitter_compensation(rtpr, TRUE);
	rtp_session_set_symmetric_rtp(rtpr, TRUE);
	rtp_session_set_local_addr(rtpr, ipv6 ? "::" : "0.0.0.0", loc_rtp_port, loc_rtcp_port);
	rtp_session_signal_connect(rtpr, "timestamp_jump", (RtpCallback)rtp_session_resync, (long)NULL);
	rtp_session_signal_connect(rtpr, "ssrc_changed", (RtpCallback)rtp_session_resync, (long)NULL);
	rtp_session_set_ssrc_changed_threshold(rtpr, 0);
	disable_checksums(rtp_session_get_rtp_socket(rtpr));
	return rtpr;
}
示例#5
0
/* Wait for an RTP packet to arrive and return it */
mblk_t *MastTool::wait_for_rtp_packet( int seconds )
{
	struct timeval timeout;
	fd_set readfds;
	int retval = -1;


	/* reset the session */
	rtp_session_reset( session );
	
	/* set the timeout */
	timeout.tv_sec = seconds;
	timeout.tv_usec = 0;

	/* Watch socket to see when it has input */
	FD_ZERO(&readfds);
	FD_SET( rtp_session_get_rtp_socket(session), &readfds);
	retval = select(FD_SETSIZE, &readfds, NULL, NULL, &timeout);


	// Check return value 
	if (retval == -1) {
		MAST_ERROR("select() failed: %s", strerror(errno));
		return NULL;
	} else if (retval==0) {
		MAST_ERROR("Timed out waiting for packet after %d seconds", seconds);
		return NULL;
	}
	
	

	/* recieve packet and put it in queue */
	rtp_session_rtp_recv( session, 0 );
	
	
	/* check that there is something in the queue */
	if (qempty(&session->rtp.rq) ) {
		MAST_ERROR("Queue is empty after trying to recieve packet");
		return NULL;
	}
	
	/* take the packet off the queue and return it */
	return getq(&session->rtp.rq);

}
示例#6
0
RtpSession * ms_create_duplex_rtp_session(const char* local_ip, int loc_rtp_port, int loc_rtcp_port, int mtu) {
	RtpSession *rtpr;

	rtpr = rtp_session_new(RTP_SESSION_SENDRECV);
	rtp_session_set_recv_buf_size(rtpr, MAX(mtu , MS_MINIMAL_MTU));
	rtp_session_set_scheduling_mode(rtpr, 0);
	rtp_session_set_blocking_mode(rtpr, 0);
	rtp_session_enable_adaptive_jitter_compensation(rtpr, TRUE);
	rtp_session_set_symmetric_rtp(rtpr, TRUE);
	rtp_session_set_local_addr(rtpr, local_ip, loc_rtp_port, loc_rtcp_port);
	rtp_session_signal_connect(rtpr, "timestamp_jump", (RtpCallback)rtp_session_resync, NULL);
	rtp_session_signal_connect(rtpr, "ssrc_changed", (RtpCallback)rtp_session_resync, NULL);
	rtp_session_set_ssrc_changed_threshold(rtpr, 0);
	rtp_session_set_rtcp_report_interval(rtpr, 2500);	/* At the beginning of the session send more reports. */
	rtp_session_set_multicast_loopback(rtpr,TRUE); /*very useful, specially for testing purposes*/
	disable_checksums(rtp_session_get_rtp_socket(rtpr));
	return rtpr;
}
示例#7
0
static int ice_process_stun_message(RtpSession *session, struct IceCheckList *checklist, OrtpEvent *evt)
{
	struct CandidatePair *remote_candidates = NULL;
	StunMessage msg;
	bool_t res;
	int highest_priority_success=-1;
	OrtpEventData *evt_data = ortp_event_get_data(evt);
	mblk_t *mp = evt_data->packet;
	struct sockaddr_in *udp_remote;
	char src6host[NI_MAXHOST];
	int recvport = 0;
	int i;

	udp_remote = (struct sockaddr_in*)&evt_data->ep->addr;

	memset( &msg, 0 , sizeof(msg) );
	res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &msg);
	if (!res)
	{
		ms_error("ice.c: Malformed STUN packet.");
		return -1;
	}

	if (checklist==NULL)
	{
		ms_error("ice.c: dropping STUN packet: ice is not configured");
		return -1;
	}

	remote_candidates = checklist->cand_pairs;
	if (remote_candidates==NULL)
	{
		ms_error("ice.c: dropping STUN packet: ice is not configured");
		return -1;
	}

	/* prepare ONCE tie-break value */
	if (checklist->tiebreak_value==0) {
		checklist->tiebreak_value = random() * (0x7fffffffffffffffLL/0x7fff);
	}

	memset (src6host, 0, sizeof (src6host));

	{
		struct sockaddr_storage *aaddr = (struct sockaddr_storage *)&evt_data->ep->addr;
		if (aaddr->ss_family==AF_INET)
			recvport = ntohs (((struct sockaddr_in *) udp_remote)->sin_port);
		else
			recvport = ntohs (((struct sockaddr_in6 *) &evt_data->ep->addr)->sin6_port);
	}
	i = getnameinfo ((struct sockaddr*)&evt_data->ep->addr, evt_data->ep->addrlen,
		src6host, NI_MAXHOST,
		NULL, 0, NI_NUMERICHOST);
	if (i != 0)
	{
		ms_error("ice.c: Error with getnameinfo");
		return -1;
	}

	if (STUN_IS_REQUEST(msg.msgHdr.msgType))
		ms_message("ice.c: STUN_CONNECTIVITYCHECK: Request received from: %s:%i",
		src6host, recvport);
	else if (STUN_IS_INDICATION(msg.msgHdr.msgType))
		ms_message("ice.c: SUN_INDICATION: Request Indication received from: %s:%i",
		src6host, recvport);
	else
		ms_message("ice.c: STUN_ANSWER: Answer received from: %s:%i",
		src6host, recvport);

	{
		int pos;
		for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
		{
			struct CandidatePair *cand_pair = &remote_candidates[pos];

			if (cand_pair->connectivity_check == ICE_SUCCEEDED)
			{
				highest_priority_success=pos;
				break;
			}
		}
	}

	if (STUN_IS_INDICATION(msg.msgHdr.msgType))
	{
		ms_message("ice.c: STUN INDICATION <- (?:?:? <- %s:%i:?)", src6host, recvport);
		return 0;
	}
	else if (STUN_IS_REQUEST(msg.msgHdr.msgType))
	{
		StunMessage resp;
		StunAtrString hmacPassword;
		StunAddress4 remote_addr;
		int rtp_socket;

		memset( &resp, 0 , sizeof(resp));
		remote_addr.addr = ntohl(udp_remote->sin_addr.s_addr);
		remote_addr.port = ntohs(udp_remote->sin_port);

		rtp_socket = rtp_session_get_rtp_socket(session);

		resp.msgHdr.magic_cookie = ntohl(msg.msgHdr.magic_cookie);
		for (i=0; i<12; i++ )
		{
			resp.msgHdr.tr_id.octet[i] = msg.msgHdr.tr_id.octet[i];
		}

		/* check mandatory params */

		if (!msg.hasUsername)
		{
			char buf[STUN_MAX_MESSAGE_SIZE];
			int len = sizeof(buf);
			ms_error("ice.c: STUN REQ <- Missing USERNAME attribute in connectivity check");
			_ice_createErrorResponse(&resp, 4, 32, "Missing USERNAME attribute");
			len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
			if (len)
				sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
			return -1;
		}
		if (!msg.hasMessageIntegrity)
		{
			char buf[STUN_MAX_MESSAGE_SIZE];
			int len = sizeof(buf);
			ms_error("ice.c: STUN REQ <- Missing MESSAGEINTEGRITY attribute in connectivity check");
			_ice_createErrorResponse(&resp, 4, 1, "Missing MESSAGEINTEGRITY attribute");
			len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
			if (len)
				sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
			return -1;
		}

		/*
		The password associated with that transport address ID is used to verify
		the MESSAGE-INTEGRITY attribute, if one was present in the request.
		*/
		{
			char hmac[20];
			/* remove length of fingerprint if present */
			if (msg.hasFingerprint==TRUE)
			{
				char *lenpos = (char *)mp->b_rptr + sizeof(uint16_t);
				uint16_t newlen = htons(msg.msgHdr.msgLength-8); /* remove fingerprint size */
				memcpy(lenpos, &newlen, sizeof(uint16_t));
				stunCalculateIntegrity_shortterm(hmac, (char*)mp->b_rptr, mp->b_wptr-mp->b_rptr-24-8, checklist->loc_ice_pwd);
			}
			else
				stunCalculateIntegrity_shortterm(hmac, (char*)mp->b_rptr, mp->b_wptr-mp->b_rptr-24, checklist->loc_ice_pwd);
			if (memcmp(msg.messageIntegrity.hash, hmac, 20)!=0)
			{
				char buf[STUN_MAX_MESSAGE_SIZE];
				int len = sizeof(buf);
				ms_error("ice.c: STUN REQ <- Wrong MESSAGEINTEGRITY attribute in connectivity check");
				_ice_createErrorResponse(&resp, 4, 1, "Wrong MESSAGEINTEGRITY attribute");
				len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
				if (len)
					sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
				return -1;
			}
			if (msg.hasFingerprint==TRUE)
			{
				char *lenpos = (char *)mp->b_rptr + sizeof(uint16_t);
				uint16_t newlen = htons(msg.msgHdr.msgLength); /* add back fingerprint size */
				memcpy(lenpos, &newlen, sizeof(uint16_t));
			}
		}


		/* 7.2.1.1. Detecting and Repairing Role Conflicts */
		/* TODO */
		if (!msg.hasIceControlling && !msg.hasIceControlled)
		{
			char buf[STUN_MAX_MESSAGE_SIZE];
			int len = sizeof(buf);
			ms_error("ice.c: STUN REQ <- Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute");
			_ice_createErrorResponse(&resp, 4, 87, "Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute");
			len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
			if (len)
				sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
			return -1;
		}

		if (checklist->rem_controlling==0 && msg.hasIceControlling) {
			/* If the agent's tie-breaker is larger than or equal
			to the contents of the ICE-CONTROLLING attribute
			-> send 487, and do not change ROLE */
			if (checklist->tiebreak_value >= msg.iceControlling.value) {
				char buf[STUN_MAX_MESSAGE_SIZE];
				int len = sizeof(buf);
				ms_error("ice.c: STUN REQ <- 487 Role Conflict");
				_ice_createErrorResponse(&resp, 4, 87, "Role Conflict");
				len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
				if (len)
					sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
				return -1;
			}
			else {
				int pos;
				for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
				{
					/* controller agent */
					uint64_t G = remote_candidates[pos].remote_candidate.priority;
					/* controlled agent */	
					uint64_t D = remote_candidates[pos].local_candidate.priority;
					remote_candidates[pos].pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
				}
				checklist->rem_controlling = 1;
				/* reset all to initial WAITING state? */
				ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state");
				for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
				{
					if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
						continue;
					remote_candidates[pos].connectivity_check = ICE_WAITING;
					memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
					remote_candidates[pos].retransmission_time = 0;
					remote_candidates[pos].retransmission_number = 0;
				}
			}
		}

		if (checklist->rem_controlling==1 && msg.hasIceControlled) {

			/* If the agent's tie-breaker is larger than or equal
			to the contents of the ICE-CONTROLLED attribute
			-> change ROLE */
			if (checklist->tiebreak_value >= msg.iceControlled.value) {
				int pos;
				for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
				{
					/* controller agent */
					uint64_t G = remote_candidates[pos].local_candidate.priority;
					/* controlled agent */	
					uint64_t D = remote_candidates[pos].remote_candidate.priority;
					remote_candidates[pos].pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
				}
				checklist->rem_controlling = 0;
				/* reset all to initial WAITING state? */
				ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state");
				for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
				{
					if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
						continue;
					remote_candidates[pos].connectivity_check = ICE_WAITING;
					memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
					remote_candidates[pos].retransmission_time = 0;
					remote_candidates[pos].retransmission_number = 0;
				}
			}
			else {
				char buf[STUN_MAX_MESSAGE_SIZE];
				int len = sizeof(buf);
				ms_error("ice.c: STUN REQ <- 487 Role Conflict");
				_ice_createErrorResponse(&resp, 4, 87, "Role Conflict");
				len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
				if (len)
					sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
				return -1;
			}
		}

		{
			struct CandidatePair *cand_pair;
			int pos;
			cand_pair=NULL;
			for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
			{
				cand_pair = &remote_candidates[pos]; 
				/* connectivity check is coming from a known remote candidate?
				we should also check the port...
				*/
				if (strcmp(cand_pair->remote_candidate.conn_addr, src6host)==0
					&& cand_pair->remote_candidate.conn_port==recvport)
				{
					ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) from known peer",
						msg.hasUseCandidate==0?"":"USE-CANDIDATE",
						pos,
						cand_pair->local_candidate.conn_addr,
						cand_pair->local_candidate.conn_port,
						cand_pair->local_candidate.cand_type,
						cand_pair->remote_candidate.conn_addr,
						cand_pair->remote_candidate.conn_port,
						cand_pair->remote_candidate.cand_type);
					if (cand_pair->connectivity_check==ICE_FROZEN
						|| cand_pair->connectivity_check==ICE_IN_PROGRESS
						|| cand_pair->connectivity_check==ICE_FAILED)
					{
						cand_pair->connectivity_check = ICE_WAITING;
						if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
							cand_pair->nominated_pair = 1;
					}
					else if (cand_pair->connectivity_check==ICE_SUCCEEDED)
					{
						if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
						{
							cand_pair->nominated_pair = 1;

							/* USE-CANDIDATE is in STUN request and we already succeeded on that link */
							ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
								pos,
								cand_pair->local_candidate.conn_addr,
								cand_pair->local_candidate.conn_port,
								cand_pair->local_candidate.cand_type,
								cand_pair->remote_candidate.conn_addr,
								cand_pair->remote_candidate.conn_port,
								cand_pair->remote_candidate.cand_type,
								cand_pair->nominated_pair==0?"FALSE":"TRUE");
							memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
							session->rtp.rem_addrlen=evt_data->ep->addrlen;
						}
					}
					break;
				}
				cand_pair=NULL;
			}
			if (cand_pair==NULL)
			{
				struct CandidatePair new_pair;
				memset(&new_pair, 0, sizeof(struct CandidatePair));

				ms_message("ice.c: STUN REQ <- connectivity check received from an unknow candidate (%s:%i)", src6host, recvport);
				/* TODO: add the peer-reflexive candidate */

				memcpy(&new_pair.local_candidate, &remote_candidates[0].local_candidate, sizeof(new_pair.local_candidate));

				new_pair.remote_candidate.foundation = 6;
				new_pair.remote_candidate.component_id = remote_candidates[0].remote_candidate.component_id;

				/* -> no known base address for peer */

				new_pair.remote_candidate.conn_port = recvport;
				snprintf(new_pair.remote_candidate.conn_addr, sizeof(new_pair.remote_candidate.conn_addr),
					"%s", src6host);

				/* take it from PRIORITY STUN attr */
				new_pair.remote_candidate.priority = msg.priority.priority;
				if (new_pair.remote_candidate.priority==0)
				{
					uint32_t type_preference = 110;
					uint32_t interface_preference = 255;
					uint32_t stun_priority=255;
					new_pair.remote_candidate.priority = (type_preference << 24) | (interface_preference << 16) | (stun_priority << 8)
						| (256 - new_pair.remote_candidate.component_id);
				}

				snprintf(new_pair.remote_candidate.cand_type, sizeof(cand_pair->remote_candidate.cand_type),
					"prflx");
				snprintf (new_pair.remote_candidate.transport,
								sizeof (new_pair.remote_candidate.transport),
								"UDP");

				if (checklist->rem_controlling==0)
				{
					uint64_t G = new_pair.local_candidate.priority;
					/* controlled agent */	
					uint64_t D = new_pair.remote_candidate.priority;
					new_pair.pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
				}
				else
				{
					uint64_t G = new_pair.remote_candidate.priority;
					/* controlled agent */	
					uint64_t D = new_pair.local_candidate.priority;
					new_pair.pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
				}
				new_pair.connectivity_check = ICE_WAITING;
				/* insert new pair candidate */
				if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
				{
					new_pair.nominated_pair = 1;
				}

				for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
				{
					if (pos==9)
					{
						ms_message("ice.c: STUN REQ (%s) <- X (%s:%i:%s <- %s:%i:%s) no room for new remote reflexive candidate",
							msg.hasUseCandidate==0?"":"USE-CANDIDATE",
							new_pair.local_candidate.conn_addr,
							new_pair.local_candidate.conn_port,
							new_pair.local_candidate.cand_type,
							new_pair.remote_candidate.conn_addr,
							new_pair.remote_candidate.conn_port,
							new_pair.remote_candidate.cand_type);
						break;
					}
					if (new_pair.pair_priority > remote_candidates[pos].pair_priority)
					{
						/* move upper data */
						memmove(&remote_candidates[pos+1], &remote_candidates[pos], sizeof(struct CandidatePair)*(10-pos-1));
						memcpy(&remote_candidates[pos], &new_pair, sizeof(struct CandidatePair));

						if (checklist->nominated_pair_index>=pos)
							checklist->nominated_pair_index++;
						ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) new learned remote reflexive candidate",
							msg.hasUseCandidate==0?"":"USE-CANDIDATE",
							pos,
							new_pair.local_candidate.conn_addr,
							new_pair.local_candidate.conn_port,
							new_pair.local_candidate.cand_type,
							new_pair.remote_candidate.conn_addr,
							new_pair.remote_candidate.conn_port,
							new_pair.remote_candidate.cand_type);
						break;
					}
				}
			}
		}

		{
			uint32_t cookie = 0x2112A442;
			resp.hasXorMappedAddress = TRUE;
			resp.xorMappedAddress.ipv4.port = remote_addr.port^(cookie>>16);
			resp.xorMappedAddress.ipv4.addr = remote_addr.addr^cookie;
		}

		resp.msgHdr.msgType = (STUN_METHOD_BINDING | STUN_SUCCESS_RESP);

		resp.hasUsername = TRUE;
		memcpy(resp.username.value, msg.username.value, msg.username.sizeValue );
		resp.username.sizeValue = msg.username.sizeValue;

		/* ? any messageintegrity in response? */
		resp.hasMessageIntegrity = TRUE;

		{
			const char serverName[] = "mediastreamer2 " STUN_VERSION;
			resp.hasSoftware = TRUE;
			memcpy( resp.softwareName.value, serverName, sizeof(serverName));
			resp.softwareName.sizeValue = sizeof(serverName);
		}

		resp.hasFingerprint = TRUE;

		{
			char buf[STUN_MAX_MESSAGE_SIZE];
			int len = sizeof(buf);
			len = stunEncodeMessage( &resp, buf, len, &hmacPassword );
			if (len)
				sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
		}
	}
示例#8
0
static int ice_sound_send_stun_request(RtpSession *session, struct IceCheckList *checklist, uint64_t ctime)
{
	struct CandidatePair *remote_candidates = NULL;

	if (checklist==NULL)
		return 0;
	remote_candidates = checklist->cand_pairs;
	if (remote_candidates==NULL)
		return 0;

	{
		struct CandidatePair *cand_pair;
		int media_socket = rtp_session_get_rtp_socket(session);
		StunAddress4 stunServerAddr;
		StunAtrString username;
		StunAtrString password;
		bool_t res;
		int pos;

		/* prepare ONCE tie-break value */
		if (checklist->tiebreak_value==0) {
			checklist->tiebreak_value = random() * (0x7fffffffffffffffLL /0x7fff);
		}

		cand_pair=NULL;
		for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
		{
			cand_pair = &remote_candidates[pos];
			if (cand_pair->connectivity_check == ICE_PRUNED)
			{
				cand_pair=NULL;
				continue;
			}
			if (cand_pair->connectivity_check == ICE_WAITING)
				break;
			if (cand_pair->connectivity_check == ICE_IN_PROGRESS)
				break;
			if (cand_pair->connectivity_check == ICE_SUCCEEDED)
				break;
			cand_pair=NULL;
		}

		if (cand_pair==NULL)
			return 0; /* nothing to do: every pair is FAILED, FROZEN or PRUNED */

		/* start first WAITING pair */
		cand_pair=NULL;
		for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
		{
			cand_pair = &remote_candidates[pos];
			if (cand_pair->connectivity_check == ICE_PRUNED)
			{
				cand_pair=NULL;
				continue;
			}
			if (cand_pair->connectivity_check == ICE_WAITING)
				break;
			cand_pair=NULL;
		}

		if (cand_pair!=NULL)
		{
			cand_pair->connectivity_check = ICE_IN_PROGRESS;
			cand_pair->retransmission_number=0;
			cand_pair->retransmission_time=ctime+checklist->RTO;
			/* keep same rem_controlling for retransmission */
			cand_pair->rem_controlling = checklist->rem_controlling;
		}

		/* try no nominate a pair if we are ready */
		if (cand_pair==NULL && checklist->nominated_pair_index<0)
		{
			for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
			{
				cand_pair = &remote_candidates[pos];
				if (cand_pair->connectivity_check == ICE_PRUNED)
				{
					cand_pair=NULL;
					continue;
				}
				if (cand_pair->connectivity_check == ICE_SUCCEEDED)
				{
					break;
				}
				cand_pair=NULL;
			}

			/* ALWAYS accept "host" candidate that have succeeded */
			if (cand_pair!=NULL
				&& (strcasecmp(cand_pair->remote_candidate.cand_type, "host")==0))
			{
				checklist->nominated_pair_index = pos;
				cand_pair->nominated_pair = 1;
				cand_pair->connectivity_check = ICE_IN_PROGRESS;
				cand_pair->retransmission_number=0;
				cand_pair->retransmission_time=ctime+checklist->RTO;
				/* keep same rem_controlling for retransmission */
				cand_pair->rem_controlling = checklist->rem_controlling;
				/* send a new STUN with USE-CANDIDATE */
				ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
					pos,
					cand_pair->local_candidate.conn_addr,
					cand_pair->local_candidate.conn_port,
					cand_pair->local_candidate.cand_type,
					cand_pair->remote_candidate.conn_addr,
					cand_pair->remote_candidate.conn_port,
					cand_pair->remote_candidate.cand_type,
					cand_pair->nominated_pair==0?"FALSE":"TRUE");
				checklist->keepalive_time=ctime+15*1000;
			}
			else if (cand_pair!=NULL)
			{
				struct CandidatePair *cand_pair2=NULL;
				int pos2;
				for (pos2=0;pos2<pos && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
				{
					cand_pair2 = &remote_candidates[pos2];
					if (cand_pair2->connectivity_check == ICE_PRUNED)
					{
						cand_pair2=NULL;
						continue;
					}
					if (cand_pair2->connectivity_check == ICE_IN_PROGRESS
						||cand_pair2->connectivity_check == ICE_WAITING)
					{
						break;
					}
					cand_pair2=NULL;
				}

				if (cand_pair2!=NULL)
				{
					/* a better candidate is still tested */
					cand_pair=NULL;
				}
				else
				{
					checklist->nominated_pair_index = pos;
					cand_pair->nominated_pair = 1;
					cand_pair->connectivity_check = ICE_IN_PROGRESS;
					cand_pair->retransmission_number=0;
					cand_pair->retransmission_time=ctime+checklist->RTO;
					/* keep same rem_controlling for retransmission */
					cand_pair->rem_controlling = checklist->rem_controlling;
					/* send a new STUN with USE-CANDIDATE */
					ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
						pos,
						cand_pair->local_candidate.conn_addr,
						cand_pair->local_candidate.conn_port,
						cand_pair->local_candidate.cand_type,
						cand_pair->remote_candidate.conn_addr,
						cand_pair->remote_candidate.conn_port,
						cand_pair->remote_candidate.cand_type,
						cand_pair->nominated_pair==0?"FALSE":"TRUE");
					checklist->keepalive_time=ctime+15*1000;
				}
			}
		}

		if (cand_pair==NULL)
		{
			/* no WAITING pair: retransmit after RTO */
			for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
			{
				cand_pair = &remote_candidates[pos];
				if (cand_pair->connectivity_check == ICE_PRUNED)
				{
					cand_pair=NULL;
					continue;
				}
				if (cand_pair->connectivity_check == ICE_IN_PROGRESS
					&& ctime > cand_pair->retransmission_time)
				{
					if (cand_pair->retransmission_number>7)
					{
						ms_message("ice.c: ICE_FAILED for candidate pair! %s:%i -> %s:%i",
							cand_pair->local_candidate.conn_addr,
							cand_pair->local_candidate.conn_port,
							cand_pair->remote_candidate.conn_addr,
							cand_pair->remote_candidate.conn_port);

						cand_pair->connectivity_check = ICE_FAILED;
						cand_pair=NULL;
						continue;
					}

					cand_pair->retransmission_number++;
					cand_pair->retransmission_time=ctime+checklist->RTO;
					break;
				}
				cand_pair=NULL;
			}
		}

		if (cand_pair==NULL)
		{
			if (checklist->nominated_pair_index<0)
				return 0;

			/* send STUN indication each 15 seconds: keepalive */
			if (ctime>checklist->keepalive_time)
			{
				checklist->keepalive_time=ctime+15*1000;
				for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
				{
					cand_pair = &remote_candidates[pos];
					if (cand_pair->connectivity_check == ICE_SUCCEEDED)
					{
						res = stunParseServerName(cand_pair->remote_candidate.conn_addr,
							&stunServerAddr);
						if ( res == TRUE )
						{
							StunMessage req;
							char buf[STUN_MAX_MESSAGE_SIZE];
							int len = STUN_MAX_MESSAGE_SIZE;
							stunServerAddr.port = cand_pair->remote_candidate.conn_port;
							memset(&req, 0, sizeof(StunMessage));
							stunBuildReqSimple( &req, NULL, FALSE, FALSE, 1);
							req.msgHdr.msgType = (STUN_METHOD_BINDING|STUN_INDICATION);
							req.hasFingerprint = TRUE;
							len = stunEncodeMessage( &req, buf, len, NULL);
							sendMessage( media_socket, buf, len, stunServerAddr.addr, stunServerAddr.port );
						}
					}
				}
			}

			return 0;
		}

		username.sizeValue = 0;
		password.sizeValue = 0;

		/* username comes from "ice-ufrag" (rfrag:lfrag) */
		/* ufrag and pwd are in first row only */
		snprintf(username.value, sizeof(username.value), "%s:%s",
			checklist->rem_ice_ufrag,
			checklist->loc_ice_ufrag);
		username.sizeValue = (uint16_t)strlen(username.value);


		snprintf(password.value, sizeof(password.value), "%s",
			checklist->rem_ice_pwd);
		password.sizeValue = (uint16_t)strlen(password.value);


		res = stunParseServerName(cand_pair->remote_candidate.conn_addr,
			&stunServerAddr);
		if ( res == TRUE )
		{
			ms_message("ice.c: STUN REQ (%s) -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
				cand_pair->nominated_pair==0?"":"USE-CANDIDATE",
				pos,
				cand_pair->local_candidate.conn_addr,
				cand_pair->local_candidate.conn_port,
				cand_pair->local_candidate.cand_type,
				cand_pair->remote_candidate.conn_addr,
				cand_pair->remote_candidate.conn_port,
				cand_pair->remote_candidate.cand_type,
				cand_pair->nominated_pair==0?"FALSE":"TRUE");
			stunServerAddr.port = cand_pair->remote_candidate.conn_port;
			ice_sendtest(checklist, cand_pair, media_socket, &stunServerAddr, &username, &password,
				&(cand_pair->tid));
		}
	}

	return 0;
}
示例#9
0
ortp_socket_t udt_getsocket(struct _RtpTransport *t){
	UDT_transport *myudt = (UDT_transport *)t->data;

	return rtp_session_get_rtp_socket(myudt->rtp_session);
}
示例#10
0
int ice_sound_send_stun_request(RtpSession *session, struct CandidatePair *remote_candidates, int round)
{
	int roll=250;
#if 0
    /* in "passive" mode (UA not behind a NATor behind a full cone NAT),
    wait a few delay before sending the first STUN request:
    this help to traverse */
    if (session->setup_passive>0)
    {
        return 0;
    }
#endif

	if (remote_candidates==NULL)
		return 0;

	if (round>500)
		roll=2*roll;

    if (round%roll==50)
    {
        int pos;

#if 0
        /* do this only with application that support this */
        if (osip_strncasecmp(remote_useragent, "linphone/", 8)!=0)
        {
            /* use stun only with linphone to linphone softphone */
            return 0;
        }
#endif

        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++)
        {
            int media_socket = rtp_session_get_rtp_socket(session);
            StunAddress4 stunServerAddr;
            StunAtrString username;
            StunAtrString password;
            bool res;
            int  pad_size;

            struct CandidatePair *cand_pair = &remote_candidates[pos]; 
            username.sizeValue = 0;
            password.sizeValue = 0;

            /* set username to L3:1:R2:1 */
            snprintf(username.value, sizeof(username.value), "%s:%i:%s:%i",
                cand_pair->local_candidate.candidate_id,
                1,
                cand_pair->remote_candidate.candidate_id,
                1);
            username.sizeValue = (UInt16)strlen(username.value);
            pad_size = username.sizeValue % 4;

            username.value[username.sizeValue]='\0';
            username.value[username.sizeValue+1]='\0';
            username.value[username.sizeValue+2]='\0';
            username.value[username.sizeValue+3]='\0';

            username.sizeValue = username.sizeValue + 4 - pad_size;

            snprintf(password.value, sizeof(password.value), "%s",
                cand_pair->remote_candidate.password);
            password.sizeValue = (UInt16)strlen(password.value);

#if 0
            pad_size = password.sizeValue%4;
            password.value[password.sizeValue]='\0';
            password.value[password.sizeValue+1]='\0';
            password.value[password.sizeValue+2]='\0';
            password.value[password.sizeValue+3]='\0';
            password.sizeValue = password.sizeValue + pad_size;
#endif

            res = stunParseServerName(cand_pair->remote_candidate.ipaddr,
                &stunServerAddr);
            if ( res == true )
            {
                stunServerAddr.port = cand_pair->remote_candidate.port;
                ice_sendtest(media_socket, &stunServerAddr, &username, &password, 1, 0/*false*/,
                    &(cand_pair->tid));
            }
        }
    }

    return 0;
}
示例#11
0
int ice_process_stun_message(RtpSession *session, struct CandidatePair *remote_candidates, OrtpEvent *evt)
{
    bool switch_to_address = -1;
    StunMessage msg;
    bool res;
    int already_worked_once=-1;
    OrtpEventData *evt_data = ortp_event_get_data(evt);
    mblk_t *mp = evt_data->packet;
    struct sockaddr_in *udp_remote;
    char src6host[NI_MAXHOST];
    int recvport = 0;
    int i;

    udp_remote = (struct sockaddr_in*)&evt_data->ep->addr;

    memset( &msg, 0 , sizeof(msg) );
    res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &msg, 0);
    if (!res)
    {
        ms_error("ice.c: Malformed STUN packet.");
        return -1;
    }

    memset (src6host, 0, sizeof (src6host));

    {
      struct sockaddr_storage *aaddr = (struct sockaddr_storage *)&evt_data->ep->addr;
      if (aaddr->ss_family==AF_INET)
        recvport = ntohs (((struct sockaddr_in *) udp_remote)->sin_port);
      else
        recvport = ntohs (((struct sockaddr_in6 *) &evt_data->ep->addr)->sin6_port);
    }
    i = getnameinfo ((struct sockaddr*)&evt_data->ep->addr, evt_data->ep->addrlen,
                    src6host, NI_MAXHOST,
                    NULL, 0, NI_NUMERICHOST);
    if (i != 0)
    {
        ms_error("ice.c: Error with getnameinfo");
    } else
    {
	    if (msg.msgHdr.msgType == BindRequestMsg)
		    ms_message("ice.c: Request received from: %s:%i",
			            src6host, recvport);
		else
		    ms_message("ice.c: Answer received from: %s:%i",
			            src6host, recvport);
    }

    if (remote_candidates!=NULL) {
        int pos;
        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++)
        {
            struct CandidatePair *cand_pair = &remote_candidates[pos];
#ifdef RESTRICTIVE_ICE
            if (cand_pair->connectivity_check == VALID
                ||cand_pair->connectivity_check == RECV_VALID)
            {
                already_worked_once=pos;
                break;
            }
#else
            if (cand_pair->connectivity_check == VALID
                ||cand_pair->connectivity_check == RECV_VALID
		||cand_pair->connectivity_check == SEND_VALID)
            {
                already_worked_once=pos;
                break;
            }
#endif
        }
    }

    if (msg.msgHdr.msgType == BindRequestMsg)
    {
        StunMessage resp;
        StunAddress4 dest;
        StunAtrString hmacPassword;
        StunAddress4 from;
        StunAddress4 secondary;
        StunAddress4 myAddr;
        StunAddress4 myAltAddr;
        bool changePort = false;
        bool changeIp = false;
        struct sockaddr_storage name;
        socklen_t namelen;
        char localip[128];
        int rtp_socket;
        memset(&name, '\0', sizeof(struct sockaddr_storage));
        memset(localip, '\0', sizeof(localip));
        _ice_get_localip_for ((struct sockaddr_storage*)&evt_data->ep->addr, evt_data->ep->addrlen, localip, 128);

        from.addr = ntohl(udp_remote->sin_addr.s_addr);
        from.port = ntohs(udp_remote->sin_port);
        
        secondary.addr = 0;
        secondary.port = 0;

        namelen = sizeof(struct sockaddr_storage);
        rtp_socket = rtp_session_get_rtp_socket(session);
        i = getsockname(rtp_socket, (struct sockaddr*)&name, &namelen);
        if (i!=0)
        {
            ms_error("ice.c: getsockname failed.");
            return -1;
        }

        myAddr.port = ntohs (((struct sockaddr_in*)&name)->sin_port);
        i = stunParseHostName(localip, &myAddr.addr, &myAddr.port, myAddr.port);
        if (!i)
        {
            ms_error("ice.c: stunParseHostName failed.");
            return -1;
        }
        myAddr.port = ntohs (((struct sockaddr_in*)&name)->sin_port);
    
        /* changed-address set to local address/port */
        myAltAddr = myAddr;
        dest.addr = 0;
        dest.port = 0;

        res = stunServerProcessMsg((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr,
            &from,
            &secondary,
            &myAddr,
            &myAltAddr, 
            &resp,
            &dest,
            &hmacPassword,
            &changePort,
            &changeIp,
            false );

        if (!res)
        {
            ms_error("ice.c: Failed to process STUN request.");
            return -1;
        }

        if (changePort == true || changeIp == true)
        {
            ms_error("ice.c: STUN request with changePort or changeIP refused.");
            return -1;
        }

        res=true;
        if ( dest.addr == 0 ) res=false;
        if ( dest.port == 0 ) res=false;
        if (!res)
        {
            ms_error("ice.c: Missing destination value for response.");
            return -1;
        }

    
        if (msg.hasUsername!=true || msg.username.sizeValue<=0)
        {
            /* reply 430 */
            ms_error("ice.c: Missing or bad username value.");
            return -1;
        }

        /*
        USERNAME is considered valid if its topmost portion (the part up to,
        but not including the second colon) corresponds to a transport address
        ID known to the agent.
        */
	    if (remote_candidates!=NULL) {
            int pos;
            for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++)
            {
                char username[256];
                struct CandidatePair *cand_pair = &remote_candidates[pos]; 
                size_t len = strlen(cand_pair->remote_candidate.candidate_id);

                if (cand_pair->connectivity_check == VALID)
                {
                    break;
                }

                memset(username, '\0', sizeof(username));
                snprintf(username, sizeof(username), "%s:%i:%s:%i",
                    cand_pair->remote_candidate.candidate_id,
                    1,
                    cand_pair->local_candidate.candidate_id,
                    1);

                if (len+3<msg.username.sizeValue
                    && strncmp(msg.username.value, cand_pair->remote_candidate.candidate_id, len)==0)
                {
                    char tmp[10];
                    int k;
                    snprintf(tmp, 10, "%s", msg.username.value + len +1);
                    for (k=0;k<10;k++)
                    {
                        if (tmp[k]=='\0')
                            break;
                        if (tmp[k]==':')
                        {
                            tmp[k]='\0';
                            break;
                        }
                    }
                    k = atoi(tmp);
                    /* TODO support for 2 stream RTP+RTCP */
                    if (k>0 && k<10 && k==1)
                    {
                        /* candidate-id found! */
#if 0
                        ms_message("ice.c: Find candidate id (index=%i) for incoming STUN request.", pos);
#endif

                        if (strncmp(msg.username.value, username, strlen(username))==0)
                        {
#ifdef RESTRICTIVE_ICE
                                ms_message("ice.c: Valid STUN request received (to=%s:%i from=%s:%i).",
                                cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port,
                                src6host, recvport);
				/* We can't be sure the remote end will receive our answer:
				connection could be only one way...
				*/
				if (cand_pair->connectivity_check != VALID)
                            {
                                switch_to_address = pos;
                            }
#else
				switch_to_address = pos;
#endif
                            if (cand_pair->connectivity_check == RECV_VALID
                                || cand_pair->connectivity_check == VALID)
                            {
                                if (cand_pair->connectivity_check != VALID)
                                {
	                                switch_to_address = pos;
                                    ms_message("ice.c: candidate id (index=%i) moved in VALID state (stunbindingrequest received).", pos);
                                    cand_pair->connectivity_check = VALID;
                                }
                            }
                            else
                                cand_pair->connectivity_check = SEND_VALID;

                            /* we have a VALID one */
                        }
                    }
                }
            }
        }
        
        /*
        The password associated with that transport address ID is used to verify
        the MESSAGE-INTEGRITY attribute, if one was present in the request.
        */


        {
            char buf[STUN_MAX_MESSAGE_SIZE];            
            int len = sizeof(buf);
            len = stunEncodeMessage( &resp, buf, len, &hmacPassword,false );
            if (len)
                sendMessage( rtp_socket, buf, len, dest.addr, dest.port, false );
        }
    }
    else
    {
        /* set state to RECV-VALID or VALID */
        StunMessage resp;
        StunAddress4 mappedAddr;
        memset(&resp, 0, sizeof(StunMessage));
        res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr,
            &resp, false );
        if (!res)
        {
            ms_error("ice.c: Bad format for STUN answer.");
            return -1;
        }

        mappedAddr = resp.mappedAddress.ipv4;

	    if (remote_candidates!=NULL) {
            int pos;
            for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++)
            {
                struct CandidatePair *cand_pair = &remote_candidates[pos];

                if (memcmp(&(cand_pair->tid), &(resp.msgHdr.id), sizeof(resp.msgHdr.id))==0)
                {
                    /* Youhouhouhou */
                    if (cand_pair->connectivity_check != VALID)
                    {
                        switch_to_address = pos;
                    }
#if 0
					ms_message("ice.c: Valid STUN answer received (to=%s:%i from=%s:%i)",
                        cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port,
                        src6host, recvport);
#endif
                    if (cand_pair->connectivity_check == SEND_VALID
                        || cand_pair->connectivity_check == VALID)
                    {
                        if (cand_pair->connectivity_check != VALID)
                        {
                            ms_message("ice.c: Switch to VALID mode for (to=%s:%i from=%s:%i)",
                                cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port,
                                src6host, recvport);
                            cand_pair->connectivity_check = VALID;
                        }
                    }
                    else
                        cand_pair->connectivity_check = RECV_VALID;
                }
            }
        }
    }

    if (remote_candidates==NULL) {
        ms_warning("ice.c: STUN connectivity check is disabled but we received a STUN message (%s:%i)\n",
            src6host, recvport);
		return 0;
	}
	if (switch_to_address == -1)
        return 0;

	{
        /* skip symmetric RTP if any previous connection is working */
        if (switch_to_address<already_worked_once || already_worked_once==-1)
        {
            /* rtp_in_direct_mode = 1; */
            /* current destination address: snprintf(rtp_remote_addr, 256, "%s:%i", src6host, recvport); */
            ms_warning("ice.c: Modifying remote socket: symmetric RTP (%s:%i)\n",
                src6host, recvport);
            memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
			session->rtp.rem_addrlen=evt_data->ep->addrlen;
        }
    }
    return 0;
}