void media_stream_iterate(MediaStream *stream){
	time_t curtime=ms_time(NULL);

	if (stream->ice_check_list) ice_check_list_process(stream->ice_check_list,stream->sessions.rtp_session);
	/*we choose to update the quality indicator as much as possible, since local statistics can be computed realtime. */
	if (stream->state==MSStreamStarted){
		if (stream->qi && curtime>stream->last_iterate_time) ms_quality_indicator_update_local(stream->qi);
	}
	stream->last_iterate_time=curtime;

	if (stream->rc) ms_bitrate_controller_update(stream->rc);

	if (stream->evq){
		OrtpEvent *ev=NULL;

		while ((ev=ortp_ev_queue_get(stream->evq))!=NULL){
			OrtpEventType evt=ortp_event_get_type(ev);
			if (evt==ORTP_EVENT_RTCP_PACKET_RECEIVED){
				mblk_t *m=ortp_event_get_data(ev)->packet;
				media_stream_process_rtcp(stream,m,curtime);
			}else if (evt==ORTP_EVENT_RTCP_PACKET_EMITTED){
				ms_message("%s_stream_iterate[%p]: local statistics available\n\tLocal's current jitter buffer size:%f ms",
					media_stream_type_str(stream), stream, rtp_session_get_jitter_stats(stream->sessions.rtp_session)->jitter_buffer_size_ms);
			}else if ((evt==ORTP_EVENT_STUN_PACKET_RECEIVED)&&(stream->ice_check_list)){
				ice_handle_stun_packet(stream->ice_check_list,stream->sessions.rtp_session,ortp_event_get_data(ev));
			} else if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED) {
				OrtpEventData *evd=ortp_event_get_data(ev);
				stream->sessions.is_secured=evd->info.zrtp_stream_encrypted;
				ms_message("%s_stream_iterate[%p]: is %s ",media_stream_type_str(stream) , stream, stream->sessions.is_secured ? "encrypted" : "not encrypted");
			}
			ortp_event_destroy(ev);
		}
	}
}
Esempio n. 2
0
/**
 * @brief Switch on the security.
 *
 * ZRTP calls this method after it has computed the SAS and checked
 * if it was verified in the past.
 *
 * This method must enable SRTP processing if it was not enabled
 * during setSecretsReady().
 *
 * This call will trigger an event which shall be catched by linphone_call_handle_stream_events
 *
 * @param[in]	clientData	Pointer to our ZrtpContext structure used to retrieve RTP session
 * @param[in]	sas		The SAS string(4 characters, not null terminated, fixed length)
 * @param[in]	verified	if <code>verified</code> is true then SAS was verified by both parties during a previous call.
 */
static int ms_zrtp_startSrtpSession(void *clientData, const char* sas, int32_t verified ){
	MSZrtpContext *userData = (MSZrtpContext *)clientData;

	// srtp processing is enabled in SecretsReady fuction when receiver secrets are ready
	// Indeed, the secrets on is called before both parts are given to secretsReady.

	OrtpEventData *eventData;
	OrtpEvent *ev;

	if (sas != NULL) {
		ev=ortp_event_new(ORTP_EVENT_ZRTP_SAS_READY);
		eventData=ortp_event_get_data(ev);
		// support both b32 and b256 format SAS strings
		snprintf(eventData->info.zrtp_sas.sas, sizeof(eventData->info.zrtp_sas.sas), "%s", sas);
		eventData->info.zrtp_sas.verified=(verified != 0) ? TRUE : FALSE;
		rtp_session_dispatch_event(userData->stream_sessions->rtp_session, ev);
		ms_message("ZRTP secrets on: SAS is %.32s previously verified %s", sas, verified == 0 ? "no" : "yes");
	}

	ev=ortp_event_new(ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED);
	eventData=ortp_event_get_data(ev);
	eventData->info.zrtp_stream_encrypted=1;
	rtp_session_dispatch_event(userData->stream_sessions->rtp_session, ev);
	ms_message("Event dispatched to all: secrets are on");


	return 0;
}
Esempio n. 3
0
OrtpEvent *ortp_event_dup(OrtpEvent *ev){
	OrtpEvent *nev = ortp_event_new(ortp_event_get_type(ev));
	OrtpEventData * ed = ortp_event_get_data(ev);
	OrtpEventData * edv = ortp_event_get_data(nev);
	memcpy(edv,ed,sizeof(OrtpEventData));
	if (ed->ep) edv->ep = rtp_endpoint_dup(ed->ep);
	if (ed->packet) edv->packet = copymsg(ed->packet);
	return nev;
}
static void handle_queue_events(stream_manager_t * stream_mgr) {
	OrtpEvent *ev;
	while (NULL != (ev=ortp_ev_queue_get(stream_mgr->evq))){
		OrtpEventType evt=ortp_event_get_type(ev);
		OrtpEventData *evd=ortp_event_get_data(ev);

		if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
			const report_block_t *rb=NULL;
			if (rtcp_is_SR(evd->packet)){
				rb=rtcp_SR_get_report_block(evd->packet,0);
			}else if (rtcp_is_RR(evd->packet)){
				rb=rtcp_RR_get_report_block(evd->packet,0);
			}

			if (rb){
				stream_mgr->rtcp_count++;

				if (stream_mgr->type==VideoStreamType&&stream_mgr->video_stream->ms.use_rc){
					const MSQosAnalyzer *analyzer=ms_bitrate_controller_get_qos_analyzer(stream_mgr->video_stream->ms.rc);
					if (analyzer->type==Stateful){
						const MSStatefulQosAnalyzer *stateful_analyzer=((const MSStatefulQosAnalyzer*)analyzer);
						stream_mgr->adaptive_stats.network_state=stateful_analyzer->network_state;
						stream_mgr->adaptive_stats.loss_estim =100*stateful_analyzer->network_loss_rate;
						stream_mgr->adaptive_stats.congestion_bw_estim =stateful_analyzer->congestion_bandwidth;
					}
				}
			}
		}
		ortp_event_destroy(ev);
	}
}
static void event_queue_cb(MediaStream *ms, void *user_pointer) {
	stats_t *st = (stats_t *)user_pointer;
	OrtpEvent *ev = NULL;

	if (st->q != NULL) {
		while ((ev = ortp_ev_queue_get(st->q)) != NULL) {
			OrtpEventType evt = ortp_event_get_type(ev);
			OrtpEventData *d = ortp_event_get_data(ev);
			if (evt == ORTP_EVENT_TMMBR_RECEIVED) {
				do {
					if (rtcp_is_RTPFB(d->packet)) {
						switch (rtcp_RTPFB_get_type(d->packet)) {
							case RTCP_RTPFB_TMMBR:
								st->number_of_TMMBR++;
								break;
							default:
								break;
						}
					}
				} while (rtcp_next_packet(d->packet));
			}
			ortp_event_destroy(ev);
		}
	}
}
static void event_queue_cb(MediaStream *ms, void *user_pointer) {
	LossRateEstimatorCtx *ctx = (LossRateEstimatorCtx*)user_pointer;
	if (ctx->q != NULL) {
		OrtpEvent *ev = NULL;
		while ((ev = ortp_ev_queue_get(ctx->q)) != NULL) {
			OrtpEventType evt = ortp_event_get_type(ev);
			OrtpEventData *evd = ortp_event_get_data(ev);
			if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED) {
				do {
					const report_block_t *rb=NULL;
					if (rtcp_is_SR(evd->packet)){
						rb=rtcp_SR_get_report_block(evd->packet,0);
					}else if (rtcp_is_RR(evd->packet)){
						rb=rtcp_RR_get_report_block(evd->packet,0);
					}

					if (rb&&ortp_loss_rate_estimator_process_report_block(ctx->estimator,&ms->sessions.rtp_session->rtp,rb)){
						float diff = fabs(ortp_loss_rate_estimator_get_value(ctx->estimator) - ctx->loss_rate);
						CU_ASSERT_IN_RANGE(diff, 0, 10);
					}
				} while (rtcp_next_packet(evd->packet));
			}
			ortp_event_destroy(ev);
		}
	}
}
Esempio n. 7
0
void ortp_event_destroy(OrtpEvent *ev){
	OrtpEventData *d=ortp_event_get_data(ev);
	if (ev->b_datap->db_ref==1){
		if (d->packet) 	freemsg(d->packet);
		if (d->ep) rtp_endpoint_destroy(d->ep);
	}
	freemsg(ev);
}
void audio_stream_iterate(AudioStream *stream){
	if (stream->ms.evq){
		OrtpEvent *ev=ortp_ev_queue_get(stream->ms.evq);
		if (ev!=NULL){
			OrtpEventType evt=ortp_event_get_type(ev);
			if (evt==ORTP_EVENT_RTCP_PACKET_RECEIVED){
				audio_stream_process_rtcp(stream,ortp_event_get_data(ev)->packet);
				stream->last_packet_time=ms_time(NULL);
			}else if (evt==ORTP_EVENT_RTCP_PACKET_EMITTED){
				ms_message("audio_stream_iterate(): local statistics available\n\tLocal's current jitter buffer size:%f ms",rtp_session_get_jitter_stats(stream->ms.session)->jitter_buffer_size_ms);
			}else if ((evt==ORTP_EVENT_STUN_PACKET_RECEIVED)&&(stream->ms.ice_check_list)){
				ice_handle_stun_packet(stream->ms.ice_check_list,stream->ms.session,ortp_event_get_data(ev));
			}
			ortp_event_destroy(ev);
		}
	}
	media_stream_iterate(&stream->ms);
}
Esempio n. 9
0
OrtpEvent * ortp_event_new(unsigned long type){
	OrtpEventData *ed;
	const int size=sizeof(OrtpEventType)+sizeof(OrtpEventData);
	mblk_t *m=allocb(size,0);
	memset(m->b_wptr,0,size);
	*((OrtpEventType*)m->b_wptr)=type;
	ed = ortp_event_get_data(m);
	ortp_get_cur_time(&ed->ts);
	return m;
}
Esempio n. 10
0
static void notify_sent_rtcp(RtpSession *session, mblk_t *rtcp){
	if (session->eventqs!=NULL){
		OrtpEvent *ev;
		OrtpEventData *evd;
		ev=ortp_event_new(ORTP_EVENT_RTCP_PACKET_EMITTED);
		evd=ortp_event_get_data(ev);
		evd->packet=dupmsg(rtcp);
		rtp_session_dispatch_event(session,ev);
	}
}
Esempio n. 11
0
void video_stream_iterate(VideoStream *stream){
	/*
	if (stream->output!=NULL)
		ms_filter_call_method_noarg(stream->output,
			MS_VIDEO_OUT_HANDLE_RESIZING);
	*/
	if (stream->ms.evq){
		OrtpEvent *ev;
		while (NULL != (ev=ortp_ev_queue_get(stream->ms.evq))) {
			OrtpEventType evt=ortp_event_get_type(ev);
			if (evt == ORTP_EVENT_RTCP_PACKET_RECEIVED){
				OrtpEventData *evd=ortp_event_get_data(ev);
				video_steam_process_rtcp(stream,evd->packet);
			}else if ((evt == ORTP_EVENT_STUN_PACKET_RECEIVED) && (stream->ms.ice_check_list)) {
				ice_handle_stun_packet(stream->ms.ice_check_list,stream->ms.session,ortp_event_get_data(ev));
			}
			ortp_event_destroy(ev);
		}
	}
	media_stream_iterate(&stream->ms);
}
static void notify_tev(RtpSession *session, telephone_event_t *event){
	OrtpEvent *ev;
	OrtpEventData *evd;
	rtp_signal_table_emit2(&session->on_telephone_event,(long)(long)event[0].event);
	if (session->eventqs!=NULL){
		ev=ortp_event_new(ORTP_EVENT_TELEPHONE_EVENT);
		evd=ortp_event_get_data(ev);
		evd->packet=dupmsg(session->current_tev);
		evd->info.telephone_event=event[0].event;
		rtp_session_dispatch_event(session,ev);
	}
}
Esempio n. 13
0
static void ms_dtls_srtp_check_channels_status(MSDtlsSrtpContext *ctx) {

	if ((ctx->rtp_channel_status == DTLS_STATUS_HANDSHAKE_OVER) && (ctx->rtcp_channel_status == DTLS_STATUS_HANDSHAKE_OVER)) {
		OrtpEventData *eventData;
		OrtpEvent *ev;
		/* send event */
		ev=ortp_event_new(ORTP_EVENT_DTLS_ENCRYPTION_CHANGED);
		eventData=ortp_event_get_data(ev);
		eventData->info.dtls_stream_encrypted=1;
		rtp_session_dispatch_event(ctx->stream_sessions->rtp_session, ev);
		ms_message("DTLS Event dispatched to all: secrets are on for this stream");
	} 
}
Esempio n. 14
0
void audio_stream_iterate(AudioStream *stream){

	if (stream->evq!=NULL){
		OrtpEvent *ev=ortp_ev_queue_get(stream->evq);
		if (ev!=NULL){
			if (ortp_event_get_type(ev)==ORTP_EVENT_RTCP_PACKET_RECEIVED){
				OrtpEventData *evd=ortp_event_get_data(ev);
				audio_steam_process_rtcp(stream,evd->packet);
			}
			ortp_event_destroy(ev);
		}
	}
}
Esempio n. 15
0
static void parse_events(OrtpEvQueue *q){
	OrtpEvent *ev;
	while((ev=ortp_ev_queue_get(q))!=NULL){
		OrtpEventData *d=ortp_event_get_data(ev);
		switch(ortp_event_get_type(ev)){
			case ORTP_EVENT_RTCP_PACKET_RECEIVED:
				parse_rtcp(d->packet);
			break;
			default:
				ms_warning("Unhandled ortp event.");
		}
		ortp_event_destroy(ev);
	}
}
static void event_queue_cb(MediaStream *ms, void *user_pointer) {
	text_stream_tester_t *tst = (text_stream_tester_t *)user_pointer;
	if (tst->stats.q != NULL) {
		OrtpEvent *ev = NULL;
		while ((ev = ortp_ev_queue_get(tst->stats.q)) != NULL) {
			OrtpEventType evt = ortp_event_get_type(ev);
			OrtpEventData *evd = ortp_event_get_data(ev);
			if (evt == ORTP_EVENT_RTT_CHARACTER_RECEIVED) {
				ms_message("Received RTT char: %lu, %c", (unsigned long)evd->info.received_rtt_character, (char)evd->info.received_rtt_character);
				tst->stats.received_chars[tst->stats.number_of_received_char++] = (char)evd->info.received_rtt_character;
			}
			ortp_event_destroy(ev);
		}
	}
}
Esempio n. 17
0
void video_stream_iterate(VideoStream *stream){
	if (stream->output!=NULL)
		ms_filter_call_method_noarg(stream->output,
			MS_VIDEO_OUT_HANDLE_RESIZING);
	if (stream->evq){
		OrtpEvent *ev=ortp_ev_queue_get(stream->evq);
		if (ev!=NULL){
			if (ortp_event_get_type(ev)==ORTP_EVENT_RTCP_PACKET_RECEIVED){
				OrtpEventData *evd=ortp_event_get_data(ev);
				video_steam_process_rtcp(stream,evd->packet);
			}
			ortp_event_destroy(ev);
		}
	}
}
Esempio n. 18
0
/**
 * Switch on the security.
 *
 * ZRTP calls this method after it has computed the SAS and check
 * if it is verified or not. In addition ZRTP provides information
 * about the cipher algorithm and key length for the SRTP session.
 *
 * This method must enable SRTP processing if it was not enabled
 * during sertSecretsReady().
 *
 * @param ctx
 *    Pointer to the opaque ZrtpContext structure.
 * @param c The name of the used cipher algorithm and mode, or
 *    NULL
 *
 * @param s The SAS string
 *
 * @param verified if <code>verified</code> is true then SAS was
 *    verified by both parties during a previous call.
 */
static void ozrtp_rtpSecretsOn (ZrtpContext* ctx, char* c, char* s, int32_t verified ){
//	OrtpZrtpContext *userData = user_data(ctx);

	// srtp processing is enabled in SecretsReady fuction when receiver secrets are ready
	// Indeed, the secrets on is called before both parts are given to secretsReady.

	OrtpEventData *eventData;
	OrtpEvent *ev;
	ev=ortp_event_new(ORTP_EVENT_ZRTP_SAS_READY);
	eventData=ortp_event_get_data(ev);
	memcpy(eventData->info.zrtp_sas.sas,s,4);
	eventData->info.zrtp_sas.sas[4]=0;
	eventData->info.zrtp_sas.verified=(verified != 0) ? TRUE : FALSE;
	rtp_session_dispatch_event(user_data(ctx)->session, ev);
	ortp_message("ZRTP secrets on: SAS is %s previously verified %s - algo %s", s, verified == 0 ? "no" : "yes", c);
}
static void event_queue_cb(MediaStream *ms, void *user_pointer) {
	video_stream_tester_stats_t *st = (video_stream_tester_stats_t *)user_pointer;
	OrtpEvent *ev = NULL;

	if (st->q != NULL) {
		while ((ev = ortp_ev_queue_get(st->q)) != NULL) {
			OrtpEventType evt = ortp_event_get_type(ev);
			OrtpEventData *d = ortp_event_get_data(ev);
			if (evt == ORTP_EVENT_RTCP_PACKET_EMITTED) {
				do {
					if (rtcp_is_RR(d->packet)) {
						st->number_of_RR++;
					} else if (rtcp_is_SR(d->packet)) {
						st->number_of_SR++;
					} else if (rtcp_is_SDES(d->packet)) {
						st->number_of_SDES++;
					} else if (rtcp_is_PSFB(d->packet)) {
						switch (rtcp_PSFB_get_type(d->packet)) {
							case RTCP_PSFB_PLI:
								st->number_of_PLI++;
								break;
							case RTCP_PSFB_SLI:
								st->number_of_SLI++;
								break;
							case RTCP_PSFB_RPSI:
								st->number_of_RPSI++;
								break;
							default:
								break;
						}
					}
				} while (rtcp_next_packet(d->packet));
			}
			ortp_event_destroy(ev);
		}
	}
}
Esempio n. 20
0
void linphone_call_background_tasks(LinphoneCall *call, bool_t one_second_elapsed){
	int disconnect_timeout = linphone_core_get_nortp_timeout(call->core);
	bool_t disconnected=FALSE;
	
	if (call->state==LinphoneCallStreamsRunning && one_second_elapsed){
		RtpSession *as=NULL,*vs=NULL;
		float audio_load=0, video_load=0;
		if (call->audiostream!=NULL){
			as=call->audiostream->session;
			if (call->audiostream->ticker)
				audio_load=ms_ticker_get_average_load(call->audiostream->ticker);
		}
		if (call->videostream!=NULL){
			if (call->videostream->ticker)
				video_load=ms_ticker_get_average_load(call->videostream->ticker);
			vs=call->videostream->session;
		}
		display_bandwidth(as,vs);
		ms_message("Thread processing load: audio=%f\tvideo=%f",audio_load,video_load);
	}
#ifdef VIDEO_ENABLED
	if (call->videostream!=NULL) {
		// Beware that the application queue should not depend on treatments fron the
		// mediastreamer queue.
		video_stream_iterate(call->videostream);

		if (call->videostream_app_evq){
			OrtpEvent *ev;
			while (NULL != (ev=ortp_ev_queue_get(call->videostream_app_evq))){
				OrtpEventType evt=ortp_event_get_type(ev);
				if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
					OrtpEventData *evd=ortp_event_get_data(ev);
					linphone_call_videostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
				}
				ortp_event_destroy(ev);
			}
		}
	}
#endif
	if (call->audiostream!=NULL) {
		// Beware that the application queue should not depend on treatments fron the
		// mediastreamer queue.
		audio_stream_iterate(call->audiostream);

		if (call->audiostream->evq){
			OrtpEvent *ev;
			while (NULL != (ev=ortp_ev_queue_get(call->audiostream_app_evq))){
				OrtpEventType evt=ortp_event_get_type(ev);
				if (evt == ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED){
					OrtpEventData *evd=ortp_event_get_data(ev);
					linphone_call_audiostream_encryption_changed(call, evd->info.zrtp_stream_encrypted);
				} else if (evt == ORTP_EVENT_ZRTP_SAS_READY) {
					OrtpEventData *evd=ortp_event_get_data(ev);
					linphone_call_audiostream_auth_token_ready(call, evd->info.zrtp_sas.sas, evd->info.zrtp_sas.verified);
				}
				ortp_event_destroy(ev);
			}
		}
	}
	if (one_second_elapsed && call->audiostream!=NULL && disconnect_timeout>0 )
		disconnected=!audio_stream_alive(call->audiostream,disconnect_timeout);
	if (disconnected)
		linphone_core_disconnected(call->core,call);
}
Esempio n. 21
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);
		}
	}
Esempio n. 22
0
void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen)
{
	int i;
	rtp_header_t *rtp;
	int msgsize;
	RtpStream *rtpstream=&session->rtp;
	rtp_stats_t *stats=&rtpstream->stats;
	
	return_if_fail(mp!=NULL);
	
	msgsize=msgdsize(mp);

	if (msgsize<RTP_FIXED_HEADER_SIZE){
		ortp_warning("Packet too small to be a rtp packet (%i)!",msgsize);
		rtpstream->stats.bad++;
		ortp_global_stats.bad++;
		freemsg(mp);
		return;
	}
	rtp=(rtp_header_t*)mp->b_rptr;
	if (rtp->version!=2)
	{
		/* try to see if it is a STUN packet */
		uint16_t stunlen=*((uint16_t*)(mp->b_rptr + sizeof(uint16_t)));
		stunlen = ntohs(stunlen);
		if (stunlen+20==mp->b_wptr-mp->b_rptr){
			/* this looks like a stun packet */
			if (session->eventqs!=NULL){
				OrtpEvent *ev=ortp_event_new(ORTP_EVENT_STUN_PACKET_RECEIVED);
				OrtpEventData *ed=ortp_event_get_data(ev);
				ed->packet=mp;
				ed->ep=rtp_endpoint_new(addr,addrlen);
				rtp_session_dispatch_event(session,ev);
				return;
			}
		}
		freemsg(mp);
		return;
	}

	/* only count non-stun packets. */
	ortp_global_stats.packet_recv++;
	stats->packet_recv++;
	ortp_global_stats.hw_recv+=msgsize;
	stats->hw_recv+=msgsize;
	session->rtp.hwrcv_since_last_SR++;

	if (rtp->version!=2)
	{
		/* discard*/
		ortp_debug("Receiving rtp packet with version number !=2...discarded");
		stats->bad++;
		ortp_global_stats.bad++;
		freemsg(mp);
		return;
	}
	
	/* convert all header data from network order to host order */
	rtp->seq_number=ntohs(rtp->seq_number);
	rtp->timestamp=ntohl(rtp->timestamp);
	rtp->ssrc=ntohl(rtp->ssrc);
	/* convert csrc if necessary */
	if (rtp->cc*sizeof(uint32_t) > (uint32_t) (msgsize-RTP_FIXED_HEADER_SIZE)){
		ortp_debug("Receiving too short rtp packet.");
		stats->bad++;
		ortp_global_stats.bad++;
		freemsg(mp);
		return;
	}

	/* Write down the last RTP/RTCP packet reception time. */
	gettimeofday(&session->last_recv_time, NULL);

	for (i=0;i<rtp->cc;i++)
		rtp->csrc[i]=ntohl(rtp->csrc[i]);
	if (session->rcv.ssrc!=0)
	{
		/*the ssrc is set, so we must check it */
		if (session->rcv.ssrc!=rtp->ssrc){
			/*ortp_debug("rtp_parse: bad ssrc - %i",rtp->ssrc);*/
			session->rcv.ssrc=rtp->ssrc;
			rtp_signal_table_emit(&session->on_ssrc_changed);
		}
	}else session->rcv.ssrc=rtp->ssrc;
	
	/* update some statistics */
	{
		poly32_t *extseq=(poly32_t*)&rtpstream->hwrcv_extseq;
		if (rtp->seq_number>extseq->split.lo){
			extseq->split.lo=rtp->seq_number;
		}else if (rtp->seq_number<200 && extseq->split.lo>((1<<16) - 200)){
			/* this is a check for sequence number looping */
			extseq->split.lo=rtp->seq_number;
			extseq->split.hi++;
		}
	}
	
	/* check for possible telephone events */
	if (rtp->paytype==session->rcv.telephone_events_pt){
		split_and_queue(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&i);
		stats->discarded+=i;
		ortp_global_stats.discarded+=i;
		return;
	}
	
	/* check for possible payload type change, in order to update accordingly our clock-rate dependant
	parameters */
	if (session->hw_recv_pt!=rtp->paytype){
		rtp_session_update_payload_type(session,rtp->paytype);
	}
	
	if (session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED) {
		int32_t slide=0;
		int32_t safe_delay=0;
		jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts,&slide,&safe_delay);
		
		session->rtp.rcv_diff_ts=session->rtp.hwrcv_diff_ts + slide - safe_delay;
		ortp_debug("  rcv_diff_ts=%i", session->rtp.rcv_diff_ts);
		
		/* detect timestamp important jumps in the future, to workaround stupid rtp senders */
		if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){
			ortp_debug("rtp_parse: timestamp jump ?");
			rtp_signal_table_emit2(&session->on_timestamp_jump,(long)&rtp->timestamp);
		}
		else if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp)){
			/* don't queue packets older than the last returned packet to the application*/
			/* Call timstamp jumb in case of
			 * large negative Ts jump or if ts is set to 0
			*/
			
			if ( RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts, rtp->timestamp + session->rtp.ts_jump) ){
				ortp_warning("rtp_parse: negative timestamp jump");
				rtp_signal_table_emit2(&session->on_timestamp_jump,
							(long)&rtp->timestamp);
			}
			ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp);
			freemsg(mp);
			stats->outoftime++;
			ortp_global_stats.outoftime++;
			return;
		}
		
	}
	
	split_and_queue(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&i);
	stats->discarded+=i;
	ortp_global_stats.discarded+=i;
}
Esempio n. 23
0
void rtp_session_rtp_parse(RtpSession *session, mblk_t *mp, uint32_t local_str_ts, struct sockaddr *addr, socklen_t addrlen)
{
	int i;
	int discarded;
	int duplicate;
	rtp_header_t *rtp;
	int msgsize;
	RtpStream *rtpstream=&session->rtp;
	rtp_stats_t *stats=&rtpstream->stats;

	msgsize=(int)(mp->b_wptr-mp->b_rptr);

	if (msgsize<RTP_FIXED_HEADER_SIZE){
		ortp_warning("Packet too small to be a rtp packet (%i)!",msgsize);
		rtpstream->stats.bad++;
		ortp_global_stats.bad++;
		freemsg(mp);
		return;
	}
	rtp=(rtp_header_t*)mp->b_rptr;
	if (rtp->version!=2)
	{
		/* try to see if it is a STUN packet */
		uint16_t stunlen=*((uint16_t*)(mp->b_rptr + sizeof(uint16_t)));
		stunlen = ntohs(stunlen);
		if (stunlen+20==mp->b_wptr-mp->b_rptr){
			/* this looks like a stun packet */
			if (session->eventqs!=NULL){
				OrtpEvent *ev=ortp_event_new(ORTP_EVENT_STUN_PACKET_RECEIVED);
				OrtpEventData *ed=ortp_event_get_data(ev);
				ed->packet=mp;
				memcpy(&ed->source_addr,addr,addrlen);
				ed->source_addrlen=addrlen;
				ed->info.socket_type = OrtpRTPSocket;
				rtp_session_dispatch_event(session,ev);
				return;
			}
		}
		/* discard in two case: the packet is not stun OR nobody is interested by STUN (no eventqs) */
		ortp_debug("Receiving rtp packet with version number !=2...discarded");
		stats->bad++;
		ortp_global_stats.bad++;
		freemsg(mp);
		return;
	}

	/* only count non-stun packets. */
	ortp_global_stats.packet_recv++;
	stats->packet_recv++;
	ortp_global_stats.hw_recv+=msgsize;
	stats->hw_recv+=msgsize;
	session->rtp.hwrcv_since_last_SR++;
	session->rtcp_xr_stats.rcv_since_last_stat_summary++;

	/* convert all header data from network order to host order */
	rtp->seq_number=ntohs(rtp->seq_number);
	rtp->timestamp=ntohl(rtp->timestamp);
	rtp->ssrc=ntohl(rtp->ssrc);
	/* convert csrc if necessary */
	if (rtp->cc*sizeof(uint32_t) > (uint32_t) (msgsize-RTP_FIXED_HEADER_SIZE)){
		ortp_debug("Receiving too short rtp packet.");
		stats->bad++;
		ortp_global_stats.bad++;
		freemsg(mp);
		return;
	}

#ifndef PERF
	/* Write down the last RTP/RTCP packet reception time. */
	ortp_gettimeofday(&session->last_recv_time, NULL);
#endif

	for (i=0;i<rtp->cc;i++)
		rtp->csrc[i]=ntohl(rtp->csrc[i]);
	/*the goal of the following code is to lock on an incoming SSRC to avoid
	receiving "mixed streams"*/
	if (session->ssrc_set){
		/*the ssrc is set, so we must check it */
		if (session->rcv.ssrc!=rtp->ssrc){
			if (session->inc_ssrc_candidate==rtp->ssrc){
				session->inc_same_ssrc_count++;
			}else{
				session->inc_same_ssrc_count=0;
				session->inc_ssrc_candidate=rtp->ssrc;
			}
			if (session->inc_same_ssrc_count>=session->rtp.ssrc_changed_thres){
				/* store the sender rtp address to do symmetric RTP */
				if (!session->use_connect){
					if (session->rtp.gs.socket>0 && session->symmetric_rtp){
						/* store the sender rtp address to do symmetric RTP */
						memcpy(&session->rtp.gs.rem_addr,addr,addrlen);
						session->rtp.gs.rem_addrlen=addrlen;
					}
				}
				session->rtp.rcv_last_ts = rtp->timestamp;
				session->rcv.ssrc=rtp->ssrc;
				rtp_signal_table_emit(&session->on_ssrc_changed);
			}else{
				/*discard the packet*/
				ortp_debug("Receiving packet with unknown ssrc.");
				stats->bad++;
				ortp_global_stats.bad++;
				freemsg(mp);
				return;
			}
		} else{
			/* The SSRC change must not happen if we still receive
			ssrc from the initial source. */
			session->inc_same_ssrc_count=0;
		}
	}else{
		session->ssrc_set=TRUE;
		session->rcv.ssrc=rtp->ssrc;

		if (!session->use_connect){
			if (session->rtp.gs.socket>0 && session->symmetric_rtp){
				/* store the sender rtp address to do symmetric RTP */
				memcpy(&session->rtp.gs.rem_addr,addr,addrlen);
				session->rtp.gs.rem_addrlen=addrlen;
			}
		}
	}

	/* update some statistics */
	{
		poly32_t *extseq=(poly32_t*)&rtpstream->hwrcv_extseq;
		if (rtp->seq_number>extseq->split.lo){
			extseq->split.lo=rtp->seq_number;
		}else if (rtp->seq_number<200 && extseq->split.lo>((1<<16) - 200)){
			/* this is a check for sequence number looping */
			extseq->split.lo=rtp->seq_number;
			extseq->split.hi++;
		}

		/* the first sequence number received should be initialized at the beginning
		or at any resync, so that the first receiver reports contains valid loss rate*/
		if (!(session->flags & RTP_SESSION_RECV_SEQ_INIT)){
			rtp_session_set_flag(session, RTP_SESSION_RECV_SEQ_INIT);
			rtpstream->hwrcv_seq_at_last_SR=rtp->seq_number-1;
			session->rtcp_xr_stats.rcv_seq_at_last_stat_summary=rtp->seq_number-1;
		}
		if (stats->packet_recv==1){
			session->rtcp_xr_stats.first_rcv_seq=extseq->one;
		}
		session->rtcp_xr_stats.last_rcv_seq=extseq->one;
	}

	/* check for possible telephone events */
	if (rtp_profile_is_telephone_event(session->snd.profile, rtp->paytype)){
		queue_packet(&session->rtp.tev_rq,session->rtp.max_rq_size,mp,rtp,&discarded,&duplicate);
		stats->discarded+=discarded;
		ortp_global_stats.discarded+=discarded;
		stats->packet_dup_recv+=duplicate;
		ortp_global_stats.packet_dup_recv+=duplicate;
		session->rtcp_xr_stats.discarded_count += discarded;
		session->rtcp_xr_stats.dup_since_last_stat_summary += duplicate;
		return;
	}

	/* check for possible payload type change, in order to update accordingly our clock-rate dependant
	parameters */
	if (session->hw_recv_pt!=rtp->paytype){
		rtp_session_update_payload_type(session,rtp->paytype);
	}

	/* Drop the packets while the RTP_SESSION_FLUSH flag is set. */
	if (session->flags & RTP_SESSION_FLUSH) {
		freemsg(mp);
		return;
	}

	jitter_control_new_packet(&session->rtp.jittctl,rtp->timestamp,local_str_ts);

	update_rtcp_xr_stat_summary(session, mp, local_str_ts);

	if (session->flags & RTP_SESSION_FIRST_PACKET_DELIVERED) {
		/* detect timestamp important jumps in the future, to workaround stupid rtp senders */
		if (RTP_TIMESTAMP_IS_NEWER_THAN(rtp->timestamp,session->rtp.rcv_last_ts+session->rtp.ts_jump)){
			ortp_warning("rtp_parse: timestamp jump in the future detected.");
			rtp_signal_table_emit2(&session->on_timestamp_jump,&rtp->timestamp);
		}
		else if (RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts,rtp->timestamp) 
			|| RTP_SEQ_IS_STRICTLY_GREATER_THAN(session->rtp.rcv_last_seq,rtp->seq_number)){
			/* don't queue packets older than the last returned packet to the application, or whose sequence number
			 is behind the last packet returned to the application*/
			/* Call timstamp jumb in case of
			 * large negative Ts jump or if ts is set to 0
			*/

			if ( RTP_TIMESTAMP_IS_STRICTLY_NEWER_THAN(session->rtp.rcv_last_ts, rtp->timestamp + session->rtp.ts_jump) ){
				ortp_warning("rtp_parse: negative timestamp jump detected");
				rtp_signal_table_emit2(&session->on_timestamp_jump, &rtp->timestamp);
			}
			ortp_debug("rtp_parse: discarding too old packet (ts=%i)",rtp->timestamp);
			freemsg(mp);
			stats->outoftime++;
			ortp_global_stats.outoftime++;
			session->rtcp_xr_stats.discarded_count++;
			return;
		}
	}

	if (queue_packet(&session->rtp.rq,session->rtp.max_rq_size,mp,rtp,&discarded,&duplicate))
		jitter_control_update_size(&session->rtp.jittctl,&session->rtp.rq);
	stats->discarded+=discarded;
	ortp_global_stats.discarded+=discarded;
	stats->packet_dup_recv+=duplicate;
	ortp_global_stats.packet_dup_recv+=duplicate;
	session->rtcp_xr_stats.discarded_count += discarded;
	session->rtcp_xr_stats.dup_since_last_stat_summary += duplicate;
	if ((discarded == 0) && (duplicate == 0)) {
		session->rtcp_xr_stats.rcv_count++;
	}
}
Esempio n. 24
0
/**
* Send information messages to the hosting environment.
*
* The ZRTP implementation uses this method to send information
* messages to the host. Along with the message ZRTP provides a
* severity indicator that defines: Info, Warning, Error,
* Alert. Refer to the <code>MessageSeverity</code> enum above.
*
* @param ctx
*    Pointer to the opaque ZrtpContext structure.
* @param severity
*     This defines the message's severity
* @param subCode
*     The subcode identifying the reason.
* @see ZrtpCodes#MessageSeverity
*/
static void ozrtp_sendInfo (ZrtpContext* ctx, int32_t severity, int32_t subCode ) {
	const char* submsg;
	switch (subCode) {
		case zrtp_InfoHelloReceived:
			/*!< Hello received, preparing a Commit */
			submsg="zrtp_InfoHelloReceived";
			break;
		case zrtp_InfoCommitDHGenerated:
			/*!< Commit: Generated a public DH key */
			submsg="zrtp_InfoCommitDHGenerated";
			break;
		case zrtp_InfoRespCommitReceived:
			 /*!< Responder: Commit received, preparing DHPart1 */
			submsg="zrtp_InfoRespCommitReceived";
			break;
		case zrtp_InfoDH1DHGenerated:
			/*!< DH1Part: Generated a public DH key */
			submsg="zrtp_InfoDH1DHGenerated";
			break;
		case zrtp_InfoInitDH1Received:
           /*!< Initiator: DHPart1 received, preparing DHPart2 */
			submsg="zrtp_InfoInitDH1Received";
			break;
		case zrtp_InfoRespDH2Received:
			/*!< Responder: DHPart2 received, preparing Confirm1 */
			submsg="zrtp_InfoRespDH2Received";
			break;
		case zrtp_InfoInitConf1Received:
			/*!< Initiator: Confirm1 received, preparing Confirm2 */
			submsg="zrtp_InfoInitConf1Received";
			break;
		case zrtp_InfoRespConf2Received:
			/*!< Responder: Confirm2 received, preparing Conf2Ack */
			submsg="zrtp_InfoRespConf2Received";
			break;
		case zrtp_InfoRSMatchFound:
			/*!< At least one retained secrets matches - security OK */
			submsg="zrtp_InfoRSMatchFound";
			break;
		case zrtp_InfoSecureStateOn:
			/*!< Entered secure state */
			submsg="zrtp_InfoSecureStateOn";
			break;
		case zrtp_InfoSecureStateOff:
			/*!< No more security for this session */
			submsg="zrtp_InfoSecureStateOff";
			break;
		default:
			submsg="unkwown";
			break;
	}

	switch (severity) {
		case zrtp_Info:
			ortp_message("ZRTP INFO %s",submsg);
			break;
		case zrtp_Warning: /*!< A Warning message - security can be established */
			ortp_warning("ZRTP %s",submsg);
			break;
		case zrtp_Severe:/*!< Severe error, security will not be established */
			ortp_error("ZRTP SEVERE %s",submsg);
			break;
		case zrtp_ZrtpError:
			ortp_error("ZRTP ERROR %s",submsg);
			break;
		default:
			ortp_error("ZRTP UNKNOWN ERROR %s",submsg);
			break;
	}


	if (subCode == zrtp_InfoSecureStateOn || subCode == zrtp_InfoSecureStateOff) {
		OrtpEventData *eventData;
		OrtpEvent *ev;
		ev=ortp_event_new(ORTP_EVENT_ZRTP_ENCRYPTION_CHANGED);
		eventData=ortp_event_get_data(ev);
		eventData->info.zrtp_stream_encrypted=(subCode == zrtp_InfoSecureStateOn);
		rtp_session_dispatch_event(user_data(ctx)->session, ev);
	}
}
Esempio n. 25
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;
}