Provided by: erlang-manpages_22.0.7+dfsg-1build1_all bug

NAME

       gen_sctp - Functions for communicating with sockets using the SCTP
           protocol.

DESCRIPTION

       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.

       During development, this implementation was tested on:

         * Linux Fedora Core 5.0 (kernel 2.6.15-2054 or later is needed)

         * Solaris 10, 11

       During OTP adaptation it was tested on:

         * SUSE  Linux  Enterprise  Server  10  (x86_64)  kernel  2.6.16.27-0.6-smp, with lksctp-
           tools-1.0.6

         * Briefly on Solaris 10

         * 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

         * FreeBSD 8.2

       This  module was written for one-to-many style sockets (type seqpacket). With the addition
       of peeloff/2, one-to-one style sockets (type stream) were introduced.

       Record definitions for this module can be found using:

       -include_lib("kernel/include/inet_sctp.hrl").

       These  record  definitions  use  the  "new"  spelling  'adaptation',  not  the  deprecated
       'adaption', regardless of which spelling the underlying C API uses.

DATA TYPES

       assoc_id()

              An  opaque term returned in, for example, #sctp_paddr_change{}, which identifies an
              association for an SCTP socket. The term is opaque except for the special value  0,
              which has a meaning such as "the whole endpoint" or "all future associations".

       option() =
           {active, true | false | once | -32768..32767} |
           {buffer, integer() >= 0} |
           {dontroute, boolean()} |
           {high_msgq_watermark, integer() >= 1} |
           {linger, {boolean(), integer() >= 0}} |
           {low_msgq_watermark, integer() >= 1} |
           {mode, list | binary} |
           list | binary |
           {priority, integer() >= 0} |
           {recbuf, integer() >= 0} |
           {reuseaddr, boolean()} |
           {ipv6_v6only, boolean()} |
           {sctp_adaptation_layer, #sctp_setadaptation{}} |
           {sctp_associnfo, #sctp_assocparams{}} |
           {sctp_autoclose, integer() >= 0} |
           {sctp_default_send_param, #sctp_sndrcvinfo{}} |
           {sctp_delayed_ack_time, #sctp_assoc_value{}} |
           {sctp_disable_fragments, boolean()} |
           {sctp_events, #sctp_event_subscribe{}} |
           {sctp_get_peer_addr_info, #sctp_paddrinfo{}} |
           {sctp_i_want_mapped_v4_addr, boolean()} |
           {sctp_initmsg, #sctp_initmsg{}} |
           {sctp_maxseg, integer() >= 0} |
           {sctp_nodelay, boolean()} |
           {sctp_peer_addr_params, #sctp_paddrparams{}} |
           {sctp_primary_addr, #sctp_prim{}} |
           {sctp_rtoinfo, #sctp_rtoinfo{}} |
           {sctp_set_peer_primary_addr, #sctp_setpeerprim{}} |
           {sctp_status, #sctp_status{}} |
           {sndbuf, integer() >= 0} |
           {tos, integer() >= 0} |
           {tclass, integer() >= 0} |
           {ttl, integer() >= 0} |
           {recvtos, boolean()} |
           {recvtclass, boolean()} |
           {recvttl, boolean()}

              One of the SCTP Socket Options.

       option_name() =
           active | buffer | dontroute | high_msgq_watermark | linger |
           low_msgq_watermark | mode | priority | recbuf | reuseaddr |
           ipv6_v6only | sctp_adaptation_layer | sctp_associnfo |
           sctp_autoclose | sctp_default_send_param |
           sctp_delayed_ack_time | sctp_disable_fragments | sctp_events |
           sctp_get_peer_addr_info | sctp_i_want_mapped_v4_addr |
           sctp_initmsg | sctp_maxseg | sctp_nodelay |
           sctp_peer_addr_params | sctp_primary_addr | sctp_rtoinfo |
           sctp_set_peer_primary_addr | sctp_status | sndbuf | tos |
           tclass | ttl | recvtos | recvtclass | recvttl

       sctp_socket()

              Socket identifier returned from open/*.

EXPORTS

       abort(Socket, Assoc) -> ok | {error, inet:posix()}

              Types:

                 Socket = sctp_socket()
                 Assoc = #sctp_assoc_change{}

              Abnormally  terminates  the  association  specified  by  Assoc, 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.

       close(Socket) -> ok | {error, inet:posix()}

              Types:

                 Socket = sctp_socket()

              Closes  the  socket  and  all  associations on it. The unsent data is flushed as in
              eof/2. The close/1 call is blocking or otherwise depending  of  the  value  of  the
              linger socket option. If close does not linger or linger time-out expires, the call
              returns and the data is flushed in the background.

       connect(Socket, Addr, Port, Opts) ->
                  {ok, Assoc} | {error, inet:posix()}

              Types:

                 Socket = sctp_socket()
                 Addr = inet:ip_address() | inet:hostname()
                 Port = inet:port_number()
                 Opts = [Opt :: option()]
                 Assoc = #sctp_assoc_change{}

              Same as connect(Socket, Addr, Port, Opts, infinity).

       connect(Socket, Addr, Port, Opts, Timeout) ->
                  {ok, Assoc} | {error, inet:posix()}

              Types:

                 Socket = sctp_socket()
                 Addr = inet:ip_address() | inet:hostname()
                 Port = inet:port_number()
                 Opts = [Opt :: option()]
                 Timeout = timeout()
                 Assoc = #sctp_assoc_change{}

              Establishes a new association for socket Socket, with the peer (SCTP server socket)
              specified  by Addr and Port. Timeout, is expressed in milliseconds. A socket can be
              associated with multiple peers.

          Warning:
              Using a value of Timeout 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  Socket (that is, source address and port), as the
              controlling process blocks until  connect/*  returns.  connect_init/*  provides  an
              alternative without this limitation.

              The  result  of  connect/*  is  an  #sctp_assoc_change{}  event  that  contains, in
              particular, the new Association ID:

              #sctp_assoc_change{
                    state             = atom(),
                    error             = atom(),
                    outbound_streams  = integer(),
                    inbound_streams   = integer(),
                    assoc_id          = assoc_id()
              }

              The number of outbound and inbound streams can be set  by  giving  an  sctp_initmsg
              option to connect as in:

              connect(Socket, Ip, Port>,
                    [{sctp_initmsg,#sctp_initmsg{num_ostreams=OutStreams,
                                                 max_instreams=MaxInStreams}}])

              All  options  Opt  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, Opt option records only define field values to
              change before connecting.

              The returned outbound_streams and inbound_streams are the  stream  numbers  on  the
              socket.   These  can  be  different  from  the  requested  values  (OutStreams  and
              MaxInStreams, respectively) if the peer requires lower values.

              state can have the following values:

                comm_up:
                  Association is successfully established. This indicates a successful completion
                  of connect.

                cant_assoc:
                  The association cannot be established (connect/* failure).

              Other  states  do not normally occur in the output from connect/*. Rather, they can
              occur in #sctp_assoc_change{} events received instead of data in recv/* calls.  All
              of  them  indicate  losing the association because of various error conditions, and
              are listed here for the sake of completeness:

                comm_lost:

                restart:

                shutdown_comp:

              Field error can provide more detailed diagnostics.

       connect_init(Socket, Addr, Port, Opts) ->
                       ok | {error, inet:posix()}

              Types:

                 Socket = sctp_socket()
                 Addr = inet:ip_address() | inet:hostname()
                 Port = inet:port_number()
                 Opts = [option()]

              Same as connect_init(Socket, Addr, Port, Opts, infinity).

       connect_init(Socket, Addr, Port, Opts, Timeout) ->
                       ok | {error, inet:posix()}

              Types:

                 Socket = sctp_socket()
                 Addr = inet:ip_address() | inet:hostname()
                 Port = inet:port_number()
                 Opts = [option()]
                 Timeout = timeout()

              Initiates a new association for socket Socket, with the peer (SCTP  server  socket)
              specified by Addr and Port.

              The  fundamental difference between this API and connect/* is that the return value
              is that of the underlying OS connect(2) system call. If ok is returned, the  result
              of  the  association  establishment  is  received  by  the  calling  process  as an
              #sctp_assoc_change{} event. The calling process must be prepared to  receive  this,
              or poll for it using recv/*, depending on the value of the active option.

              The parameters are as described in connect/*, except the Timeout value.

              The timer associated with Timeout only supervises IP resolution of Addr.

       controlling_process(Socket, Pid) -> ok | {error, Reason}

              Types:

                 Socket = sctp_socket()
                 Pid = pid()
                 Reason = closed | not_owner | badarg | inet:posix()

              Assigns   a   new  controlling  process  Pid  to  Socket.  Same  implementation  as
              gen_udp:controlling_process/2.

       eof(Socket, Assoc) -> ok | {error, Reason}

              Types:

                 Socket = sctp_socket()
                 Assoc = #sctp_assoc_change{}
                 Reason = term()

              Gracefully terminates the association specified by  Assoc,  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.

       error_string(ErrorNumber) -> ok | string() | unknown_error

              Types:

                 ErrorNumber = integer()

              Translates  an  SCTP  error  number  from,  for  example,  #sctp_remote_error{}  or
              #sctp_send_failed{} into an explanatory string, or one of the atoms ok for no error
              or undefined for an unrecognized error.

       listen(Socket, IsServer) -> ok | {error, Reason}

       listen(Socket, Backlog) -> ok | {error, Reason}

              Types:

                 Socket = sctp_socket()
                 Backlog = integer()
                 Reason = term()

              Sets up a socket to listen on the IP address and port number it is bound to.

              For type seqpacket, sockets (the default)  IsServer  must  be  true  or  false.  In
              contrast  to  TCP, there is no listening queue length in SCTP. If IsServer is true,
              the socket accepts new associations, that is, it becomes an SCTP server socket.

              For type stream, sockets Backlog define the backlog queue length just like in TCP.

       open() -> {ok, Socket} | {error, inet:posix()}

       open(Port) -> {ok, Socket} | {error, inet:posix()}

       open(Opts) -> {ok, Socket} | {error, inet:posix()}

       open(Port, Opts) -> {ok, Socket} | {error, inet:posix()}

              Types:

                 Opts = [Opt]
                 Opt =
                     {ip, IP} |
                     {ifaddr, IP} |
                     inet:address_family() |
                     {port, Port} |
                     {type, SockType} |
                     option()
                 IP = inet:ip_address() | any | loopback
                 Port = inet:port_number()
                 SockType = seqpacket | stream
                 Socket = sctp_socket()

              Creates an SCTP socket and binds it to the local addresses specified by all {ip,IP}
              (or  synonymously  {ifaddr,IP}) options (this feature is called SCTP multi-homing).
              The default IP and Port are any and 0, meaning bind to all local addresses  on  any
              free port.

              Other options:

                inet6:
                  Sets up the socket for IPv6.

                inet:
                  Sets up the socket for IPv4. This is the default.

              A  default  set  of  socket options is used. In particular, the socket is opened in
              binary and passive mode, with SockType seqpacket, and with reasonably large  kernel
              and driver buffers.

              If the socket is in passive mode data can be received through the recv/1,2 calls.

              If  the socket is in active mode data received data is delivered to the controlling
              process as messages:

              {sctp, Socket, FromIP, FromPort, {AncData, Data}}

              See recv/1,2 for a description of the message fields.

          Note:
              This message format unfortunately differs slightly from the gen_udp message  format
              with ancillary data, and from the recv/1,2 return tuple format.

       peeloff(Socket, Assoc) -> {ok, NewSocket} | {error, Reason}

              Types:

                 Socket = sctp_socket()
                 Assoc = #sctp_assoc_change{} | assoc_id()
                 NewSocket = sctp_socket()
                 Reason = term()

              Branches  off  an  existing  association Assoc in a socket Socket of type seqpacket
              (one-to-many style) into a new socket NewSocket of type stream (one-to-one style).

              The existing association argument Assoc can be either a #sctp_assoc_change{} record
              as  returned  from,  for  example, recv/*, connect/*, or from a listening socket in
              active mode. It can also be just the field assoc_id integer from such a record.

       recv(Socket) ->
               {ok, {FromIP, FromPort, AncData, Data}} | {error, Reason}

       recv(Socket, Timeout) ->
               {ok, {FromIP, FromPort, AncData, Data}} | {error, Reason}

              Types:

                 Socket = sctp_socket()
                 Timeout = timeout()
                 FromIP = inet:ip_address()
                 FromPort = inet:port_number()
                 AncData = [#sctp_sndrcvinfo{} | inet:ancillary_data()]
                 Data =
                     binary() |
                     string() |
                     #sctp_sndrcvinfo{} |
                     #sctp_assoc_change{} |
                     #sctp_paddr_change{} |
                     #sctp_adaptation_event{}
                 Reason =
                     inet:posix() |
                     #sctp_send_failed{} |
                     #sctp_paddr_change{} |
                     #sctp_pdapi_event{} |
                     #sctp_remote_error{} |
                     #sctp_shutdown_event{}

              Receives the Data message from any association of the socket. If the receive  times
              out,  {error,timeout}  is  returned.  The  default time-out is infinity. FromIP and
              FromPort indicate the address of the sender.

              AncData is a list of ancillary data items that can be received along with the  main
              Data.  This  list  can  be  empty, or contain a single #sctp_sndrcvinfo{} record if
              receiving of such ancillary data is enabled (see option sctp_events). 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  FromIP  and  FromPort  using  socket  option
              sctp_get_peer_addr_info, but this does still not produce the stream number).

              AncData may also  contain   ancillary  data    from  the  socket  options  recvtos,
              recvtclass or recvttl, if that is supported by the platform for the socket.

              The  Data  received can be a binary() or a list() of bytes (integers in the range 0
              through 255) depending on the socket mode, or an SCTP event.

              Possible SCTP events:

                * #sctp_sndrcvinfo{}

                * #sctp_assoc_change{}

                *

                #sctp_paddr_change{
                      addr      = {ip_address(),port()},
                      state     = atom(),
                      error     = integer(),
                      assoc_id  = assoc_id()
                }

                  Indicates change of the status of the IP address of the peer specified by  addr
                  within association assoc_id. Possible values of state (mostly self-explanatory)
                  include:

                  addr_unreachable:

                  addr_available:

                  addr_removed:

                  addr_added:

                  addr_made_prim:

                  addr_confirmed:

                  In case of an error (for example, addr_unreachable), field error provides  more
                  diagnostics.   In  such  cases,  event  #sctp_paddr_change{}  is  automatically
                  converted into an error term returned by recv. The error  field  value  can  be
                  converted into a string using error_string/1.

                *

                #sctp_send_failed{
                      flags     = true | false,
                      error     = integer(),
                      info      = #sctp_sndrcvinfo{},
                      assoc_id  = assoc_id()
                      data      = binary()
                }

                  The sender can receive this event if a send operation fails.

                  flags:
                    A Boolean specifying if the data has been transmitted over the wire.

                  error:
                    Provides extended diagnostics, use error_string/1.

                  info:
                    The original #sctp_sndrcvinfo{} record used in the failed send/*.

                  data:
                    The whole original data chunk attempted to be sent.

                  In  the  current  implementation  of  the  Erlang/SCTP  binding,  this event is
                  internally converted into an error term returned by recv/*.

                *

                #sctp_adaptation_event{
                      adaptation_ind = integer(),
                      assoc_id       = assoc_id()
                }

                  Delivered  when  a  peer  sends  an  adaptation  layer   indication   parameter
                  (configured through option sctp_adaptation_layer). Notice that with the current
                  implementation of the Erlang/SCTP binding, this event is disabled by default.

                *

                #sctp_pdapi_event{
                      indication = sctp_partial_delivery_aborted,
                      assoc_id   = assoc_id()
                }

                  A partial delivery failure. In the current implementation  of  the  Erlang/SCTP
                  binding,  this  event  is  internally  converted into an error term returned by
                  recv/*.

       send(Socket, SndRcvInfo, Data) -> ok | {error, Reason}

              Types:

                 Socket = sctp_socket()
                 SndRcvInfo = #sctp_sndrcvinfo{}
                 Data = binary() | iolist()
                 Reason = term()

              Sends the Data message  with  all  sending  parameters  from  a  #sctp_sndrcvinfo{}
              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 send/4 is sufficient for most applications.

       send(Socket, Assoc, Stream, Data) -> ok | {error, Reason}

              Types:

                 Socket = sctp_socket()
                 Assoc = #sctp_assoc_change{} | assoc_id()
                 Stream = integer()
                 Data = binary() | iolist()
                 Reason = term()

              Sends a Data message over an existing association and specified stream.

SCTP SOCKET OPTIONS

       The set of admissible SCTP socket options is by construction orthogonal  to  the  sets  of
       TCP, UDP, and generic inet options. Only options listed here are allowed for SCTP sockets.
       Options can be set on  the  socket  using  open/1,2  or  inet:setopts/2,  retrieved  using
       inet:getopts/2. Options can be changed when calling connect/4,5.

         {mode, list|binary} or just list or binary:
           Determines the type of data returned from recv/1,2.

         {active, true|false|once|N}:

           * If  false  (passive  mode, the default), the caller must do an explicit recv call to
             retrieve the available data from the socket.

           * If true|once|N (active modes) received  data  or  events  are  sent  to  the  owning
             process. See open/0..2 for the message format.

           * If true (full active mode) there is no flow control.

       Note:
           Note that this can cause the message queue to overflow causing for example the virtual
           machine to run out of memory and crash.

           * If once, 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.

           * If  active  is  specified  as an integer N 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 0. Once the count reaches 0, either through the delivery of messages or by  being
             explicitly  set  with  inet:setopts/2,  the  socket  mode  is automatically reset to
             passive ({active, false}). When a socket in this active mode transitions to  passive
             mode,  the  message  {sctp_passive,  Socket}  is  sent to the controlling process to
             notify it that if it wants to receive more data messages from the  socket,  it  must
             call inet:setopts/2 to set the socket back into an active mode.

         {tos, integer()}:
           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.

         {priority, integer()}:
           A  protocol-independent  equivalent of tos above. Setting priority implies setting tos
           as well.

         {dontroute, true|false}:
           Defaults to false. If true, the kernel does not send packets through any gateway, only
           sends them to directly connected hosts.

         {reuseaddr, true|false}:
           Defaults  to  false. If true, the local binding address {IP,Port} of the socket can be
           reused immediately. No waiting in state CLOSE_WAIT is performed (can be  required  for
           high-throughput servers).

         {sndbuf, integer()}:
           The size, in bytes, of the OS kernel send buffer for this socket. Sending errors would
           occur for datagrams larger than val(sndbuf). Setting this option also adjusts the size
           of the driver buffer (see buffer above).

         {recbuf, integer()}:
           The  size,  in  bytes, of the OS kernel receive buffer for this socket. Sending errors
           would occur for datagrams larger than val(recbuf). Setting this  option  also  adjusts
           the size of the driver buffer (see buffer above).

         {sctp_module, module()}:
           Overrides which callback module is used. Defaults to inet_sctp for IPv4 and inet6_sctp
           for IPv6.

         {sctp_rtoinfo, #sctp_rtoinfo{}}:

         #sctp_rtoinfo{
               assoc_id = assoc_id(),
               initial  = integer(),
               max      = integer(),
               min      = integer()
         }

           Determines retransmission time-out parameters, in milliseconds, for the association(s)
           specified by assoc_id.

           assoc_id  =  0  (default)  indicates  the whole endpoint. See RFC 2960 and Sockets API
           Extensions for SCTP for the exact semantics of the field values.

         {sctp_associnfo, #sctp_assocparams{}}:

         #sctp_assocparams{
               assoc_id                 = assoc_id(),
               asocmaxrxt               = integer(),
               number_peer_destinations = integer(),
               peer_rwnd                = integer(),
               local_rwnd               = integer(),
               cookie_life              = integer()
         }

           Determines association parameters for the association(s) specified by assoc_id.

           assoc_id = 0 (default) indicates the whole endpoint. See Sockets  API  Extensions  for
           SCTP for the discussion of their semantics. Rarely used.

         {sctp_initmsg, #sctp_initmsg{}}:

         #sctp_initmsg{
              num_ostreams   = integer(),
              max_instreams  = integer(),
              max_attempts   = integer(),
              max_init_timeo = integer()
         }

           Determines  the  default  parameters that this socket tries to negotiate with its peer
           while establishing an association with it. Is to be set after open/*  but  before  the
           first  connect/*.  #sctp_initmsg{}  can  also be used as ancillary data with the first
           call of send/* to a new peer (when a new association is created).

           num_ostreams:
             Number of outbound streams

           max_instreams:
             Maximum number of inbound streams

           max_attempts:
             Maximum retransmissions while establishing an association

           max_init_timeo:
             Time-out, in milliseconds, for establishing an association

         {sctp_autoclose, integer() >= 0}:
           Determines the time, in seconds, after which  an  idle  association  is  automatically
           closed. 0 means that the association is never automatically closed.

         {sctp_nodelay, true|false}:
           Turns  on|off  the  Nagle  algorithm  for merging small packets into larger ones. This
           improves throughput at the expense of latency.

         {sctp_disable_fragments, true|false}:
           If true, 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.

         {sctp_i_want_mapped_v4_addr, true|false}:
           Turns on|off automatic mapping of IPv4 addresses into IPv6 ones (if the socket address
           family is AF_INET6).

         {sctp_maxseg, integer()}:
           Determines the maximum chunk size if message fragmentation is used. If  0,  the  chunk
           size is limited by the Path MTU only.

         {sctp_primary_addr, #sctp_prim{}}:

         #sctp_prim{
               assoc_id = assoc_id(),
               addr     = {IP, Port}
         }
          IP = ip_address()
          Port = port_number()

           For  the  association  specified  by  assoc_id,  {IP,Port}  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.

         {sctp_set_peer_primary_addr, #sctp_setpeerprim{}}:

         #sctp_setpeerprim{
               assoc_id = assoc_id(),
               addr     = {IP, Port}
         }
          IP = ip_address()
          Port = port_number()

           When  set,  informs  the  peer  to  use {IP, Port} as the primary address of the local
           endpoint for the association specified by assoc_id.

         {sctp_adaptation_layer, #sctp_setadaptation{}}:

         #sctp_setadaptation{
               adaptation_ind = integer()
         }

           When set, requests that the local endpoint uses the value specified by  adaptation_ind
           as the Adaptation Indication parameter for establishing new associations. For details,
           see RFC 2960 and Sockets API Extenstions for SCTP.

         {sctp_peer_addr_params, #sctp_paddrparams{}}:

         #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()

           Determines various per-address parameters for the association  specified  by  assoc_id
           and  the  peer  address address (the SCTP protocol supports multi-homing, so more than
           one address can correspond to a specified association).

           hbinterval:
             Heartbeat interval, in milliseconds

           pathmaxrxt:
             Maximum number of retransmissions before this address is considered unreachable (and
             an alternative address is selected)

           pathmtu:
             Fixed Path MTU, if automatic discovery is disabled (see flags below)

           sackdelay:
             Delay, in milliseconds, for SAC messages (if the delay is enabled, see flags below)

           flags:
             The following flags are available:

             hb_enable:
               Enables heartbeat

             hb_disable:
               Disables heartbeat

             hb_demand:
               Initiates heartbeat immediately

             pmtud_enable:
               Enables automatic Path MTU discovery

             pmtud_disable:
               Disables automatic Path MTU discovery

             sackdelay_enable:
               Enables SAC delay

             sackdelay_disable:
               Disables SAC delay

         {sctp_default_send_param, #sctp_sndrcvinfo{}}:

         #sctp_sndrcvinfo{
               stream     = integer(),
               ssn        = integer(),
               flags      = list(),
               ppid       = integer(),
               context    = integer(),
               timetolive = integer(),
               tsn        = integer(),
               cumtsn     = integer(),
               assoc_id   = assoc_id()
         }

           #sctp_sndrcvinfo{}  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 send calls on the association specified by assoc_id.

           assoc_id = 0 (default) indicates the whole endpoint.

           The following fields typically must be specified by the sender:

           sinfo_stream:
             Stream number (0-base) within the association to send the messages through;

           sinfo_flags:
             The following flags are recognised:

             unordered:
               The message is to be sent unordered

             addr_over:
               The address specified in send overwrites the primary peer address

             abort:
               Aborts the current association without flushing any unsent data

             eof:
               Gracefully shuts down the current association, with flushing of unsent data

             Other fields are rarely used. For complete information, see RFC 2960 and Sockets API
             Extensions for SCTP.

         {sctp_events, #sctp_event_subscribe{}}:

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

           This option determines which SCTP Events are to be  received  (through  recv/*)  along
           with  the  data.  The  only  exception  is  data_io_event,  which  enables or disables
           receiving of #sctp_sndrcvinfo{} ancillary data, not  events.  By  default,  all  flags
           except   adaptation_layer_event   are   enabled,   although   sctp_data_io_event   and
           association_event are used by the driver itself and not exported to the user level.

         {sctp_delayed_ack_time, #sctp_assoc_value{}}:

         #sctp_assoc_value{
               assoc_id    = assoc_id(),
               assoc_value = integer()
         }

           Rarely used. Determines the ACK time (specified by assoc_value, in  milliseconds)  for
           the specified association or the whole endpoint if assoc_value = 0 (default).

         {sctp_status, #sctp_status{}}:

         #sctp_status{
               assoc_id            = assoc_id(),
               state               = atom(),
               rwnd                = integer(),
               unackdata           = integer(),
               penddata            = integer(),
               instrms             = integer(),
               outstrms            = integer(),
               fragmentation_point = integer(),
               primary             = #sctp_paddrinfo{}
         }

           This  option  is read-only. It determines the status of the SCTP association specified
           by assoc_id. The following are the possible values of state  (the  state  designations
           are mostly self-explanatory):

           sctp_state_empty:
             Default. Means that no other state is active.

           sctp_state_closed:

           sctp_state_cookie_wait:

           sctp_state_cookie_echoed:

           sctp_state_established:

           sctp_state_shutdown_pending:

           sctp_state_shutdown_sent:

           sctp_state_shutdown_received:

           sctp_state_shutdown_ack_sent:

           Semantics of the other fields:

           sstat_rwnd:
             Current receiver window size of the association

           sstat_unackdata:
             Number of unacked data chunks

           sstat_penddata:
             Number of data chunks pending receipt

           sstat_instrms:
             Number of inbound streams

           sstat_outstrms:
             Number of outbound streams

           sstat_fragmentation_point:
             Message size at which SCTP fragmentation occurs

           sstat_primary:
             Information  on  the  current  primary  peer  address  (see  below for the format of
             #sctp_paddrinfo{})

         {sctp_get_peer_addr_info, #sctp_paddrinfo{}}:

         #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()

           This option is read-only. It determines the parameters specific to  the  peer  address
           specified by address within the association specified by assoc_id. Field address fmust
           be set by the caller; all other fields are filled  in  on  return.  If  assoc_id  =  0
           (default),  the address 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.

SCTP EXAMPLES

       Example  of  an  Erlang  SCTP  server  that  receives SCTP messages and prints them on the
       standard output:

       -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).

       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 "Test 0" over stream 0 succeeds, but sending of "Test 5" over stream
       5  fails.  The client then aborts the association, which results in that the corresponding
       event is received on the server side.

       -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).

       A simple Erlang SCTP client that uses the connect_init API:

       -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.

SEE ALSO

       gen_tcp(3erl), gen_udp(3erl), inet(3erl), RFC 2960 (Stream Control Transmission Protocol),
       Sockets API Extensions for SCTP