static void udp_recv_handler(const struct sa *src, struct mbuf *mb, void *arg) { struct rtp_sock *rs = arg; struct rtp_header hdr; int err; /* Handle RTCP multiplexed on RTP-port */ if (rs->rtcp_mux) { uint8_t pt; if (mbuf_get_left(mb) < 2) return; pt = mbuf_buf(mb)[1] & 0x7f; if (64 <= pt && pt <= 95) { rtcp_recv_handler(src, mb, arg); return; } } err = rtp_decode(rs, mb, &hdr); if (err) return; if (rs->rtcp) { rtcp_sess_rx_rtp(rs->rtcp, hdr.seq, hdr.ts, hdr.ssrc, mbuf_get_left(mb), src); } if (rs->recvh) rs->recvh(src, &hdr, mb, rs->arg); }
/* read from incoming RTP/RTCP socket */ static int rtp_socket_read(struct rtp_socket *rs, struct rtp_sub_socket *rss) { int rc; struct msgb *msg = msgb_alloc(RTP_ALLOC_SIZE, "RTP/RTCP"); struct msgb *new_msg; struct rtp_sub_socket *other_rss; if (!msg) return -ENOMEM; rc = read(rss->bfd.fd, msg->data, RTP_ALLOC_SIZE); if (rc <= 0) { rss->bfd.when &= ~BSC_FD_READ; return rc; } msgb_put(msg, rc); switch (rs->rx_action) { case RTP_PROXY: if (!rs->proxy.other_sock) { rc = -EIO; goto out_free; } if (rss->bfd.priv_nr == RTP_PRIV_RTP) other_rss = &rs->proxy.other_sock->rtp; else if (rss->bfd.priv_nr == RTP_PRIV_RTCP) { other_rss = &rs->proxy.other_sock->rtcp; /* modify RTCP SDES CNAME */ rc = rtcp_mangle(msg, rs); if (rc < 0) goto out_free; } else { rc = -EINVAL; goto out_free; } msgb_enqueue(&other_rss->tx_queue, msg); other_rss->bfd.when |= BSC_FD_WRITE; break; case RTP_RECV_UPSTREAM: if (!rs->receive.callref || !rs->receive.net) { rc = -EIO; goto out_free; } if (rss->bfd.priv_nr == RTP_PRIV_RTCP) { if (!mangle_rtcp_cname) { msgb_free(msg); break; } /* modify RTCP SDES CNAME */ rc = rtcp_mangle(msg, rs); if (rc < 0) goto out_free; msgb_enqueue(&rss->tx_queue, msg); rss->bfd.when |= BSC_FD_WRITE; break; } if (rss->bfd.priv_nr != RTP_PRIV_RTP) { rc = -EINVAL; goto out_free; } rc = rtp_decode(msg, rs->receive.callref, &new_msg); if (rc < 0) goto out_free; msgb_free(msg); msgb_enqueue(&rs->receive.net->upqueue, new_msg); break; case RTP_NONE: /* if socket exists, but disabled by app */ msgb_free(msg); break; } return 0; out_free: msgb_free(msg); return rc; }
int test_rtp(void) { struct rtp_sock *rtp = NULL; struct mbuf *mb = NULL; uint8_t payload[PAYLOAD_SIZE]; int j; int err; memset(payload, 0, sizeof(payload)); mb = mbuf_alloc(RTP_HEADER_SIZE); if (!mb) return ENOMEM; err = rtp_alloc(&rtp); if (err) goto out; for (j=0; j<100; j++) { struct rtp_header hdr, hdr2; memset(&hdr, 0, sizeof(hdr)); hdr.m = rand_u16() & 0x01; hdr.pt = rand_u16() & 0x7f; hdr.ts = rand_u32(); rand_bytes(payload, sizeof(payload)); mb->pos = mb->end = RTP_HEADER_SIZE; err = mbuf_write_mem(mb, payload, sizeof(payload)); if (err) break; mb->pos = 0; err = rtp_encode(rtp, hdr.m, hdr.pt, hdr.ts, mb); if (err) break; mb->pos = 0; err = rtp_decode(rtp, mb, &hdr2); if (err) break; if (hdr.m != hdr2.m) { DEBUG_WARNING("marker bit mismatch (%d != %d)\n", hdr.m, hdr2.m); err = EBADMSG; break; } if (hdr.pt != hdr2.pt) { DEBUG_WARNING("payload type mismatch (%u != %u)\n", hdr.pt, hdr2.pt); err = EBADMSG; break; } if (hdr.ts != hdr2.ts) { DEBUG_WARNING("timestamp mismatch (%lu != %lu)\n", hdr.ts, hdr2.ts); err = EBADMSG; break; } if (hdr2.pad) { DEBUG_WARNING("unexpected padding bit\n"); err = EBADMSG; break; } if (hdr2.ext) { DEBUG_WARNING("unexpected extension bit\n"); err = EBADMSG; break; } if (RTP_HEADER_SIZE != mb->pos || (RTP_HEADER_SIZE + PAYLOAD_SIZE) != mb->end) { DEBUG_WARNING("invalid mbuf size (pos=%u end=%u)\n", mb->pos, mb->end); err = EBADMSG; break; } if (0 != memcmp(mbuf_buf(mb), payload, sizeof(payload))) { DEBUG_WARNING("RTP payload mismatch\n"); err = EBADMSG; break; } } out: mem_deref(rtp); mem_deref(mb); return err; }