Go to main content

Oracle® Solaris 11.4 Programming Interfaces Guide

Exit Print View

Updated: November 2020
 
 

Stream Control Transmission Protocol

Stream Control Transmission Protocol (SCTP) is a reliable transport protocol that provides services similar to the services provided by TCP. In addition, SCTP provides network-level fault tolerance. SCTP supports multihoming at either end of an association. The SCTP socket API supports a one-to-one socket is modeled after TCP. The SCTP socket API also supports a one-to-many socket model designed for use with signaling. The one-to-many socket model reduces the number of file descriptors used in a process. You must link the libsctp library to use SCTP function calls.

An SCTP association is set up between two endpoints. The endpoints use a four-way handshake mechanism that uses a cookie to guard against some types of denial-of-service (DoS) attacks. The endpoints can be represented by multiple IP addresses.

SCTP Stack Implementation

This section lists the details of the Oracle Solaris implementation of the IETF standard for the Stream Control Transmission Protocol, RFC 4960. The table in this section lists the Oracle Solaris exceptions to RFC 4960. The SCTP protocol in the Oracle Solaris operating system implements any section of RFC 4960 that is not explicitly mentioned in the table.

Table 10  Oracle Solaris SCTP Implementation Exceptions from RFC 4960
RFC 4960 Section
Exceptions in the Oracle Solaris Implementation
3. SCTP Packet Format
3.2 Chunk Field Descriptions: Oracle Solaris SCTP does not implement the optional ECNE and CWR.
3.3.2: Oracle Solaris SCTP does not implement the Initiation (INIT) Optional ECN, Host Name Address, and Cookie Preserving parameters.
3.3.3: Oracle Solaris SCTP does not implement the Initiation Acknowledgement, Optional ECN, and Host Name Address parameters.
5. Association Initialization
5.1.2, Handle Address Parameters: Section (B), Optional Host Name parameter, is not implemented.
10. Interface with Upper Layer
Oracle Solaris SCTP implements the IETF TSVWG SCTP socket API draft.

Note - The Oracle Solaris 11 implementation of the TSVWG SCTP socket API is based on a version of the API draft that was published at the time when Oracle Solaris 11 was first shipped.

SCTP Socket Interfaces

When the socket() call creates a socket for IPPROTO_SCTP, it calls an SCTP-specific socket creation routine. Socket calls made on an SCTP socket call the appropriate SCTP socket routine automatically. In a one-to-one socket, each socket corresponds to one SCTP association. Create a one-to-one socket by calling this function:

socket()AF_INET[6], SOCK_STREAM, IPPROTO_STCP

In a one-to-many socket model, each socket handles multiple SCTP associations. Each association has an association identifier called sctp_assoc_t. Create a one-to-many socket by calling this function:

socket()AF_INET[6], SOCK_SEQPACKET, IPPROTO_STCP

sctp_bindx() Function

int sctp_bindx()int sock, void *addrs, int addrcnt, int flags

The sctp_bindx() function manages addresses on an SCTP socket. If the sock parameter is an IPv4 socket, the addresses passed to the sctp_bindx() function must be IPv4 addresses.

If the sock parameter is an IPv6 socket, the addresses passed to the sctp_bindx() function can be either IPv4 (in IPv4–mapped address format) or IPv6 addresses. When the address that is passed to the sctp_bindx() function is INADDR_ANY or IN6ADDR_ANY, the socket binds to all available addresses. Bind the SCTP endpoint with the bind.

If the sock parameter is an IPv4 socket, *addrs should be an array of sockaddr_in structures containing IPv4 addresses. If sock is an IPv6 socket, *addrs should be an array of sockaddr_in6 structures containing IPv6 or IPv4-mapped IPv6 addresses. The addrcnt is the number of array elements in addrs. The family of the address type is used with addrcnt to determine the size of the array.

If the addresses are IPv6 addresses, they are contained in sockaddr_in6 structures. The address type's family distinguishes the address length. The caller specifies the number of addresses in the array with the addrcnt parameter.

The sctp_bindx() function returns 0 on success. The sctp_bindx() function returns -1 on failure and sets the value of errno to the appropriate error code.

If the same port is not given for each socket address, the sctp_bindx() function fails and sets the value of errno to EINVAL.

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

  • SCTP_BINDX_ADD_ADDR

  • SCTP_BINDX_REM_ADDR

SCTP_BINDX_ADD_ADDR directs SCTP to add the given addresses to the association. SCTP_BINDX_REM_ADDR directs SCTP to remove the given addresses from the association. The two flags are mutually exclusive. If both are given, the sctp_bindx() fails and sets the value of errno to EINVAL.

The caller should add or remove addresses one at a time. If an error occurs, and a list of addresses has been used, it is not possible for the caller to find the address that caused the error. Adding or removing addresses one at a time helps the caller resolve this issue.

A caller may not remove all addresses from an association. The sctp_bindx() function rejects such an attempt by failing and setting the value of errno to EINVAL. An application can use sctp_bindx(SCTP_BINDX_ADD_ADDR) to associate additional addresses with an endpoint after calling the bind() function. An application can use sctp_bindx(SCTP_BINDX_REM_ADDR) to remove addresses associated with a listening socket. After using sctp_bindx(SCTP_BINDX_REM_ADDR) to remove addresses, accepting new associations will not reassociate the removed address. If the endpoint supports dynamic address, using SCTP_BINDX_REM_ADDR or SCTP_BINDX_ADD_ADDR sends a message to the peer to change the peer's address lists. Adding and removing addresses from a connected association is optional functionality. Implementations that do not support this functionality return EOPNOTSUPP.

If the address family is not AF_INET or AF_INET6, the sctp_bindx() function fails and returns EAFNOSUPPORT. If the file descriptor passed to the sctp_bindx() in the sock parameter is invalid, the sctp_bindx() function fails and returns EBADF.

sctp_opt_info() Function

int sctp_opt_info()int sock, sctp_assoc_id_t id, int opt, void *arg, socklen_t *len

The sctp_opt_info() function returns the SCTP level options that are associated with the socket described in the sock parameter. If the socket is a one-to-many SCTP socket model the value of the id parameter refers to a specific association. The id parameter is ignored for one-to-one SCTP sockets. The value of the opt parameter specifies the SCTP socket option to get. The value of the arg parameter is an option-specific structure buffer that is allocated by the calling program. The value of the *len parameter is the length of the option.

The opt parameter can have the following values:

  • SCTP_RTOINFO

  • SCTP_ASSOCINFO

  • SCTP_DEFAULT_SEND_PARAM

  • SCTP_PEER_ADDR_PARAMS

  • SCTP_STATUS

  • SCTP_INITMSG

  • SCTP_NODELAY

  • SCTP_AUTOCLOSE

  • SCTP_PRIMARY_ADDR

  • SCTP_GET_PEER_ADDR_INFO

  • SCTP_EVENT

  • SCTP_DELAYED_SACK

  • SCTP_PARTIAL_DELIVERY_POINT

  • SCTP_FRAGMENT_INTERLEAVE

  • SCTP_MAX_BURST

  • SCTP_CONTEXT

  • SCTP_EXPLICIT_EOR

  • SCTP_REUSE_PORT

  • SCTP_RECVRVCINFO

  • SCTP_RECVNXTINFO

  • SCTP_DEFAULT_SNDINFO

  • SCTP_GETASSOC_NUMBER

  • SCTP_GET_ASSOC_ID_LIST

A few of the opt parameters are described in detail here:

SCTP_RTOINFO

Returns the protocol parameters that are used to initialize and bind the retransmission timeout (RTO) tunable. The protocol parameters use the following structure:

struct sctp_rtoinfo {
    sctp_assoc_t    srto_assoc_id;
    uint32_t        srto_initial;
    uint32_t        srto_max; 
    uint32_t        srto_min;
};
srto_assoc_id

The calling program provides this value, which specifies the association of interest.

srto_initial

This value is the initial RTO value.

srto_max

This value is the maximum RTO value.

srto_min

This value is the minimum RTO value.

SCTP_ASSOCINFO

Returns the association-specific parameters. The parameters use the following structure:

struct sctp_assocparams {
    sctp_assoc_t    sasoc_assoc_id;
    uint16_t        sasoc_asocmaxrxt;
    uint16_t        sasoc_number_peer_destinations;
    uint32_t        sasoc_peer_rwnd;
    uint32_t        sasoc_local_rwnd;
    uint32_t        sasoc_cookie_life;
};
sasoc_assoc_id

The calling program provides this value, which specifies the association of interest.

sasoc_assocmaxrxt

This value specifies the maximum retransmission count for the association.

sasoc_number_peer_destinations

This value specifies the number of addresses that the peer has.

sasoc_peer_rwnd

This value specifies the current value of the peer's receive window.

sasoc_local_rwnd

This value specifies the last reported receive window that the peer transmitted to.

sasoc_cookie_life

The value specifies the lifetime of the association's cookie. The value is used when issuing cookies.

All parameters that use time values are measured in milliseconds.

SCTP_DEFAULT_SEND_PARAM

Returns the default set of parameters that a call to the sendto function uses on this association. For more information, see the sendto(3C) man page. The parameters use the following structure:

struct sctp_sndrcvinfo {
    uint16_t        sinfo_stream;
    uint16_t        sinfo_ssn;
    uint16_t        sinfo_flags;
    uint32_t        sinfo_ppid;
    uint32_t        sinfo_context;
    uint32_t        sinfo_timetolive;
    uint32_t        sinfo_tsn;
    uint32_t        sinfo_cumtsn;
    sctp_assoc_t    sinfo_assoc_id;
};
sinfo_stream

This value specifies the default stream for the sendmsg() call.

sinfo_ssn

This value is always zero.

sinfo_flags

This value contains the default flags for the sendmsg() call. This flag can take on the following values:

  • MSG_UNORDERED

  • MSG_ADDR_OVER

  • MSG_ABORT

  • MSG_EOF

  • MSG_PR_SCTP

sinfo_ppid

This value is the default payload protocol identifier for the sendmsg() call.

sinfo_context

This value is the default context for the sendmsg() call.

sinfo_timetolive

This value specifies a time period in milliseconds. After this time period has passed, the message expires if its transmission has not begun. A value of zero indicates that the message does not expire. If the MSG_PR_SCTP flag is set, the message expires when its transmission has not successfully completed within the time period specified in sinfo_timetolive.

sinfo_tsn

This value is always zero.

sinfo_cumtsn

This value is always zero.

sinfo_assoc_id

This value is filled in by the calling application. This value specifies the association of interest.

SCTP_PEER_ADDR_PARAMS

Returns the parameters for a specified peer address. The parameters use the following structure:

struct sctp_paddrparams {
    sctp_assoc_t               spp_assoc_id;
    struct sockaddr_storage    spp_address;
    uint32_t                   spp_hbinterval;
    uint16_t                   spp_pathmaxrxt;
		uint32_t			             spp_pathmtu;
    uint32_t      		          spp_flags;
    uint32_t         	       spp_ipv6_flowlabel;
    uint8_t             	    spp_ipv4_tos;
};
spp_assoc_id

The calling program provides this value, which specifies the association of interest.

spp_address

This value specifies the peer's address of interest.

spp_hbinterval

This value specifies the heartbeat interval in milliseconds.

spp_pathmaxrxt

This value specifies the maximum number of retransmissions to attempt on an address before considering the address unreachable.

spp_pathmtu

The current path MTU of the peer address. It is the number of bytes available in an SCTP packet for chunks. Providing a value of 0 does not change the current setting. If a positive value is provided and SPP_PMTUD_DISABLE is set in the spp_flags, the given value is used as the path MTU. If SPP_PMTUD_ENABLE is set in the spp_flags, then the spp_pathmtu field is ignored.

spp_ipv6_flowlabel

This field is used in conjunction with the SPP_IPV6_FLOWLABEL flag. This setting has precedence over any other IPv6 layer setting.

spp_flags

The spp_flags flags are used to control various features on an association. The flag field is a bit mask which may contain one of the following options:

  • SPP_HB_ENABLE – Enable heartbeats on the specified address.

  • SPP_HB_DISABLE – Disable heartbeats on the specified address. SPP_HB_ENABLE and SPP_HB_DISABLE are mutually exclusive, only one of the two should be specified. Enabling both fields will result in undetermined results.

  • SPP_HB_DEMAND – Request a user initiated heartbeat to be made immediately. This option should not be used in conjunction with a wildcard address.

  • SPP_HB_TIME_IS_ZERO – Specifies that the time for heartbeat delay is to be set to the value of 0 milliseconds.

  • SPP_PMTUD_ENABLE – Enable PMTU discovery on the specified address.

  • SPP_PMTUD_DISABLE – Disable PMTU discovery on the specified address. If the address field is empty then all addresses on the association are affected. SPP_PMTUD_ENABLE and SPP_PMTUD_DISABLE options are mutually exclusive. Enabling both options will result in undetermined results.

  • SPP_IPV6_FLOWLABEL – Enables the setting of the IPV6 flowlabel value. The value is obtained from the spp_ipv6_flowlabel field. Upon retrieval, this flag will be set to indicate that the ipv6_flowlabel field has a valid value returned. If a specific destination address is set in the spp_address field, then the value of the address is returned. If only an association is specified and no address is specified, then the association's default flowlabel is returned. If neither an association nor a destination is specified, then the socket's default flowlabel is returned. For non– IPv6 sockets, this flag is left empty.

  • SPP_IPV4_TOS – Setting this flag enables the setting of the IPV4 TOS value associated with either the association or a specific address. The value is obtained from the spp_ipv4_tos field. Upon retrieval, this flag will be set to indicate that the spp_ipv4_tos field has a valid value returned. If a specific destination address in the spp_address field is set when called, then the TOS value of the specific destination address returned. If only an association is specified then the default TOS of the association is returned. If neither an association nor a destination is specified, then the default TOS value of the socket is returned.

SCTP_STATUS

Returns the current status information about the association. The parameters use the following structure:

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;
};
sstat_assoc_id

The calling program provides this value, which specifies the association of interest.

sstat_state

This value is the association's current state. The association can take on the following states:

SCTP_IDLE

The SCTP endpoint does not have any association associated with it. Immediately after the call to the socket() function opens an endpoint, or after the endpoint closes, the endpoint is in this state.

SCTP_BOUND

An SCTP endpoint is bound to one or more local addresses after calling the bind().

SCTP_LISTEN

This endpoint is waiting for an association request from any remote SCTP endpoint.

SCTP_COOKIE_WAIT

This SCTP endpoint has sent an INIT chunk and is waiting for an INIT-ACK chunk.

SCTP_COOKIE_ECHOED

This SCTP endpoint has echoed the cookie that it received from its peer's INIT-ACK chunk back to the peer.

SCTP_ESTABLISHED

This SCTP endpoint can exchange data with its peer.

SCTP_SHUTDOWN_PENDING

This SCTP endpoint has received a SHUTDOWN primitive from its upper layer. This endpoint no longer accepts data from its upper layer.

SCTP_SHUTDOWN_SEND

An SCTP endpoint that was in the SCTP_SHUTDOWN_PENDING state has sent a SHUTDOWN chunk to its peer. The SHUTDOWN chunk is sent only after all outstanding data from this endpoint to its peer is acknowledged. When this endpoint's peer sends a SHUTDOWN ACK chunk, this endpoint sends a SHUTDOWN COMPLETE chunk and the association is considered closed.

SCTP_SHUTDOWN_RECEIVED

An SCTP endpoint has received a SHUTDOWN chunk from its peer. This endpoint no longer accepts new data from its user.

SCTP_SHUTDOWN_ACK_SEND

An SCTP endpoint in the SCTP_SHUTDOWN_RECEIVED state has sent the SHUTDOWN ACK chunk to its peer. The endpoint only sends the SHUTDOWN ACK chunk after the peer acknowledges all outstanding data from this endpoint. When this endpoint's peer sends a SHUTDOWN COMPLETE chunk, the association is closed.

sstat_rwnd

This value is the association peer's current receive window.

sstat_unackdata

This value is the number of unacknowledged DATA chunks.

sstat_penddata

This value is the number of DATA chunks that are awaiting receipt.

sstat_instrms

This value is the number of inbound streams.

sstat_outstrms

This value is the number of outbound streams.

sstat_fragmentation_point

If the combined size of the message, the SCTP headers, and the IP headers exceeds the value of sstat_fragmentation_point, the message fragments. This value is equal to the Path Maximum Transmission Unit (P-MTU) for the packet's destination address

sstat_primary

This value contains information about the primary peer address. This information uses the following structure:

struct sctp_paddrinfo {
    sctp_assoc_t               spinfo_assoc_id;
    struct sockaddr_storage    spinfo_address;
    int32_t                    spinfo_state;
    uint32_t                   spinfo_cwnd;
    uint32_t                   spinfo_srtt;
    uint32_t                   spinfo_rto;
    uint32_t                   spinfo_mtu;
};
spinfo_assoc_id

The calling program provides this value, which specifies the association of interest.

spinfo_address

This value is the primary peer's address.

spinfo_state

This value can take on either of the two values SCTP_ACTIVE or SCTP_INACTIVE.

spinfo_cwnd

This value is the congestion window of the peer address.

spinfo_srtt

This value is the current smoothed round-trip time calculation for the peer address. This value is expressed in milliseconds.

spinfo_rto

This value is the current retransmission timeout value for the peer address. This value is expressed in milliseconds.

spinfo_mtu

This value is the P-MTU for the peer address.

The sctp_opt_info() function returns 0 on success. The sctp_opt_info() function returns -1 on failure and sets the value of errno to the appropriate error code. If the file descriptor passed to the sctp_opt_info() in the sock parameter is invalid, the sctp_opt_info() function fails and returns EBADF. If the file descriptor passed to the sctp_opt_info() function in the sock parameter does not describe a socket, the sctp_opt_info() function fails and returns ENOTSOCK. If the association ID is invalid for a one-to-many SCTP socket model, the sctp_opt_info() function fails and sets the value of errno to EINVAL. If the input buffer length is too short for the option specified, the sctp_opt_info() function fails and sets the value of errno to EINVAL. If the address family for the peer's address is not AF_INET or AF_INET6, the sctp_opt_info() function fails and sets the value of errno to EAFNOSUPPORT.

sctp_recvmsg() Function

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

The sctp_recvmsg() function enables receipt of a message from the SCTP endpoint specified by the s parameter. The calling program can specify the following attributes:

msg

This parameter is the address of the message buffer.

len

This parameter is the length of the message buffer.

from

This parameter is a pointer to an address that contains the sender's address.

fromlen

This parameter is the size of the buffer associated with the address in the from parameter.

sinfo

This parameter is only active if the calling program enables sctp_data_io_events. To enable sctp_data_io_events, call the setsockopt() function with the socket option SCTP_EVENTS. When sctp_data_io_events is enabled, the application receives the contents of the sctp_sndrcvinfo structure for each incoming message. This parameter is a pointer to a sctp_sndrcvinfo structure. The structure is populated upon receipt of the message.

msg_flags

This parameter contains any message flags that are present.

The sctp_recvmsg() function returns the number of bytes it receives. The sctp_recvmsg() function returns -1 when an error occurs.

If the file descriptor passed in the s parameter is not valid, the sctp_recvmsg() function fails and sets the value of errno to EBADF. If the file descriptor passed in the s parameter does not describe a socket, the sctp_recvmsg() function fails and sets the value of errno to ENOTSOCK. If the msg_flags parameter includes the value MSG_OOB, the sctp_recvmsg() function fails and sets the value of errno to EOPNOTSUPP. If there is no established association, the sctp_recvmsg() function fails and sets the value of errno to ENOTCONN.

sctp_sendmsg() Function

ssize_t sctp_sendmsg()int s, 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

The sctp_sendmsg() function enables advanced SCTP features while sending a message from an SCTP endpoint.

s

This value specifies the SCTP endpoint that is sending the message.

msg

This value contains the message sent by the sctp_sendmsg() function.

len

This value is the length of the message. This value is expressed in bytes.

to

This value is the destination address of the message.

tolen

This value is the length of the destination address.

ppid

This value is the application-specified payload protocol identifier.

stream_no

This value is the target stream for this message.

timetolive

This value is the time period after which the message expires if it has not been successfully sent to the peer. This value is expressed in milliseconds.

context

This value is returned if an error occurs during the sending of the message.

flags

This value is formed from applying the logical operation OR in bitwise fashion on zero or more of the following flag bits:

MSG_UNORDERED

When this flag is set, the sctp_sendmsg() function delivers the message unordered.

MSG_ADDR_OVER

When this flag is set, the sctp_sendmsg() function uses the address in the to parameter instead of the association's primary destination address. This flag is only used with one-to-many SCTP sockets model.

MSG_ABORT

When this flag is set, the specified association aborts by sending an ABORT signal to its peer. This flag is only used with one-to-many SCTP sockets model.

MSG_EOF

When this flag is set, the specified association enters graceful shutdown. This flag is only used with one-to-many SCTP sockets model.

MSG_PR_SCTP

When this flag is set, the message expires when its transmission has not successfully completed within the time period specified in the timetolive parameter.

The sctp_sendmsg() function returns the number of bytes it sent. The sctp_sendmsg() function returns -1 when an error occurs.

If the file descriptor passed in the s parameter is not valid, the sctp_sendmsg() function fails and sets the value of errno to EBADF. If the file descriptor passed in the s parameter does not describe a socket, the sctp_sendmsg() function fails and sets the value of errno to ENOTSOCK. If the flags parameter includes the value MSG_OOB, the sctp_sendmsg() function fails and sets the value of errno to EOPNOTSUPP. If the flags parameter includes the values MSG_ABORT or MSG_EOF for a one-to-one socket model, the sctp_sendmsg() function fails and sets the value of errno to EOPNOTSUPP. If there is no established association, the sctp_sendmsg() function fails and sets the value of errno to ENOTCONN. If the socket is shutting down, disallowing further writes, the sctp_sendmsg() function fails and sets the value of errno to EPIPE. If the socket is nonblocking and the transmit queue is full, the sctp_sendmsg() function fails and sets the value of errno to EAGAIN.

If the control message length is incorrect, the sctp_sendmsg() function fails and sets the value of errno to EINVAL. If the specified destination address does not belong to the association, the sctp_sendmsg() function fails and sets the value of errno to EINVAL. If the value of stream_no is outside the number of outbound streams that the association supports, the sctp_sendmsg() function fails and sets the value of errno to EINVAL. If the address family of the specified destination address is not AF_INET or AF_INET6, the sctp_sendmsg() function fails and sets the value of errno to EINVAL.

sctp_send() Function

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

The sctp_send() function is usable by one-to-one and one-to-many sockets model. The sctp_send() function enables advanced SCTP features while sending a message from an SCTP endpoint.

s

This value specifies the socket created by the socket() function.

msg

This value contains the message sent by the sctp_send() function.

len

This value is the length of the message. This value is expressed in bytes.

sinfo

This value contains the parameters used to send the message. For a one-to-many sockets model, this value can contain the association ID to which the message is being sent.

flags

This value is identical to the flags parameter in the sendmsg() function.

The sctp_send() function returns the number of bytes it sent. The sctp_send() function returns -1 when an error occurs.

If the file descriptor passed in the s parameter is not valid, the sctp_send() function fails and sets the value of errno to EBADF. If the file descriptor passed in the s parameter does not describe a socket, the sctp_send() function fails and sets the value of errno to ENOTSOCK. If the sinfo_flags field of the sinfo parameter includes the value MSG_OOB, the sctp_send() function fails and sets the value of errno to EOPNOTSUPP. If the sinfo_flags field of the sinfo parameter includes the values MSG_ABORT or MSG_EOF for a one-to-one socket model, the sctp_send() function fails and sets the value of errno to EOPNOTSUPP. If there is no established association, the sctp_send() function fails and sets the value of errno to ENOTCONN. If the socket is shutting down, disallowing further writes, the sctp_send() function fails and sets the value of errno to EPIPE. If the socket is nonblocking and the transmit queue is full, the sctp_send() function fails and sets the value of errno to EAGAIN.

If the control message length is incorrect, the sctp_send() function fails and sets the value of errno to EINVAL. If the specified destination address does not belong to the association, the sctp_send() function fails and sets the value of errno to EINVAL. If the value of stream_no is outside the number of outbound streams that the association supports, the sctp_send() function fails and sets the value of errno to EINVAL. If the address family of the specified destination address is not AF_INET or AF_INET6, the sctp_send() function fails and sets the value of errno to EINVAL.

sctp_sendv() Function

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 sctp_sendv() sends a message to an SCTP socket. The following attributes are specified:

sd

The socket descriptor.

iov

The message to be sent. The data in the buffer are treated as one single user message.

iovcnt

The number of elements in iov.

addrs

An array of addresses to be used to set up an association or one single address to be used to send the message. Pass in NULL if the caller does not want to set up an association nor want 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 info_type parameter.

infolen

The length in bytes of info.

infotype

The type of the info buffer. The following values are defined:

SCTP_SENDV_SNDFO

The type of info is struct sctp_sndinfo.

SCTP_SENDV_PRINFO

The type of info is struct sctp_prinfo.

SCTP_SENDV_AUTHINFO

The type of info is struct sctp_authinfo. This type is not supported.

SCTP_SENDV_SPA

The type of info is struct sctp_send_spa.

The sctp_sendv() function provides an extensible way for an application to communicate different send attributes to the SCTP stack when sending a message. This function can also be used to set up an association. The addrs array is similar to the addrs array used by sctp_connectx Function.

There are three types of attributes which can be used to describe a message to be sent. They are represented by struct sctp_sndinfo, struct sctp_prinfo, and struct sctp_authinfo which is currently not supported.

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;
};

The sendv_flags field holds a bitwise–OR of SCTP_SEND_SNDINFO_VALID, SCTP_SEND_PRINFO_VALID, and SCTP_SEND_AUTHINFO_VALID values, indicating whether the sendv_sndinfo, sendv_prinfo, and sendv_authinfo fields contain valid information.

The sctp_sndinfo structure is defined as follows:

struct sctp_sndinfo {
    uint16_t       snd_sid;
    uint16_t       snd_flags;
    uint32_t       snd_ppid;
    uint32_t       snd_context;
    sctp_assoc_t   snd_assoc_id;
};

where:

snd_sid

This value holds the stream number to send the message to. If a sender specifies an invalid stream number, an error value is returned and the call fails.

snd_flags

This field is a bit wise OR of the following flags:

SCTP_UNORDERED

his flag requests the unordered delivery of the message.

SCTP_ADDR_OVER

This flag requests the SCTP stack to override the primary destination address and send the message to the given address in addrs. Only one address can be given is this case. If this flag is not specified and addrs is not NULL, this call is treated as a connect request. This flag is applicable to one-to-many sockets model only.

SCTP_ABORT

Setting this flag causes the specified association to be aborted by sending an ABORT message to the peer. The ABORT message will contain an error cause User Initiated Abort with cause code 12. The specific information the cause of this error is provided in msg_iov.

SCTP_EOF

Setting this flag invokes the SCTP graceful shutdown procedures on the specified association. Graceful shutdown assures that all data queued by both endpoints is successfully transmitted before closing the association.

SCTP_SENDALL

This flag requests that the message is sent to all associations that are currently established on the socket. This flag is applicable to one-to-many sockets model only.

snd_ppid

An unsigned integer that is passed to the remote end in each user message (SCTP DATA chunk). The SCTP stack performs no byte order modification of this field. For example, if the DATA chunk has to contain a given value in network byte order, the SCTP user has to perform the htonl computation. For more information, see the htonl(3C) man page.

snd_context

This value is an opaque 32 bit context datum. It is passed back to the caller if an error occurs on the transmission of the message and is retrieved with each undelivered message.

snd_assoc_id

When sending a message, this field holds the identifier for the association which the message is sent to. When this call is used to set up an association, the association identifier of the newly created association is returned in this field. This field is applicable to one-to-many sockets model only.

The sctp_prininfo structure is defined as follows:

struct sctp_prinfo {
    uint16_t pr_policy;
    uint32_t pr_value;
};

where:

pr_policy

This field specifies the partial reliability (PR-SCTP) policy that is used to send the message. If it is SCTP_PR_SCTP_NONE, the message is sent reliably (the default is normal send). If it is SCTP_PR_SCTP_TTL, timed reliability as defined in Stream Control Transmission Protocol (SCTP) Partial Reliability Extension, RFC 3758 is used. In this case, the lifetime is provided in pr_value.

pr_value

The meaning of this field depends on the PR-SCTP policy specified by the pr_policy field. It is ignored when SCTP_PR_SCTP_NONE is specified. In case of SCTP_PR_SCTP_TTL, this field specifies the lifetime in milliseconds of the message.

When new send attributes are needed, new structures can be defined. Those new structures do not need to be based on any of the above defined structures.

The struct sctp_sndinfo attribute for one-to-many sockets model must always be used in order to specify the association the message is to be sent to. 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(), first using the list of addresses, and then calling sendmsg() with the given message and attributes. For an one-to-many sockets model, if a 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. The struct sctp_sndinfo attribute is not required to set up an association for one-to-many sockets model. 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 (overriding the primary address), the caller can provide the specific address in the addrs parameter and provide a struct sctp_sndinfo attribute with the snd_flags field set to SCTP_ADDR_OVER.

This function can 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, the length of the message would be zero. Sending a message using sctp_sendv() is atomic unless explicit EOR marking is enabled on the socket specified by sd.

Upon successful completion, the number of bytes sent is returned. Otherwise, -1 is returned and errno is set to indicate the error.

The following error values are defined:

EADDRINUSE

The address is already in use.

EADDRNOTAVAIL

No local address is available for this operation.

EAFNOSUPPORT

Addresses in the specified address family cannot be used with this socket.

EBADF

The sd parameter is not a valid file descriptor.

ECONNREFUSED

The attempt to connect was forcefully rejected. The calling program should close the socket descriptor using close and issue another socket call to obtain a new descriptor before making another attempt. For more information, see the close(2) and socket(3C) man pages.

EFAULT

A parameter can not be accessed.

EINTR

The operation was interrupted by delivery of a signal before any data could be buffered to be sent.

EINVAL

A parameter provided is invalid for this operation.

EMSGSIZE

The message is too large to be sent all at once.

ENETUNREACH

The network is not reachable from this host.

ENOBUFS

Insufficient memory is available to complete the operation.

EOPNOTSUPP

Operation not supported in this type of socket.

EPIPE

The peer end point has shutdown the association.

ETIMEDOUT

Attempt timed out.

EWOULDBLOCK

The socket is marked as non-blocking, and the requested operation would block.

sctp_recvv() Function

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

The sctp_recvv() function provides an extensible way for the SCTP stack to pass up different SCTP attributes associated with a received message to an application. The following attributes are specified:

sd

The socket descriptor.

iov

The scatter buffer containing the received message.

iovlen

The number of elements in iov.

from

A pointer to a buffer to be filled with the sender address of the received message.

fromlen

The size of the from buffer. Upon return, it is set to the actual size of the sender's address.

info

A pointer to the buffer containing the attributes of the received message. The type of structure is indicated by info_type parameter.

infolen

The length in bytes of info buffer. Upon return, it is set to the actual size of the returned info buffer.

infotype

The type of the info buffer. The following values are defined:

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, there will also no attribute be returned. In these cases, infotype will be set to SCTP_RECVV_NOINFO.

SCTP_RECVV_RCVINFO

The type of info is struct sctp_rcvinfo and the attribute is about the received message.

SCTP_RECVV_NXTINFO

The type of info is struct sctp_nxtinfo and the attribute is about the next message in 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 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

Flag for receive as in recvmsg. On return, its value will be different from what was set in to the call. It has the same value as rcv_flags. For more information, see the recvmsg(3C) man page.

There are two types of attributes which can be returned by the call to sctp_recvv():

  • The attribute of the received message and the attribute of the next message in receive buffer. The caller enables the SCTP_RECVRCVINFO and SCTP_RECVNXTINFO socket option to receive these attributes respectively.

Attributes of the received message are returned in struct sctp_rcvinfo and attributes of the next message are returned in the structure sctp_nxtinfo. 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;
};

The sctp_rcvinfo structure is defined as follows:

struct sctp_rcvinfo {
    uint16_t rcv_sid;
    uint16_t rcv_ssn;
    uint16_t rcv_flags;
    uint32_t rcv_ppid;
    uint32_t rcv_tsn;
    uint32_t rcv_cumtsn;
    uint32_t rcv_context;
    sctp_assoc_t rcv_assoc_id;
};

where:

rcv_info

The stream number of the received message.

rcv_ssn

The stream sequence number that the peer endpoint assigned to the DATA chunk of this message. For fragmented messages, this is the same number for all deliveries of the message (if more than one sctp_recvv() is needed to read the message).

rcv_flags

May be set to SCTP_UNORDERED when the message was sent unordered.

rcv_ppid

This value is the same information that is passed by the peer socket to its SCTP stack. The SCTP stack performs no byte order modification of this field.

rcv_tsn

The transmission sequence number that the peer endpoint assigned to the received message.

rcv_cumtsn

The current cumulative transmission sequence number of the association known to the SCTP stack.

rcv_assoc_id

The association identifier of the association of the received message. This field applies only to a one-to-many sockets model.

rcv_context

This value is an opaque 32 bit context datum that was set by the caller with the SCTP_CONTEXT socket option. This value is passed back to the upper layer if an error occurs on the transmission of a message and is retrieved with each undelivered message.

The sctp_nxtinfo structure is defined as follows:

struct sctp_nxtinfo {
    uint16_t nxt_sid;
    uint16_t nxt_flags;
    uint32_t nxt_ppid;
    size_t  nxt_length;
    sctp_assoc_t nxt_assoc_id;
};

where:

nxt_sid

The stream number of the next message.

flags

This field can contain any of the following flags and is composed of a bitwise– OR of the following values:

SCTP_UNORDERED

The next message was sent unordered.

SCTP_COMPLETE

The entire message has been received and is in the socket buffer. This flag has special implications with respect to the nxt_length field.

SCTP_NOTIFICATION

The next message is not a user message but instead is a notification.

ppid

This value is the same information that was passed by the peer socket to its SCTP stack when sending the next message. The SCTP stack performs no byte order modification of this field.

length

The length of the message currently received in the socket buffer. This might not be the entire length of the next message since a partial delivery may be in progress. This field represents the entire next message size only if the flag SCTP_COMPLETE is set in the nxt_flags field.

assoc_id

The association identifier of the association of the next message. This field applies only to a one-to-many sockets model.

The following error values are defined for sctp_recvv():

EBADF

The sd parameter is not a valid file descriptor.

EFAULT

A parameter can not be accessed.

EINTR

The operation was interrupted by delivery of a signal before any data could be buffered to be sent or the operation was interrupted by delivery of a signal before any data is available to be received.

EINVAL

A parameter provided is invalid for this operation.

ENOBUFS

Insufficient memory is available to complete the operation.

EWOULDBLOCK

The socket is marked as non-blocking and the requested operation would get blocked.

sctp_connectx() Function

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

The sctp_connectx() requests an SCTP association to be made on a socket. This is similar to connect(3C) except that an array of peer addresses can be given.

Similar to sctp_bindx, this function allows a caller to specify multiple addresses at which a peer can be reached. The SCTP stack tries each addresses in the array in a round robin fashion to set up the association. 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, the caller must use sctp_getpaddrs to retrieve them after the association has been set up. For more information, see the sctp_bindx(3C) and sctp_getpaddrs(3C) man pages.

The following attributes are specified:

sd

The socket descriptor.

addrs

If sd is an IPv4 socket, addrs should be an array of sockaddr_in structures containing IPv4 addresses. If sd is an IPv6 socket, addrs should be an array of sockaddr_in6 structures containing IPv6 or IPv4-mapped IPv6 addresses.

addrcnt

The number of addresses in the array addrs.

aid

If the call to sctp_connectx() function returns successfully, the association identifier for the newly created association is returned in aid. This parameter is applicable only to one-to-many SCTP sockets model.

The following error values are defined for sctp_connectx():

EADDRINUSE

The address is already in use.

EADDRNOTAVAIL

No local address is available for this operation.

EAFNOSUPPORT

Addresses in the specified address family cannot be used with this socket.

EALREADY

The socket is non-blocking and a previous connection attempt has not yet been completed.

EBADF

The sd parameter is not a valid file descriptor.

ECONNREFUSED

The attempt to connect was forcefully rejected. The calling program should use connect to close the socket descriptor, and issue another socket call to obtain a new descriptor before making another attempt.

EFAULT

A parameter can not be accessed.

EINTR

The connect attempt was interrupted before it is completed. The attempt will be established asynchronously.

EINVAL

A parameter provided is invalid for this operation.

ENOBUFS

Insufficient memory is available to complete the operation.

EWOULDBLOCK

The socket is marked as non-blocking and the requested operation would get blocked.

ETIMEDOUT

The attempt timed out.

EOPNOTSUPP

The operation is not supported in this type of socket.

sctp_getladdrs() Function

The sctp_getladdrs() function returns all locally bound addresses on a socket. The syntax for the sctp_getladdrs() function is as follows:

int sctp_getladdrs()int sock, sctp_assoc_t id, void **addrs

When the sctp_getladdrs() function returns successfully, the value of addrs points to a dynamically allocated packed array of sockaddr structures. The sockaddr structures are of the appropriate type for each local address. The calling application uses the sctp_freeladdrs() function to free the memory. The value of the addrs parameter must not be NULL.

If the socket referenced by the sd parameter is an IPv4 socket, the sctp_getladdrs() function returns IPv4 addresses. If the socket referenced by the sd parameter is an IPv6 socket, the sctp_getladdrs() function returns a mix of IPv4 or IPv6 addresses as appropriate.

When the sctp_getladdrs() function is invoked for a one-to-many sockets model, the value of the id parameter specifies the association to query. The sctp_getladdrs() function ignores the id parameter when the function is operating on a one-to-one socket.

When the value of the id parameter is zero, the sctp_getladdrs() function returns locally bound addresses without regard to any particular association. When the sctp_getladdrs() function returns successfully, it reports the number of local addresses bound to the socket. If the socket is unbound, the sctp_getladdrs() function returns 0 and the value of *addrs is undefined. If an error occurs, the sctp_getladdrs() function returns -1 and the value of *addrs is undefined.

sctp_freeladdrs() Function

The sctp_freeladdrs() function frees all of the resources that were allocated by a previous call to the sctp_getladdrs(). The syntax for the sctp_freeladdrs() function is as follows:

void sctp_freeladdrs()void *addrs

The *addrs parameter is an array that contains the peer addresses that are returned by the sctp_getladdrs() function.

sctp_getpaddrs() Function

The sctp_getpaddrs() function returns all peer addresses in an association.

int sctp_getpaddrs()int sock, sctp_assoc_t id, void **addrs

When the sctp_getpaddrs() function returns successfully, the value of the **addrs parameter points to a dynamically allocated packed array of sockaddr structures of the appropriate type for each address. The calling thread frees the memory with the sctp_freepaddrs() function. The **addrs parameter cannot have a value of NULL. If the socket descriptor given in sock is for an IPv4 socket, the sctp_getpaddrs() function returns IPv4 addresses. If the socket descriptor given in sock is for an IPv6 socket, the sctp_getpaddrs() function returns a mix of IPv4 and IPv6 addresses. For one-to-many sockets model, the id parameter specifies the association to query. The sctp_getpaddrs() function ignores the id parameter for one-to-one socket model. When the sctp_getpaddrs() function returns successfully, it returns the number of peer addresses in the association. If there is no association on this socket, the sctp_getpaddrs() function returns 0 and the value of the **addrs parameter is undefined. If an error occurs, the sctp_getpaddrs() function returns -1 and the value of the **addrs parameter is undefined.

If the file descriptor passed to the sctp_getpaddrs() function in the sock parameter is invalid, the sctp_getpaddrs() function fails and returns EBADF. If the file descriptor passed to the sctp_getpaddrs() function in the sock parameter does not describe a socket, the sctp_getpaddrs() function fails and returns ENOTSOCK. If the file descriptor passed to the sctp_getpaddrs() function in the sock parameter describes a socket that is not connected, the sctp_getpaddrs() function fails and returns ENOTCONN.

sctp_freepaddrs() Function

The sctp_freepaddrs() function frees all of the resources that were allocated by a previous call to the sctp_getpaddrs(). The syntax for the sctp_freepaddrs() function is as follows:

void sctp_freepaddrs()void *addrs

The *addrs parameter is an array that contains the peer addresses that are returned by the sctp_getpaddrs() function.

Branched-off Association

Applications can branch an established association on a one-to-many sockets model into a separate socket and file descriptor. A separate socket and file descriptor is useful for applications that have a number of sporadic message senders or receivers that need to remain under the original one-to-many sockets model. The application branches off associations that carry high volume data traffic into separate socket descriptors. The application uses the sctp_peeloff() call to branch off an association into a separate socket. The new socket is a one-to-one socket model. The syntax for the sctp_peeloff() function is as follows:

int sctp_peeloff()int sock, sctp_assoc_t id
sock

The original one-to-many sockets model descriptor returned from the socket() system call.

id

The identifier of the association to branch off to a separate file descriptor.

The sctp_peeloff() function fails and returns EOPTNOTSUPP if the socket descriptor passed in the sock parameter is not a one-to-many SCTP sockets model. The sctp_peeloff() function fails and returns EINVAL if the value of id is zero or if the value of id is greater than the maximum number of associations for the socket descriptor passed in the sock parameter. The sctp_peeloff() function fails and returns EMFILE if the function fails to create a new user file descriptor or file structure.

Using SCTP Sockets

This section details three uses of SCTP sockets.

Example 37  Using SCTP Echo Client in One-to-One Socket Model
/*
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 */

/*
 * IPv4 echo client.
 */

/* To enable socket features used for SCTP socket. */
#define	_XPG4_2
#define	__EXTENSIONS__

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <netinet/sctp.h>
#include <errno.h>
#define	BUFLEN		2048
#define	SERVER_PORT	5000
#define	MAX_STREAM	64

static void
usagBe(char *a0)
{
	fprintf(stderr, "Usage: %s <server address>\n", a0);
}
static void
print_notif(char *buf)
{
	union sctp_notification		*snp;
	struct sctp_assoc_change	*sac;
 snp = (union sctp_notification *)buf;
	/* We only subscribe the association change event. */
	if (snp->sn_header.sn_type != SCTP_ASSOC_CHANGE) {
		fprintf(stderr, "unexpected notification type: %d\n",
		snp->sn_header.sn_type);
		exit(1);
	}
	sac = &snp->sn_assoc_change;
	printf("[ Receive assocication change event: state = %hu," error = %hu,"
 instr = %hu, outstr = %hu ]\n", sac->sac_state, 
	sac->sac_error,sac->sac_inbound_streams,
 sac->sac_outbound_streams);
}

/*
 * Read from the network.
 */
static void
readit(void *vfdp)
{
	int		fd;
	ssize_t		n;
	char		buf[BUFLEN];
	struct iovec	iov[1];
	int		flags;
	socklen_t	info_len;
	uint_t		info_type;
	struct sctp_rcvinfo	info;
	union sctp_notification	*snp;

	pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
	fd = *(int *)vfdp;

	/* Initialize the iov for receiving */
	memset(buf, 0, BUFLEN);
	iov->iov_base = buf;
	iov->iov_len = BUFLEN;

	info_len = sizeof (info);
	info_type = 0;
	flags = 0;
	while ((n = sctp_recvv(fd, iov, 1, NULL, NULL, &info, 
	&info_len,&info_type, &flags)) > 0) {
		/* Intercept notifications here */
		if (flags & MSG_NOTIFICATION) {
			print_notif(buf);
			continue;
		}
		/* The message should be accompanied by sctp_rcvinfo. */
		if (info_type != SCTP_RECVV_RCVINFO) {
			fprintf(stderr, "no sctp_rcvinfo attached\n");
			exit(1);
		}
		printf("[ Receive echo (%u bytes): stream = %hu, ssn = %hu," "tsn = %hu,
    flags = %hx, ppid = %u ]\n", n, info.rcv_sid, info.rcv_ssn, info.rcv_tsn, 
    info.rcv_flags, info.rcv_ppid);
		flags = 0;
		info_len = sizeof (info);
	}
	if (n < 0) {
		perror("sctp_recvv");
		exit(1);
	}
	close(fd);
	exit(0);
}

static void
echo(struct sockaddr_in *addrs, int addrcnt)
{
	int		fd;
	uchar_t		buf[BUFLEN];
	ssize_t		n;
	int		perr;
	pthread_t	tid;
	struct iovec	iov[1];
	int		ret, on;
	struct sctp_sndinfo	info;
	struct sctp_initmsg	initmsg;
	struct sctp_event	event;

	/* Create a one-one SCTP socket */
	if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
		perror("socket");
		exit(1);
	}
	/*
	 * We are interested in association change events and we want
	 * to get sctp_rcvinfo in each receive.
	 */
	event.se_assoc_id = 0;	/* Ignored for one-one SCTP socket */
	event.se_type = SCTP_ASSOC_CHANGE;
	event.se_on = 1;
	ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, sizeof (event));
	if (ret < 0) {
		perror("setsockopt SCTP_EVENT");
		exit(1);
	}
	on = 1;
	ret = setsockopt(fd, IPPROTO_SCTP, SCTP_RECVRCVINFO, &on, sizeof (on));
	if (ret < 0) {
		perror("setsockopt SCTP_RECVRCVINFO");
		exit(1);
	}

	/*
	 * Set the SCTP stream parameters to tell the other side when
	 * setting up the association.
	 */
	memset(&initmsg, 0, sizeof (struct sctp_initmsg));
	initmsg.sinit_num_ostreams = MAX_STREAM;
	initmsg.sinit_max_instreams = MAX_STREAM;
	initmsg.sinit_max_attempts = MAX_STREAM;
	ret = setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,sizeof (struct sctp_initmsg));
	if (ret < 0) {
		perror("setsockopt SCTP_INITMSG");
		exit(1);
	}

	/* Now connect to the peer. */
	if (sctp_connectx(fd, (struct sockaddr *)addrs, addrcnt, NULL) == -1) {
		perror("sctp_connectx");
		exit(1);
	}

	/* Initialize the struct sctp_sndinfo for sending. */
	memset(&info, 0, sizeof (info));
	/* Start sending to stream 0. */
	info.snd_sid = 0;
	/*
	 * Note that the server is expected to echo back the snd_ppid value.
	 * So we don't need to do any conversion here.  But if the server needs
	 * to understand this value, we need to do a htonl() on it so that the
	 * server side can do a ntohl() to convert it back to the host byte
	 * order.
	 */
	info.snd_ppid = 0;

	/* Create a thread to receive network traffic. */
	perr = pthread_create(&tid, NULL, (void *(*)(void *))readit, &fd);
	if (perr != 0) {
		fprintf(stderr, "pthread_create: %d\n", perr);
		exit(1);
	}

	iov->iov_base = buf;
	/* Read from stdin and then send to the echo server. */
	while ((n = read(fileno(stdin), buf, BUFLEN)) > 0) {
		iov->iov_len = n;
		if (sctp_sendv(fd, iov, 1, NULL, 0, &info, sizeof (info),
		    SCTP_SENDV_SNDINFO, 0) < 0) {
			perror("sctp_sendv");
			exit(1);
		}
		/* Send the next message to a different stream. */
		info.snd_sid = (info.snd_sid + 1) % MAX_STREAM;
		info.snd_ppid++;
	}
	pthread_cancel(tid);
	close(fd);
}

static struct sockaddr_in *
setup_addrs(const char *name, int *addrcnt)
{
	int			num_addrs, i;
	int			error;
	struct hostent		*hp;
	struct sockaddr_in	*addrs;

	hp = getipnodebyname(name, AF_INET, AI_DEFAULT, &error);
	if (hp == NULL) {
		fprintf(stderr, "host %s not found\n", name);
		return (NULL);
	}
	for (num_addrs = 0; hp->h_addr_list[num_addrs] != NULL; num_addrs++)
		;
	addrs = malloc((num_addrs) * sizeof (*addrs));
	if (addrs == NULL) {
		fprintf(stderr, "cannot allocate address list\n");
		return (NULL);
	}
	for (i = 0; i < num_addrs; i++) {
		addrs[i].sin_family = AF_INET;
		addrs[i].sin_addr.s_addr = *(ipaddr_t *)hp->h_addr_list[i];
		addrs[i].sin_port = htons(SERVER_PORT);
	}
	*addrcnt = num_addrs;
	return (addrs);
}

int
main(int argc, char **argv)
{
	struct sockaddr_in	*addrs;
	int addrcnt;

	if (argc < 2) {
		usage(*argv);
		exit(1);
	}

	/* Find the host to connect to. */
	if ((addrs = setup_addrs(argv[1], &addrcnt)) == NULL)
		exit(1);
	echo(addrs, addrcnt);
	return (0);
}
Example 38  Using SCTP Echo Server in One-to-One Socket Model
/*
 * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
 */
/*
 * IPv4 echo server
*/
/* To enable socket features used for SCTP socket. */
#define _XPG4_2
#define __EXTENSIONS__

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

#define	BUFLEN		1024
#define	SERVER_PORT	5000
#define	MAX_STREAM	64
/*
 * Given an event notification, print out what it is.
 */
static void
handle_event(void *buf)
{
	struct sctp_assoc_change	*sac;
	struct sctp_send_failed_event	*ssfe;
	struct sctp_paddr_change	*spc;
	struct sctp_remote_error	*sre;
	union sctp_notification		*snp;
	char	addrbuf[INET6_ADDRSTRLEN];
	const char	*ap;
	struct sockaddr_in *sin;

	snp = buf;
	switch (snp->sn_header.sn_type) {
	case SCTP_ASSOC_CHANGE:
		sac = &snp->sn_assoc_change;
		printf(">>> assoc_change: state=%hu, error=%hu, instr=%hu "
		"outstr=%hu\n", sac->sac_state, sac->sac_error,
		sac->sac_inbound_streams, sac->sac_outbound_streams);
		break;
	case SCTP_SEND_FAILED_EVENT:
		ssfe = &snp->sn_send_failed_event;
		printf(">>> sendfailed: len=%hu err=%d\n", ssfe->ssfe_length,
		ssfe->ssfe_error);
		break;
	case SCTP_PEER_ADDR_CHANGE:
		spc = &snp->sn_paddr_change;
		if (spc->spc_aaddr.ss_family != AF_INET) {
			fprintf(stderr, "getmsg: unexpected family %d\n",spc->spc_aaddr.ss_family);
			exit(1);
		} else {
			sin = (struct sockaddr_in *)&spc->spc_aaddr;
			ap = inet_ntop(AF_INET, &sin->sin_addr, addrbuf,INET6_ADDRSTRLEN);
		}
		printf(">>> intf_change: %s state=%d, error=%d\n", ap,
		    spc->spc_state, spc->spc_error);
		break;
	case SCTP_REMOTE_ERROR:
		sre = &snp->sn_remote_error;
		printf(">>> remote_error: err=%hu len=%hu\n",
		ntohs(sre->sre_error), ntohs(sre->sre_length));
		break;
	case SCTP_SHUTDOWN_EVENT:
		printf(">>> shutdown event\n");
		break;
	default:
		printf(">>> unexpected type: %hu\n", snp->sn_header.sn_type);
		break;
	}
}

/*
 * Receive a message from the network.
 */
static ssize_t
getmsg(int fd, struct iovec *iov, struct sctp_rcvinfo *info, int *flags)
{
	ssize_t		tot = 0, nr;
	size_t		buflen;
	socklen_t	info_len;
	uint_t		info_type;
	char		*buf;

	buf = iov->iov_base;
	buflen = iov->iov_len;

	/* Loop until a whole message is received. */
	for (;;) {
		info_len = sizeof (*info);
		memset(info, 0, sizeof (*info));
		*flags = 0;
		nr = sctp_recvv(fd, iov, 1, NULL, NULL, info, &info_len,
		    &info_type, flags);
		if (nr <= 0) {
			/* EOF or error */
			iov->iov_base = buf;
			return (nr);
		}
		tot += nr;

		/* Whole message/notification is received, return it. */
		if (*flags & MSG_EOR || *flags & MSG_NOTIFICATION) {
			iov->iov_base = buf;
			/* Buffer may be realloc().  Return the new size. */
			iov->iov_len = buflen;
			return (tot);
		}

		/* Only sctp_rcvinfo is expected. */
		if (info_type != SCTP_RECVV_RCVINFO) {
			fprintf(stderr, "unexpected info received: %d\n",
			    info_type);
			iov->iov_base = buf;
			return (-1);
		}

		/* Maybe we need a bigger buffer, do realloc(). */
		if (buflen == tot) {
			buf = realloc(buf, buflen * 2);
			if (buf == NULL) {
				fprintf(stderr, "out of memory\n");
				exit(1);
			}
			buflen *= 2;
		}
		/* Set the next read offset */
		iov->iov_base = buf + tot;
		iov->iov_len = buflen - tot;
	}
}

/*
 * The echo server.
 */
static void
echo(int fd)
{
	ssize_t			nr;
	size_t			buflen;
	int			flags;
	struct iovec		iov[1];
	struct sctp_rcvinfo	rinfo;
	struct sctp_sndinfo	sinfo;

	if ((iov->iov_base = malloc(BUFLEN)) == NULL) {
		fprintf(stderr, "out of memory\n");
		exit(1);
	}
	iov->iov_len = BUFLEN;

	memset(&sinfo, 0, sizeof (sinfo));

	/* Wait for something to echo */
	while ((nr = getmsg(fd, iov, &rinfo, &flags)) > 0) {
		/* Intercept notifications here */
		if (flags & SCTP_NOTIFICATION) {
			handle_event(iov->iov_base);
			continue;
		}

		printf(">>> got %u bytes on stream %hu: ", nr, rinfo.rcv_sid);
		fflush(stdout);
		write(fileno(stdout), iov->iov_base, nr);
		fflush(stdout);

		/* The buffer may be realloc(), so get the new size. */
		buflen = iov->iov_len;

		/*
		 * Echo the message back using the incoming info.
		 *
		 * Note that rcv_sid is in host byte order.  But rcv_ppid is
		 * what is stored by the peer.  If both sides wnat to use this
		 * value for communication (interpreting it on both sides), 
		 * the sender needs to do htonl() when setting snd_ppid.  And
		 * the receiver side needs to do ntohl() to convert rcv_ppid
		 * back to the host byte order.
		 */
		sinfo.snd_sid = rinfo.rcv_sid;
		sinfo.snd_ppid = rinfo.rcv_ppid;
		iov->iov_len = nr;

		if (sctp_sendv(fd, iov, 1, NULL, 0, &sinfo, sizeof (sinfo),
		SCTP_SENDV_SNDINFO, 0) < 0) {
			fprintf(stderr, "sctp_sendv\n");
			exit(1);
		}

		/* Restore the original buffer size. */
		iov->iov_len = buflen;
	}
	free(iov->iov_base);
	close(fd);
}

static void
subscribe_event(int fd, uint16_t event)
{
	struct sctp_event	ev;
	int			ret;

	ev.se_assoc_id = 0;	/* Ignored for one-one SCTP socket */
	ev.se_type = event;
	ev.se_on = 1;
	ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &ev, sizeof (ev));
	if (ret < 0) {
		fprintf(stderr, "%s: setsockopt SCTP_EVENT: %d\n",strerror(errno), event);
		exit(1);
	}
}

/* List of events we are interested in. */
static uint16_t event_interested[] = {
	SCTP_ASSOC_CHANGE,
	SCTP_SEND_FAILED_EVENT,
	SCTP_PEER_ADDR_CHANGE,
	SCTP_REMOTE_ERROR,
	SCTP_SHUTDOWN_EVENT
};

int main(void)
{
	int		lfd;
	int		cfd;
	int		onoff;
	int		i;
	struct sockaddr_in	sin[1];
	struct sctp_initmsg	initmsg;

	if ((lfd = socket(AF_INET, SOCK_STREAM, IPPROTO_SCTP)) == -1) {
		perror("socket");
		exit(1);
	}
	sin->sin_family = AF_INET;
	sin->sin_port = htons(SERVER_PORT);
	sin->sin_addr.s_addr = INADDR_ANY;
	if (bind(lfd, (struct sockaddr *)sin, sizeof (*sin)) == -1) {
		perror("bind");
		exit(1);
	}
	if (listen(lfd, 1) == -1) {
		perror("listen");
		exit(1);
	}

	(void) memset(&initmsg, 0, sizeof (struct sctp_initmsg));
	initmsg.sinit_num_ostreams = MAX_STREAM;
	initmsg.sinit_max_instreams = MAX_STREAM;
	initmsg.sinit_max_attempts = MAX_STREAM;
	if (setsockopt(lfd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
	    sizeof (struct sctp_initmsg)) < 0) {
			perror("SCTP_INITMSG");
			exit(1);
		}

	/* Subscribe to events. */
	for (i = 0; i < sizeof (event_interested) / sizeof (uint16_t); i++)
		subscribe_event(lfd, event_interested[i]);

	/* Wait for new associations */
	for (;;) {
		if ((cfd = accept(lfd, NULL, 0)) == -1) {
			perror("accept");
			exit(1);
		}
		/* Subcribe to interesting events for the new association. */
		for (i = 0; i < sizeof (event_interested) / sizeof (int); i++)
			subscribe_event(cfd, event_interested[i]);

		/* We want sctp_rcvinfo in each receive. */
		onoff = 1;
		i = setsockopt(cfd, IPPROTO_SCTP, SCTP_RECVRCVINFO, &onoff,
		    sizeof (onoff));
		if (i < 0) {
			perror("setsockopt SCTP_RECVRCVINFO");
			close(cfd);
			continue;
		}

		/* Echo back any and all data */
		echo(cfd);
	}
}
Example 39  Using SCTP Echo Server in One-to-Many Sockets Model
/*
 * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved.
 */

/*
 * IPv4 echo server.
 */

/* To enable socket features used for SCTP socket. */
#define	_XPG4_2
#define	__EXTENSIONS__

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

#define	BUFLEN		1024
#define	SERVER_PORT	5000
#define	MAX_STREAM	64

/*
 * Given an event notification, print out what it is.
 */
static void
handle_event(void *buf)
{
	struct sctp_assoc_change	*sac;
	struct sctp_send_failed_event	*ssfe;
	struct sctp_paddr_change	*spc;
	struct sctp_remote_error	*sre;
	struct sctp_shutdown_event	*sse;
	union sctp_notification		*snp;
	char				addrbuf[INET6_ADDRSTRLEN];
	const char			*ap;
	struct sockaddr_in		*sin;

	snp = buf;
	switch (snp->sn_header.sn_type) {
	case SCTP_ASSOC_CHANGE:
		sac = &snp->sn_assoc_change;
		switch (sac->sac_state) {
		case SCTP_COMM_UP:
			/* A new association comes in. */
			printf(">>> assoc_change COMM_UP: aid=%d instr=%hu "
			    "outstr=%hu\n", sac->sac_assoc_id,
			    sac->sac_inbound_streams,
			    sac->sac_outbound_streams);
			break;
		case SCTP_SHUTDOWN_COMP:
			/* An association goes away. */
			printf(">>> assoc_change SHUTDOWN_COMPLETE: aid=%d\n",
			    sac->sac_assoc_id);
			break;
		defaul:
			printf(">>> assoc_change: aid=%d state=%hu error=%hu\n",
			sac->sac_assoc_id, sac->sac_state, sac->sac_error);
			break;
		}
		break;
	case SCTP_SEND_FAILED_EVENT:
		ssfe = &snp->sn_send_failed_event;
		printf(">>> sendfailed: aid=%d len=%hu err=%d\n",
		    ssfe->ssfe_assoc_id, ssfe->ssfe_length, ssfe->ssfe_error);
		break;
	case SCTP_PEER_ADDR_CHANGE:
		spc = &snp->sn_paddr_change;
		if (spc->spc_aaddr.ss_family != AF_INET) {
			fprintf(stderr, "getmsg: unexpected family %d\n",
				spc->spc_aaddr.ss_family);
			exit(1);
		} else {
			sin = (struct sockaddr_in *)&spc->spc_aaddr;
			ap = inet_ntop(AF_INET, &sin->sin_addr, addrbuf,
			    INET6_ADDRSTRLEN);
		}
		printf(">>> intf_change: aid=%d %s state=%d, error=%d\n",
		       spc->spc_assoc_id, ap, spc->spc_state, spc->spc_error);
		break;
	case SCTP_REMOTE_ERROR:
		sre = &snp->sn_remote_error;
		printf(">>> remote_error: aid=%d err=%hu len=%hu\n",
		    sre->sre_assoc_id, ntohs(sre->sre_error),
		    ntohs(sre->sre_length));
		break;
	case SCTP_SHUTDOWN_EVENT:
		sse = &snp->sn_shutdown_event;
		printf(">>> shutdown event: aid=%d\n", sse->sse_assoc_id);
		break;
	default:
		printf(">>> unexpected type: %hu\n", snp->sn_header.sn_type);
		break;
	}
}

/*
 * Receive a message from the network.
 */
static ssize_t
getmsg(int fd, struct iovec *iov, struct sctp_rcvinfo *info, int *flags)
{
	ssize_t			tot = 0, nr;
	size_t			buflen;
	socklen_t		info_len;
	uint_t			info_type;
	char			*buf;
	struct sockaddr_in	addr;
	socklen_t		addrlen;

	buf = iov->iov_base;
	buflen = iov->iov_len;

	/* Loop until a whole message is received. */
	for (;;) {
		info_len = sizeof (*info);
		memset(info, 0, sizeof (*info));
		*flags = 0;
		nr = sctp_recvv(fd, iov, 1, (struct sockaddr *)&addr, &addrlen,
		    info, &info_len, &info_type, flags);
		if (nr <= 0) {
			if (nr < 0)
				perror("sctp_recvv");
			/* EOF or error */
			iov->iov_base = buf;
			return (nr);
		}
		tot += nr;

		/* Whole message/notification is received, return it. */
		if (*flags & MSG_EOR || *flags & MSG_NOTIFICATION) {
			iov->iov_base = buf;
			/* Buffer may be realloc().  Return the new size. */
			iov->iov_len = buflen;
			return (tot);
		}

		/* Only sctp_rcvinfo is expected. */
		if (info_type != SCTP_RECVV_RCVINFO) {
			fprintf(stderr, "unexpected info received: %d\n",
			    info_type);
			iov->iov_base = buf;
			return (-1);
		}

		/* Maybe we need a bigger buffer, do realloc(). */
		if (buflen == tot) {
			buf = realloc(buf, buflen * 2);
			if (buf == NULL) {
				fprintf(stderr, "out of memory\n");
				exit(1);
			}
			buflen *= 2;
		}
		/* Set the next read offset */
		iov->iov_base = buf + tot;
		iov->iov_len = buflen - tot;
	}
}

/*
 * The echo server.
 */
static void
echo(int fd)
{
	ssize_t			nr;
	size_t			buflen;
	int			flags;
	struct iovec		iov[1];
	struct sctp_rcvinfo	rinfo;
	struct sctp_sndinfo	sinfo;

	if ((iov->iov_base = malloc(BUFLEN)) == NULL) {
		fprintf(stderr, "out of memory\n");
		exit(1);
	}
	iov->iov_len = BUFLEN;

	memset(&sinfo, 0, sizeof (sinfo));

	/* Wait for something to echo */
	while ((nr = getmsg(fd, iov, &rinfo, &flags)) > 0) {
		/* Intercept notifications here */
		if (flags & SCTP_NOTIFICATION) {
			handle_event(iov->iov_base);
			continue;
		}

		printf(">>> got %u bytes from aid %d on stream %hu (ssn %hu): ",
		    nr, rinfo.rcv_assoc_id, rinfo.rcv_sid, rinfo.rcv_ssn);
		fflush(stdout);
		write(fileno(stdout), iov->iov_base, nr);
		fflush(stdout);
		printf("\n");

		/* The buffer may be realloc(), so get the new size. */
		buflen = iov->iov_len;

		/*
		 * Echo the message back using the incoming info.
		 *
		 * Note that rcv_sid is in host byte order.  But rcv_ppid is
		 * what is stored by the peer.  If both sides wnat to use this
		 * value for communication (interpreting it on both sides), 
		 * the sender needs to do htonl() when setting snd_ppid.  And
		 * the receiver side needs to do ntohl() to convert rcv_ppid
		 * back to the host byte order.
		 */
		sinfo.snd_sid = rinfo.rcv_sid;
		sinfo.snd_ppid = rinfo.rcv_ppid;
		sinfo.snd_assoc_id = rinfo.rcv_assoc_id;
		iov->iov_len = nr;

		if (sctp_sendv(fd, iov, 1, NULL, 0, &sinfo, sizeof (sinfo),
		    SCTP_SENDV_SNDINFO, 0) < 0) {
			fprintf(stderr, "sctp_sendv: %s\n", strerror(errno));
			exit(1);
		}

		/* Restore the original buffer size. */
		iov->iov_len = buflen;
	}
	free(iov->iov_base);
	close(fd);
}

static void
subscribe_event(int fd, uint16_t event)
{
	struct sctp_event	ev;
	int			ret;

	ev.se_assoc_id = 0;
	ev.se_type = event;
	ev.se_on = 1;
	ret = setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &ev, sizeof (ev));
	if (ret < 0) {
		fprintf(stderr, "%s: setsockopt SCTP_EVENT: %d\n",
		    strerror(errno), event);
		exit(1);
	}
}

/* List of events we are interested in. */
static uint16_t event_interested[] = {
	SCTP_ASSOC_CHANGE,
	SCTP_SEND_FAILED_EVENT,
	SCTP_PEER_ADDR_CHANGE,
	SCTP_REMOTE_ERROR,
	SCTP_SHUTDOWN_EVENT
};

int
main(void)
{
	int			fd;
	int			onoff;
	int			i;
	struct sockaddr_in	sin[1];
	struct sctp_initmsg	initmsg;

	if ((fd = socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)) == -1) {
		perror("socket");
		exit(1);
	}
	sin->sin_family = AF_INET;
	sin->sin_port = htons(SERVER_PORT);
	sin->sin_addr.s_addr = INADDR_ANY;
	if (bind(fd, (struct sockaddr *)sin, sizeof (*sin)) == -1) {
		perror("bind");
		exit(1);
	}
	/* Enable accepting assocation set up request. */
	if (listen(fd, 5) == -1) {
		perror("listen");
		exit(1);
	}

	(void) memset(&initmsg, 0, sizeof (struct sctp_initmsg));
	initmsg.sinit_num_ostreams = MAX_STREAM;
	initmsg.sinit_max_instreams = MAX_STREAM;
	initmsg.sinit_max_attempts = MAX_STREAM;
	if (setsockopt(fd, IPPROTO_SCTP, SCTP_INITMSG, &initmsg,
	    sizeof (struct sctp_initmsg)) < 0) {
		perror("SCTP_INITMSG");
		exit(1);
	}

	/* Subscribe to events. */
	for (i = 0; i < sizeof (event_interested) / sizeof (uint16_t); i++)
		subscribe_event(fd, event_interested[i]);

	/* Enable receiving SCTP_RCVINFO on every recv. */
	onoff = 1;
	if (setsockopt(fd, IPPROTO_SCTP, SCTP_RECVRCVINFO, &onoff,
	    sizeof(onoff)) < 0) {
		perror("SCTP_RECVRCVINFO");
		exit(1);
	}

	/* Start the echo server. */
	echo (fd);
	return (0);
}