Tech-invite3GPPspaceIETF RFCsSIP
in Index   Prev   Next

RFC 1889

RTP: A Transport Protocol for Real-Time Applications

Pages: 75
Obsoleted by:  3550
Part 3 of 3 – Pages 44 to 75
First   Prev   None

ToP   noToC   RFC1889 - Page 44   prevText
8.  SSRC Identifier Allocation and Use

   The SSRC identifier carried in the RTP header and in various fields
   of RTCP packets is a random 32-bit number that is required to be
   globally unique within an RTP session. It is crucial that the number
   be chosen with care in order that participants on the same network or
   starting at the same time are not likely to choose the same number.

   It is not sufficient to use the local network address (such as an
   IPv4 address) for the identifier because the address may not be
   unique. Since RTP translators and mixers enable interoperation among
   multiple networks with different address spaces, the allocation
   patterns for addresses within two spaces might result in a much
   higher rate of collision than would occur with random allocation.

   Multiple sources running on one host would also conflict.

   It is also not sufficient to obtain an SSRC identifier simply by
   calling random() without carefully initializing the state. An example
   of how to generate a random identifier is presented in Appendix A.6.

8.1 Probability of Collision

   Since the identifiers are chosen randomly, it is possible that two or
   more sources will choose the same number. Collision occurs with the
   highest probability when all sources are started simultaneously, for
   example when triggered automatically by some session management
   event. If N is the number of sources and L the length of the
   identifier (here, 32 bits), the probability that two sources
ToP   noToC   RFC1889 - Page 45
   independently pick the same value can be approximated for large N
   [20] as 1 - exp(-N**2 / 2**(L+1)). For N=1000, the probability is
   roughly 10**-4.

   The typical collision probability is much lower than the worst-case
   above. When one new source joins an RTP session in which all the
   other sources already have unique identifiers, the probability of
   collision is just the fraction of numbers used out of the space.
   Again, if N is the number of sources and L the length of the
   identifier, the probability of collision is N / 2**L. For N=1000, the
   probability is roughly 2*10**-7.

   The probability of collision is further reduced by the opportunity
   for a new source to receive packets from other participants before
   sending its first packet (either data or control). If the new source
   keeps track of the other participants (by SSRC identifier), then
   before transmitting its first packet the new source can verify that
   its identifier does not conflict with any that have been received, or
   else choose again.

8.2 Collision Resolution and Loop Detection

   Although the probability of SSRC identifier collision is low, all RTP
   implementations must be prepared to detect collisions and take the
   appropriate actions to resolve them. If a source discovers at any
   time that another source is using the same SSRC identifier as its
   own, it must send an RTCP BYE packet for the old identifier and
   choose another random one. If a receiver discovers that two other
   sources are colliding, it may keep the packets from one and discard
   the packets from the other when this can be detected by different
   source transport addresses or CNAMEs. The two sources are expected to
   resolve the collision so that the situation doesn't last.

   Because the random identifiers are kept globally unique for each RTP
   session, they can also be used to detect loops that may be introduced
   by mixers or translators. A loop causes duplication of data and
   control information, either unmodified or possibly mixed, as in the
   following examples:

        o A translator may incorrectly forward a packet to the same
         multicast group from which it has received the packet, either
         directly or through a chain of translators. In that case, the
         same packet appears several times, originating from different
         network sources.

        o Two translators incorrectly set up in parallel, i.e., with the
         same multicast groups on both sides, would both forward packets
         from one multicast group to the other. Unidirectional
ToP   noToC   RFC1889 - Page 46
         translators would produce two copies; bidirectional translators
         would form a loop.

        o A mixer can close a loop by sending to the same transport
         destination upon which it receives packets, either directly or
         through another mixer or translator. In this case a source
         might show up both as an SSRC on a data packet and a CSRC in a
         mixed data packet.

   A source may discover that its own packets are being looped, or that
   packets from another source are being looped (a third-party loop).

   Both loops and collisions in the random selection of a source
   identifier result in packets arriving with the same SSRC identifier
   but a different source transport address, which may be that of the
   end system originating the packet or an intermediate system.
   Consequently, if a source changes its source transport address, it
   must also choose a new SSRC identifier to avoid being interpreted as
   a looped source. Loops or collisions occurring on the far side of a
   translator or mixer cannot be detected using the source transport
   address if all copies of the packets go through the translator or
   mixer, however collisions may still be detected when chunks from two
   RTCP SDES packets contain the same SSRC identifier but different

   To detect and resolve these conflicts, an RTP implementation must
   include an algorithm similar to the one described below. It ignores
   packets from a new source or loop that collide with an established
   source. It resolves collisions with the participant's own SSRC
   identifier by sending an RTCP BYE for the old identifier and choosing
   a new one. However, when the collision was induced by a loop of the
   participant's own packets, the algorithm will choose a new identifier
   only once and thereafter ignore packets from the looping source
   transport address. This is required to avoid a flood of BYE packets.

   This algorithm depends upon the source transport address being the
   same for both RTP and RTCP packets from a source. The algorithm would
   require modifications to support applications that don't meet this

   This algorithm requires keeping a table indexed by source identifiers
   and containing the source transport address from which the identifier
   was (first) received, along with other state for that source. Each
   SSRC or CSRC identifier received in a data or control packet is
   looked up in this table in order to process that data or control
   information.  For control packets, each element with its own SSRC,
   for example an SDES chunk, requires a separate lookup. (The SSRC in a
   reception report block is an exception.) If the SSRC or CSRC is not
ToP   noToC   RFC1889 - Page 47
   found, a new entry is created. These table entries are removed when
   an RTCP BYE packet is received with the corresponding SSRC, or after
   no packets have arrived for a relatively long time (see Section

   In order to track loops of the participant's own data packets, it is
   also necessary to keep a separate list of source transport addresses
   (not identifiers) that have been found to be conflicting. Note that
   this should be a short list, usually empty. Each element in this list
   stores the source address plus the time when the most recent
   conflicting packet was received. An element may be removed from the
   list when no conflicting packet has arrived from that source for a
   time on the order of 10 RTCP report intervals (see Section 6.2).

   For the algorithm as shown, it is assumed that the participant's own
   source identifier and state are included in the source identifier
   table. The algorithm could be restructured to first make a separate
   comparison against the participant's own source identifier.

       IF the SSRC or CSRC identifier is not found in the source
          identifier table:
       THEN create a new entry storing the source transport address
            and the SSRC or CSRC along with other state.
            CONTINUE with normal processing.

       (identifier is found in the table)

       IF the source transport address from the packet matches
          the one saved in the table entry for this identifier:
       THEN CONTINUE with normal processing.

       (an identifier collision or a loop is indicated)

       IF the source identifier is not the participant's own:
       THEN IF the source identifier is from an RTCP SDES chunk
               containing a CNAME item that differs from the CNAME
               in the table entry:
            THEN (optionally) count a third-party collision.
            ELSE (optionally) count a third-party loop.
            ABORT processing of data packet or control element.

       (a collision or loop of the participant's own data)

       IF the source transport address is found in the list of
         conflicting addresses:
       THEN IF the source identifier is not from an RTCP SDES chunk
               containing a CNAME item OR if that CNAME is the
               participant's own:
ToP   noToC   RFC1889 - Page 48
            THEN (optionally) count occurrence of own traffic looped.
                 mark current time in conflicting address list entry.
                 ABORT processing of data packet or control element.
       log occurrence of a collision.
       create a new entry in the conflicting address list and
       mark current time.
       send an RTCP BYE packet with the old SSRC identifier.
       choose a new identifier.
       create a new entry in the source identifier table with the
         old SSRC plus the source transport address from the packet
         being processed.
       CONTINUE with normal processing.

   In this algorithm, packets from a newly conflicting source address
   will be ignored and packets from the original source will be kept.
   (If the original source was through a mixer and later the same source
   is received directly, the receiver may be well advised to switch
   unless other sources in the mix would be lost.) If no packets arrive
   from the original source for an extended period, the table entry will
   be timed out and the new source will be able to take over. This might
   occur if the original source detects the collision and moves to a new
   source identifier, but in the usual case an RTCP BYE packet will be
   received from the original source to delete the state without having
   to wait for a timeout.

   When a new SSRC identifier is chosen due to a collision, the
   candidate identifier should first be looked up in the source
   identifier table to see if it was already in use by some other
   source. If so, another candidate should be generated and the process

   A loop of data packets to a multicast destination can cause severe
   network flooding. All mixers and translators are required to
   implement a loop detection algorithm like the one here so that they
   can break loops. This should limit the excess traffic to no more than
   one duplicate copy of the original traffic, which may allow the
   session to continue so that the cause of the loop can be found and
   fixed. However, in extreme cases where a mixer or translator does not
   properly break the loop and high traffic levels result, it may be
   necessary for end systems to cease transmitting data or control
   packets entirely. This decision may depend upon the application. An
   error condition should be indicated as appropriate. Transmission
   might be attempted again periodically after a long, random time (on
   the order of minutes).
ToP   noToC   RFC1889 - Page 49
9.  Security

   Lower layer protocols may eventually provide all the security
   services that may be desired for applications of RTP, including
   authentication, integrity, and confidentiality. These services  have
   recently been specified for IP. Since the need for a confidentiality
   service is well established in the initial audio and video
   applications that are expected to use RTP, a confidentiality service
   is defined in the next section for use with RTP and RTCP until lower
   layer services are available. The overhead on the protocol for this
   service is low, so the penalty will be minimal if this service is
   obsoleted by lower layer services in the future.

   Alternatively, other services, other implementations of services and
   other algorithms may be defined for RTP in the future if warranted.
   The selection presented here is meant to simplify implementation of
   interoperable, secure applications and provide guidance to
   implementors. No claim is made that the methods presented here are
   appropriate for a particular security need. A profile may specify
   which services and algorithms should be offered by applications, and
   may provide guidance as to their appropriate use.

   Key distribution and certificates are outside the scope of this

9.1 Confidentiality

   Confidentiality means that only the intended receiver(s) can decode
   the received packets; for others, the packet contains no useful
   information. Confidentiality of the content is achieved by

   When encryption of RTP or RTCP is desired, all the octets that will
   be encapsulated for transmission in a single lower-layer packet are
   encrypted as a unit. For RTCP, a 32-bit random number is prepended to
   the unit before encryption to deter known plaintext attacks. For RTP,
   no prefix is required because the sequence number and timestamp
   fields are initialized with random offsets.

   For RTCP, it is allowed to split a compound RTCP packet into two
   lower-layer packets, one to be encrypted and one to be sent in the
   clear. For example, SDES information might be encrypted while
   reception reports were sent in the clear to accommodate third-party
   monitors that are not privy to the encryption key. In this example,
   depicted in Fig. 4, the SDES information must be appended to an RR
   packet with no reports (and the encrypted) to satisfy the requirement
   that all compound RTCP packets begin with an SR or RR packet.
ToP   noToC   RFC1889 - Page 50
                 UDP packet                        UDP packet
   -------------------------------------  -------------------------
   [32-bit ][       ][     #           ]  [    # sender # receiver]
   [random ][  RR   ][SDES # CNAME, ...]  [ SR # report # report  ]
   [integer][(empty)][     #           ]  [    #        #         ]
   -------------------------------------  -------------------------
                 encrypted                       not encrypted

   #: SSRC

           Figure 4: Encrypted and non-encrypted RTCP packets

   The presence of encryption and the use of the correct key are
   confirmed by the receiver through header or payload validity checks.
   Examples of such validity checks for RTP and RTCP headers are given
   in Appendices A.1 and A.2.

   The default encryption algorithm is the Data Encryption Standard
   (DES) algorithm in cipher block chaining (CBC) mode, as described in
   Section 1.1 of RFC 1423 [21], except that padding to a multiple of 8
   octets is indicated as described for the P bit in Section 5.1. The
   initialization vector is zero because random values are supplied in
   the RTP header or by the random prefix for compound RTCP packets. For
   details on the use of CBC initialization vectors, see [22].
   Implementations that support encryption should always support the DES
   algorithm in CBC mode as the default to maximize interoperability.
   This method is chosen because it has been demonstrated to be easy and
   practical to use in experimental audio and video tools in operation
   on the Internet. Other encryption algorithms may be specified
   dynamically for a session by non-RTP means.

   As an alternative to encryption at the RTP level as described above,
   profiles may define additional payload types for encrypted encodings.
   Those encodings must specify how padding and other aspects of the
   encryption should be handled. This method allows encrypting only the
   data while leaving the headers in the clear for applications where
   that is desired. It may be particularly useful for hardware devices
   that will handle both decryption and decoding.

9.2 Authentication and Message Integrity

   Authentication and message integrity are not defined in the current
   specification of RTP since these services would not be directly
   feasible without a key management infrastructure. It is expected that
   authentication and integrity services will be provided by lower layer
   protocols in the future.
ToP   noToC   RFC1889 - Page 51
10.  RTP over Network and Transport Protocols

   This section describes issues specific to carrying RTP packets within
   particular network and transport protocols. The following rules apply
   unless superseded by protocol-specific definitions outside this

   RTP relies on the underlying protocol(s) to provide demultiplexing of
   RTP data and RTCP control streams. For UDP and similar protocols, RTP
   uses an even port number and the corresponding RTCP stream uses the
   next higher (odd) port number. If an application is supplied with an
   odd number for use as the RTP port, it should replace this number
   with the next lower (even) number.

   RTP data packets contain no length field or other delineation,
   therefore RTP relies on the underlying protocol(s) to provide a
   length indication. The maximum length of RTP packets is limited only
   by the underlying protocols.

   If RTP packets are to be carried in an underlying protocol that
   provides the abstraction of a continuous octet stream rather than
   messages (packets), an encapsulation of the RTP packets must be
   defined to provide a framing mechanism. Framing is also needed if the
   underlying protocol may contain padding so that the extent of the RTP
   payload cannot be determined. The framing mechanism is not defined

   A profile may specify a framing method to be used even when RTP is
   carried in protocols that do provide framing in order to allow
   carrying several RTP packets in one lower-layer protocol data unit,
   such as a UDP packet. Carrying several RTP packets in one network or
   transport packet reduces header overhead and may simplify
   synchronization between different streams.

11.  Summary of Protocol Constants

   This section contains a summary listing of the constants defined in
   this specification.

   The RTP payload type (PT) constants are defined in profiles rather
   than this document. However, the octet of the RTP header which
   contains the marker bit(s) and payload type must avoid the reserved
   values 200 and 201 (decimal) to distinguish RTP packets from the RTCP
   SR and RR packet types for the header validation procedure described
   in Appendix A.1. For the standard definition of one marker bit and a
   7-bit payload type field as shown in this specification, this
   restriction means that payload types 72 and 73 are reserved.
ToP   noToC   RFC1889 - Page 52
11.1 RTCP packet types

   abbrev.    name                   value
   SR         sender report            200
   RR         receiver report          201
   SDES       source description       202
   BYE        goodbye                  203
   APP        application-defined      204

   These type values were chosen in the range 200-204 for improved
   header validity checking of RTCP packets compared to RTP packets or
   other unrelated packets. When the RTCP packet type field is compared
   to the corresponding octet of the RTP header, this range corresponds
   to the marker bit being 1 (which it usually is not in data packets)
   and to the high bit of the standard payload type field being 1 (since
   the static payload types are typically defined in the low half). This
   range was also chosen to be some distance numerically from 0 and 255
   since all-zeros and all-ones are common data patterns.

   Since all compound RTCP packets must begin with SR or RR, these codes
   were chosen as an even/odd pair to allow the RTCP validity check to
   test the maximum number of bits with mask and value.

   Other constants are assigned by IANA. Experimenters are encouraged to
   register the numbers they need for experiments, and then unregister
   those which prove to be unneeded.

11.2 SDES types

   abbrev.    name                              value
   END        end of SDES list                      0
   CNAME      canonical name                        1
   NAME       user name                             2
   EMAIL      user's electronic mail address        3
   PHONE      user's phone number                   4
   LOC        geographic user location              5
   TOOL       name of application or tool           6
   NOTE       notice about the source               7
   PRIV       private extensions                    8

   Other constants are assigned by IANA. Experimenters are encouraged to
   register the numbers they need for experiments, and then unregister
   those which prove to be unneeded.
ToP   noToC   RFC1889 - Page 53
12.  RTP Profiles and Payload Format Specifications

   A complete specification of RTP for a particular application will
   require one or more companion documents of two types described here:
   profiles, and payload format specifications.

   RTP may be used for a variety of applications with somewhat differing
   requirements. The flexibility to adapt to those requirements is
   provided by allowing multiple choices in the main protocol
   specification, then selecting the appropriate choices or defining
   extensions for a particular environment and class of applications in
   a separate profile document. Typically an application will operate
   under only one profile so there is no explicit indication of which
   profile is in use. A profile for audio and video applications may be
   found in the companion Internet-Draft draft-ietf-avt-profile for

   The second type of companion document is a payload format
   specification, which defines how a particular kind of payload data,
   such as H.261 encoded video, should be carried in RTP. These
   documents are typically titled "RTP Payload Format for XYZ
   Audio/Video Encoding". Payload formats may be useful under multiple
   profiles and may therefore be defined independently of any particular
   profile. The profile documents are then responsible for assigning a
   default mapping of that format to a payload type value if needed.

   Within this specification, the following items have been identified
   for possible definition within a profile, but this list is not meant
   to be exhaustive:

   RTP data header: The octet in the RTP data header that contains the
        marker bit and payload type field may be redefined by a profile
        to suit different requirements, for example with more or fewer
        marker bits (Section 5.3).

   Payload types: Assuming that a payload type field is included, the
        profile will usually define a set of payload formats (e.g.,
        media encodings) and a default static mapping of those formats
        to payload type values. Some of the payload formats may be
        defined by reference to separate payload format specifications.
        For each payload type defined, the profile must specify the RTP
        timestamp clock rate to be used (Section 5.1).

   RTP data header additions: Additional fields may be appended to the
        fixed RTP data header if some additional functionality is
        required across the profile's class of applications independent
        of payload type (Section 5.3).
ToP   noToC   RFC1889 - Page 54
   RTP data header extensions: The contents of the first 16 bits of the
        RTP data header extension structure must be defined if use of
        that mechanism is to be allowed under the profile for
        implementation-specific extensions (Section 5.3.1).

   RTCP packet types: New application-class-specific RTCP packet types
        may be defined and registered with IANA.

   RTCP report interval: A profile should specify that the values
        suggested in Section 6.2 for the constants employed in the
        calculation of the RTCP report interval will be used.  Those are
        the RTCP fraction of session bandwidth, the minimum report
        interval, and the bandwidth split between senders and receivers.
        A profile may specify alternate values if they have been
        demonstrated to work in a scalable manner.

   SR/RR extension: An extension section may be defined for the RTCP SR
        and RR packets if there is additional information that should be
        reported regularly about the sender or receivers (Section 6.3.3).

   SDES use: The profile may specify the relative priorities for RTCP
        SDES items to be transmitted or excluded entirely (Section
        6.2.2); an alternate syntax or semantics for the CNAME item
        (Section 6.4.1); the format of the LOC item (Section 6.4.5); the
        semantics and use of the NOTE item (Section 6.4.7); or new SDES
        item types to be registered with IANA.

   Security: A profile may specify which security services and
        algorithms should be offered by applications, and may provide
        guidance as to their appropriate use (Section 9).

   String-to-key mapping: A profile may specify how a user-provided
        password or pass phrase is mapped into an encryption key.

   Underlying protocol: Use of a particular underlying network or
        transport layer protocol to carry RTP packets may be required.

   Transport mapping: A mapping of RTP and RTCP to transport-level
        addresses, e.g., UDP ports, other than the standard mapping
        defined in Section 10 may be specified.

   Encapsulation: An encapsulation of RTP packets may be defined to
        allow multiple RTP data packets to be carried in one lower-layer
        packet or to provide framing over underlying protocols that do
        not already do so (Section 10).
ToP   noToC   RFC1889 - Page 55
   It is not expected that a new profile will be required for every
   application. Within one application class, it would be better to
   extend an existing profile rather than make a new one in order to
   facilitate interoperation among the applications since each will
   typically run under only one profile. Simple extensions such as the
   definition of additional payload type values or RTCP packet types may
   be accomplished by registering them through the Internet Assigned
   Numbers Authority and publishing their descriptions in an addendum to
   the profile or in a payload format specification.
ToP   noToC   RFC1889 - Page 56
A.  Algorithms

   We provide examples of C code for aspects of RTP sender and receiver
   algorithms. There may be other implementation methods that are faster
   in particular operating environments or have other advantages. These
   implementation notes are for informational purposes only and are
   meant to clarify the RTP specification.

   The following definitions are used for all examples; for clarity and
   brevity, the structure definitions are only valid for 32-bit big-
   endian (most significant octet first) architectures. Bit fields are
   assumed to be packed tightly in big-endian bit order, with no
   additional padding. Modifications would be required to construct a
   portable implementation.

    * rtp.h  --  RTP header file (RFC XXXX)
   #include <sys/types.h>

    * The type definitions below are valid for 32-bit architectures and
    * may have to be adjusted for 16- or 64-bit architectures.
   typedef unsigned char  u_int8;
   typedef unsigned short u_int16;
   typedef unsigned int   u_int32;
   typedef          short int16;

    * Current protocol version.
   #define RTP_VERSION    2

   #define RTP_SEQ_MOD (1<<16)
   #define RTP_MAX_SDES 255      /* maximum text length for SDES */

   typedef enum {
       RTCP_SR   = 200,
       RTCP_RR   = 201,
       RTCP_SDES = 202,
       RTCP_BYE  = 203,
       RTCP_APP  = 204
   } rtcp_type_t;

   typedef enum {
       RTCP_SDES_END   = 0,
       RTCP_SDES_CNAME = 1,
ToP   noToC   RFC1889 - Page 57
       RTCP_SDES_NAME  = 2,
       RTCP_SDES_EMAIL = 3,
       RTCP_SDES_PHONE = 4,
       RTCP_SDES_LOC   = 5,
       RTCP_SDES_TOOL  = 6,
       RTCP_SDES_NOTE  = 7,
       RTCP_SDES_PRIV  = 8
   } rtcp_sdes_type_t;

    * RTP data header
   typedef struct {
       unsigned int version:2;   /* protocol version */
       unsigned int p:1;         /* padding flag */
       unsigned int x:1;         /* header extension flag */
       unsigned int cc:4;        /* CSRC count */
       unsigned int m:1;         /* marker bit */
       unsigned int pt:7;        /* payload type */
       u_int16 seq;              /* sequence number */
       u_int32 ts;               /* timestamp */
       u_int32 ssrc;             /* synchronization source */
       u_int32 csrc[1];          /* optional CSRC list */
   } rtp_hdr_t;

    * RTCP common header word
   typedef struct {
       unsigned int version:2;   /* protocol version */
       unsigned int p:1;         /* padding flag */
       unsigned int count:5;     /* varies by packet type */
       unsigned int pt:8;        /* RTCP packet type */
       u_int16 length;           /* pkt len in words, w/o this word */
   } rtcp_common_t;

    * Big-endian mask for version, padding bit and packet type pair
   #define RTCP_VALID_MASK (0xc000 | 0x2000 | 0xfe)

    * Reception report block
   typedef struct {
       u_int32 ssrc;             /* data source being reported */
       unsigned int fraction:8;  /* fraction lost since last SR/RR */
ToP   noToC   RFC1889 - Page 58
       int lost:24;              /* cumul. no. pkts lost (signed!) */
       u_int32 last_seq;         /* extended last seq. no. received */
       u_int32 jitter;           /* interarrival jitter */
       u_int32 lsr;              /* last SR packet from this source */
       u_int32 dlsr;             /* delay since last SR packet */
   } rtcp_rr_t;

    * SDES item
   typedef struct {
       u_int8 type;              /* type of item (rtcp_sdes_type_t) */
       u_int8 length;            /* length of item (in octets) */
       char data[1];             /* text, not null-terminated */
   } rtcp_sdes_item_t;

    * One RTCP packet
   typedef struct {
       rtcp_common_t common;     /* common header */
       union {
           /* sender report (SR) */
           struct {
               u_int32 ssrc;     /* sender generating this report */
               u_int32 ntp_sec;  /* NTP timestamp */
               u_int32 ntp_frac;
               u_int32 rtp_ts;   /* RTP timestamp */
               u_int32 psent;    /* packets sent */
               u_int32 osent;    /* octets sent */
               rtcp_rr_t rr[1];  /* variable-length list */
           } sr;

           /* reception report (RR) */
           struct {
               u_int32 ssrc;     /* receiver generating this report */
               rtcp_rr_t rr[1];  /* variable-length list */
           } rr;

           /* source description (SDES) */
           struct rtcp_sdes {
               u_int32 src;      /* first SSRC/CSRC */
               rtcp_sdes_item_t item[1]; /* list of SDES items */
           } sdes;

           /* BYE */
           struct {
               u_int32 src[1];   /* list of sources */
ToP   noToC   RFC1889 - Page 59
               /* can't express trailing text for reason */
           } bye;
       } r;
   } rtcp_t;

   typedef struct rtcp_sdes rtcp_sdes_t;

    * Per-source state information
   typedef struct {
       u_int16 max_seq;        /* highest seq. number seen */
       u_int32 cycles;         /* shifted count of seq. number cycles */
       u_int32 base_seq;       /* base seq number */
       u_int32 bad_seq;        /* last 'bad' seq number + 1 */
       u_int32 probation;      /* sequ. packets till source is valid */
       u_int32 received;       /* packets received */
       u_int32 expected_prior; /* packet expected at last interval */
       u_int32 received_prior; /* packet received at last interval */
       u_int32 transit;        /* relative trans time for prev pkt */
       u_int32 jitter;         /* estimated jitter */
       /* ... */
   } source;

A.1 RTP Data Header Validity Checks

   An RTP receiver should check the validity of the RTP header on
   incoming packets since they might be encrypted or might be from a
   different application that happens to be misaddressed. Similarly, if
   encryption is enabled, the header validity check is needed to verify
   that incoming packets have been correctly decrypted, although a
   failure of the header validity check (e.g., unknown payload type) may
   not necessarily indicate decryption failure.

   Only weak validity checks are possible on an RTP data packet from a
   source that has not been heard before:

        o RTP version field must equal 2.

        o The payload type must be known, in particular it must not be
         equal to SR or RR.

        o If the P bit is set, then the last octet of the packet must
         contain a valid octet count, in particular, less than the total
         packet length minus the header size.

        o The X bit must be zero if the profile does not specify that
         the header extension mechanism may be used. Otherwise, the
ToP   noToC   RFC1889 - Page 60
         extension length field must be less than the total packet size
         minus the fixed header length and padding.

        o The length of the packet must be consistent with CC and
         payload type (if payloads have a known length).

   The last three checks are somewhat complex and not always possible,
   leaving only the first two which total just a few bits. If the SSRC
   identifier in the packet is one that has been received before, then
   the packet is probably valid and checking if the sequence number is
   in the expected range provides further validation. If the SSRC
   identifier has not been seen before, then data packets carrying that
   identifier may be considered invalid until a small number of them
   arrive with consecutive sequence numbers.

   The routine update_seq shown below ensures that a source is declared
   valid only after MIN_SEQUENTIAL packets have been received in
   sequence. It also validates the sequence number seq of a newly
   received packet and updates the sequence state for the packet's
   source in the structure to which s points.

   When a new source is heard for the first time, that is, its SSRC
   identifier is not in the table (see Section 8.2), and the per-source
   state is allocated for it, s->probation should be set to the number
   of sequential packets required before declaring a source valid
   (parameter MIN_SEQUENTIAL ) and s->max_seq initialized to seq-1 s-
   >probation marks the source as not yet valid so the state may be
   discarded after a short timeout rather than a long one, as discussed
   in Section 6.2.1.

   After a source is considered valid, the sequence number is considered
   valid if it is no more than MAX_DROPOUT ahead of s->max_seq nor more
   than MAX_MISORDER behind. If the new sequence number is ahead of
   max_seq modulo the RTP sequence number range (16 bits), but is
   smaller than max_seq , it has wrapped around and the (shifted) count
   of sequence number cycles is incremented. A value of one is returned
   to indicate a valid sequence number.

   Otherwise, the value zero is returned to indicate that the validation
   failed, and the bad sequence number is stored. If the next packet
   received carries the next higher sequence number, it is considered
   the valid start of a new packet sequence presumably caused by an
   extended dropout or a source restart. Since multiple complete
   sequence number cycles may have been missed, the packet loss
   statistics are reset.

   Typical values for the parameters are shown, based on a maximum
   misordering time of 2 seconds at 50 packets/second and a maximum
ToP   noToC   RFC1889 - Page 61
   dropout of 1 minute. The dropout parameter MAX_DROPOUT should be a
   small fraction of the 16-bit sequence number space to give a
   reasonable probability that new sequence numbers after a restart will
   not fall in the acceptable range for sequence numbers from before the

   void init_seq(source *s, u_int16 seq)
       s->base_seq = seq - 1;
       s->max_seq = seq;
       s->bad_seq = RTP_SEQ_MOD + 1;
       s->cycles = 0;
       s->received = 0;
       s->received_prior = 0;
       s->expected_prior = 0;
       /* other initialization */

   int update_seq(source *s, u_int16 seq)
       u_int16 udelta = seq - s->max_seq;
       const int MAX_DROPOUT = 3000;
       const int MAX_MISORDER = 100;
       const int MIN_SEQUENTIAL = 2;

        * Source is not valid until MIN_SEQUENTIAL packets with
        * sequential sequence numbers have been received.
       if (s->probation) {
           /* packet is in sequence */
           if (seq == s->max_seq + 1) {
               s->max_seq = seq;
               if (s->probation == 0) {
                   init_seq(s, seq);
                   return 1;
           } else {
               s->probation = MIN_SEQUENTIAL - 1;
               s->max_seq = seq;
           return 0;
       } else if (udelta < MAX_DROPOUT) {
           /* in order, with permissible gap */
           if (seq < s->max_seq) {
ToP   noToC   RFC1889 - Page 62
                * Sequence number wrapped - count another 64K cycle.
               s->cycles += RTP_SEQ_MOD;
           s->max_seq = seq;
       } else if (udelta <= RTP_SEQ_MOD - MAX_MISORDER) {
           /* the sequence number made a very large jump */
           if (seq == s->bad_seq) {
                * Two sequential packets -- assume that the other side
                * restarted without telling us so just re-sync
                * (i.e., pretend this was the first packet).
               init_seq(s, seq);
           else {
               s->bad_seq = (seq + 1) & (RTP_SEQ_MOD-1);
               return 0;
       } else {
           /* duplicate or reordered packet */
       return 1;

   The validity check can be made stronger requiring more than two
   packets in sequence.  The disadvantages are that a larger number of
   initial packets will be discarded and that high packet loss rates
   could prevent validation. However, because the RTCP header validation
   is relatively strong, if an RTCP packet is received from a source
   before the data packets, the count could be adjusted so that only two
   packets are required in sequence.  If initial data loss for a few
   seconds can be tolerated, an application could choose to discard all
   data packets from a source until a valid RTCP packet has been
   received from that source.

   Depending on the application and encoding, algorithms may exploit
   additional knowledge about the payload format for further validation.
   For payload types where the timestamp increment is the same for all
   packets, the timestamp values can be predicted from the previous
   packet received from the same source using the sequence number
   difference (assuming no change in payload type).

   A strong "fast-path" check is possible since with high probability
   the first four octets in the header of a newly received RTP data
   packet will be just the same as that of the previous packet from the
   same SSRC except that the sequence number will have increased by one.
ToP   noToC   RFC1889 - Page 63
   Similarly, a single-entry cache may be used for faster SSRC lookups
   in applications where data is typically received from one source at a

A.2 RTCP Header Validity Checks

   The following checks can be applied to RTCP packets.

        o RTP version field must equal 2.

        o The payload type field of the first RTCP packet in a compound
         packet must be equal to SR or RR.

        o The padding bit (P) should be zero for the first packet of a
         compound RTCP packet because only the last should possibly need

        o The length fields of the individual RTCP packets must total to
         the overall length of the compound RTCP packet as received.
         This is a fairly strong check.

   The code fragment below performs all of these checks. The packet type
   is not checked for subsequent packets since unknown packet types may
   be present and should be ignored.

       u_int32 len;        /* length of compound RTCP packet in words */
       rtcp_t *r;          /* RTCP header */
       rtcp_t *end;        /* end of compound RTCP packet */

       if ((*(u_int16 *)r & RTCP_VALID_MASK) != RTCP_VALID_VALUE) {
           /* something wrong with packet format */
       end = (rtcp_t *)((u_int32 *)r + len);

       do r = (rtcp_t *)((u_int32 *)r + r->common.length + 1);
       while (r < end && r->common.version == 2);

       if (r != end) {
           /* something wrong with packet format */

A.3 Determining the Number of RTP Packets Expected and Lost

   In order to compute packet loss rates, the number of packets expected
   and actually received from each source needs to be known, using per-
   source state information defined in struct source referenced via
   pointer s in the code below. The number of packets received is simply
   the count of packets as they arrive, including any late or duplicate
ToP   noToC   RFC1889 - Page 64
   packets. The number of packets expected can be computed by the
   receiver as the difference between the highest sequence number
   received ( s->max_seq ) and the first sequence number received ( s-
   >base_seq ). Since the sequence number is only 16 bits and will wrap
   around, it is necessary to extend the highest sequence number with
   the (shifted) count of sequence number wraparounds ( s->cycles ).
   Both the received packet count and the count of cycles are maintained
   the RTP header validity check routine in Appendix A.1.

       extended_max = s->cycles + s->max_seq;
       expected = extended_max - s->base_seq + 1;

   The number of packets lost is defined to be the number of packets
   expected less the number of packets actually received:

       lost = expected - s->received;

   Since this number is carried in 24 bits, it should be clamped at
   0xffffff rather than wrap around to zero.

   The fraction of packets lost during the last reporting interval
   (since the previous SR or RR packet was sent) is calculated from
   differences in the expected and received packet counts across the
   interval, where expected_prior and received_prior are the values
   saved when the previous reception report was generated:

       expected_interval = expected - s->expected_prior;
       s->expected_prior = expected;
       received_interval = s->received - s->received_prior;
       s->received_prior = s->received;
       lost_interval = expected_interval - received_interval;
       if (expected_interval == 0 || lost_interval <= 0) fraction = 0;
       else fraction = (lost_interval << 8) / expected_interval;

   The resulting fraction is an 8-bit fixed point number with the binary
   point at the left edge.

A.4 Generating SDES RTCP Packets

   This function builds one SDES chunk into buffer b composed of argc
   items supplied in arrays type , value and length b

   char *rtp_write_sdes(char *b, u_int32 src, int argc,
                        rtcp_sdes_type_t type[], char *value[],
                        int length[])
       rtcp_sdes_t *s = (rtcp_sdes_t *)b;
       rtcp_sdes_item_t *rsp;
ToP   noToC   RFC1889 - Page 65
       int i;
       int len;
       int pad;

       /* SSRC header */
       s->src = src;
       rsp = &s->item[0];

       /* SDES items */
       for (i = 0; i < argc; i++) {
           rsp->type = type[i];
           len = length[i];
           if (len > RTP_MAX_SDES) {
               /* invalid length, may want to take other action */
               len = RTP_MAX_SDES;
           rsp->length = len;
           memcpy(rsp->data, value[i], len);
           rsp = (rtcp_sdes_item_t *)&rsp->data[len];

       /* terminate with end marker and pad to next 4-octet boundary */
       len = ((char *) rsp) - b;
       pad = 4 - (len & 0x3);
       b = (char *) rsp;
       while (pad--) *b++ = RTCP_SDES_END;

       return b;

A.5 Parsing RTCP SDES Packets

   This function parses an SDES packet, calling functions find_member()
   to find a pointer to the information for a session member given the
   SSRC identifier and member_sdes() to store the new SDES information
   for that member. This function expects a pointer to the header of the
   RTCP packet.

   void rtp_read_sdes(rtcp_t *r)
       int count = r->common.count;
       rtcp_sdes_t *sd = &r->r.sdes;
       rtcp_sdes_item_t *rsp, *rspn;
       rtcp_sdes_item_t *end = (rtcp_sdes_item_t *)
                               ((u_int32 *)r + r->common.length + 1);
       source *s;

       while (--count >= 0) {
ToP   noToC   RFC1889 - Page 66
           rsp = &sd->item[0];
           if (rsp >= end) break;
           s = find_member(sd->src);

           for (; rsp->type; rsp = rspn ) {
               rspn = (rtcp_sdes_item_t *)((char*)rsp+rsp->length+2);
               if (rspn >= end) {
                   rsp = rspn;
               member_sdes(s, rsp->type, rsp->data, rsp->length);
           sd = (rtcp_sdes_t *)
                ((u_int32 *)sd + (((char *)rsp - (char *)sd) >> 2)+1);
       if (count >= 0) {
           /* invalid packet format */

A.6 Generating a Random 32-bit Identifier

   The following subroutine generates a random 32-bit identifier using
   the MD5 routines published in RFC 1321 [23]. The system routines may
   not be present on all operating systems, but they should serve as
   hints as to what kinds of information may be used. Other system calls
   that may be appropriate include

        o getdomainname() ,

        o getwd() , or

        o getrusage()

   "Live" video or audio samples are also a good source of random
   numbers, but care must be taken to avoid using a turned-off
   microphone or blinded camera as a source [7].

   Use of this or similar routine is suggested to generate the initial
   seed for the random number generator producing the RTCP period (as
   shown in Appendix A.7), to generate the initial values for the
   sequence number and timestamp, and to generate SSRC values.  Since
   this routine is likely to be CPU-intensive, its direct use to
   generate RTCP periods is inappropriate because predictability is not
   an issue. Note that this routine produces the same result on repeated
   calls until the value of the system clock changes unless different
   values are supplied for the type argument.
ToP   noToC   RFC1889 - Page 67
    * Generate a random 32-bit quantity.
   #include <sys/types.h>   /* u_long */
   #include <sys/time.h>    /* gettimeofday() */
   #include <unistd.h>      /* get..() */
   #include <stdio.h>       /* printf() */
   #include <time.h>        /* clock() */
   #include <sys/utsname.h> /* uname() */
   #include "global.h"      /* from RFC 1321 */
   #include "md5.h"         /* from RFC 1321 */

   #define MD_CTX MD5_CTX
   #define MDInit MD5Init
   #define MDUpdate MD5Update
   #define MDFinal MD5Final

   static u_long md_32(char *string, int length)
       MD_CTX context;
       union {
           char   c[16];
           u_long x[4];
       } digest;
       u_long r;
       int i;

       MDInit (&context);
       MDUpdate (&context, string, length);
       MDFinal ((unsigned char *)&digest, &context);
       r = 0;
       for (i = 0; i < 3; i++) {
           r ^= digest.x[i];
       return r;
   }                               /* md_32 */

    * Return random unsigned 32-bit quantity. Use 'type' argument if you
    * need to generate several different values in close succession.
   u_int32 random32(int type)
       struct {
           int     type;
           struct  timeval tv;
           clock_t cpu;
ToP   noToC   RFC1889 - Page 68
           pid_t   pid;
           u_long  hid;
           uid_t   uid;
           gid_t   gid;
           struct  utsname name;
       } s;

       gettimeofday(&, 0);
       s.type = type;
       s.cpu  = clock();  = getpid();
       s.hid  = gethostid();
       s.uid  = getuid();
       s.gid  = getgid();

       return md_32((char *)&s, sizeof(s));
   }                               /* random32 */

A.7 Computing the RTCP Transmission Interval

   The following function returns the time between transmissions of RTCP
   packets, measured in seconds. It should be called after sending one
   compound RTCP packet to calculate the delay until the next should be
   sent. This function should also be called to calculate the delay
   before sending the first RTCP packet upon startup rather than send
   the packet immediately. This avoids any burst of RTCP packets if an
   application is started at many sites simultaneously, for example as a
   result of a session announcement.

   The parameters have the following meaning:

   rtcp_bw: The target RTCP bandwidth, i.e., the total bandwidth that
        will be used for RTCP packets by all members of this session, in
        octets per second. This should be 5% of the "session bandwidth"
        parameter supplied to the application at startup.

   senders: Number of active senders since sending last report, known
        from construction of receiver reports for this RTCP packet.
        Includes ourselves, if we also sent during this interval.

   members: The estimated number of session members, including
        ourselves. Incremented as we discover new session members from
        the receipt of RTP or RTCP packets, and decremented as session
        members leave (via RTCP BYE) or their state is timed out (30
        minutes is recommended). On the first call, this parameter
        should have the value 1.
ToP   noToC   RFC1889 - Page 69
   we_sent: Flag that is true if we have sent data during the last two
        RTCP intervals. If the flag is true, the compound RTCP packet
        just sent contained an SR packet.

   packet_size: The size of the compound RTCP packet just sent, in
        octets, including the network encapsulation (e.g., 28 octets for
        UDP over IP).

   avg_rtcp_size: Pointer to estimator for compound RTCP packet size;
        initialized and updated by this function for the packet just
        sent, and also updated by an identical line of code in the RTCP
        receive routine for every RTCP packet received from other
        participants in the session.

   initial: Flag that is true for the first call upon startup to
        calculate the time until the first report should be sent.

   #include <math.h>

   double rtcp_interval(int members,
                        int senders,
                        double rtcp_bw,
                        int we_sent,
                        int packet_size,
                        int *avg_rtcp_size,
                        int initial)
        * Minimum time between RTCP packets from this site (in seconds).
        * This time prevents the reports from `clumping' when sessions
        * are small and the law of large numbers isn't helping to smooth
        * out the traffic.  It also keeps the report interval from
        * becoming ridiculously small during transient outages like a
        * network partition.
       double const RTCP_MIN_TIME = 5.;
        * Fraction of the RTCP bandwidth to be shared among active
        * senders.  (This fraction was chosen so that in a typical
        * session with one or two active senders, the computed report
        * time would be roughly equal to the minimum report time so that
        * we don't unnecessarily slow down receiver reports.) The
        * receiver fraction must be 1 - the sender fraction.
       double const RTCP_SENDER_BW_FRACTION = 0.25;
        * Gain (smoothing constant) for the low-pass filter that
ToP   noToC   RFC1889 - Page 70
        * estimates the average RTCP packet size (see Cadzow reference).
       double const RTCP_SIZE_GAIN = (1./16.);

       double t;                   /* interval */
       double rtcp_min_time = RTCP_MIN_TIME;
       int n;                      /* no. of members for computation */

        * Very first call at application start-up uses half the min
        * delay for quicker notification while still allowing some time
        * before reporting for randomization and to learn about other
        * sources so the report interval will converge to the correct
        * interval more quickly.  The average RTCP size is initialized
        * to 128 octets which is conservative (it assumes everyone else
        * is generating SRs instead of RRs: 20 IP + 8 UDP + 52 SR + 48
        * SDES CNAME).
       if (initial) {
           rtcp_min_time /= 2;
           *avg_rtcp_size = 128;

        * If there were active senders, give them at least a minimum
        * share of the RTCP bandwidth.  Otherwise all participants share
        * the RTCP bandwidth equally.
       n = members;
       if (senders > 0 && senders < members * RTCP_SENDER_BW_FRACTION) {
           if (we_sent) {
               rtcp_bw *= RTCP_SENDER_BW_FRACTION;
               n = senders;
           } else {
               rtcp_bw *= RTCP_RCVR_BW_FRACTION;
               n -= senders;

        * Update the average size estimate by the size of the report
        * packet we just sent.
       *avg_rtcp_size += (packet_size - *avg_rtcp_size)*RTCP_SIZE_GAIN;

        * The effective number of sites times the average packet size is
        * the total number of octets sent when each site sends a report.
ToP   noToC   RFC1889 - Page 71
        * Dividing this by the effective bandwidth gives the time
        * interval over which those packets must be sent in order to
        * meet the bandwidth target, with a minimum enforced.  In that
        * time interval we send one report so this time is also our
        * average time between reports.
       t = (*avg_rtcp_size) * n / rtcp_bw;
       if (t < rtcp_min_time) t = rtcp_min_time;

        * To avoid traffic bursts from unintended synchronization with
        * other sites, we then pick our actual next report interval as a
        * random number uniformly distributed between 0.5*t and 1.5*t.
       return t * (drand48() + 0.5);

A.8 Estimating the Interarrival Jitter

   The code fragments below implement the algorithm given in Section
   6.3.1 for calculating an estimate of the statistical variance of the
   RTP data interarrival time to be inserted in the interarrival jitter
   field of reception reports. The inputs are r->ts , the timestamp from
   the incoming packet, and arrival , the current time in the same
   units. Here s points to state for the source; s->transit holds the
   relative transit time for the previous packet, and s->jitter holds
   the estimated jitter. The jitter field of the reception report is
   measured in timestamp units and expressed as an unsigned integer, but
   the jitter estimate is kept in a floating point. As each data packet
   arrives, the jitter estimate is updated:

       int transit = arrival - r->ts;
       int d = transit - s->transit;
       s->transit = transit;
       if (d < 0) d = -d;
       s->jitter += (1./16.) * ((double)d - s->jitter);

   When a reception report block (to which rr points) is generated for
   this member, the current jitter estimate is returned:

       rr->jitter = (u_int32) s->jitter;

   Alternatively, the jitter estimate can be kept as an integer, but
   scaled to reduce round-off error. The calculation is the same except
   for the last line:

       s->jitter += d - ((s->jitter + 8) >> 4);
ToP   noToC   RFC1889 - Page 72
   In this case, the estimate is sampled for the reception report as:

       rr->jitter = s->jitter >> 4;

B.  Security Considerations

   RTP suffers from the same security liabilities as the underlying
   protocols. For example, an impostor can fake source or destination
   network addresses, or change the header or payload. Within RTCP, the
   CNAME and NAME information may be used to impersonate another
   participant. In addition, RTP may be sent via IP multicast, which
   provides no direct means for a sender to know all the receivers of
   the data sent and therefore no measure of privacy. Rightly or not,
   users may be more sensitive to privacy concerns with audio and video
   communication than they have been with more traditional forms of
   network communication [24]. Therefore, the use of security mechanisms
   with RTP is important. These mechanisms are discussed in Section 9.

   RTP-level translators or mixers may be used to allow RTP traffic to
   reach hosts behind firewalls. Appropriate firewall security
   principles and practices, which are beyond the scope of this
   document, should be followed in the design and installation of these
   devices and in the admission of RTP applications for use behind the

C. Authors' Addresses

   Henning Schulzrinne
   GMD Fokus
   Hardenbergplatz 2
   D-10623 Berlin


   Stephen L. Casner
   Precept Software, Inc.
   21580 Stevens Creek Boulevard, Suite 207
   Cupertino, CA 95014
   United States

ToP   noToC   RFC1889 - Page 73
   Ron Frederick
   Xerox Palo Alto Research Center
   3333 Coyote Hill Road
   Palo Alto, CA 94304
   United States


   Van Jacobson
   MS 46a-1121
   Lawrence Berkeley National Laboratory
   Berkeley, CA 94720
   United States



   This memorandum is based on discussions within the IETF Audio/Video
   Transport working group chaired by Stephen Casner. The current
   protocol has its origins in the Network Voice Protocol and the Packet
   Video Protocol (Danny Cohen and Randy Cole) and the protocol
   implemented by the vat application (Van Jacobson and Steve McCanne).
   Christian Huitema provided ideas for the random identifier generator.

D.  Bibliography

   [1] D. D. Clark and D. L. Tennenhouse, "Architectural considerations
       for a new generation of protocols," in SIGCOMM Symposium on
       Communications Architectures and Protocols , (Philadelphia,
       Pennsylvania), pp. 200--208, IEEE, Sept. 1990.  Computer
       Communications Review, Vol. 20(4), Sept. 1990.

   [2] H. Schulzrinne, "Issues in designing a transport protocol for
       audio and video conferences and other multiparticipant real-time
       applications", Work in Progress.

   [3] D. E. Comer, Internetworking with TCP/IP , vol. 1.  Englewood
       Cliffs, New Jersey: Prentice Hall, 1991.

   [4] Postel, J., "Internet Protocol", STD 5, RFC 791, USC/Information
       Sciences Institute, September 1981.

   [5] Mills, D., "Network Time Protocol Version 3", RFC 1305, UDEL,
       March 1992.
ToP   noToC   RFC1889 - Page 74
   [6] Reynolds, J., and J. Postel, "Assigned Numbers", STD 2, RFC 1700,
       USC/Information Sciences Institute, October 1994.

   [7] Eastlake, D., Crocker, S., and J. Schiller, "Randomness
       Recommendations for Security", RFC 1750, DEC, Cybercash, MIT,
       December 1994.

   [8] J.-C. Bolot, T. Turletti, and I. Wakeman, "Scalable feedback
       control for multicast video distribution in the internet," in
       SIGCOMM Symposium on Communications Architectures and Protocols ,
       (London, England), pp. 58--67, ACM, Aug. 1994.

   [9] I. Busse, B. Deffner, and H. Schulzrinne, "Dynamic QoS control of
       multimedia applications based on RTP," Computer Communications ,
       Jan.  1996.

  [10] S. Floyd and V. Jacobson, "The synchronization of periodic
       routing messages," in SIGCOMM Symposium on Communications
       Architectures and Protocols (D. P. Sidhu, ed.), (San Francisco,
       California), pp. 33--44, ACM, Sept. 1993.  also in [25].

  [11] J. A. Cadzow, Foundations of digital signal processing and data
       analysis New York, New York: Macmillan, 1987.

  [12] International Standards Organization, "ISO/IEC DIS 10646-1:1993
       information technology -- universal multiple-octet coded
       character set (UCS) -- part I: Architecture and basic
       multilingual plane," 1993.

  [13] The Unicode Consortium, The Unicode Standard New York, New York:
       Addison-Wesley, 1991.

  [14] Mockapetris, P., "Domain Names - Concepts and Facilities", STD
       13, RFC 1034, USC/Information Sciences Institute, November 1987.

  [15] Mockapetris, P., "Domain Names - Implementation and
       Specification", STD 13, RFC 1035, USC/Information Sciences
       Institute, November 1987.

  [16] Braden, R., "Requirements for Internet Hosts - Application and
       Support", STD 3, RFC 1123, Internet Engineering Task Force,
       October 1989.

  [17] Rekhter, Y., Moskowitz, R., Karrenberg, D., and G. de Groot,
       "Address Allocation for Private Internets", RFC 1597, T.J. Watson
       Research Center, IBM Corp., Chrysler Corp., RIPE NCC, March 1994.
ToP   noToC   RFC1889 - Page 75
  [18] Lear, E., Fair, E., Crocker, D., and T. Kessler, "Network 10
       Considered Harmful (Some Practices Shouldn't be Codified)", RFC
       1627, Silicon Graphics, Inc., Apple Computer, Inc., Silicon
       Graphics, Inc., July 1994.

  [19] Crocker, D., "Standard for the Format of ARPA Internet Text
       Messages", STD 11, RFC 822, UDEL, August 1982.

  [20] W. Feller, An Introduction to Probability Theory and its
       Applications, Volume 1 , vol. 1.  New York, New York: John Wiley
       and Sons, third ed., 1968.

  [21] Balenson, D., "Privacy Enhancement for Internet Electronic Mail:
       Part III: Algorithms, Modes, and Identifiers", RFC 1423, TIS, IAB
       IRTF PSRG, IETF PEM WG, February 1993.

  [22] V. L. Voydock and S. T. Kent, "Security mechanisms in high-level
       network protocols," ACM Computing Surveys , vol. 15, pp. 135--
       171, June 1983.

  [23] Rivest, R., "The MD5 Message-Digest Algorithm", RFC 1321, MIT
       Laboratory for Computer Science and RSA Data Security, Inc.,
       April 1992.

  [24] S. Stubblebine, "Security services for multimedia conferencing,"
       in 16th National Computer Security Conference , (Baltimore,
       Maryland), pp. 391--395, Sept. 1993.

  [25] S. Floyd and V. Jacobson, "The synchronization of periodic
       routing messages," IEEE/ACM Transactions on Networking , vol. 2,
       pp.  122-136, April 1994.