.TH gen_sctp 3erl "kernel 7.2" "Ericsson AB" "Erlang Module Definition" .SH NAME gen_sctp \- Functions for communicating with sockets using the SCTP protocol. .SH DESCRIPTION .LP This module provides functions for communicating with sockets using the SCTP protocol\&. The implementation assumes that the OS kernel supports SCTP (RFC 2960) through the user-level Sockets API Extensions\&. .LP During development, this implementation was tested on: .RS 2 .TP 2 * Linux Fedora Core 5\&.0 (kernel 2\&.6\&.15-2054 or later is needed) .LP .TP 2 * Solaris 10, 11 .LP .RE .LP During OTP adaptation it was tested on: .RS 2 .TP 2 * SUSE Linux Enterprise Server 10 (x86_64) kernel 2\&.6\&.16\&.27-0\&.6-smp, with lksctp-tools-1\&.0\&.6 .LP .TP 2 * Briefly on Solaris 10 .LP .TP 2 * SUSE Linux Enterprise Server 10 Service Pack 1 (x86_64) kernel 2\&.6\&.16\&.54-0\&.2\&.3-smp with lksctp-tools-1\&.0\&.7 .LP .TP 2 * FreeBSD 8\&.2 .LP .RE .LP This module was written for one-to-many style sockets (type \fIseqpacket\fR\&)\&. With the addition of \fIpeeloff/2\fR\&, one-to-one style sockets (type \fIstream\fR\&) were introduced\&. .LP Record definitions for this module can be found using: .LP .nf -include_lib("kernel/include/inet_sctp.hrl"). .fi .LP These record definitions use the "new" spelling \&'adaptation\&', not the deprecated \&'adaption\&', regardless of which spelling the underlying C API uses\&. .SH DATA TYPES .nf .B assoc_id() .br .fi .RS .LP An opaque term returned in, for example, \fI#sctp_paddr_change{}\fR\&, which identifies an association for an SCTP socket\&. The term is opaque except for the special value \fI0\fR\&, which has a meaning such as "the whole endpoint" or "all future associations"\&. .RE .nf \fBoption()\fR\& = .br {active, true | false | once | -32768\&.\&.32767} | .br {buffer, integer() >= 0} | .br {dontroute, boolean()} | .br {high_msgq_watermark, integer() >= 1} | .br {linger, {boolean(), integer() >= 0}} | .br {low_msgq_watermark, integer() >= 1} | .br {mode, list | binary} | .br list | binary | .br {priority, integer() >= 0} | .br {recbuf, integer() >= 0} | .br {reuseaddr, boolean()} | .br {ipv6_v6only, boolean()} | .br {sctp_adaptation_layer, #sctp_setadaptation{}} | .br {sctp_associnfo, #sctp_assocparams{}} | .br {sctp_autoclose, integer() >= 0} | .br {sctp_default_send_param, #sctp_sndrcvinfo{}} | .br {sctp_delayed_ack_time, #sctp_assoc_value{}} | .br {sctp_disable_fragments, boolean()} | .br {sctp_events, #sctp_event_subscribe{}} | .br {sctp_get_peer_addr_info, #sctp_paddrinfo{}} | .br {sctp_i_want_mapped_v4_addr, boolean()} | .br {sctp_initmsg, #sctp_initmsg{}} | .br {sctp_maxseg, integer() >= 0} | .br {sctp_nodelay, boolean()} | .br {sctp_peer_addr_params, #sctp_paddrparams{}} | .br {sctp_primary_addr, #sctp_prim{}} | .br {sctp_rtoinfo, #sctp_rtoinfo{}} | .br {sctp_set_peer_primary_addr, #sctp_setpeerprim{}} | .br {sctp_status, #sctp_status{}} | .br {sndbuf, integer() >= 0} | .br {tos, integer() >= 0} | .br {tclass, integer() >= 0} | .br {ttl, integer() >= 0} | .br {recvtos, boolean()} | .br {recvtclass, boolean()} | .br {recvttl, boolean()} .br .fi .RS .LP One of the SCTP Socket Options\&. .RE .nf \fBoption_name()\fR\& = .br active | buffer | dontroute | high_msgq_watermark | linger | .br low_msgq_watermark | mode | priority | recbuf | reuseaddr | .br ipv6_v6only | sctp_adaptation_layer | sctp_associnfo | .br sctp_autoclose | sctp_default_send_param | .br sctp_delayed_ack_time | sctp_disable_fragments | sctp_events | .br sctp_get_peer_addr_info | sctp_i_want_mapped_v4_addr | .br sctp_initmsg | sctp_maxseg | sctp_nodelay | .br sctp_peer_addr_params | sctp_primary_addr | sctp_rtoinfo | .br sctp_set_peer_primary_addr | sctp_status | sndbuf | tos | .br tclass | ttl | recvtos | recvtclass | recvttl .br .fi .nf .B sctp_socket() .br .fi .RS .LP Socket identifier returned from \fIopen/*\fR\&\&. .RE .SH EXPORTS .LP .nf .B abort(Socket, Assoc) -> ok | {error, inet:posix()} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Assoc = #sctp_assoc_change{} .br .RE .RE .RS .LP Abnormally terminates the association specified by \fIAssoc\fR\&, without flushing of unsent data\&. The socket itself remains open\&. Other associations opened on this socket are still valid, and the socket can be used in new associations\&. .RE .LP .nf .B close(Socket) -> ok | {error, inet:posix()} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br .RE .RE .RS .LP Closes the socket and all associations on it\&. The unsent data is flushed as in \fIeof/2\fR\&\&. The \fIclose/1\fR\& call is blocking or otherwise depending of the value of the \fIlinger\fR\& socket option\&. If \fIclose\fR\& does not linger or linger time-out expires, the call returns and the data is flushed in the background\&. .RE .LP .nf .B connect(Socket, Addr, Port, Opts) -> .B {ok, #sctp_assoc_change{state = comm_up}} | .B {error, #sctp_assoc_change{state = cant_assoc}} | .B {error, inet:posix()} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Addr = inet:ip_address() | inet:hostname() .br Port = inet:port_number() .br Opts = [Opt :: option()] .br .RE .RE .RS .LP Same as \fIconnect(Socket, Addr, Port, Opts, infinity)\fR\&\&. .RE .LP .nf .B connect(Socket, Addr, Port, Opts, Timeout) -> .B {ok, #sctp_assoc_change{state = comm_up}} | .B {error, #sctp_assoc_change{state = cant_assoc}} | .B {error, inet:posix()} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Addr = inet:ip_address() | inet:hostname() .br Port = inet:port_number() .br Opts = [Opt :: option()] .br Timeout = timeout() .br .RE .RE .RS .LP Establishes a new association for socket \fISocket\fR\&, with the peer (SCTP server socket) specified by \fIAddr\fR\& and \fIPort\fR\&\&. \fITimeout\fR\&, is expressed in milliseconds\&. A socket can be associated with multiple peers\&. .LP .RS -4 .B Warning: .RE Using a value of \fITimeout\fR\& less than the maximum time taken by the OS to establish an association (around 4\&.5 minutes if the default values from RFC 4960 are used), can result in inconsistent or incorrect return values\&. This is especially relevant for associations sharing the same \fISocket\fR\& (that is, source address and port), as the controlling process blocks until \fIconnect/*\fR\& returns\&. \fIconnect_init/*\fR\& provides an alternative without this limitation\&. .LP The result of \fIconnect/*\fR\& is an \fI#sctp_assoc_change{}\fR\& event that contains, in particular, the new Association ID: .LP .nf #sctp_assoc_change{ state = atom(), error = integer(), outbound_streams = integer(), inbound_streams = integer(), assoc_id = assoc_id() } .fi .LP The number of outbound and inbound streams can be set by giving an \fIsctp_initmsg\fR\& option to \fIconnect\fR\& as in: .LP .nf connect(Socket, Ip, Port>, [{sctp_initmsg,#sctp_initmsg{num_ostreams=OutStreams, max_instreams=MaxInStreams}}]) .fi .LP All options \fIOpt\fR\& are set on the socket before the association is attempted\&. If an option record has undefined field values, the options record is first read from the socket for those values\&. In effect, \fIOpt\fR\& option records only define field values to change before connecting\&. .LP The returned \fIoutbound_streams\fR\& and \fIinbound_streams\fR\& are the stream numbers on the socket\&. These can be different from the requested values (\fIOutStreams\fR\& and \fIMaxInStreams\fR\&, respectively) if the peer requires lower values\&. .LP \fIstate\fR\& can have the following values: .RS 2 .TP 2 .B \fIcomm_up\fR\&: Association is successfully established\&. This indicates a successful completion of \fIconnect\fR\&\&. .TP 2 .B \fIcant_assoc\fR\&: The association cannot be established (\fIconnect/*\fR\& failure)\&. .RE .LP Other states do not normally occur in the output from \fIconnect/*\fR\&\&. Rather, they can occur in \fI#sctp_assoc_change{}\fR\& events received instead of data in \fIrecv/*\fR\& calls\&. All of them indicate losing the association because of various error conditions, and are listed here for the sake of completeness: .RS 2 .TP 2 .B \fIcomm_lost\fR\&: .TP 2 .B \fIrestart\fR\&: .TP 2 .B \fIshutdown_comp\fR\&: .RE .LP Field \fIerror\fR\& can provide more detailed diagnostics\&. The \fIerror\fR\& field value can be converted into a string using \fIerror_string/1\fR\&\&. .RE .LP .nf .B connect_init(Socket, Addr, Port, Opts) -> .B ok | {error, inet:posix()} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Addr = inet:ip_address() | inet:hostname() .br Port = inet:port_number() .br Opts = [option()] .br .RE .RE .RS .LP Same as \fIconnect_init(Socket, Addr, Port, Opts, infinity)\fR\&\&. .RE .LP .nf .B connect_init(Socket, Addr, Port, Opts, Timeout) -> .B ok | {error, inet:posix()} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Addr = inet:ip_address() | inet:hostname() .br Port = inet:port_number() .br Opts = [option()] .br Timeout = timeout() .br .RE .RE .RS .LP Initiates a new association for socket \fISocket\fR\&, with the peer (SCTP server socket) specified by \fIAddr\fR\& and \fIPort\fR\&\&. .LP The fundamental difference between this API and \fIconnect/*\fR\& is that the return value is that of the underlying OS \fIconnect(2)\fR\& system call\&. If \fIok\fR\& is returned, the result of the association establishment is received by the calling process as an \fI#sctp_assoc_change{}\fR\& event\&. The calling process must be prepared to receive this, or poll for it using \fIrecv/*\fR\&, depending on the value of the active option\&. .LP The parameters are as described in \fIconnect/*\fR\&, except the \fITimeout\fR\& value\&. .LP The timer associated with \fITimeout\fR\& only supervises IP resolution of \fIAddr\fR\&\&. .RE .LP .nf .B controlling_process(Socket, Pid) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Pid = pid() .br Reason = closed | not_owner | badarg | inet:posix() .br .RE .RE .RS .LP Assigns a new controlling process \fIPid\fR\& to \fISocket\fR\&\&. Same implementation as \fIgen_udp:controlling_process/2\fR\&\&. .RE .LP .nf .B eof(Socket, Assoc) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Assoc = #sctp_assoc_change{} .br Reason = term() .br .RE .RE .RS .LP Gracefully terminates the association specified by \fIAssoc\fR\&, with flushing of all unsent data\&. The socket itself remains open\&. Other associations opened on this socket are still valid\&. The socket can be used in new associations\&. .RE .LP .nf .B error_string(ErrorNumber) -> ok | string() | unknown_error .br .fi .br .RS .LP Types: .RS 3 ErrorNumber = integer() .br .RE .RE .RS .LP Translates an SCTP error number from, for example, \fI#sctp_remote_error{}\fR\& or \fI#sctp_send_failed{}\fR\& into an explanatory string, or one of the atoms \fIok\fR\& for no error or \fIundefined\fR\& for an unrecognized error\&. .RE .LP .nf .B listen(Socket, IsServer) -> ok | {error, Reason} .br .fi .br .nf .B listen(Socket, Backlog) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Backlog = integer() .br Reason = term() .br .RE .RE .RS .LP Sets up a socket to listen on the IP address and port number it is bound to\&. .LP For type \fIseqpacket\fR\&, sockets (the default) \fIIsServer\fR\& must be \fItrue\fR\& or \fIfalse\fR\&\&. In contrast to TCP, there is no listening queue length in SCTP\&. If \fIIsServer\fR\& is \fItrue\fR\&, the socket accepts new associations, that is, it becomes an SCTP server socket\&. .LP For type \fIstream\fR\&, sockets Backlog define the backlog queue length just like in TCP\&. .RE .LP .nf .B open() -> {ok, Socket} | {error, inet:posix()} .br .fi .br .nf .B open(Port) -> {ok, Socket} | {error, inet:posix()} .br .fi .br .nf .B open(Opts) -> {ok, Socket} | {error, inet:posix()} .br .fi .br .nf .B open(Port, Opts) -> {ok, Socket} | {error, inet:posix()} .br .fi .br .RS .LP Types: .RS 3 Opts = [Opt] .br Opt = .br {ip, IP} | .br {ifaddr, IP} | .br inet:address_family() | .br {port, Port} | .br {type, SockType} | .br option() .br IP = inet:ip_address() | any | loopback .br Port = inet:port_number() .br SockType = seqpacket | stream .br Socket = sctp_socket() .br .RE .RE .RS .LP Creates an SCTP socket and binds it to the local addresses specified by all \fI{ip,IP}\fR\& (or synonymously \fI{ifaddr,IP}\fR\&) options (this feature is called SCTP multi-homing)\&. The default \fIIP\fR\& and \fIPort\fR\& are \fIany\fR\& and \fI0\fR\&, meaning bind to all local addresses on any free port\&. .LP Other options: .RS 2 .TP 2 .B \fIinet6\fR\&: Sets up the socket for IPv6\&. .TP 2 .B \fIinet\fR\&: Sets up the socket for IPv4\&. This is the default\&. .RE .LP A default set of socket options is used\&. In particular, the socket is opened in binary and passive mode, with SockType \fIseqpacket\fR\&, and with reasonably large kernel and driver buffers\&. .LP If the socket is in passive mode data can be received through the \fIrecv/1,2\fR\& calls\&. .LP If the socket is in active mode data received data is delivered to the controlling process as messages: .LP .nf {sctp, Socket, FromIP, FromPort, {AncData, Data}} .fi .LP See \fIrecv/1,2\fR\& for a description of the message fields\&. .LP .RS -4 .B Note: .RE This message format unfortunately differs slightly from the \fIgen_udp\fR\& message format with ancillary data, and from the \fIrecv/1,2\fR\& return tuple format\&. .RE .LP .nf .B peeloff(Socket, Assoc) -> {ok, NewSocket} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Assoc = #sctp_assoc_change{} | assoc_id() .br NewSocket = sctp_socket() .br Reason = term() .br .RE .RE .RS .LP Branches off an existing association \fIAssoc\fR\& in a socket \fISocket\fR\& of type \fIseqpacket\fR\& (one-to-many style) into a new socket \fINewSocket\fR\& of type \fIstream\fR\& (one-to-one style)\&. .LP The existing association argument \fIAssoc\fR\& can be either a \fI#sctp_assoc_change{}\fR\& record as returned from, for example, \fIrecv/*\fR\&, \fIconnect/*\fR\&, or from a listening socket in active mode\&. It can also be just the field \fIassoc_id\fR\& integer from such a record\&. .RE .LP .nf .B recv(Socket) -> .B {ok, {FromIP, FromPort, AncData, Data}} | {error, Reason} .br .fi .br .nf .B recv(Socket, Timeout) -> .B {ok, {FromIP, FromPort, AncData, Data}} | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Timeout = timeout() .br FromIP = inet:ip_address() .br FromPort = inet:port_number() .br AncData = [#sctp_sndrcvinfo{} | inet:ancillary_data()] .br Data = .br binary() | .br string() | .br #sctp_sndrcvinfo{} | .br #sctp_assoc_change{} | .br #sctp_paddr_change{} | .br #sctp_adaptation_event{} .br Reason = .br inet:posix() | .br #sctp_send_failed{} | .br #sctp_paddr_change{} | .br #sctp_pdapi_event{} | .br #sctp_remote_error{} | .br #sctp_shutdown_event{} .br .RE .RE .RS .LP Receives the \fIData\fR\& message from any association of the socket\&. If the receive times out, \fI{error,timeout}\fR\& is returned\&. The default time-out is \fIinfinity\fR\&\&. \fIFromIP\fR\& and \fIFromPort\fR\& indicate the address of the sender\&. .LP \fIAncData\fR\& is a list of ancillary data items that can be received along with the main \fIData\fR\&\&. This list can be empty, or contain a single \fI#sctp_sndrcvinfo{}\fR\& record if receiving of such ancillary data is enabled (see option \fIsctp_events\fR\&)\&. It is enabled by default, as such ancillary data provides an easy way of determining the association and stream over which the message is received\&. (An alternative way is to get the association ID from \fIFromIP\fR\& and \fIFromPort\fR\& using socket option \fIsctp_get_peer_addr_info\fR\&, but this does still not produce the stream number)\&. .LP \fIAncData\fR\& may also contain ancillary data from the socket options \fIrecvtos\fR\&, \fIrecvtclass\fR\& or \fIrecvttl\fR\&, if that is supported by the platform for the socket\&. .LP The \fIData\fR\& received can be a \fIbinary()\fR\& or a \fIlist()\fR\& of bytes (integers in the range 0 through 255) depending on the socket mode, or an SCTP event\&. .LP Possible SCTP events: .RS 2 .TP 2 * \fI#sctp_sndrcvinfo{}\fR\& .LP .TP 2 * \fI#sctp_assoc_change{}\fR\& .LP .TP 2 * .LP .nf #sctp_paddr_change{ addr = {ip_address(),port()}, state = atom(), error = integer(), assoc_id = assoc_id() } .fi .RS 2 .LP Indicates change of the status of the IP address of the peer specified by \fIaddr\fR\& within association \fIassoc_id\fR\&\&. Possible values of \fIstate\fR\& (mostly self-explanatory) include: .RE .RS 2 .TP 2 .B \fIaddr_unreachable\fR\&: .TP 2 .B \fIaddr_available\fR\&: .TP 2 .B \fIaddr_removed\fR\&: .TP 2 .B \fIaddr_added\fR\&: .TP 2 .B \fIaddr_made_prim\fR\&: .TP 2 .B \fIaddr_confirmed\fR\&: .RE .RS 2 .LP In case of an error (for example, \fIaddr_unreachable\fR\&), field \fIerror\fR\& provides more diagnostics\&. In such cases, event \fI#sctp_paddr_change{}\fR\& is automatically converted into an \fIerror\fR\& term returned by \fIrecv\fR\&\&. The \fIerror\fR\& field value can be converted into a string using \fIerror_string/1\fR\&\&. .RE .LP .TP 2 * .LP .nf #sctp_send_failed{ flags = true | false, error = integer(), info = #sctp_sndrcvinfo{}, assoc_id = assoc_id() data = binary() } .fi .RS 2 .LP The sender can receive this event if a send operation fails\&. .RE .RS 2 .TP 2 .B \fIflags\fR\&: A Boolean specifying if the data has been transmitted over the wire\&. .TP 2 .B \fIerror\fR\&: Provides extended diagnostics, use \fIerror_string/1\fR\&\&. .TP 2 .B \fIinfo\fR\&: The original \fI#sctp_sndrcvinfo{}\fR\& record used in the failed \fIsend/*\fR\&\&. .TP 2 .B \fIdata\fR\&: The whole original data chunk attempted to be sent\&. .RE .RS 2 .LP In the current implementation of the Erlang/SCTP binding, this event is internally converted into an \fIerror\fR\& term returned by \fIrecv/*\fR\&\&. .RE .LP .TP 2 * .LP .nf #sctp_adaptation_event{ adaptation_ind = integer(), assoc_id = assoc_id() } .fi .RS 2 .LP Delivered when a peer sends an adaptation layer indication parameter (configured through option \fIsctp_adaptation_layer\fR\&)\&. Notice that with the current implementation of the Erlang/SCTP binding, this event is disabled by default\&. .RE .LP .TP 2 * .LP .nf #sctp_pdapi_event{ indication = sctp_partial_delivery_aborted, assoc_id = assoc_id() } .fi .RS 2 .LP A partial delivery failure\&. In the current implementation of the Erlang/SCTP binding, this event is internally converted into an \fIerror\fR\& term returned by \fIrecv/*\fR\&\&. .RE .LP .RE .RE .LP .nf .B send(Socket, SndRcvInfo, Data) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br SndRcvInfo = #sctp_sndrcvinfo{} .br Data = binary() | iolist() .br Reason = term() .br .RE .RE .RS .LP Sends the \fIData\fR\& message with all sending parameters from a \fI#sctp_sndrcvinfo{}\fR\& record\&. This way, the user can specify the PPID (passed to the remote end) and context (passed to the local SCTP layer), which can be used, for example, for error identification\&. However, such a fine level of user control is rarely required\&. The function \fIsend/4\fR\& is sufficient for most applications\&. .RE .LP .nf .B send(Socket, Assoc, Stream, Data) -> ok | {error, Reason} .br .fi .br .RS .LP Types: .RS 3 Socket = sctp_socket() .br Assoc = #sctp_assoc_change{} | assoc_id() .br Stream = integer() .br Data = binary() | iolist() .br Reason = term() .br .RE .RE .RS .LP Sends a \fIData\fR\& message over an existing association and specified stream\&. .RE .SH "SCTP SOCKET OPTIONS" .LP The set of admissible SCTP socket options is by construction orthogonal to the sets of TCP, UDP, and generic \fIinet\fR\& options\&. Only options listed here are allowed for SCTP sockets\&. Options can be set on the socket using \fIopen/1,2\fR\& or \fIinet:setopts/2\fR\&, retrieved using \fIinet:getopts/2\fR\&\&. Options can be changed when calling \fIconnect/4,5\fR\&\&. .RS 2 .TP 2 .B \fI{mode, list|binary}\fR\& or just \fIlist\fR\& or \fIbinary\fR\&: Determines the type of data returned from \fIrecv/1,2\fR\&\&. .TP 2 .B \fI{active, true|false|once|N}\fR\&: .RS 2 .TP 2 * If \fIfalse\fR\& (passive mode, the default), the caller must do an explicit \fIrecv\fR\& call to retrieve the available data from the socket\&. .LP .TP 2 * If \fItrue|once|N\fR\& (active modes) received data or events are sent to the owning process\&. See \fIopen/0\&.\&.2\fR\& for the message format\&. .LP .TP 2 * If \fItrue\fR\& (full active mode) there is no flow control\&. .LP .RS -4 .B Note: .RE Note that this can cause the message queue to overflow causing for example the virtual machine to run out of memory and crash\&. .LP .TP 2 * If \fIonce\fR\&, only one message is automatically placed in the message queue, and after that the mode is automatically reset to passive\&. This provides flow control and the possibility for the receiver to listen for its incoming SCTP data interleaved with other inter-process messages\&. .LP .TP 2 * If \fIactive\fR\& is specified as an integer \fIN\fR\& in the range -32768 to 32767 (inclusive), that number is added to the socket\&'s counting of data messages to be delivered to the controlling process\&. If the result of the addition is negative, the count is set to \fI0\fR\&\&. Once the count reaches \fI0\fR\&, either through the delivery of messages or by being explicitly set with \fIinet:setopts/2\fR\&, the socket mode is automatically reset to passive (\fI{active, false}\fR\&)\&. When a socket in this active mode transitions to passive mode, the message \fI{sctp_passive, Socket}\fR\& is sent to the controlling process to notify it that if it wants to receive more data messages from the socket, it must call \fIinet:setopts/2\fR\& to set the socket back into an active mode\&. .LP .RE .TP 2 .B \fI{tos, integer()}\fR\&: Sets the Type-Of-Service field on the IP datagrams that are sent, to the specified value\&. This effectively determines a prioritization policy for the outbound packets\&. The acceptable values are system-dependent\&. .TP 2 .B \fI{priority, integer()}\fR\&: A protocol-independent equivalent of \fItos\fR\& above\&. Setting priority implies setting \fItos\fR\& as well\&. .TP 2 .B \fI{dontroute, true|false}\fR\&: Defaults to \fIfalse\fR\&\&. If \fItrue\fR\&, the kernel does not send packets through any gateway, only sends them to directly connected hosts\&. .TP 2 .B \fI{reuseaddr, true|false}\fR\&: Defaults to \fIfalse\fR\&\&. If true, the local binding address \fI{IP,Port}\fR\& of the socket can be reused immediately\&. No waiting in state \fICLOSE_WAIT\fR\& is performed (can be required for high-throughput servers)\&. .TP 2 .B \fI{sndbuf, integer()}\fR\&: The size, in bytes, of the OS kernel send buffer for this socket\&. Sending errors would occur for datagrams larger than \fIval(sndbuf)\fR\&\&. Setting this option also adjusts the size of the driver buffer (see \fIbuffer\fR\& above)\&. .TP 2 .B \fI{recbuf, integer()}\fR\&: The size, in bytes, of the OS kernel receive buffer for this socket\&. Sending errors would occur for datagrams larger than \fIval(recbuf)\fR\&\&. Setting this option also adjusts the size of the driver buffer (see \fIbuffer\fR\& above)\&. .TP 2 .B \fI{sctp_module, module()}\fR\&: Overrides which callback module is used\&. Defaults to \fIinet_sctp\fR\& for IPv4 and \fIinet6_sctp\fR\& for IPv6\&. .TP 2 .B \fI{sctp_rtoinfo, #sctp_rtoinfo{}}\fR\&: .LP .nf #sctp_rtoinfo{ assoc_id = assoc_id(), initial = integer(), max = integer(), min = integer() } .fi .RS 2 .LP Determines retransmission time-out parameters, in milliseconds, for the association(s) specified by \fIassoc_id\fR\&\&. .RE .RS 2 .LP \fIassoc_id = 0\fR\& (default) indicates the whole endpoint\&. See RFC 2960 and Sockets API Extensions for SCTP for the exact semantics of the field values\&. .RE .TP 2 .B \fI{sctp_associnfo, #sctp_assocparams{}}\fR\&: .LP .nf #sctp_assocparams{ assoc_id = assoc_id(), asocmaxrxt = integer(), number_peer_destinations = integer(), peer_rwnd = integer(), local_rwnd = integer(), cookie_life = integer() } .fi .RS 2 .LP Determines association parameters for the association(s) specified by \fIassoc_id\fR\&\&. .RE .RS 2 .LP \fIassoc_id = 0\fR\& (default) indicates the whole endpoint\&. See Sockets API Extensions for SCTP for the discussion of their semantics\&. Rarely used\&. .RE .TP 2 .B \fI{sctp_initmsg, #sctp_initmsg{}}\fR\&: .LP .nf #sctp_initmsg{ num_ostreams = integer(), max_instreams = integer(), max_attempts = integer(), max_init_timeo = integer() } .fi .RS 2 .LP Determines the default parameters that this socket tries to negotiate with its peer while establishing an association with it\&. Is to be set after \fIopen/*\fR\& but before the first \fIconnect/*\fR\&\&. \fI#sctp_initmsg{}\fR\& can also be used as ancillary data with the first call of \fIsend/*\fR\& to a new peer (when a new association is created)\&. .RE .RS 2 .TP 2 .B \fInum_ostreams\fR\&: Number of outbound streams .TP 2 .B \fImax_instreams\fR\&: Maximum number of inbound streams .TP 2 .B \fImax_attempts\fR\&: Maximum retransmissions while establishing an association .TP 2 .B \fImax_init_timeo\fR\&: Time-out, in milliseconds, for establishing an association .RE .TP 2 .B \fI{sctp_autoclose, integer() >= 0}\fR\&: Determines the time, in seconds, after which an idle association is automatically closed\&. \fI0\fR\& means that the association is never automatically closed\&. .TP 2 .B \fI{sctp_nodelay, true|false}\fR\&: Turns on|off the Nagle algorithm for merging small packets into larger ones\&. This improves throughput at the expense of latency\&. .TP 2 .B \fI{sctp_disable_fragments, true|false}\fR\&: If \fItrue\fR\&, induces an error on an attempt to send a message larger than the current PMTU size (which would require fragmentation/reassembling)\&. Notice that message fragmentation does not affect the logical atomicity of its delivery; this option is provided for performance reasons only\&. .TP 2 .B \fI{sctp_i_want_mapped_v4_addr, true|false}\fR\&: Turns on|off automatic mapping of IPv4 addresses into IPv6 ones (if the socket address family is \fIAF_INET6\fR\&)\&. .TP 2 .B \fI{sctp_maxseg, integer()}\fR\&: Determines the maximum chunk size if message fragmentation is used\&. If \fI0\fR\&, the chunk size is limited by the Path MTU only\&. .TP 2 .B \fI{sctp_primary_addr, #sctp_prim{}}\fR\&: .LP .nf #sctp_prim{ assoc_id = assoc_id(), addr = {IP, Port} } IP = ip_address() Port = port_number() .fi .RS 2 .LP For the association specified by \fIassoc_id\fR\&, \fI{IP,Port}\fR\& must be one of the peer addresses\&. This option determines that the specified address is treated by the local SCTP stack as the primary address of the peer\&. .RE .TP 2 .B \fI{sctp_set_peer_primary_addr, #sctp_setpeerprim{}}\fR\&: .LP .nf #sctp_setpeerprim{ assoc_id = assoc_id(), addr = {IP, Port} } IP = ip_address() Port = port_number() .fi .RS 2 .LP When set, informs the peer to use \fI{IP, Port}\fR\& as the primary address of the local endpoint for the association specified by \fIassoc_id\fR\&\&. .RE .TP 2 .B \fI{sctp_adaptation_layer, #sctp_setadaptation{}}\fR\&: .LP .nf #sctp_setadaptation{ adaptation_ind = integer() } .fi .RS 2 .LP When set, requests that the local endpoint uses the value specified by \fIadaptation_ind\fR\& as the Adaptation Indication parameter for establishing new associations\&. For details, see RFC 2960 and Sockets API Extenstions for SCTP\&. .RE .TP 2 .B \fI{sctp_peer_addr_params, #sctp_paddrparams{}}\fR\&: .LP .nf #sctp_paddrparams{ assoc_id = assoc_id(), address = {IP, Port}, hbinterval = integer(), pathmaxrxt = integer(), pathmtu = integer(), sackdelay = integer(), flags = list() } IP = ip_address() Port = port_number() .fi .RS 2 .LP Determines various per-address parameters for the association specified by \fIassoc_id\fR\& and the peer address \fIaddress\fR\& (the SCTP protocol supports multi-homing, so more than one address can correspond to a specified association)\&. .RE .RS 2 .TP 2 .B \fIhbinterval\fR\&: Heartbeat interval, in milliseconds .TP 2 .B \fIpathmaxrxt\fR\&: Maximum number of retransmissions before this address is considered unreachable (and an alternative address is selected) .TP 2 .B \fIpathmtu\fR\&: Fixed Path MTU, if automatic discovery is disabled (see \fIflags\fR\& below) .TP 2 .B \fIsackdelay\fR\&: Delay, in milliseconds, for SAC messages (if the delay is enabled, see \fIflags\fR\& below) .TP 2 .B \fIflags\fR\&: The following flags are available: .RS 2 .TP 2 .B \fIhb_enable\fR\&: Enables heartbeat .TP 2 .B \fIhb_disable\fR\&: Disables heartbeat .TP 2 .B \fIhb_demand\fR\&: Initiates heartbeat immediately .TP 2 .B \fIpmtud_enable\fR\&: Enables automatic Path MTU discovery .TP 2 .B \fIpmtud_disable\fR\&: Disables automatic Path MTU discovery .TP 2 .B \fIsackdelay_enable\fR\&: Enables SAC delay .TP 2 .B \fIsackdelay_disable\fR\&: Disables SAC delay .RE .RE .TP 2 .B \fI{sctp_default_send_param, #sctp_sndrcvinfo{}}\fR\&: .LP .nf #sctp_sndrcvinfo{ stream = integer(), ssn = integer(), flags = list(), ppid = integer(), context = integer(), timetolive = integer(), tsn = integer(), cumtsn = integer(), assoc_id = assoc_id() } .fi .RS 2 .LP \fI#sctp_sndrcvinfo{}\fR\& is used both in this socket option, and as ancillary data while sending or receiving SCTP messages\&. When set as an option, it provides default values for subsequent \fIsend\fR\& calls on the association specified by \fIassoc_id\fR\&\&. .RE .RS 2 .LP \fIassoc_id = 0\fR\& (default) indicates the whole endpoint\&. .RE .RS 2 .LP The following fields typically must be specified by the sender: .RE .RS 2 .TP 2 .B \fIsinfo_stream\fR\&: Stream number (0-base) within the association to send the messages through; .TP 2 .B \fIsinfo_flags\fR\&: The following flags are recognised: .RS 2 .TP 2 .B \fIunordered\fR\&: The message is to be sent unordered .TP 2 .B \fIaddr_over\fR\&: The address specified in \fIsend\fR\& overwrites the primary peer address .TP 2 .B \fIabort\fR\&: Aborts the current association without flushing any unsent data .TP 2 .B \fIeof\fR\&: Gracefully shuts down the current association, with flushing of unsent data .RE .RS 2 .LP Other fields are rarely used\&. For complete information, see RFC 2960 and Sockets API Extensions for SCTP\&. .RE .RE .TP 2 .B \fI{sctp_events, #sctp_event_subscribe{}}\fR\&: .LP .nf #sctp_event_subscribe{ data_io_event = true | false, association_event = true | false, address_event = true | false, send_failure_event = true | false, peer_error_event = true | false, shutdown_event = true | false, partial_delivery_event = true | false, adaptation_layer_event = true | false } .fi .RS 2 .LP This option determines which SCTP Events are to be received (through \fIrecv/*\fR\&) along with the data\&. The only exception is \fIdata_io_event\fR\&, which enables or disables receiving of \fI#sctp_sndrcvinfo{}\fR\& ancillary data, not events\&. By default, all flags except \fIadaptation_layer_event\fR\& are enabled, although \fIsctp_data_io_event\fR\& and \fIassociation_event\fR\& are used by the driver itself and not exported to the user level\&. .RE .TP 2 .B \fI{sctp_delayed_ack_time, #sctp_assoc_value{}}\fR\&: .LP .nf #sctp_assoc_value{ assoc_id = assoc_id(), assoc_value = integer() } .fi .RS 2 .LP Rarely used\&. Determines the ACK time (specified by \fIassoc_value\fR\&, in milliseconds) for the specified association or the whole endpoint if \fIassoc_value = 0\fR\& (default)\&. .RE .TP 2 .B \fI{sctp_status, #sctp_status{}}\fR\&: .LP .nf #sctp_status{ assoc_id = assoc_id(), state = atom(), rwnd = integer(), unackdata = integer(), penddata = integer(), instrms = integer(), outstrms = integer(), fragmentation_point = integer(), primary = #sctp_paddrinfo{} } .fi .RS 2 .LP This option is read-only\&. It determines the status of the SCTP association specified by \fIassoc_id\fR\&\&. The following are the possible values of \fIstate\fR\& (the state designations are mostly self-explanatory): .RE .RS 2 .TP 2 .B \fIsctp_state_empty\fR\&: Default\&. Means that no other state is active\&. .TP 2 .B \fIsctp_state_closed\fR\&: .TP 2 .B \fIsctp_state_cookie_wait\fR\&: .TP 2 .B \fIsctp_state_cookie_echoed\fR\&: .TP 2 .B \fIsctp_state_established\fR\&: .TP 2 .B \fIsctp_state_shutdown_pending\fR\&: .TP 2 .B \fIsctp_state_shutdown_sent\fR\&: .TP 2 .B \fIsctp_state_shutdown_received\fR\&: .TP 2 .B \fIsctp_state_shutdown_ack_sent\fR\&: .RE .RS 2 .LP Semantics of the other fields: .RE .RS 2 .TP 2 .B \fIsstat_rwnd\fR\&: Current receiver window size of the association .TP 2 .B \fIsstat_unackdata\fR\&: Number of unacked data chunks .TP 2 .B \fIsstat_penddata\fR\&: Number of data chunks pending receipt .TP 2 .B \fIsstat_instrms\fR\&: Number of inbound streams .TP 2 .B \fIsstat_outstrms\fR\&: Number of outbound streams .TP 2 .B \fIsstat_fragmentation_point\fR\&: Message size at which SCTP fragmentation occurs .TP 2 .B \fIsstat_primary\fR\&: Information on the current primary peer address (see below for the format of \fI#sctp_paddrinfo{}\fR\&) .RE .TP 2 .B \fI{sctp_get_peer_addr_info, #sctp_paddrinfo{}}\fR\&: .LP .nf #sctp_paddrinfo{ assoc_id = assoc_id(), address = {IP, Port}, state = inactive | active | unconfirmed, cwnd = integer(), srtt = integer(), rto = integer(), mtu = integer() } IP = ip_address() Port = port_number() .fi .RS 2 .LP This option is read-only\&. It determines the parameters specific to the peer address specified by \fIaddress\fR\& within the association specified by \fIassoc_id\fR\&\&. Field \fIaddress\fR\& fmust be set by the caller; all other fields are filled in on return\&. If \fIassoc_id = 0\fR\& (default), the \fIaddress\fR\& is automatically translated into the corresponding association ID\&. This option is rarely used\&. For the semantics of all fields, see RFC 2960 and Sockets API Extensions for SCTP\&. .RE .RE .SH "SCTP EXAMPLES" .LP Example of an Erlang SCTP server that receives SCTP messages and prints them on the standard output: .LP .nf -module(sctp_server). -export([server/0,server/1,server/2]). -include_lib("kernel/include/inet.hrl"). -include_lib("kernel/include/inet_sctp.hrl"). server() -> server(any, 2006). server([Host,Port]) when is_list(Host), is_list(Port) -> {ok, #hostent{h_addr_list = [IP|_]}} = inet:gethostbyname(Host), io:format("~w -> ~w~n", [Host, IP]), server([IP, list_to_integer(Port)]). server(IP, Port) when is_tuple(IP) orelse IP == any orelse IP == loopback, is_integer(Port) -> {ok,S} = gen_sctp:open(Port, [{recbuf,65536}, {ip,IP}]), io:format("Listening on ~w:~w. ~w~n", [IP,Port,S]), ok = gen_sctp:listen(S, true), server_loop(S). server_loop(S) -> case gen_sctp:recv(S) of {error, Error} -> io:format("SCTP RECV ERROR: ~p~n", [Error]); Data -> io:format("Received: ~p~n", [Data]) end, server_loop(S). .fi .LP Example of an Erlang SCTP client interacting with the above server\&. Notice that in this example the client creates an association with the server with 5 outbound streams\&. Therefore, sending of \fI"Test 0"\fR\& over stream 0 succeeds, but sending of \fI"Test 5"\fR\& over stream 5 fails\&. The client then \fIabort\fR\&s the association, which results in that the corresponding event is received on the server side\&. .LP .nf -module(sctp_client). -export([client/0, client/1, client/2]). -include_lib("kernel/include/inet.hrl"). -include_lib("kernel/include/inet_sctp.hrl"). client() -> client([localhost]). client([Host]) -> client(Host, 2006); client([Host, Port]) when is_list(Host), is_list(Port) -> client(Host,list_to_integer(Port)), init:stop(). client(Host, Port) when is_integer(Port) -> {ok,S} = gen_sctp:open(), {ok,Assoc} = gen_sctp:connect (S, Host, Port, [{sctp_initmsg,#sctp_initmsg{num_ostreams=5}}]), io:format("Connection Successful, Assoc=~p~n", [Assoc]), io:write(gen_sctp:send(S, Assoc, 0, <<"Test 0">>)), io:nl(), timer:sleep(10000), io:write(gen_sctp:send(S, Assoc, 5, <<"Test 5">>)), io:nl(), timer:sleep(10000), io:write(gen_sctp:abort(S, Assoc)), io:nl(), timer:sleep(1000), gen_sctp:close(S). .fi .LP A simple Erlang SCTP client that uses the \fIconnect_init\fR\& API: .LP .nf -module(ex3). -export([client/4]). -include_lib("kernel/include/inet.hrl"). -include_lib("kernel/include/inet_sctp.hrl"). client(Peer1, Port1, Peer2, Port2) when is_tuple(Peer1), is_integer(Port1), is_tuple(Peer2), is_integer(Port2) -> {ok,S} = gen_sctp:open(), SctpInitMsgOpt = {sctp_initmsg,#sctp_initmsg{num_ostreams=5}}, ActiveOpt = {active, true}, Opts = [SctpInitMsgOpt, ActiveOpt], ok = gen_sctp:connect(S, Peer1, Port1, Opts), ok = gen_sctp:connect(S, Peer2, Port2, Opts), io:format("Connections initiated~n", []), client_loop(S, Peer1, Port1, undefined, Peer2, Port2, undefined). client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2) -> receive {sctp, S, Peer1, Port1, {_Anc, SAC}} when is_record(SAC, sctp_assoc_change), AssocId1 == undefined -> io:format("Association 1 connect result: ~p. AssocId: ~p~n", [SAC#sctp_assoc_change.state, SAC#sctp_assoc_change.assoc_id]), client_loop(S, Peer1, Port1, SAC#sctp_assoc_change.assoc_id, Peer2, Port2, AssocId2); {sctp, S, Peer2, Port2, {_Anc, SAC}} when is_record(SAC, sctp_assoc_change), AssocId2 == undefined -> io:format("Association 2 connect result: ~p. AssocId: ~p~n", [SAC#sctp_assoc_change.state, SAC#sctp_assoc_change.assoc_id]), client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, SAC#sctp_assoc_change.assoc_id); {sctp, S, Peer1, Port1, Data} -> io:format("Association 1: received ~p~n", [Data]), client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2); {sctp, S, Peer2, Port2, Data} -> io:format("Association 2: received ~p~n", [Data]), client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2); Other -> io:format("Other ~p~n", [Other]), client_loop(S, Peer1, Port1, AssocId1, Peer2, Port2, AssocId2) after 5000 -> ok end. .fi .SH "SEE ALSO" .LP \fIgen_tcp(3erl)\fR\&, \fIgen_udp(3erl)\fR\&, \fIinet(3erl)\fR\&, RFC 2960 (Stream Control Transmission Protocol), Sockets API Extensions for SCTP