Stream Control Transmission Protocol (SCTP) Associations

This second in a series of articles on the SCTP network protocol examines associations and connections.

In TCP, a stream is just a sequence of bytes. In SCTP, it has a different meaning; a stream is a logical channel along which messages are sent, and a single association can have many streams. The original motivation for streams came from the telephony domain, where multiple reliable channels were needed, but the messages on each channel were independent of those on other channels. In last month's article, we pointed out some TCP applications that could benefit from streams, such as FTP, which uses two sockets for data and control messages. In addition, an increasing number of applications are multithreaded, and streams open up the possibility of a thread in one peer being able to communicate with a thread in another peer without worrying about being blocked by messages sent by other threads.

The socket I/O calls read/write/send/recv do not know about SCTP streams. By default, the write calls all use stream number zero (this can be changed by a socket option), but the read calls will read messages on all streams, and there is no indication as to which stream is used. So, to use streams effectively, you need to use some of the I/O calls that are designed specifically for SCTP.

Negotiating the Number of Streams

Each endpoint of an association will support a certain number of streams. A Linux endpoint, by default, will expect to be able to send to ten streams, while it can receive on 65,535 streams. Other SCTP stacks may have different default values. These values can be changed by setting the socket option SCTP_INITMSG, which takes a structure sctp_initmsg:

struct sctp_initmsg { 
    uint16_t sinit_num_ostreams; 
    uint16_t sinit_max_ostreams; 
    uint16_t sinit_max_attempts; 
    uint16_t sinit_max_init_timeo; 

If this socket option is used to set values, it must be done before an association is made. The parameters will be sent to the peer endpoint during association initialisation.

Each endpoint in an association will have an idea of how many input and output streams it will allow on an association, as discussed in the previous paragraph. During the establishment of the association, the endpoints exchange these values. Negotiation of final values is just a matter of taking the minimum values. If one end wants 20 output streams, and the other wants only 10 input streams, the result is the smaller, 10, and similarly for the number of streams in the opposite direction.

An endpoint will need to know how many output streams are available for writing in order not to exceed the limits. This value is determined during association setup. After setup, the endpoint can find this by making a query using getsockopt(). However, there is a little wrinkle here: a socket may have many associations (to different endpoints), and each association may have set different values. So, we have to make a query that asks for the parameters for a particular association, not just for the socket. The parameter to ask for is SCTP_STATUS, which takes a structure of type sctp_status:

struct sctp_status { 
       sctp_assoc_t    sstat_assoc_id; 
       int32_t         sstat_state; 
       uint32_t        sstat_rwnd; 
       uint16_t        sstat_unackdata; 
       uint16_t        sstat_penddata; 
       uint16_t        sstat_instrms; 
       uint16_t        sstat_outstrms; 
       uint32_t        sstat_fragmentation_point; 
       struct sctp_paddrinfo sstat_primary; 

This has fields sstat_instrms and sstat_outstrms, which contain the required information. See Listings 2 and 3 for a client and server negotiating the number of streams in each direction.


Jan Newmarch has written many books and papers about software engineering, network programming, user interfaces and artificial intelligence, and he is currently digging into the IoT.