static pj_status_t transport_send_rtp( pjmedia_transport *tp, const void *pkt, pj_size_t size) { pj_status_t status; transport_srtp *srtp = (transport_srtp*) tp; int len = size; err_status_t err; if (srtp->bypass_srtp) return pjmedia_transport_send_rtp(srtp->member_tp, pkt, size); if (!srtp->session_inited) return PJ_SUCCESS; if (size > sizeof(srtp->rtp_tx_buffer)) return PJ_ETOOBIG; pj_memcpy(srtp->rtp_tx_buffer, pkt, size); pj_lock_acquire(srtp->mutex); err = srtp_protect(srtp->srtp_tx_ctx, srtp->rtp_tx_buffer, &len); pj_lock_release(srtp->mutex); if (err == err_status_ok) { status = pjmedia_transport_send_rtp(srtp->member_tp, srtp->rtp_tx_buffer, len); } else { status = PJMEDIA_ERRNO_FROM_LIBSRTP(err); } return status; }
/* * send_rtp() is called to send RTP packet. The "pkt" and "size" argument * contain both the RTP header and the payload. */ static pj_status_t transport_send_rtp( pjmedia_transport *tp, const void *pkt, pj_size_t size) { struct tp_adapter *adapter = (struct tp_adapter*)tp; /* You may do some processing to the RTP packet here if you want. */ /* Send the packet using the slave transport */ return pjmedia_transport_send_rtp(adapter->slave_tp, pkt, size); }
/* * send_rtp() is called to send RTP packet. The "pkt" and "size" argument * contain both the RTP header and the payload. */ static pj_status_t transport_send_rtp(pjmedia_transport *tp, const void *pkt, pj_size_t size) { struct tp_zrtp *zrtp = (struct tp_zrtp*)tp; pj_uint32_t* pui = (pj_uint32_t*)pkt; int32_t newLen = 0; pj_status_t rc = PJ_SUCCESS; PJ_ASSERT_RETURN(tp && pkt, PJ_EINVAL); if (!zrtp->started && zrtp->enableZrtp) { if (zrtp->localSSRC == 0) zrtp->localSSRC = pj_ntohl(pui[2]); /* Learn own SSRC before starting ZRTP */ pjmedia_transport_zrtp_startZrtp((pjmedia_transport *)zrtp); } if (zrtp->srtpSend == NULL) { return pjmedia_transport_send_rtp(zrtp->slave_tp, pkt, size); } else { if (size+80 > MAX_RTP_BUFFER_LEN) return PJ_ETOOBIG; pj_memcpy(zrtp->sendBuffer, pkt, size); rc = zsrtp_protect(zrtp->srtpSend, zrtp->sendBuffer, size, &newLen); zrtp->protect++; if (rc == 1) return pjmedia_transport_send_rtp(zrtp->slave_tp, zrtp->sendBuffer, newLen); else return PJ_EIGNORED; } }
/* * Here start with callback functions that support the ZRTP core */ static int32_t zrtp_sendDataZRTP(ZrtpContext* ctx, const uint8_t* data, int32_t length) { struct tp_zrtp *zrtp = (struct tp_zrtp*)ctx->userData; pj_uint16_t totalLen = length + 12; /* Fixed number of bytes of ZRTP header */ pj_uint32_t crc; pj_uint8_t* buffer = zrtp->zrtpBuffer; pj_uint16_t* pus; pj_uint32_t* pui; if ((totalLen) > MAX_ZRTP_SIZE) return 0; /* Get some handy pointers */ pus = (pj_uint16_t*)buffer; pui = (pj_uint32_t*)buffer; /* set up fixed ZRTP header */ *buffer = 0x10; /* invalid RTP version - refer to ZRTP spec chap 5 */ *(buffer + 1) = 0; pus[1] = pj_htons(zrtp->zrtpSeq++); pui[1] = pj_htonl(ZRTP_MAGIC); pui[2] = pj_htonl(zrtp->localSSRC); /* stored in host order */ /* Copy ZRTP message data behind the header data */ pj_memcpy(buffer+12, data, length); /* Setup and compute ZRTP CRC */ crc = zrtp_GenerateCksum(buffer, totalLen-CRC_SIZE); /* convert and store CRC in ZRTP packet.*/ crc = zrtp_EndCksum(crc); *(uint32_t*)(buffer+totalLen-CRC_SIZE) = pj_htonl(crc); /* Send the ZRTP packet using the slave transport */ return (pjmedia_transport_send_rtp(zrtp->slave_tp, buffer, totalLen) == PJ_SUCCESS) ? 1 : 0; }
int CChannel::sendto(const sockaddr* addr, CPacket& packet) const { // convert control information into network order if (packet.getFlag()) { for (int i = 0, n = packet.getLength() / 4; i < n; ++ i) *((uint32_t *)packet.m_pcData + i) = htonl(*((uint32_t *)packet.m_pcData + i)); } uint32_t* p = packet.m_nHeader; for (int j = 0; j < 4; ++ j) { *p = htonl(*p); ++ p; } #ifdef DEBUGP //dump ctrl packet printf("\nSend Header:\n"); dumpHex((char *)packet.m_PacketVector[0].iov_base, packet.m_PacketVector[0].iov_len); char *bb = (char *)packet.m_PacketVector[0].iov_base; if(bb[0]&0x80) { printf("Data:\n"); dumpHex((char *)packet.m_PacketVector[1].iov_base, packet.m_PacketVector[1].iov_len); printf("================\n"); } #endif int res = -1; unsigned size; unsigned len; natnl_hdr hdr = {0xff, 0x00, 0x0000}; int is_tnl_data = 0; pj_thread_desc desc; pj_thread_t *thread = 0; if(m_iSocket == -1) { pjsua_call *call = (pjsua_call *)m_call; if(call == NULL) return -1; // DEAN, prevent assert fail while garbage collector remove UDT socket on multiple instance. if (!pj_thread_is_registered(call->inst_id)) { int status = pj_thread_register(call->inst_id, "CChannel::sendto", desc, &thread ); if (status != PJ_SUCCESS) return -1; } pj_mutex_lock(call->tnl_stream_lock2); natnl_stream *stream = (natnl_stream *)call->tnl_stream; if(stream == NULL) { pj_mutex_unlock(call->tnl_stream_lock2); return -1; } size = CPacket::m_iPktHdrSize + packet.getLength() + sizeof(natnl_hdr); len = (CPacket::m_iPktHdrSize + packet.getLength()); hdr.length = htons(len); memcpy((char *)&m_pktBuffer[sizeof(natnl_hdr)], packet.m_PacketVector[0].iov_base, packet.m_PacketVector[0].iov_len); memcpy((char *)&m_pktBuffer[packet.m_PacketVector[0].iov_len+sizeof(natnl_hdr)], packet.m_PacketVector[1].iov_base, packet.m_PacketVector[1].iov_len); memcpy((char *)&m_pktBuffer[0], &hdr, sizeof(natnl_hdr)); resend: // DEAN, check if this is tunnel data. If true, update last_data time. is_tnl_data = pjmedia_natnl_udt_packet_is_tnl_data(&m_pktBuffer[0], size); pj_assert(size < sizeof(m_pktBuffer)); ((pj_uint8_t*)m_pktBuffer)[size] = 0; // tunnel data flag off if (is_tnl_data) { pj_get_timestamp(&stream->last_data); // DEAN save current time ((pj_uint8_t*)m_pktBuffer)[size] = 1; // tunnel data flag on } res = pjmedia_transport_send_rtp(stream->med_tp, m_pktBuffer, size); // +Roger modified - stream pointer to med_tp #if 0 // No need to resend it, because UDT will handle this. if(res == 70011) { //EAGAIN m_pTimer->sleepto(50000); //sleep for 50 us goto resend; } #endif pj_mutex_unlock(call->tnl_stream_lock2); } res = (0 == res) ? size : -1; // convert back into local host order //for (int k = 0; k < 4; ++ k) // packet.m_nHeader[k] = ntohl(packet.m_nHeader[k]); p = packet.m_nHeader; for (int k = 0; k < 4; ++ k) { *p = ntohl(*p); ++ p; } if (packet.getFlag()) { for (int l = 0, n = packet.getLength() / 4; l < n; ++ l) *((uint32_t *)packet.m_pcData + l) = ntohl(*((uint32_t *)packet.m_pcData + l)); } return res; }
/* * This callback is called by transport when incoming rtp is received */ static void srtp_rtp_cb( void *user_data, void *pkt, pj_ssize_t size) { transport_srtp *srtp = (transport_srtp *) user_data; int len = (int)size; srtp_err_status_t err; void (*cb)(void*, void*, pj_ssize_t) = NULL; void *cb_data = NULL; if (srtp->bypass_srtp) { srtp->rtp_cb(srtp->user_data, pkt, size); return; } if (size < 0) { return; } /* Give the packet to keying first by invoking its send_rtp() op. * Yes, the usage of send_rtp() is rather hacky, but it is convenient * as the signature suits the purpose and it is ready to use * (no futher registration/setting needed), and it may never be used * by any keying method in the future. */ { unsigned i; pj_status_t status; for (i=0; i < srtp->keying_cnt; i++) { if (!srtp->keying[i]->op->send_rtp) continue; status = pjmedia_transport_send_rtp(srtp->keying[i], pkt, size); if (status != PJ_EIGNORED) { /* Packet is already consumed by the keying method */ return; } } } /* Make sure buffer is 32bit aligned */ PJ_ASSERT_ON_FAIL( (((pj_ssize_t)pkt) & 0x03)==0, return ); if (srtp->probation_cnt > 0) --srtp->probation_cnt; pj_lock_acquire(srtp->mutex); if (!srtp->session_inited) { pj_lock_release(srtp->mutex); return; } err = srtp_unprotect(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len); if (srtp->probation_cnt > 0 && (err == srtp_err_status_replay_old || err == srtp_err_status_replay_fail)) { /* Handle such condition that stream is updated (RTP seq is reinited * & SRTP is restarted), but some old packets are still coming * so SRTP is learning wrong RTP seq. While the newly inited RTP seq * comes, SRTP thinks the RTP seq is replayed, so srtp_unprotect() * will return err_status_replay_*. Restarting SRTP can resolve this. */ pjmedia_srtp_crypto tx, rx; pj_status_t status; tx = srtp->tx_policy; rx = srtp->rx_policy; status = pjmedia_transport_srtp_start((pjmedia_transport*)srtp, &tx, &rx); if (status != PJ_SUCCESS) { PJ_LOG(5,(srtp->pool->obj_name, "Failed to restart SRTP, err=%s", get_libsrtp_errstr(err))); } else if (!srtp->bypass_srtp) { err = srtp_unprotect(srtp->srtp_rx_ctx, (pj_uint8_t*)pkt, &len); } } if (err != srtp_err_status_ok) { PJ_LOG(5,(srtp->pool->obj_name, "Failed to unprotect SRTP, pkt size=%d, err=%s", size, get_libsrtp_errstr(err))); } else { cb = srtp->rtp_cb; cb_data = srtp->user_data; } pj_lock_release(srtp->mutex); if (cb) { (*cb)(cb_data, pkt, len); } }