/* This is our RTP callback, that is called by the slave transport when it * receives RTP packet. */ static void transport_rtp_cb(void *user_data, void *pkt, pj_ssize_t size) { struct tp_zrtp *zrtp = (struct tp_zrtp*)user_data; pj_uint8_t* buffer = (pj_uint8_t*)pkt; int32_t newLen = 0; pj_status_t rc = PJ_SUCCESS; pj_assert(zrtp && zrtp->stream_rtcp_cb && pkt); // check if this could be a real RTP/SRTP packet. if ((*buffer & 0xf0) != 0x10) { // Could be real RTP, check if we are in secure mode if (zrtp->srtpReceive == NULL || size < 0) { zrtp->stream_rtp_cb(zrtp->stream_user_data, pkt, size); } else { rc = zsrtp_unprotect(zrtp->srtpReceive, pkt, size, &newLen); if (rc == 1) { zrtp->unprotect++; zrtp->stream_rtp_cb(zrtp->stream_user_data, pkt, newLen); zrtp->unprotect_err = 0; } else { if (zrtp->userCallback != NULL) { if (rc == -1) { zrtp->userCallback->zrtp_showMessage(zrtp->userCallback->userData, zrtp_Warning, zrtp_WarningSRTPauthError); } else { zrtp->userCallback->zrtp_showMessage(zrtp->userCallback->userData, zrtp_Warning, zrtp_WarningSRTPreplayError); } } zrtp->unprotect_err = rc; } } if (!zrtp->started && zrtp->enableZrtp) pjmedia_transport_zrtp_startZrtp((pjmedia_transport *)zrtp); return; } // We assume all other packets are ZRTP packets here. Process // if ZRTP processing is enabled. Because valid RTP packets are // already handled we delete any packets here after processing. if (zrtp->enableZrtp && zrtp->zrtpCtx != NULL) { // Get CRC value into crc (see above how to compute the offset) pj_uint16_t temp = size - CRC_SIZE; pj_uint32_t crc = *(uint32_t*)(buffer + temp); crc = pj_ntohl(crc); if (!zrtp_CheckCksum(buffer, temp, crc)) { if (zrtp->userCallback != NULL) zrtp->userCallback->zrtp_showMessage(zrtp->userCallback->userData, zrtp_Warning, zrtp_WarningCRCmismatch); return; } pj_uint32_t magic = *(pj_uint32_t*)(buffer + 4); magic = pj_ntohl(magic); // Check if it is really a ZRTP packet, return, no further processing if (magic != ZRTP_MAGIC || zrtp->zrtpCtx == NULL) { return; } // cover the case if the other party sends _only_ ZRTP packets at the // beginning of a session. Start ZRTP in this case as well. if (!zrtp->started) { pjmedia_transport_zrtp_startZrtp((pjmedia_transport *)zrtp); } // this now points beyond the undefined and length field. // We need them, thus adjust unsigned char* zrtpMsg = (buffer + 12); // store peer's SSRC in host order, used when creating the CryptoContext zrtp->peerSSRC = *(pj_uint32_t*)(buffer + 8); zrtp->peerSSRC = pj_ntohl(zrtp->peerSSRC); zrtp_processZrtpMessage(zrtp->zrtpCtx, zrtpMsg, zrtp->peerSSRC, size); } }
static int ozrtp_rtp_recvfrom(RtpTransport *t, mblk_t *m, int flags, struct sockaddr *from, socklen_t *fromlen){ int rlen; ZrtpContext *zrtpContext = (ZrtpContext*) t->data; OrtpZrtpContext *userData = (OrtpZrtpContext*) zrtpContext->userData; // Do extra stuff first check_timer(zrtpContext, userData); // Check if something to receive rlen=rtp_session_rtp_recv_abstract(t->session->rtp.socket,m,flags,from,fromlen); if (rlen<=0) { // nothing was received or error: pass the information to caller return rlen; } uint8_t* rtp = m->b_rptr; int rtpVersion = ((rtp_header_t*)rtp)->version; // If plain or secured RTP if (rtpVersion == 2) { if (userData->srtpRecv != NULL && zrtp_inState(zrtpContext, SecureState)) { // probably srtp packet, unprotect err_status_t err = srtp_unprotect(userData->srtpRecv,m->b_wptr,&rlen); if (err != err_status_ok) { ortp_warning("srtp_unprotect failed; packet may be plain RTP"); } } // in both cases (RTP plain and deciphered srtp) return rlen; } // if ZRTP packet, send to engine uint32_t *magicField=(uint32_t *)(rtp + 4); if (rlen >= ZRTP_MIN_MSG_LENGTH && rtpVersion==0 && ntohl(*magicField) == ZRTP_MAGIC) { print_zrtp_packet("received", rtp); uint8_t *ext_header = rtp+ZRTP_MESSAGE_OFFSET; uint16_t ext_length = get_zrtp_message_length(ext_header); char messageType[9]; parseZrtpMessageType(messageType, ext_header); // Check max length if (rlen < 12 + ext_length + 4) { ortp_warning("Received malformed ZRTP-like packet: size %d (expected %d)", rlen, 12 + ext_length + 4); return 0; } // Check sequence number uint16_t seq_number = get_rtp_seqnumber(rtp); if (userData->last_recv_zrtp_seq_number != 0 && seq_number <= userData->last_recv_zrtp_seq_number) { // Discard out of order ZRTP packet ortp_message("Discarding received out of order zrtp packet: %d (expected >%d)", seq_number, userData->last_recv_zrtp_seq_number); return 0; } // Check packet checksum uint32_t rcv_crc = get_zrtp_packet_crc((uint32_t*)rtp, ext_length); uint32_t zrtp_total_packet_length = ZRTP_MESSAGE_OFFSET + 4*ext_length + 4; if (!zrtp_CheckCksum(rtp, zrtp_total_packet_length-CRC_SIZE, rcv_crc)) { ortp_warning("Bad ZRTP packet checksum %u total %u", rcv_crc, zrtp_total_packet_length); return 0; } uint32_t peerssrc = ntohl(*(uint32_t*)(rtp+8)); #if HAVE_zrtpcpp_with_len zrtp_processZrtpMessage(zrtpContext, ext_header, peerssrc,rlen); #else zrtp_processZrtpMessage(zrtpContext, ext_header, peerssrc); #endif userData->last_recv_zrtp_seq_number=seq_number; return 0; } else { // Not a ZRTP packet, accept it return rlen; } }