/** * @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; }
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); } }
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"); } }
/** * 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); }
/** * 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); } }
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++; } }
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; }