⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 rtp.c

📁 完整的RTP RTSP代码库
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * 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.34 $  * $Date: 2007/01/22 17:31:08 $ *  * 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 "mutex.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#if 0static 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);#endif#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_sdes_t {      uint32_t	ssrc;      rtcp_sdes_item 	item[1];	/* list of SDES */} rtcp_sdes_t;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;    rtcp_sdes_t 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;/* * The "struct rtp" defines an RTP session. */struct rtp {  udp_set         *udp_session;  socket_udp	*rtp_socket;  socket_udp	*rtcp_socket;  int           free_sockets;  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;  void		*recv_userdata, *send_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 rtp_encryption_enabled;  int rtcp_encryption_enabled;  rtp_encrypt_f rtp_encrypt_func;  rtp_decrypt_f rtp_decrypt_func;  rtp_encrypt_f rtcp_encrypt_func;  rtp_decrypt_f rtcp_decrypt_func;  unsigned int rtp_encryption_pad_length;  unsigned int rtp_encryption_lenadd;  unsigned int rtcp_encryption_pad_length;  unsigned int rtcp_encryption_lenadd;  void *encrypt_userdata;  rtp_callback_f	 callback;  send_packet_f rtcp_send_packet;  send_packet_f rtp_send_packet;#ifdef HAVE_STRUCT_IOVEC  send_packet_iov_f rtp_send_packet_iov;#endif  uint32_t	 magic;				/* For debugging...  */  uint8_t *m_output_buffer; // to consolidate IOVs for encryption  uint32_t m_output_buffer_size;  mutex_t mutex;  int use_mutex;};static inline void lock_mutex (struct rtp *session){  if (session->use_mutex) {    MutexLock(session->mutex);  }}static inline void unlock_mutex (struct rtp *session){  if (session->use_mutex) {    MutexUnlock(session->mutex);  }}static void local_callback (struct rtp *session, rtp_event *e){  if (e->type == RX_RTP || e->type == RX_APP) {    xfree(e->data);  }}static inline int filter_event(struct rtp *session, uint32_t ssrc){  return session->opt->filter_my_packets && (ssrc == rtp_my_ssrc(session));}static inline 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...     */    lock_mutex(session);    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;	  }	  unlock_mutex(session);	  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;  lock_mutex(session);  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  */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -