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