tech-invite   World Map     

IETF     RFCs     Groups     SIP     ABNFs    |    3GPP     Specs     Glossaries     Architecture     IMS     UICC    |    search     info

RFC 6458

 
 
 

Sockets API Extensions for the Stream Control Transmission Protocol (SCTP)

Part 4 of 4, p. 88 to 115
Prev RFC Part

 


prevText      Top      Up      ToC       Page 88 
9.  New Functions

   Depending on the system, the following interface can be implemented
   as a system call or library function.

9.1.  sctp_bindx()

   This function allows the user to bind a specific subset of addresses
   or, if the SCTP extension described in [RFC5061] is supported, add or
   delete specific addresses.

Top      Up      ToC       Page 89 
   The function prototype is

   int sctp_bindx(int sd,
                  struct sockaddr *addrs,
                  int addrcnt,
                  int flags);

   If sd is an IPv4 socket, the addresses passed must be IPv4 addresses.
   If the sd is an IPv6 socket, the addresses passed can either be IPv4
   or IPv6 addresses.

   A single address may be specified as INADDR_ANY for an IPv4 address,
   or as IN6ADDR_ANY_INIT or in6addr_any for an IPv6 address; see
   Section 3.1.2 for this usage.

   addrs is a pointer to an array of one or more socket addresses.  Each
   address is contained in its appropriate structure.  For an IPv6
   socket, an array of sockaddr_in6 is used.  For an IPv4 socket, an
   array of sockaddr_in is used.  The caller specifies the number of
   addresses in the array with addrcnt.  Note that the wildcard
   addresses cannot be used in combination with non-wildcard addresses
   on a socket with this function; doing so will result in an error.

   On success, sctp_bindx() returns 0.  On failure, sctp_bindx() returns
   -1 and sets errno to the appropriate error code.

   For SCTP, the port given in each socket address must be the same, or
   sctp_bindx() will fail, setting errno to EINVAL.

   The flags parameter is formed from the bitwise OR of zero or more of
   the following currently defined flags:

   o  SCTP_BINDX_ADD_ADDR

   o  SCTP_BINDX_REM_ADDR

   SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the
   socket (i.e., endpoint), and SCTP_BINDX_REM_ADDR directs SCTP to
   remove the given addresses from the socket.  The two flags are
   mutually exclusive; if both are given, sctp_bindx() will fail with
   EINVAL.  A caller may not remove all addresses from a socket;
   sctp_bindx() will reject such an attempt with EINVAL.

   An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate
   additional addresses with an endpoint after calling bind().  Or, an
   application can use sctp_bindx(SCTP_BINDX_REM_ADDR) to remove some
   addresses with which a listening socket is associated, so that no new
   association accepted will be associated with these addresses.  If the

Top      Up      ToC       Page 90 
   endpoint supports dynamic address reconfiguration, an
   SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR may cause an endpoint to
   send the appropriate message to its peers to change the peers'
   address lists.

   Adding and removing addresses from established associations is an
   optional functionality.  Implementations that do not support this
   functionality should return -1 and set errno to EOPNOTSUPP.

   sctp_bindx() can be called on an already bound socket or on an
   unbound socket.  If the socket is unbound and the first port number
   in the addrs parameter is zero, the kernel will choose a port number.
   All port numbers after the first one being 0 must also be zero.  If
   the first port number is not zero, the following port numbers must be
   zero or have the same value as the first one.  For an already bound
   socket, all port numbers provided must be the bound one or 0.

   sctp_bindx() is an atomic operation.  Therefore, the binding will
   either succeed on all addresses or fail on all addresses.  If
   multiple addresses are provided and the sctp_bindx() call fails,
   there is no indication of which address is responsible for the
   failure.  The only way to identify the specific error indication is
   to call sctp_bindx() sequentially with only one address per call.

9.2.  sctp_peeloff()

   After an association is established on a one-to-many style socket,
   the application may wish to branch off the association into a
   separate socket/file descriptor.

   This is particularly desirable when, for instance, the application
   wishes to have a number of sporadic message senders/receivers remain
   under the original one-to-many style socket but branch off these
   associations carrying high-volume data traffic into their own
   separate socket descriptors.

   The application uses the sctp_peeloff() call to branch off an
   association into a separate socket.  (Note that the semantics are
   somewhat changed from the traditional one-to-one style accept()
   call.)  Note also that the new socket is a one-to-one style socket.
   Thus, it will be confined to operations allowed for a one-to-one
   style socket.

   The function prototype is

   int sctp_peeloff(int sd,
                    sctp_assoc_t assoc_id);

Top      Up      ToC       Page 91 
   and the arguments are

   sd:  The original one-to-many style socket descriptor returned from
      the socket() system call (see Section 3.1.1).

   assoc_id:  The specified identifier of the association that is to be
      branched off to a separate file descriptor.  (Note that in a
      traditional one-to-one style accept() call, this would be an out
      parameter, but for the one-to-many style call, this is an in
      parameter.)

   The function returns a non-negative file descriptor representing the
   branched-off association, or -1 if an error occurred.  The variable
   errno is then set appropriately.

9.3.  sctp_getpaddrs()

   sctp_getpaddrs() returns all peer addresses in an association.

   The function prototype is

   int sctp_getpaddrs(int sd,
                      sctp_assoc_t id,
                      struct sockaddr **addrs);

   On return, addrs will point to a dynamically allocated array of
   sockaddr structures of the appropriate type for the socket type.  The
   caller should use sctp_freepaddrs() to free the memory.  Note that
   the in/out parameter addrs must not be NULL.

   If sd is an IPv4 socket, the addresses returned will be all IPv4
   addresses.  If sd is an IPv6 socket, the addresses returned can be a
   mix of IPv4 or IPv6 addresses, with IPv4 addresses returned according
   to the SCTP_I_WANT_MAPPED_V4_ADDR option setting.

   For one-to-many style sockets, id specifies the association to query.
   For one-to-one style sockets, id is ignored.

   On success, sctp_getpaddrs() returns the number of peer addresses in
   the association.  If there is no association on this socket,
   sctp_getpaddrs() returns 0, and the value of *addrs is undefined.  If
   an error occurs, sctp_getpaddrs() returns -1, and the value of *addrs
   is undefined.

Top      Up      ToC       Page 92 
9.4.  sctp_freepaddrs()

   sctp_freepaddrs() frees all resources allocated by sctp_getpaddrs().

   The function prototype is

   void sctp_freepaddrs(struct sockaddr *addrs);

   and addrs is the array of peer addresses returned by
   sctp_getpaddrs().

9.5.  sctp_getladdrs()

   sctp_getladdrs() returns all locally bound addresses on a socket.

   The function prototype is

   int sctp_getladdrs(int sd,
                      sctp_assoc_t id,
                      struct sockaddr **addrs);

   On return, addrs will point to a dynamically allocated array of
   sockaddr structures of the appropriate type for the socket type.  The
   caller should use sctp_freeladdrs() to free the memory.  Note that
   the in/out parameter addrs must not be NULL.

   If sd is an IPv4 socket, the addresses returned will be all IPv4
   addresses.  If sd is an IPv6 socket, the addresses returned can be a
   mix of IPv4 or IPv6 addresses, with IPv4 addresses returned according
   to the SCTP_I_WANT_MAPPED_V4_ADDR option setting.

   For one-to-many style sockets, id specifies the association to query.
   For one-to-one style sockets, id is ignored.

   If the id field is set to the value '0', then the locally bound
   addresses are returned without regard to any particular association.

   On success, sctp_getladdrs() returns the number of local addresses
   bound to the socket.  If the socket is unbound, sctp_getladdrs()
   returns 0, and the value of *addrs is undefined.  If an error occurs,
   sctp_getladdrs() returns -1, and the value of *addrs is undefined.

Top      Up      ToC       Page 93 
9.6.  sctp_freeladdrs()

   sctp_freeladdrs() frees all resources allocated by sctp_getladdrs().

   The function prototype is

   void sctp_freeladdrs(struct sockaddr *addrs);

   and addrs is the array of local addresses returned by
   sctp_getladdrs().

9.7.  sctp_sendmsg() - DEPRECATED

   This function is deprecated; sctp_sendv() (see Section 9.12) should
   be used instead.

   An implementation may provide a library function (or possibly system
   call) to assist the user with the advanced features of SCTP.

   The function prototype is

   ssize_t sctp_sendmsg(int sd,
                        const void *msg,
                        size_t len,
                        const struct sockaddr *to,
                        socklen_t tolen,
                        uint32_t ppid,
                        uint32_t flags,
                        uint16_t stream_no,
                        uint32_t timetolive,
                        uint32_t context);

   and the arguments are

   sd:  The socket descriptor.

   msg:  The message to be sent.

   len:  The length of the message.

   to:  The destination address of the message.

   tolen:  The length of the destination address.

   ppid:  The same as sinfo_ppid (see Section 5.3.2).

   flags:  The same as sinfo_flags (see Section 5.3.2).

Top      Up      ToC       Page 94 
   stream_no:  The same as sinfo_stream (see Section 5.3.2).

   timetolive:  The same as sinfo_timetolive (see Section 5.3.2).

   context:  The same as sinfo_context (see Section 5.3.2).

   The call returns the number of characters sent, or -1 if an error
   occurred.  The variable errno is then set appropriately.

   Sending a message using sctp_sendmsg() is atomic (unless explicit EOR
   marking is enabled on the socket specified by sd).

   Using sctp_sendmsg() on a non-connected one-to-one style socket for
   implicit connection setup may or may not work, depending on the SCTP
   implementation.

9.8.  sctp_recvmsg() - DEPRECATED

   This function is deprecated; sctp_recvv() (see Section 9.13) should
   be used instead.

   An implementation may provide a library function (or possibly system
   call) to assist the user with the advanced features of SCTP.  Note
   that in order for the sctp_sndrcvinfo structure to be filled in by
   sctp_recvmsg(), the caller must enable the sctp_data_io_event with
   the SCTP_EVENTS option.  Note that the setting of the
   SCTP_USE_EXT_RCVINFO will affect this function as well, causing the
   sctp_sndrcvinfo information to be extended.

   The function prototype is

   ssize_t sctp_recvmsg(int sd,
                        void *msg,
                        size_t len,
                        struct sockaddr *from,
                        socklen_t *fromlen
                        struct sctp_sndrcvinfo *sinfo
                        int *msg_flags);

   and the arguments are

   sd:  The socket descriptor.

   msg:  The message buffer to be filled.

   len:  The length of the message buffer.

Top      Up      ToC       Page 95 
   from:  A pointer to an address to be filled with the address of the
      sender of this message.

   fromlen:  An in/out parameter describing the from length.

   sinfo:  A pointer to an sctp_sndrcvinfo structure to be filled upon
      receipt of the message.

   msg_flags:  A pointer to an integer to be filled with any message
      flags (e.g., MSG_NOTIFICATION).  Note that this field is an in-out
      field.  Options for the receive may also be passed into the value
      (e.g., MSG_PEEK).  On return from the call, the msg_flags value
      will be different than what was sent in to the call.  If
      implemented via a recvmsg() call, the msg_flags parameter should
      only contain the value of the flags from the recvmsg() call.

   The call returns the number of bytes received, or -1 if an error
   occurred.  The variable errno is then set appropriately.

9.9.  sctp_connectx()

   An implementation may provide a library function (or possibly system
   call) to assist the user with associating to an endpoint that is
   multi-homed.  Much like sctp_bindx(), this call allows a caller to
   specify multiple addresses at which a peer can be reached.  The way
   the SCTP stack uses the list of addresses to set up the association
   is implementation dependent.  This function only specifies that the
   stack will try to make use of all of the addresses in the list when
   needed.

   Note that the list of addresses passed in is only used for setting up
   the association.  It does not necessarily equal the set of addresses
   the peer uses for the resulting association.  If the caller wants to
   find out the set of peer addresses, it must use sctp_getpaddrs() to
   retrieve them after the association has been set up.

   The function prototype is

   int sctp_connectx(int sd,
                     struct sockaddr *addrs,
                     int addrcnt,
                     sctp_assoc_t *id);

   and the arguments are

   sd:  The socket descriptor.

   addrs:  An array of addresses.

Top      Up      ToC       Page 96 
   addrcnt:  The number of addresses in the array.

   id:  An output parameter that, if passed in as non-NULL, will return
      the association identifier for the newly created association (if
      successful).

   The call returns 0 on success or -1 if an error occurred.  The
   variable errno is then set appropriately.

9.10.  sctp_send() - DEPRECATED

   This function is deprecated; sctp_sendv() should be used instead.

   An implementation may provide another alternative function or system
   call to assist an application with the sending of data without the
   use of the cmsghdr structures.

   The function prototype is

   ssize_t sctp_send(int sd,
                     const void *msg,
                     size_t len,
                     const struct sctp_sndrcvinfo *sinfo,
                     int flags);

   and the arguments are

   sd:  The socket descriptor.

   msg:  The message to be sent.

   len:  The length of the message.

   sinfo:  A pointer to an sctp_sndrcvinfo structure used as described
      in Section 5.3.2 for a sendmsg() call.

   flags:  The same flags as used by the sendmsg() call flags (e.g.,
      MSG_DONTROUTE).

   The call returns the number of bytes sent, or -1 if an error
   occurred.  The variable errno is then set appropriately.

   This function call may also be used to terminate an association using
   an association identifier by setting the sinfo.sinfo_flags to
   SCTP_EOF and the sinfo.sinfo_assoc_id to the association that needs
   to be terminated.  In such a case, len can be zero.

Top      Up      ToC       Page 97 
   Using sctp_send() on a non-connected one-to-one style socket for
   implicit connection setup may or may not work, depending on the SCTP
   implementation.

   Sending a message using sctp_send() is atomic unless explicit EOR
   marking is enabled on the socket specified by sd.

9.11.  sctp_sendx() - DEPRECATED

   This function is deprecated; sctp_sendv() should be used instead.

   An implementation may provide another alternative function or system
   call to assist an application with the sending of data without the
   use of the cmsghdr structure, and to provide a list of addresses.
   The list of addresses is provided for implicit association setup.  In
   such a case, the list of addresses serves the same purpose as the
   addresses given in sctp_connectx() (see Section 9.9).

   The function prototype is

   ssize_t sctp_sendx(int sd,
                      const void *msg,
                      size_t len,
                      struct sockaddr *addrs,
                      int addrcnt,
                      struct sctp_sndrcvinfo *sinfo,
                      int flags);

   and the arguments are

   sd:  The socket descriptor.

   msg:  The message to be sent.

   len:  The length of the message.

   addrs:  An array of addresses.

   addrcnt:  The number of addresses in the array.

   sinfo:  A pointer to an sctp_sndrcvinfo structure used as described
      in Section 5.3.2 for a sendmsg() call.

   flags:  The same flags as used by the sendmsg() call flags (e.g.,
      MSG_DONTROUTE).

   The call returns the number of bytes sent, or -1 if an error
   occurred.  The variable errno is then set appropriately.

Top      Up      ToC       Page 98 
   Note that in the case of implicit connection setup, on return from
   this call, the sinfo_assoc_id field of the sinfo structure will
   contain the new association identifier.

   This function call may also be used to terminate an association using
   an association identifier by setting the sinfo.sinfo_flags to
   SCTP_EOF and the sinfo.sinfo_assoc_id to the association that needs
   to be terminated.  In such a case, len would be zero.

   Sending a message using sctp_sendx() is atomic unless explicit EOR
   marking is enabled on the socket specified by sd.

   Using sctp_sendx() on a non-connected one-to-one style socket for
   implicit connection setup may or may not work, depending on the SCTP
   implementation.

9.12.  sctp_sendv()

   The function prototype is

   ssize_t sctp_sendv(int sd,
                      const struct iovec *iov,
                      int iovcnt,
                      struct sockaddr *addrs,
                      int addrcnt,
                      void *info,
                      socklen_t infolen,
                      unsigned int infotype,
                      int flags);

   The function sctp_sendv() provides an extensible way for an
   application to communicate different send attributes to the SCTP
   stack when sending a message.  An implementation may provide
   sctp_sendv() as a library function or a system call.

   This document defines three types of attributes that can be used to
   describe a message to be sent.  They are struct sctp_sndinfo
   (Section 5.3.4), struct sctp_prinfo (Section 5.3.7), and struct
   sctp_authinfo (Section 5.3.8).  The following structure,
   sctp_sendv_spa, is defined to be used when more than one of the above
   attributes are needed to describe a message to be sent.

   struct sctp_sendv_spa {
     uint32_t sendv_flags;
     struct sctp_sndinfo sendv_sndinfo;
     struct sctp_prinfo sendv_prinfo;
     struct sctp_authinfo sendv_authinfo;
   };

Top      Up      ToC       Page 99 
   The sendv_flags field holds a bitwise OR of SCTP_SEND_SNDINFO_VALID,
   SCTP_SEND_PRINFO_VALID, and SCTP_SEND_AUTHINFO_VALID indicating if
   the sendv_sndinfo/sendv_prinfo/sendv_authinfo fields contain valid
   information.

   In future, when new send attributes are needed, new structures can be
   defined.  But those new structures do not need to be based on any of
   the above defined structures.

   The function takes the following arguments:

   sd:  The socket descriptor.

   iov:  The gather buffer.  The data in the buffer is treated as a
      single user message.

   iovcnt:  The number of elements in iov.

   addrs:  An array of addresses to be used to set up an association or
      a single address to be used to send the message.  NULL is passed
      in if the caller neither wants to set up an association nor wants
      to send the message to a specific address.

   addrcnt:  The number of addresses in the addrs array.

   info:  A pointer to the buffer containing the attribute associated
      with the message to be sent.  The type is indicated by the
      info_type parameter.

   infolen:  The length of info, in bytes.

   infotype:  Identifies the type of the information provided in info.
      The current defined values are as follows:

      SCTP_SENDV_NOINFO:  No information is provided.  The parameter
         info is a NULL pointer, and infolen is 0.

      SCTP_SENDV_SNDINFO:  The parameter info is pointing to a struct
         sctp_sndinfo.

      SCTP_SENDV_PRINFO:  The parameter info is pointing to a struct
         sctp_prinfo.

      SCTP_SENDV_AUTHINFO:  The parameter info is pointing to a struct
         sctp_authinfo.

      SCTP_SENDV_SPA:  The parameter info is pointing to a struct
         sctp_sendv_spa.

Top      Up      ToC       Page 100 
   flags:  The same flags as used by the sendmsg() call flags (e.g.,
      MSG_DONTROUTE).

   The call returns the number of bytes sent, or -1 if an error
   occurred.  The variable errno is then set appropriately.

   A note on the one-to-many style socket: The struct sctp_sndinfo
   attribute must always be used in order to specify the association on
   which the message is to be sent.  The only case where it is not
   needed is when this call is used to set up a new association.

   The caller provides a list of addresses in the addrs parameter to set
   up an association.  This function will behave like calling
   sctp_connectx() (see Section 9.9), first using the list of addresses
   and then calling sendmsg() with the given message and attributes.
   For a one-to-many style socket, if the struct sctp_sndinfo attribute
   is provided, the snd_assoc_id field must be 0.  When this function
   returns, the snd_assoc_id field will contain the association
   identifier of the newly established association.  Note that the
   struct sctp_sndinfo attribute is not required to set up an
   association for a one-to-many style socket.  If this attribute is not
   provided, the caller can enable the SCTP_ASSOC_CHANGE notification
   and use the SCTP_COMM_UP message to find out the association
   identifier.

   If the caller wants to send the message to a specific peer address
   (hence overriding the primary address), it can provide the specific
   address in the addrs parameter and provide a struct sctp_sndinfo
   attribute with the field snd_flags set to SCTP_ADDR_OVER.

   This function call may also be used to terminate an association.  The
   caller provides an sctp_sndinfo attribute with the snd_flags set to
   SCTP_EOF.  In this case, len would be zero.

   Sending a message using sctp_sendv() is atomic unless explicit EOR
   marking is enabled on the socket specified by sd.

Top      Up      ToC       Page 101 
9.13.  sctp_recvv()

   The function prototype is

   ssize_t sctp_recvv(int sd,
                      const struct iovec *iov,
                      int iovlen,
                      struct sockaddr *from,
                      socklen_t *fromlen,
                      void *info,
                      socklen_t *infolen,
                      unsigned int *infotype,
                      int *flags);

   The function sctp_recvv() provides an extensible way for the SCTP
   stack to pass up different SCTP attributes associated with a received
   message to an application.  An implementation may provide
   sctp_recvv() as a library function or as a system call.

   This document defines two types of attributes that can be returned by
   this call: the attribute of the received message and the attribute of
   the next message in the receive buffer.  The caller enables the
   SCTP_RECVRCVINFO and SCTP_RECVNXTINFO socket options, respectively,
   to receive these attributes.  Attributes of the received message are
   returned in struct sctp_rcvinfo (Section 5.3.5), and attributes of
   the next message are returned in struct sctp_nxtinfo (Section 5.3.6).
   If both options are enabled, both attributes are returned using the
   following structure.

   struct sctp_recvv_rn {
     struct sctp_rcvinfo recvv_rcvinfo;
     struct sctp_nxtinfo recvv_nxtinfo;
   };

   In future, new structures can be defined to hold new types of
   attributes.  The new structures do not need to be based on struct
   sctp_recvv_rn or struct sctp_rcvinfo.

   This function takes the following arguments:

   sd:  The socket descriptor.

   iov:  The scatter buffer.  Only one user message is returned in this
      buffer.

   iovlen:  The number of elements in iov.

Top      Up      ToC       Page 102 
   from:  A pointer to an address to be filled with the sender of the
      received message's address.

   fromlen:  An in/out parameter describing the from length.

   info:  A pointer to the buffer to hold the attributes of the received
      message.  The structure type of info is determined by the
      info_type parameter.

   infolen:  An in/out parameter describing the size of the info buffer.

   infotype:  On return, *info_type is set to the type of the info
      buffer.  The current defined values are as follows:

      SCTP_RECVV_NOINFO:  If both SCTP_RECVRCVINFO and SCTP_RECVNXTINFO
         options are not enabled, no attribute will be returned.  If
         only the SCTP_RECVNXTINFO option is enabled but there is no
         next message in the buffer, no attribute will be returned.  In
         these cases, *info_type will be set to SCTP_RECVV_NOINFO.

      SCTP_RECVV_RCVINFO:  The type of info is struct sctp_rcvinfo, and
         the attribute relates to the received message.

      SCTP_RECVV_NXTINFO:  The type of info is struct sctp_nxtinfo, and
         the attribute relates to the next message in the receive
         buffer.  This is the case when only the SCTP_RECVNXTINFO option
         is enabled and there is a next message in the buffer.

      SCTP_RECVV_RN:  The type of info is struct sctp_recvv_rn.  The
         recvv_rcvinfo field is the attribute of the received message,
         and the recvv_nxtinfo field is the attribute of the next
         message in the buffer.  This is the case when both
         SCTP_RECVRCVINFO and SCTP_RECVNXTINFO options are enabled and
         there is a next message in the receive buffer.

   flags:  A pointer to an integer to be filled with any message flags
      (e.g., MSG_NOTIFICATION).  Note that this field is an in/out
      parameter.  Options for the receive may also be passed into the
      value (e.g., MSG_PEEK).  On return from the call, the flags value
      will be different than what was sent in to the call.  If
      implemented via a recvmsg() call, the flags should only contain
      the value of the flags from the recvmsg() call when calling
      sctp_recvv(), and on return it has the value from msg_flags.

   The call returns the number of bytes received, or -1 if an error
   occurred.  The variable errno is then set appropriately.

Top      Up      ToC       Page 103 
10.  Security Considerations

   Many TCP and UDP implementations reserve port numbers below 1024 for
   privileged users.  If the target platform supports privileged users,
   the SCTP implementation should restrict the ability to call bind() or
   sctp_bindx() on these port numbers to privileged users.

   Similarly, unprivileged users should not be able to set protocol
   parameters that could result in the congestion control algorithm
   being more aggressive than permitted on the public Internet.  These
   parameters are as follows:

   o  struct sctp_rtoinfo

   If an unprivileged user inherits a one-to-many style socket with open
   associations on a privileged port, accepting new associations might
   be permitted, but opening new associations should not be permitted.
   This could be relevant for the r* family (rsh, rlogin, rwho, ...) of
   protocols.

   Applications using the one-to-many style sockets and using the
   interleave level (if 0) are subject to denial-of-service attacks, as
   described in Section 8.1.20.

   Applications needing transport layer security can use Datagram
   Transport Layer Security/SCTP (DTLS/SCTP) as specified in [RFC6083].
   This can be implemented using the sockets API described in this
   document.

11.  Acknowledgments

   Special acknowledgment is given to Ken Fujita, Jonathan Woods,
   Qiaobing Xie, and La Monte Yarroll, who helped extensively in the
   early formation of this document.

   The authors also wish to thank Kavitha Baratakke, Mike Bartlett,
   Martin Becke, Jon Berger, Mark Butler, Thomas Dreibholz, Andreas
   Fink, Scott Kimble, Jonathan Leighton, Renee Revis, Irene Ruengeler,
   Dan Wing, and many others on the TSVWG mailing list for contributing
   valuable comments.

   A special thanks to Phillip Conrad, for his suggested text, quick and
   constructive insights, and most of all his persistent fighting to
   keep the interface to SCTP usable for the application programmer.

Top      Up      ToC       Page 104 
12.  References

12.1.  Normative References

   [IEEE-1003.1-2008]
              Institute of Electrical and Electronics Engineers,
              "Information Technology - Portable Operating System
              Interface (POSIX)", IEEE Standard 1003.1, 2008.

   [RFC3493]  Gilligan, R., Thomson, S., Bound, J., McCann, J., and W.
              Stevens, "Basic Socket Interface Extensions for IPv6",
              RFC 3493, February 2003.

   [RFC3542]  Stevens, W., Thomas, M., Nordmark, E., and T. Jinmei,
              "Advanced Sockets Application Program Interface (API) for
              IPv6", RFC 3542, May 2003.

   [RFC3758]  Stewart, R., Ramalho, M., Xie, Q., Tuexen, M., and P.
              Conrad, "Stream Control Transmission Protocol (SCTP)
              Partial Reliability Extension", RFC 3758, May 2004.

   [RFC4895]  Tuexen, M., Stewart, R., Lei, P., and E. Rescorla,
              "Authenticated Chunks for the Stream Control Transmission
              Protocol (SCTP)", RFC 4895, August 2007.

   [RFC4960]  Stewart, R., Ed., "Stream Control Transmission Protocol",
              RFC 4960, September 2007.

   [RFC5061]  Stewart, R., Xie, Q., Tuexen, M., Maruyama, S., and M.
              Kozuka, "Stream Control Transmission Protocol (SCTP)
              Dynamic Address Reconfiguration", RFC 5061,
              September 2007.

12.2.  Informative References

   [RFC0768]  Postel, J., "User Datagram Protocol", STD 6, RFC 768,
              August 1980.

   [RFC0793]  Postel, J., "Transmission Control Protocol", STD 7,
              RFC 793, September 1981.

   [RFC1644]  Braden, R., "T/TCP -- TCP Extensions for Transactions
              Functional Specification", RFC 1644, July 1994.

Top      Up      ToC       Page 105 
   [RFC6083]  Tuexen, M., Seggelmann, R., and E. Rescorla, "Datagram
              Transport Layer Security (DTLS) for Stream Control
              Transmission Protocol (SCTP)", RFC 6083, January 2011.

   [RFC6247]  Eggert, L., "Moving the Undeployed TCP Extensions RFC
              1072, RFC 1106, RFC 1110, RFC 1145, RFC 1146, RFC 1379,
              RFC 1644, and RFC 1693 to Historic Status", RFC 6247,
              May 2011.

Top      Up      ToC       Page 106 
Appendix A.  Example Using One-to-One Style Sockets

   The following code is an implementation of a simple client that sends
   a number of messages marked for unordered delivery to an echo server
   making use of all outgoing streams.  The example shows how to use
   some features of one-to-one style IPv4 SCTP sockets, including

   o  Creating and connecting an SCTP socket.

   o  Making a request to negotiate a number of outgoing streams.

   o  Determining the negotiated number of outgoing streams.

   o  Setting an adaptation layer indication.

   o  Sending messages with a given payload protocol identifier on a
      particular stream using sctp_sendv().

   <CODE BEGINS>
   /*

      Copyright (c) 2011 IETF Trust and the persons identified
      as authors of the code.  All rights reserved.

      Redistribution and use in source and binary forms, with
      or without modification, is permitted pursuant to, and subject
      to the license terms contained in, the Simplified BSD License
      set forth in Section 4.c of the IETF Trust's Legal Provisions
      Relating to IETF Documents (http://trustee.ietf.org/license-info).

   */

   #include <sys/types.h>
   #include <sys/socket.h>
   #include <netinet/in.h>
   #include <netinet/sctp.h>
   #include <arpa/inet.h>
   #include <string.h>
   #include <stdio.h>
   #include <unistd.h>
   #include <stdlib.h>

   #define PORT 9
   #define ADDR "127.0.0.1"
   #define SIZE_OF_MESSAGE 1000
   #define NUMBER_OF_MESSAGES 10
   #define PPID 1234

Top      Up      ToC       Page 107 
   int
   main(void) {
     unsigned int i;
     int sd;
     struct sockaddr_in addr;
     char buffer[SIZE_OF_MESSAGE];
     struct iovec iov;
     struct sctp_status status;
     struct sctp_initmsg init;
     struct sctp_sndinfo info;
     struct sctp_setadaptation ind;
     socklen_t opt_len;

     /* Create a one-to-one style SCTP socket. */
     if ((sd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) < 0) {
       perror("socket");
       exit(1);
     }

     /* Prepare for requesting 2048 outgoing streams. */
     memset(&init, 0, sizeof(init));
     init.sinit_num_ostreams = 2048;
     if (setsockopt(sd, IPPROTO_SCTP, SCTP_INITMSG,
                    &init, (socklen_t)sizeof(init)) < 0) {
       perror("setsockopt");
       exit(1);
     }

     ind.ssb_adaptation_ind  = 0x01020304;
     if (setsockopt(sd, IPPROTO_SCTP, SCTP_ADAPTATION_LAYER,
                    &ind, (socklen_t)sizeof(ind)) < 0) {
       perror("setsockopt");
       exit(1);
     }

     /* Connect to the discard server. */
     memset(&addr, 0, sizeof(addr));
   #ifdef HAVE_SIN_LEN
     addr.sin_len         = sizeof(struct sockaddr_in);
   #endif
     addr.sin_family      = AF_INET;
     addr.sin_port        = htons(PORT);
     addr.sin_addr.s_addr = inet_addr(ADDR);

Top      Up      ToC       Page 108 
     if (connect(sd,
                 (const struct sockaddr *)&addr,
                 sizeof(struct sockaddr_in)) < 0) {
       perror("connect");
       exit(1);
     }

     /* Get the actual number of outgoing streams. */
     memset(&status, 0, sizeof(status));
     opt_len = (socklen_t)sizeof(status);
     if (getsockopt(sd, IPPROTO_SCTP, SCTP_STATUS,
                    &status, &opt_len) < 0) {
       perror("getsockopt");
       exit(1);
     }

     memset(&info, 0, sizeof(info));
     info.snd_ppid = htonl(PPID);
     info.snd_flags = SCTP_UNORDERED;
     memset(buffer, 'A', SIZE_OF_MESSAGE);
     iov.iov_base = buffer;
     iov.iov_len = SIZE_OF_MESSAGE;
     for (i = 0; i <  NUMBER_OF_MESSAGES; i++) {
       info.snd_sid = i % status.sstat_outstrms;
       if (sctp_sendv(sd,
                      (const struct iovec *)&iov, 1,
                      NULL, 0,
                      &info, sizeof(info), SCTP_SENDV_SNDINFO,
                      0) < 0) {
         perror("sctp_sendv");
         exit(1);
       }
     }

     if (close(sd) < 0) {
       perror("close");
       exit(1);
     }
     return(0);
   }
   <CODE ENDS>

Top      Up      ToC       Page 109 
Appendix B.  Example Using One-to-Many Style Sockets

   The following code is a simple implementation of a discard server
   over SCTP.  The example shows how to use some features of one-to-many
   style IPv6 SCTP sockets, including

   o  Opening and binding of a socket.

   o  Enabling notifications.

   o  Handling notifications.

   o  Configuring the auto-close timer.

   o  Using sctp_recvv() to receive messages.

   Please note that this server can be used in combination with the
   client described in Appendix A.

   <CODE BEGINS>
   /*

      Copyright (c) 2011 IETF Trust and the persons identified
      as authors of the code.  All rights reserved.

      Redistribution and use in source and binary forms, with
      or without modification, is permitted pursuant to, and subject
      to the license terms contained in, the Simplified BSD License
      set forth in Section 4.c of the IETF Trust's Legal Provisions
      Relating to IETF Documents (http://trustee.ietf.org/license-info).

   */

   #include <sys/types.h>
   #include <sys/socket.h>
   #include <netinet/in.h>
   #include <netinet/sctp.h>
   #include <arpa/inet.h>
   #include <string.h>
   #include <stdio.h>
   #include <stdlib.h>
   #include <unistd.h>

   #define BUFFER_SIZE (1<<16)
   #define PORT 9
   #define ADDR "0.0.0.0"
   #define TIMEOUT 5

Top      Up      ToC       Page 110 
   static void
   print_notification(void *buf)
   {
     struct sctp_assoc_change *sac;
     struct sctp_paddr_change *spc;
     struct sctp_adaptation_event *sad;
     union sctp_notification *snp;
     char addrbuf[INET6_ADDRSTRLEN];
     const char *ap;
     struct sockaddr_in *sin;
     struct sockaddr_in6 *sin6;

     snp = buf;

     switch (snp->sn_header.sn_type) {
     case SCTP_ASSOC_CHANGE:
       sac = &snp->sn_assoc_change;
       printf("^^^ Association change: ");
       switch (sac->sac_state) {
       case SCTP_COMM_UP:
         printf("Communication up (streams (in/out)=(%u/%u)).\n",
                sac->sac_inbound_streams, sac->sac_outbound_streams);
         break;
       case SCTP_COMM_LOST:
         printf("Communication lost (error=%d).\n", sac->sac_error);
         break;
       case SCTP_RESTART:
         printf("Communication restarted (streams (in/out)=(%u/%u).\n",
                sac->sac_inbound_streams, sac->sac_outbound_streams);
         break;
       case SCTP_SHUTDOWN_COMP:
         printf("Communication completed.\n");
         break;
       case SCTP_CANT_STR_ASSOC:
         printf("Communication couldn't be started.\n");
         break;
       default:
         printf("Unknown state: %d.\n", sac->sac_state);
         break;
       }
       break;
     case SCTP_PEER_ADDR_CHANGE:
       spc = &snp->sn_paddr_change;
       if (spc->spc_aaddr.ss_family == AF_INET) {
         sin = (struct sockaddr_in *)&spc->spc_aaddr;
         ap = inet_ntop(AF_INET, &sin->sin_addr,
                        addrbuf, INET6_ADDRSTRLEN);
       } else {

Top      Up      ToC       Page 111 
         sin6 = (struct sockaddr_in6 *)&spc->spc_aaddr;
         ap = inet_ntop(AF_INET6, &sin6->sin6_addr,
                        addrbuf, INET6_ADDRSTRLEN);
       }
       printf("^^^ Peer Address change: %s ", ap);
       switch (spc->spc_state) {
       case SCTP_ADDR_AVAILABLE:
         printf("is available.\n");
         break;
       case SCTP_ADDR_UNREACHABLE:
         printf("is not available (error=%d).\n", spc->spc_error);
         break;
       case SCTP_ADDR_REMOVED:
         printf("was removed.\n");
         break;
       case SCTP_ADDR_ADDED:
         printf("was added.\n");
         break;
       case SCTP_ADDR_MADE_PRIM:
         printf("is primary.\n");
         break;
       default:
         printf("unknown state (%d).\n", spc->spc_state);
         break;
       }
       break;
     case SCTP_SHUTDOWN_EVENT:
       printf("^^^ Shutdown received.\n");
       break;
     case SCTP_ADAPTATION_INDICATION:
       sad = &snp->sn_adaptation_event;
       printf("^^^ Adaptation indication 0x%08x received.\n",
              sad->sai_adaptation_ind);
       break;
     default:
       printf("^^^ Unknown event of type: %u.\n",
              snp->sn_header.sn_type);
       break;
     };
   }

Top      Up      ToC       Page 112 
   int
   main(void) {
     int sd, flags, timeout, on;
     ssize_t n;
     unsigned int i;
     union {
       struct sockaddr sa;
       struct sockaddr_in sin;
       struct sockaddr_in6 sin6;
     } addr;
     socklen_t fromlen, infolen;
     struct sctp_rcvinfo info;
     unsigned int infotype;
     struct iovec iov;
     char buffer[BUFFER_SIZE];
     struct sctp_event event;
     uint16_t event_types[] = {SCTP_ASSOC_CHANGE,
                               SCTP_PEER_ADDR_CHANGE,
                               SCTP_SHUTDOWN_EVENT,
                               SCTP_ADAPTATION_INDICATION};

     /* Create a one-to-many style SCTP socket. */
     if ((sd = socket(AF_INET6, SOCK_SEQPACKET, IPPROTO_SCTP)) < 0) {
       perror("socket");
       exit(1);
     }

     /* Enable the events of interest. */
     memset(&event, 0, sizeof(event));
     event.se_assoc_id = SCTP_FUTURE_ASSOC;
     event.se_on = 1;
     for (i = 0; i < sizeof(event_types)/sizeof(uint16_t); i++) {
       event.se_type = event_types[i];
       if (setsockopt(sd, IPPROTO_SCTP, SCTP_EVENT,
                      &event, sizeof(event)) < 0) {
         perror("setsockopt");
         exit(1);
       }
     }

     /* Configure auto-close timer. */
     timeout = TIMEOUT;
     if (setsockopt(sd, IPPROTO_SCTP, SCTP_AUTOCLOSE,
                    &timeout, sizeof(timeout)) < 0) {
       perror("setsockopt SCTP_AUTOCLOSE");
       exit(1);
     }

Top      Up      ToC       Page 113 
     /* Enable delivery of SCTP_RCVINFO. */
     on = 1;
     if (setsockopt(sd, IPPROTO_SCTP, SCTP_RECVRCVINFO,
                    &on, sizeof(on)) < 0) {
       perror("setsockopt SCTP_RECVRCVINFO");
       exit(1);
     }

     /* Bind the socket to all local addresses. */
     memset(&addr, 0, sizeof(addr));
   #ifdef HAVE_SIN6_LEN
     addr.sin6.sin6_len         = sizeof(addr.sin6);
   #endif
     addr.sin6.sin6_family      = AF_INET6;
     addr.sin6.sin6_port        = htons(PORT);
     addr.sin6.sin6_addr        = in6addr_any;
     if (bind(sd, &addr.sa, sizeof(addr.sin6)) < 0) {
       perror("bind");
       exit(1);
     }
     /* Enable accepting associations. */
     if (listen(sd, 1) < 0) {
       perror("listen");
       exit(1);
     }

     for (;;) {
       flags = 0;
       memset(&addr, 0, sizeof(addr));
       fromlen = (socklen_t)sizeof(addr);
       memset(&info, 0, sizeof(info));
       infolen = (socklen_t)sizeof(info);
       infotype = 0;
       iov.iov_base = buffer;
       iov.iov_len = BUFFER_SIZE;

       n = sctp_recvv(sd, &iov, 1,
                      &addr.sa, &fromlen,
                      &info, &infolen, &infotype,
                      &flags);

       if (flags & MSG_NOTIFICATION) {
         print_notification(iov.iov_base);
       } else {
         char addrbuf[INET6_ADDRSTRLEN];
         const char *ap;
         in_port_t port;

Top      Up      ToC       Page 114 
         if (addr.sa.sa_family == AF_INET) {
                ap = inet_ntop(AF_INET, &addr.sin.sin_addr,
                               addrbuf, INET6_ADDRSTRLEN);
                port = ntohs(addr.sin.sin_port);
         } else {
                ap = inet_ntop(AF_INET6, &addr.sin6.sin6_addr,
                               addrbuf, INET6_ADDRSTRLEN);
                port = ntohs(addr.sin6.sin6_port);
         }
         printf("Message received from %s:%u: len=%d",
                ap, port, (int)n);
         switch (infotype) {
         case SCTP_RECVV_RCVINFO:
           printf(", sid=%u", info.rcv_sid);
           if (info.rcv_flags & SCTP_UNORDERED) {
             printf(", unordered");
           } else {
             printf(", ssn=%u", info.rcv_ssn);
           }
           printf(", tsn=%u", info.rcv_tsn);
           printf(", ppid=%u.\n", ntohl(info.rcv_ppid));
           break;
         case SCTP_RECVV_NOINFO:
         case SCTP_RECVV_NXTINFO:
         case SCTP_RECVV_RN:
           printf(".\n");
           break;
         default:
           printf(" unknown infotype.\n");
         }
       }
     }

     if (close(sd) < 0) {
       perror("close");
       exit(1);
     }

     return (0);
   }
   <CODE ENDS>

Top      Up      ToC       Page 115 
Authors' Addresses

   Randall R. Stewart
   Adara Networks
   Chapin, SC  29036
   USA

   EMail: randall@lakerest.net


   Michael Tuexen
   Muenster University of Applied Sciences
   Stegerwaldstr. 39
   48565 Steinfurt
   Germany

   EMail: tuexen@fh-muenster.de


   Kacheong Poon
   Oracle Corporation

   EMail: ka-cheong.poon@oracle.com


   Peter Lei
   Cisco Systems, Inc.
   9501 Technology Blvd.
   West Office Center
   Rosemont, IL  60018
   USA

   EMail: peterlei@cisco.com


   Vladislav Yasevich
   HP
   110 Spitrook Rd.
   Nashua, NH  03062
   USA

   EMail: vladislav.yasevich@hp.com