Пример #1
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;
}
Пример #2
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);
	}
}
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);
	}
}
Пример #4
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");
	} 
}
Пример #5
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);
}
Пример #6
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);
	}
}
Пример #7
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++;
	}
}
Пример #8
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;
}