?? 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: 1.24 $
* $Date: 2002/07/05 22:03:53 $
*
* 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 16
static 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 204
typedef 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. */
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -