📄 rtp.c
字号:
/* * FILE: rtp.c * AUTHOR: Colin Perkins <csp@isi.edu> * MODIFIED: Orion Hodson <o.hodson@cs.ucl.ac.uk> * Markus Germeier <mager@tzi.de> * Bill Fenner <fenner@research.att.com> * Timur Friedman <timur@research.att.com> * * The routines in this file implement the Real-time Transport Protocol, * RTP, as specified in RFC1889 with current updates under discussion in * the IETF audio/video transport working group. Portions of the code are * derived from the algorithms published in that specification. * * $Revision$ * $Date$ * * Copyright (c) 1998-2001 University College London * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, is permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the Computer Science * Department at University College London. * 4. Neither the name of the University nor of the Department may be used * to endorse or promote products derived from this software without * specific prior written permission. * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */#include "config_unix.h"#include "config_win32.h"#include "memory.h"#include "debug.h"#include "net_udp.h"#include "crypt_random.h"#include "rijndael-api-fst.h"#include "drand48.h"#include "gettimeofday.h"#include "qfDES.h"#include "md5.h"#include "ntp.h"#include "rtp.h"typedef struct { uint32_t key; /* Original allocation number */ uint32_t size; /* Size of allocation requested */ uint32_t pad; /* Alignment padding to 8 bytes */ uint32_t magic; /* Magic number */} chk_header; extern int chk_header_okay(const chk_header *ch);/* * Encryption stuff. */#define MAX_ENCRYPTION_PAD 16static int rijndael_initialize(struct rtp *session, u_char *hash, int hash_len);static int rijndael_decrypt(void *ifptr, uint8_t *data, unsigned int *size);static int rijndael_encrypt(void *ifptr, uint8_t *data, unsigned int *size);static int des_initialize(struct rtp *session, u_char *hash, int hash_len);static int des_decrypt(void *ifptr, uint8_t *data, unsigned int *size);static int des_encrypt(void *ifptr, uint8_t *data, unsigned int *size);#define MAX_DROPOUT 3000#define MAX_MISORDER 100#define MIN_SEQUENTIAL 2/* * Definitions for the RTP/RTCP packets on the wire... */#define RTP_SEQ_MOD 0x10000#define RTP_MAX_SDES_LEN 256#define RTP_LOWER_LAYER_OVERHEAD 28 /* IPv4 + UDP */#define RTCP_SR 200#define RTCP_RR 201#define RTCP_SDES 202#define RTCP_BYE 203#define RTCP_APP 204typedef struct {#ifdef WORDS_BIGENDIAN unsigned short version:2; /* packet type */ unsigned short p:1; /* padding flag */ unsigned short count:5; /* varies by payload type */ unsigned short pt:8; /* payload type */#else unsigned short count:5; /* varies by payload type */ unsigned short p:1; /* padding flag */ unsigned short version:2; /* packet type */ unsigned short pt:8; /* payload type */#endif uint16_t length; /* packet length */} rtcp_common;typedef struct { rtcp_common common; union { struct { rtcp_sr sr; rtcp_rr rr[1]; /* variable-length list */ } sr; struct { uint32_t ssrc; /* source this RTCP packet is coming from */ rtcp_rr rr[1]; /* variable-length list */ } rr; struct rtcp_sdes_t { uint32_t ssrc; rtcp_sdes_item item[1]; /* list of SDES */ } sdes; struct { uint32_t ssrc[1]; /* list of sources */ /* can't express the trailing text... */ } bye; struct { uint32_t ssrc; uint8_t name[4]; uint8_t data[1]; } app; } r;} rtcp_t;typedef struct _rtcp_rr_wrapper { struct _rtcp_rr_wrapper *next; struct _rtcp_rr_wrapper *prev; uint32_t reporter_ssrc; rtcp_rr *rr; struct timeval *ts; /* Arrival time of this RR */} rtcp_rr_wrapper;/* * The RTP database contains source-specific information needed * to make it all work. */typedef struct _source { struct _source *next; struct _source *prev; uint32_t ssrc; char *cname; char *name; char *email; char *phone; char *loc; char *tool; char *note; char *priv; rtcp_sr *sr; struct timeval last_sr; struct timeval last_active; int should_advertise_sdes; /* TRUE if this source is a CSRC which we need to advertise SDES for */ int sender; int got_bye; /* TRUE if we've received an RTCP bye from this source */ uint32_t base_seq; uint16_t max_seq; uint32_t bad_seq; uint32_t cycles; int received; int received_prior; int expected_prior; int probation; uint32_t jitter; uint32_t transit; uint32_t magic; /* For debugging... */} source;/* The size of the hash table used to hold the source database. *//* Should be large enough that we're unlikely to get collisions *//* when sources are added, but not too large that we waste too *//* much memory. Sedgewick ("Algorithms", 2nd Ed, Addison-Wesley *//* 1988) suggests that this should be around 1/10th the number *//* of entries that we expect to have in the database and should *//* be a prime number. Everything continues to work if this is *//* too low, it just goes slower... for now we assume around 100 *//* participants is a sensible limit so we set this to 11. */ #define RTP_DB_SIZE 11/* * Options for an RTP session are stored in the "options" struct. */typedef struct { int promiscuous_mode; int wait_for_rtcp; int filter_my_packets;} options;/* * Encryption function types */// moved to rtp.h by nori/* * typedef int (*rtp_encrypt_func)(struct rtp *, unsigned char *data, * unsigned int size); * * typedef int (*rtp_decrypt_func)(struct rtp *, unsigned char *data, * unsigned int size); */typedef int (*rtcp_send_f)(struct rtp *s, uint8_t *buffer, int buflen);/* * The "struct rtp" defines an RTP session. */struct rtp { socket_udp *rtp_socket; socket_udp *rtcp_socket; char *addr; uint16_t rx_port; uint16_t tx_port; int ttl; uint32_t my_ssrc; int last_advertised_csrc; source *db[RTP_DB_SIZE]; rtcp_rr_wrapper rr[RTP_DB_SIZE][RTP_DB_SIZE]; /* Indexed by [hash(reporter)][hash(reportee)] */ options *opt; uint8_t *userdata; int invalid_rtp_count; int invalid_rtcp_count; int bye_count; int csrc_count; int ssrc_count; int ssrc_count_prev; /* ssrc_count at the time we last recalculated our RTCP interval */ int sender_count; int initial_rtcp; int sending_bye; /* TRUE if we're in the process of sending a BYE packet */ double avg_rtcp_size; int we_sent; double rtcp_bw; /* RTCP bandwidth fraction, in octets per second. */ struct timeval last_update; struct timeval last_rtp_send_time; struct timeval last_rtcp_send_time; struct timeval next_rtcp_send_time; double rtcp_interval; int sdes_count_pri; int sdes_count_sec; int sdes_count_ter; uint16_t rtp_seq; uint32_t rtp_pcount; uint32_t rtp_bcount; char *encryption_algorithm; int encryption_enabled; rtp_encrypt_func encrypt_func; rtp_decrypt_func decrypt_func; int encryption_pad_length; int encryption_lenadd; void *encrypt_userdata; // added by nori union { struct { keyInstance keyInstEncrypt; keyInstance keyInstDecrypt; cipherInstance cipherInst; } rijndael; struct { char *encryption_key; } des; } crypto_state; rtp_callback callback; rtcp_send_f rtcp_send; rtcp_send_packet_t rtcp_send_packet; uint32_t magic; /* For debugging... */};static int filter_event(struct rtp *session, uint32_t ssrc){ int filter; rtp_get_option(session, RTP_OPT_FILTER_MY_PACKETS, &filter); return filter && (ssrc == rtp_my_ssrc(session));}static double tv_diff(struct timeval curr_time, struct timeval prev_time){ /* Return curr_time - prev_time */ double ct, pt; ct = (double) curr_time.tv_sec + (((double) curr_time.tv_usec) / 1000000.0); pt = (double) prev_time.tv_sec + (((double) prev_time.tv_usec) / 1000000.0); return (ct - pt);}static void tv_add(struct timeval *ts, double offset){ /* Add offset seconds to ts */ double offset_sec, offset_usec; offset_usec = modf(offset, &offset_sec) * 1000000; ts->tv_sec += (long) offset_sec; ts->tv_usec += (long) offset_usec; if (ts->tv_usec > 1000000) { ts->tv_sec++; ts->tv_usec -= 1000000; }}static int tv_gt(struct timeval a, struct timeval b){ /* Returns (a>b) */ if (a.tv_sec > b.tv_sec) { return TRUE; } if (a.tv_sec < b.tv_sec) { return FALSE; } ASSERT(a.tv_sec == b.tv_sec); return a.tv_usec > b.tv_usec;}static uint32_t next_csrc(struct rtp *session){ /* This returns each source marked "should_advertise_sdes" in turn. */ int chain, cc; source *s; cc = 0; for (chain = 0; chain < RTP_DB_SIZE; chain++) { /* Check that the linked lists making up the chains in */ /* the hash table are correctly linked together... */ for (s = session->db[chain]; s != NULL; s = s->next) { if (s->should_advertise_sdes) { if (cc == session->last_advertised_csrc) { session->last_advertised_csrc++; if (session->last_advertised_csrc == session->csrc_count) { session->last_advertised_csrc = 0; } return s->ssrc; } else { cc++; } } } } /* We should never get here... */ abort();}static int ssrc_hash(uint32_t ssrc){ /* Hash from an ssrc to a position in the source database. */ /* Assumes that ssrc values are uniformly distributed, which */ /* should be true but probably isn't (Rosenberg has reported */ /* that many implementations generate ssrc values which are */ /* not uniformly distributed over the space, and the H.323 */ /* spec requires that they are non-uniformly distributed). */ /* This routine is written as a function rather than inline */ /* code to allow it to be made smart in future: probably we */ /* should run MD5 on the ssrc and derive a hash value from */ /* that, to ensure it's more uniformly distributed? */ return ssrc % RTP_DB_SIZE;}static void insert_rr(struct rtp *session, uint32_t reporter_ssrc, rtcp_rr *rr, struct timeval *ts){ /* Insert the reception report into the receiver report */ /* database. This database is a two dimensional table of */ /* rr_wrappers indexed by hashes of reporter_ssrc and */ /* reportee_src. The rr_wrappers in the database are */ /* sentinels to reduce conditions in list operations. */ /* The ts is used to determine when to timeout this rr. */ rtcp_rr_wrapper *cur, *start; start = &session->rr[ssrc_hash(reporter_ssrc)][ssrc_hash(rr->ssrc)]; cur = start->next; while (cur != start) { if (cur->reporter_ssrc == reporter_ssrc && cur->rr->ssrc == rr->ssrc) { /* Replace existing entry in the database */ xfree(cur->rr); xfree(cur->ts); cur->rr = rr; cur->ts = (struct timeval *) xmalloc(sizeof(struct timeval)); memcpy(cur->ts, ts, sizeof(struct timeval)); return;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -