Tech-invite3GPPspaceIETFspace
959493929190898887868584838281807978777675747372717069686766656463626160595857565554535251504948474645444342414039383736353433323130292827262524232221201918171615141312111009080706050403020100
in Index   Prev   Next

RFC 6458

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

Pages: 115
Informational
Errata
Part 4 of 4 – Pages 88 to 115
First   Prev   None

Top   ToC   RFC6458 - Page 88   prevText

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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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   ToC   RFC6458 - 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