aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-07-19 14:00:42 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commitd28129b7098bce154264937862fcdafb21541433 (patch)
tree43a167872afa2413c87b49662638d3a98f9a9d29
parent1a3aca0a849af0bae994c9cf89de0dcfe7b310c2 (diff)
downloadotp-d28129b7098bce154264937862fcdafb21541433.tar.gz
otp-d28129b7098bce154264937862fcdafb21541433.tar.bz2
otp-d28129b7098bce154264937862fcdafb21541433.zip
[socket-nif] Add support for socket (level sctp) option events
Added support for the SCTP option EVENTS. OTP-14831
-rw-r--r--erts/doc/src/socket.xml21
-rw-r--r--erts/doc/src/socket_usage.xml7
-rw-r--r--erts/emulator/nifs/common/socket_nif.c578
-rw-r--r--erts/preloaded/ebin/socket.beambin51660 -> 52584 bytes
-rw-r--r--erts/preloaded/src/socket.erl117
-rw-r--r--lib/kernel/test/socket_server.erl48
6 files changed, 600 insertions, 171 deletions
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index 2681910a72..4ecf35b8ed 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -122,6 +122,21 @@
<datatype>
<name name="ip_mreq"/>
</datatype>
+ <datatype>
+ <name name="ip_mreq_source"/>
+ </datatype>
+ <datatype>
+ <name name="ip_pmtudisc"/>
+ </datatype>
+ <datatype>
+ <name name="ipv6_mreq"/>
+ </datatype>
+ <datatype>
+ <name name="ipv6_pmtudisc"/>
+ </datatype>
+ <datatype>
+ <name name="sctp_event_subscribe"/>
+ </datatype>
</datatypes>
<funcs>
@@ -132,9 +147,9 @@
<desc>
<p>Accept a connection on a socket.</p>
<p>This call is used with connection-based socket types
- (stream or seqpacket). It extracs the first pending connection
- request for the listen socket and returns the (newly) connected
- socket.</p>
+ (<c>stream</c> or <c>seqpacket</c>). It extracs the first pending
+ connection request for the listen socket and returns the (newly)
+ connected socket.</p>
</desc>
</func>
diff --git a/erts/doc/src/socket_usage.xml b/erts/doc/src/socket_usage.xml
index 247cd0eccb..1d7b98d1a3 100644
--- a/erts/doc/src/socket_usage.xml
+++ b/erts/doc/src/socket_usage.xml
@@ -459,6 +459,13 @@
<cell>none</cell>
</row>
<row>
+ <cell>events</cell>
+ <cell>sctp_event_subscribe()</cell>
+ <cell>yes</cell>
+ <cell>no</cell>
+ <cell>none</cell>
+ </row>
+ <row>
<cell>nodelay</cell>
<cell>boolean()</cell>
<cell>yes</cell>
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index d2f7e21ad0..7271db2143 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -164,6 +164,149 @@
#define HAVE_UDP
+/* SCTP support -- currently for UNIX platforms only: */
+#undef HAVE_SCTP
+#if defined(HAVE_SCTP_H)
+
+#include <netinet/sctp.h>
+
+/* SCTP Socket API Draft from version 11 on specifies that netinet/sctp.h must
+ explicitly define HAVE_SCTP in case when SCTP is supported, but Solaris 10
+ still apparently uses Draft 10, and does not define that symbol, so we have
+ to define it explicitly:
+*/
+#ifndef HAVE_SCTP
+# define HAVE_SCTP
+#endif
+
+/* These changed in draft 11, so SOLARIS10 uses the old MSG_* */
+#if ! HAVE_DECL_SCTP_UNORDERED
+# define SCTP_UNORDERED MSG_UNORDERED
+#endif
+#if ! HAVE_DECL_SCTP_ADDR_OVER
+# define SCTP_ADDR_OVER MSG_ADDR_OVER
+#endif
+#if ! HAVE_DECL_SCTP_ABORT
+# define SCTP_ABORT MSG_ABORT
+#endif
+#if ! HAVE_DECL_SCTP_EOF
+# define SCTP_EOF MSG_EOF
+#endif
+
+/* More Solaris 10 fixes: */
+#if ! HAVE_DECL_SCTP_CLOSED && HAVE_DECL_SCTPS_IDLE
+# define SCTP_CLOSED SCTPS_IDLE
+# undef HAVE_DECL_SCTP_CLOSED
+# define HAVE_DECL_SCTP_CLOSED 1
+#endif
+#if ! HAVE_DECL_SCTP_BOUND && HAVE_DECL_SCTPS_BOUND
+# define SCTP_BOUND SCTPS_BOUND
+# undef HAVE_DECL_SCTP_BOUND
+# define HAVE_DECL_SCTP_BOUND 1
+#endif
+#if ! HAVE_DECL_SCTP_LISTEN && HAVE_DECL_SCTPS_LISTEN
+# define SCTP_LISTEN SCTPS_LISTEN
+# undef HAVE_DECL_SCTP_LISTEN
+# define HAVE_DECL_SCTP_LISTEN 1
+#endif
+#if ! HAVE_DECL_SCTP_COOKIE_WAIT && HAVE_DECL_SCTPS_COOKIE_WAIT
+# define SCTP_COOKIE_WAIT SCTPS_COOKIE_WAIT
+# undef HAVE_DECL_SCTP_COOKIE_WAIT
+# define HAVE_DECL_SCTP_COOKIE_WAIT 1
+#endif
+#if ! HAVE_DECL_SCTP_COOKIE_ECHOED && HAVE_DECL_SCTPS_COOKIE_ECHOED
+# define SCTP_COOKIE_ECHOED SCTPS_COOKIE_ECHOED
+# undef HAVE_DECL_SCTP_COOKIE_ECHOED
+# define HAVE_DECL_SCTP_COOKIE_ECHOED 1
+#endif
+#if ! HAVE_DECL_SCTP_ESTABLISHED && HAVE_DECL_SCTPS_ESTABLISHED
+# define SCTP_ESTABLISHED SCTPS_ESTABLISHED
+# undef HAVE_DECL_SCTP_ESTABLISHED
+# define HAVE_DECL_SCTP_ESTABLISHED 1
+#endif
+#if ! HAVE_DECL_SCTP_SHUTDOWN_PENDING && HAVE_DECL_SCTPS_SHUTDOWN_PENDING
+# define SCTP_SHUTDOWN_PENDING SCTPS_SHUTDOWN_PENDING
+# undef HAVE_DECL_SCTP_SHUTDOWN_PENDING
+# define HAVE_DECL_SCTP_SHUTDOWN_PENDING 1
+#endif
+#if ! HAVE_DECL_SCTP_SHUTDOWN_SENT && HAVE_DECL_SCTPS_SHUTDOWN_SENT
+# define SCTP_SHUTDOWN_SENT SCTPS_SHUTDOWN_SENT
+# undef HAVE_DECL_SCTP_SHUTDOWN_SENT
+# define HAVE_DECL_SCTP_SHUTDOWN_SENT 1
+#endif
+#if ! HAVE_DECL_SCTP_SHUTDOWN_RECEIVED && HAVE_DECL_SCTPS_SHUTDOWN_RECEIVED
+# define SCTP_SHUTDOWN_RECEIVED SCTPS_SHUTDOWN_RECEIVED
+# undef HAVE_DECL_SCTP_SHUTDOWN_RECEIVED
+# define HAVE_DECL_SCTP_SHUTDOWN_RECEIVED 1
+#endif
+#if ! HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT && HAVE_DECL_SCTPS_SHUTDOWN_ACK_SENT
+# define SCTP_SHUTDOWN_ACK_SENT SCTPS_SHUTDOWN_ACK_SENT
+# undef HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT
+# define HAVE_DECL_SCTP_SHUTDOWN_ACK_SENT 1
+#endif
+/* New spelling in lksctp 2.6.22 or maybe even earlier:
+ * adaption -> adaptation
+ */
+#if !defined(SCTP_ADAPTATION_LAYER) && defined (SCTP_ADAPTION_LAYER)
+# define SCTP_ADAPTATION_LAYER SCTP_ADAPTION_LAYER
+# define SCTP_ADAPTATION_INDICATION SCTP_ADAPTION_INDICATION
+# define sctp_adaptation_event sctp_adaption_event
+# define sctp_setadaptation sctp_setadaption
+# define sn_adaptation_event sn_adaption_event
+# define sai_adaptation_ind sai_adaption_ind
+# define ssb_adaptation_ind ssb_adaption_ind
+# define sctp_adaptation_layer_event sctp_adaption_layer_event
+#endif
+
+/*
+ * We *may* need this stuff later when we *fully* implement support for SCTP
+ *
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_BINDX)
+static typeof(sctp_bindx) *p_sctp_bindx = NULL;
+#else
+static int (*p_sctp_bindx)
+ (int sd, struct sockaddr *addrs, int addrcnt, int flags) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_PEELOFF)
+static typeof(sctp_peeloff) *p_sctp_peeloff = NULL;
+#else
+static int (*p_sctp_peeloff)
+ (int sd, sctp_assoc_t assoc_id) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_GETLADDRS)
+static typeof(sctp_getladdrs) *p_sctp_getladdrs = NULL;
+#else
+static int (*p_sctp_getladdrs)
+ (int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_FREELADDRS)
+static typeof(sctp_freeladdrs) *p_sctp_freeladdrs = NULL;
+#else
+static void (*p_sctp_freeladdrs)(struct sockaddr *addrs) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_GETPADDRS)
+static typeof(sctp_getpaddrs) *p_sctp_getpaddrs = NULL;
+#else
+static int (*p_sctp_getpaddrs)
+ (int sd, sctp_assoc_t assoc_id, struct sockaddr **ss) = NULL;
+#endif
+
+#if defined(__GNUC__) && defined(HAVE_SCTP_FREEPADDRS)
+static typeof(sctp_freepaddrs) *p_sctp_freepaddrs = NULL;
+#else
+static void (*p_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
+#endif
+
+*/
+
+#endif /* #if defined(HAVE_SCTP_H) */
+
+
#ifndef WANT_NONBLOCKING
#define WANT_NONBLOCKING
#endif
@@ -394,12 +537,13 @@ typedef union {
#define SOCKET_OPT_TCP_CONGESTION 1
#define SOCKET_OPT_TCP_CORK 2
-#define SOCKET_OPT_TCP_MAXSEG 3
-#define SOCKET_OPT_TCP_NODELAY 4
+#define SOCKET_OPT_TCP_MAXSEG 7
+#define SOCKET_OPT_TCP_NODELAY 9
#define SOCKET_OPT_UDP_CORK 1
#define SOCKET_OPT_SCTP_AUTOCLOSE 8
+#define SOCKET_OPT_SCTP_EVENTS 14
#define SOCKET_OPT_SCTP_NODELAY 23
@@ -1072,6 +1216,11 @@ static ERL_NIF_TERM nsetopt_lvl_sctp_autoclose(ErlNifEnv* env,
SocketDescriptor* descP,
ERL_NIF_TERM eVal);
#endif
+#if defined(SCTP_EVENTS)
+static ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal);
+#endif
#if defined(SCTP_NODELAY)
static ERL_NIF_TERM nsetopt_lvl_sctp_nodelay(ErlNifEnv* env,
SocketDescriptor* descP,
@@ -1618,38 +1767,48 @@ static const struct in6_addr in6addr_loopback =
/* *** String constants *** */
-// static char str_any[] = "any";
-static char str_close[] = "close";
-static char str_closed[] = "closed";
-static char str_closing[] = "closing";
-static char str_do[] = "do";
-static char str_dont[] = "dont";
-static char str_false[] = "false";
-static char str_global_counters[] = "global_counters";
-static char str_in4_sockaddr[] = "in4_sockaddr";
-static char str_in6_sockaddr[] = "in6_sockaddr";
-static char str_iow[] = "iow";
-static char str_interface[] = "interface";
-// static char str_loopback[] = "loopback";
-static char str_multiaddr[] = "multiaddr";
-static char str_nif_abort[] = "nif_abort";
-static char str_num_dlocal[] = "num_domain_local";
-static char str_num_dinet[] = "num_domain_inet";
-static char str_num_dinet6[] = "num_domain_inet6";
-static char str_num_pip[] = "num_proto_ip";
-static char str_num_psctp[] = "num_proto_sctp";
-static char str_num_ptcp[] = "num_proto_tcp";
-static char str_num_pudp[] = "num_proto_udp";
-static char str_num_sockets[] = "num_sockets";
-static char str_num_tdgrams[] = "num_type_dgram";
-static char str_num_tseqpkgs[] = "num_type_seqpacket";
-static char str_num_tstreams[] = "num_type_stream";
-static char str_probe[] = "probe";
-static char str_select[] = "select";
-static char str_sourceaddr[] = "sourceaddr";
-static char str_timeout[] = "timeout";
-static char str_true[] = "true";
-static char str_want[] = "want";
+static char str_adaptation_layer[] = "adaptation_layer";
+static char str_address[] = "address";
+static char str_association[] = "association";
+static char str_authentication[] = "authentication";
+// static char str_any[] = "any";
+static char str_close[] = "close";
+static char str_closed[] = "closed";
+static char str_closing[] = "closing";
+static char str_data_in[] = "data_in";
+static char str_do[] = "do";
+static char str_dont[] = "dont";
+static char str_false[] = "false";
+static char str_global_counters[] = "global_counters";
+static char str_in4_sockaddr[] = "in4_sockaddr";
+static char str_in6_sockaddr[] = "in6_sockaddr";
+static char str_iow[] = "iow";
+static char str_interface[] = "interface";
+// static char str_loopback[] = "loopback";
+static char str_multiaddr[] = "multiaddr";
+static char str_nif_abort[] = "nif_abort";
+static char str_num_dlocal[] = "num_domain_local";
+static char str_num_dinet[] = "num_domain_inet";
+static char str_num_dinet6[] = "num_domain_inet6";
+static char str_num_pip[] = "num_proto_ip";
+static char str_num_psctp[] = "num_proto_sctp";
+static char str_num_ptcp[] = "num_proto_tcp";
+static char str_num_pudp[] = "num_proto_udp";
+static char str_num_sockets[] = "num_sockets";
+static char str_num_tdgrams[] = "num_type_dgram";
+static char str_num_tseqpkgs[] = "num_type_seqpacket";
+static char str_num_tstreams[] = "num_type_stream";
+static char str_partial_delivery[] = "partial_delivery";
+static char str_peer_error[] = "peer_error";
+static char str_probe[] = "probe";
+static char str_select[] = "select";
+static char str_sender_dry[] = "sender_dry";
+static char str_send_failure[] = "send_failure";
+static char str_shutdown[] = "shutdown";
+static char str_sourceaddr[] = "sourceaddr";
+static char str_timeout[] = "timeout";
+static char str_true[] = "true";
+static char str_want[] = "want";
static char str_lowdelay[] = "lowdelay";
static char str_throughput[] = "throughput";
@@ -1706,9 +1865,14 @@ ERL_NIF_TERM esock_atom_eafnosupport;
ERL_NIF_TERM esock_atom_einval;
/* *** Atoms *** */
+static ERL_NIF_TERM atom_adaptation_layer;
+static ERL_NIF_TERM atom_address;
+static ERL_NIF_TERM atom_association;
+static ERL_NIF_TERM atom_authentication;
static ERL_NIF_TERM atom_close;
static ERL_NIF_TERM atom_closed;
static ERL_NIF_TERM atom_closing;
+static ERL_NIF_TERM atom_data_in;
static ERL_NIF_TERM atom_do;
static ERL_NIF_TERM atom_dont;
static ERL_NIF_TERM atom_false;
@@ -1730,8 +1894,13 @@ static ERL_NIF_TERM atom_num_sockets;
static ERL_NIF_TERM atom_num_tdgrams;
static ERL_NIF_TERM atom_num_tseqpkgs;
static ERL_NIF_TERM atom_num_tstreams;
+static ERL_NIF_TERM atom_partial_delivery;
+static ERL_NIF_TERM atom_peer_error;
static ERL_NIF_TERM atom_probe;
static ERL_NIF_TERM atom_select;
+static ERL_NIF_TERM atom_sender_dry;
+static ERL_NIF_TERM atom_send_failure;
+static ERL_NIF_TERM atom_shutdown;
static ERL_NIF_TERM atom_sourceaddr;
static ERL_NIF_TERM atom_timeout;
static ERL_NIF_TERM atom_true;
@@ -1895,7 +2064,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
const ERL_NIF_TERM argv[])
{
int edomain, etype, eproto;
- int domain, type, proto;
+ int domain, type, proto;
char* netns;
ERL_NIF_TERM emap;
ERL_NIF_TERM result;
@@ -1920,19 +2089,27 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env,
"\r\n extra: %T"
"\r\n", argv[0], argv[1], argv[2], argv[3]) );
- if (!edomain2domain(edomain, &domain))
- return enif_make_badarg(env);
+ if (!edomain2domain(edomain, &domain)) {
+ SGDBG( ("SOCKET", "nif_open -> domain: %d\r\n", domain) );
+ return esock_make_error(env, esock_atom_einval);
+ }
- if (!etype2type(etype, &type))
- return enif_make_badarg(env);
+ if (!etype2type(etype, &type)) {
+ SGDBG( ("SOCKET", "nif_open -> type: %d\r\n", type) );
+ return esock_make_error(env, esock_atom_einval);
+ }
- if (!eproto2proto(eproto, &proto))
- return enif_make_badarg(env);
+ if (!eproto2proto(eproto, &proto)) {
+ SGDBG( ("SOCKET", "nif_open -> protocol: %d\r\n", proto) );
+ return esock_make_error(env, esock_atom_einval);
+ }
#ifdef HAVE_SETNS
/* We *currently* only support one extra option: netns */
- if (!emap2netns(env, emap, &netns))
+ if (!emap2netns(env, emap, &netns)) {
+ SGDBG( ("SOCKET", "nif_open -> namespace: %s\r\n", netns) );
return enif_make_badarg(env);
+ }
#else
netns = NULL;
#endif
@@ -3733,12 +3910,13 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[])
{
- SocketDescriptor* descP;
+ SocketDescriptor* descP = NULL;
int eLevel, level = -1;
int eOpt;
ERL_NIF_TERM eIsEncoded;
ERL_NIF_TERM eVal;
BOOLEAN_T isEncoded, isOTP;
+ ERL_NIF_TERM result;
SGDBG( ("SOCKET", "nif_setopt -> entry with argc: %d\r\n", argc) );
@@ -3748,6 +3926,7 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
!enif_get_resource(env, argv[0], sockets, (void**) &descP) ||
!GET_INT(env, argv[2], &eLevel) ||
!GET_INT(env, argv[3], &eOpt)) {
+ SGDBG( ("SOCKET", "nif_setopt -> failed initial arg check\r\n") );
return enif_make_badarg(env);
}
eIsEncoded = argv[1];
@@ -3755,23 +3934,35 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env,
isEncoded = esock_decode_bool(eIsEncoded);
- if (!elevel2level(isEncoded, eLevel, &isOTP, &level))
+ /* SGDBG( ("SOCKET", "nif_setopt -> eIsDecoded (%T) decoded: %d\r\n", */
+ /* eIsEncoded, isEncoded) ); */
+
+ if (!elevel2level(isEncoded, eLevel, &isOTP, &level)) {
+ SSDBG( descP, ("SOCKET", "nif_seopt -> failed decode level\r\n") );
return esock_make_error(env, esock_atom_einval);
+ }
SSDBG( descP,
("SOCKET", "nif_setopt -> args when sock = %d:"
"\r\n Socket: %T"
- "\r\n Encoded: %T (%d)"
+ "\r\n Encoded: %d (%T)"
"\r\n Level: %d (%d)"
"\r\n Opt: %d"
"\r\n Value: %T"
"\r\n",
descP->sock, argv[0],
- eIsEncoded, isEncoded,
- eLevel, level,
+ isEncoded, eIsEncoded,
+ level, eLevel,
eOpt, eVal) );
- return nsetopt(env, descP, isEncoded, isOTP, level, eOpt, eVal);
+ result = nsetopt(env, descP, isEncoded, isOTP, level, eOpt, eVal);
+
+ SSDBG( descP,
+ ("SOCKET", "nif_setopt -> done when"
+ "\r\n result: %T"
+ "\r\n", result) );
+
+ return result;
}
@@ -5318,6 +5509,12 @@ ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env,
break;
#endif
+#if defined(SCTP_EVENTS)
+ case SOCKET_OPT_SCTP_EVENTS:
+ result = nsetopt_lvl_sctp_events(env, descP, eVal);
+ break;
+#endif
+
#if defined(SCTP_NODELAY)
case SOCKET_OPT_SCTP_NODELAY:
result = nsetopt_lvl_sctp_nodelay(env, descP, eVal);
@@ -5346,6 +5543,104 @@ ERL_NIF_TERM nsetopt_lvl_sctp_autoclose(ErlNifEnv* env,
#endif
+/* nsetopt_lvl_sctp_events - Level SCTP EVENTS option
+ */
+#if defined(SCTP_EVENTS)
+static
+ERL_NIF_TERM nsetopt_lvl_sctp_events(ErlNifEnv* env,
+ SocketDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ERL_NIF_TERM result;
+ ERL_NIF_TERM eDataIn, eAssoc, eAddr, eSndFailure;
+ ERL_NIF_TERM ePeerError, eShutdown, ePartialDelivery;
+ ERL_NIF_TERM eAdaptLayer, eAuth, eSndDry;
+ struct sctp_event_subscribe events;
+ int res;
+ size_t sz;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_events -> entry with"
+ "\r\n eVal: %T"
+ "\r\n", eVal) );
+
+ // It must be a map
+ if (!IS_MAP(env, eVal))
+ return esock_make_error(env, esock_atom_einval);
+
+ // It must have atleast ten attributes
+ if (!enif_get_map_size(env, eVal, &sz) || (sz < 10))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_events -> extract attributes\r\n") );
+
+ if (!GET_MAP_VAL(env, eVal, atom_data_in, &eDataIn))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_association, &eAssoc))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_address, &eAddr))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_send_failure, &eSndFailure))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_peer_error, &ePeerError))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_shutdown, &eShutdown))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_partial_delivery, &ePartialDelivery))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_adaptation_layer, &eAdaptLayer))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_authentication, &eAuth))
+ return esock_make_error(env, esock_atom_einval);
+
+ if (!GET_MAP_VAL(env, eVal, atom_sender_dry, &eSndDry))
+ return esock_make_error(env, esock_atom_einval);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_events -> decode attributes\r\n") );
+
+ events.sctp_data_io_event = esock_decode_bool(eDataIn);
+ events.sctp_association_event = esock_decode_bool(eAssoc);
+ events.sctp_address_event = esock_decode_bool(eAddr);
+ events.sctp_send_failure_event = esock_decode_bool(eSndFailure);
+ events.sctp_peer_error_event = esock_decode_bool(ePeerError);
+ events.sctp_shutdown_event = esock_decode_bool(eShutdown);
+ events.sctp_partial_delivery_event = esock_decode_bool(ePartialDelivery);
+ events.sctp_adaptation_layer_event = esock_decode_bool(eAdaptLayer);
+ events.sctp_authentication_event = esock_decode_bool(eAuth);
+ events.sctp_sender_dry_event = esock_decode_bool(eSndDry);
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_events -> set events option\r\n") );
+
+ res = socket_setopt(descP->sock, IPPROTO_SCTP, SCTP_EVENTS,
+ &events, sizeof(events));
+
+ if (res != 0)
+ result = esock_make_error_errno(env, sock_errno());
+ else
+ result = esock_atom_ok;
+
+ SSDBG( descP,
+ ("SOCKET", "nsetopt_lvl_sctp_events -> done with"
+ "\r\n result: %T"
+ "\r\n", result) );
+
+ return result;
+
+}
+#endif
+
+
/* nsetopt_lvl_sctp_nodelay - Level SCTP NODELAY option
*/
#if defined(SCTP_NODELAY)
@@ -8269,6 +8564,7 @@ BOOLEAN_T edomain2domain(int edomain, int* domain)
#endif
default:
+ *domain = -1;
return FALSE;
}
@@ -8303,6 +8599,7 @@ BOOLEAN_T etype2type(int etype, int* type)
#endif
default:
+ *type = -1;
return FALSE;
}
@@ -8337,11 +8634,12 @@ BOOLEAN_T eproto2proto(int eproto, int* proto)
#endif
default:
+ *proto = -1;
return FALSE;
}
- return TRUE;
- }
+ return TRUE;
+}
#ifdef HAVE_SETNS
@@ -8909,8 +9207,8 @@ void socket_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
SSDBG( descP,
("SOCKET", "socket_stop -> entry when"
"\r\n sock: %d (%d)"
- "\r\n is_direct_call: %d"
- "\r\n", descP->sock, fd, is_direct_call) );
+ "\r\n Is Direct Call: %s"
+ "\r\n", descP->sock, fd, B2S(is_direct_call)) );
MLOCK(descP->writeMtx);
MLOCK(descP->readMtx);
@@ -9051,6 +9349,10 @@ void inform_waiting_procs(ErlNifEnv* env,
* </KOLLA>
*/
+ SSDBG( descP,
+ ("SOCKET", "inform_waiting_procs -> abort %T (%T)\r\n",
+ currentP->data.ref, currentP->data.pid) );
+
ESOCK_ASSERT( (NULL == send_msg_nif_abort(env,
currentP->data.ref,
reason,
@@ -9088,59 +9390,71 @@ void socket_down(ErlNifEnv* env,
/* Eventually we should go through the other queues also,
* the process can be one of them...
+ *
+ * Currently only the accteptors actuallu use the queues.
*/
- /* Check first if its the current acceptor, and if not check the queue */
- if (compare_pids(env, &descP->currentAcceptor.pid, pid)) {
-
- SSDBG( descP, ("SOCKET",
- "socket_down -> current acceptor - try pop the queue\r\n") );
-
- if (acceptor_pop(env, descP,
- &descP->currentAcceptor.pid,
- &descP->currentAcceptor.mon,
- &descP->currentAcceptor.ref)) {
- int res;
-
- /* There was another one, so we will still be in accepting state */
-
- SSDBG( descP, ("SOCKET", "socket_down -> new (active) acceptor: "
- "\r\n pid: %T"
- "\r\n ref: %T"
- "\r\n",
- descP->currentAcceptor.pid,
- descP->currentAcceptor.ref) );
+ if (descP->currentAcceptorP != NULL) {
- if ((res = enif_select(env,
- descP->sock,
- (ERL_NIF_SELECT_READ),
- descP,
- &descP->currentAcceptor.pid,
- descP->currentAcceptor.ref) < 0)) {
+ /*
+ * We have acceptor(s) (atleast one)
+ *
+ * Check first if its the current acceptor,
+ * and if not check the queue.
+ */
- esock_warning_msg("Failed select (%d) for new acceptor "
- "after current (%T) died\r\n",
- res, *pid);
+ if (compare_pids(env, &descP->currentAcceptor.pid, pid)) {
+ SSDBG( descP, ("SOCKET",
+ "socket_down -> "
+ "current acceptor - try pop the queue\r\n") );
+
+ if (acceptor_pop(env, descP,
+ &descP->currentAcceptor.pid,
+ &descP->currentAcceptor.mon,
+ &descP->currentAcceptor.ref)) {
+ int res;
+
+ /* There was another one, so we will still be in accepting state */
+
+ SSDBG( descP, ("SOCKET", "socket_down -> new (active) acceptor: "
+ "\r\n pid: %T"
+ "\r\n ref: %T"
+ "\r\n",
+ descP->currentAcceptor.pid,
+ descP->currentAcceptor.ref) );
+
+ if ((res = enif_select(env,
+ descP->sock,
+ (ERL_NIF_SELECT_READ),
+ descP,
+ &descP->currentAcceptor.pid,
+ descP->currentAcceptor.ref) < 0)) {
+
+ esock_warning_msg("Failed select (%d) for new acceptor "
+ "after current (%T) died\r\n",
+ res, *pid);
+
+ }
+
+ } else {
+
+ SSDBG( descP, ("SOCKET", "socket_down -> no active acceptor\r\n") );
+
+ descP->currentAcceptorP = NULL;
+ descP->state = SOCKET_STATE_LISTENING;
}
-
+
} else {
-
- SSDBG( descP, ("SOCKET", "socket_down -> no active acceptor\r\n") );
-
- descP->currentAcceptorP = NULL;
- descP->state = SOCKET_STATE_LISTENING;
+
+ /* Maybe unqueue one of the waiting acceptors */
+
+ SSDBG( descP, ("SOCKET",
+ "socket_down -> "
+ "not current acceptor - maybe a waiting acceptor\r\n") );
+
+ qunqueue(env, &descP->acceptorsQ, pid);
}
-
- } else {
-
- /* Maybe unqueue one of the waiting acceptors */
-
- SSDBG( descP, ("SOCKET",
- "socket_down -> "
- "not current acceptor - maybe a waiting acceptor\r\n") );
-
- qunqueue(env, &descP->acceptorsQ, pid);
}
SSDBG( descP, ("SOCKET", "socket_down -> done\r\n") );
@@ -9246,36 +9560,46 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
data.numProtoSCTP = 0;
/* +++ Misc atoms +++ */
- atom_close = MKA(env, str_close);
- atom_closed = MKA(env, str_closed);
- atom_closing = MKA(env, str_closing);
- atom_do = MKA(env, str_do);
- atom_dont = MKA(env, str_dont);
- atom_false = MKA(env, str_false);
- atom_global_counters = MKA(env, str_global_counters);
- atom_in4_sockaddr = MKA(env, str_in4_sockaddr);
- atom_in6_sockaddr = MKA(env, str_in6_sockaddr);
- atom_iow = MKA(env, str_iow);
- atom_interface = MKA(env, str_interface);
- atom_multiaddr = MKA(env, str_multiaddr);
- atom_nif_abort = MKA(env, str_nif_abort);
- atom_num_dinet = MKA(env, str_num_dinet);
- atom_num_dinet6 = MKA(env, str_num_dinet6);
- atom_num_dlocal = MKA(env, str_num_dlocal);
- atom_num_pip = MKA(env, str_num_pip);
- atom_num_psctp = MKA(env, str_num_psctp);
- atom_num_ptcp = MKA(env, str_num_ptcp);
- atom_num_pudp = MKA(env, str_num_pudp);
- atom_num_sockets = MKA(env, str_num_sockets);
- atom_num_tdgrams = MKA(env, str_num_tdgrams);
- atom_num_tseqpkgs = MKA(env, str_num_tseqpkgs);
- atom_num_tstreams = MKA(env, str_num_tstreams);
- atom_probe = MKA(env, str_probe);
- atom_select = MKA(env, str_select);
- atom_sourceaddr = MKA(env, str_sourceaddr);
- atom_timeout = MKA(env, str_timeout);
- atom_true = MKA(env, str_true);
- atom_want = MKA(env, str_want);
+ atom_adaptation_layer = MKA(env, str_adaptation_layer);
+ atom_address = MKA(env, str_address);
+ atom_association = MKA(env, str_association);
+ atom_authentication = MKA(env, str_authentication);
+ atom_close = MKA(env, str_close);
+ atom_closed = MKA(env, str_closed);
+ atom_closing = MKA(env, str_closing);
+ atom_data_in = MKA(env, str_data_in);
+ atom_do = MKA(env, str_do);
+ atom_dont = MKA(env, str_dont);
+ atom_false = MKA(env, str_false);
+ atom_global_counters = MKA(env, str_global_counters);
+ atom_in4_sockaddr = MKA(env, str_in4_sockaddr);
+ atom_in6_sockaddr = MKA(env, str_in6_sockaddr);
+ atom_iow = MKA(env, str_iow);
+ atom_interface = MKA(env, str_interface);
+ atom_multiaddr = MKA(env, str_multiaddr);
+ atom_nif_abort = MKA(env, str_nif_abort);
+ atom_num_dinet = MKA(env, str_num_dinet);
+ atom_num_dinet6 = MKA(env, str_num_dinet6);
+ atom_num_dlocal = MKA(env, str_num_dlocal);
+ atom_num_pip = MKA(env, str_num_pip);
+ atom_num_psctp = MKA(env, str_num_psctp);
+ atom_num_ptcp = MKA(env, str_num_ptcp);
+ atom_num_pudp = MKA(env, str_num_pudp);
+ atom_num_sockets = MKA(env, str_num_sockets);
+ atom_num_tdgrams = MKA(env, str_num_tdgrams);
+ atom_num_tseqpkgs = MKA(env, str_num_tseqpkgs);
+ atom_num_tstreams = MKA(env, str_num_tstreams);
+ atom_partial_delivery = MKA(env, str_partial_delivery);
+ atom_peer_error = MKA(env, str_peer_error);
+ atom_probe = MKA(env, str_probe);
+ atom_select = MKA(env, str_select);
+ atom_sender_dry = MKA(env, str_sender_dry);
+ atom_send_failure = MKA(env, str_send_failure);
+ atom_shutdown = MKA(env, str_shutdown);
+ atom_sourceaddr = MKA(env, str_sourceaddr);
+ atom_timeout = MKA(env, str_timeout);
+ atom_true = MKA(env, str_true);
+ atom_want = MKA(env, str_want);
/* Global atom(s) */
esock_atom_addr = MKA(env, "addr");
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index cb1c5fc815..fd62a18a49 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index ead058c607..74b6bfd543 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -94,6 +94,7 @@
ip_pmtudisc/0,
ipv6_mreq/0,
ipv6_pmtudisc/0,
+ sctp_event_subscribe/0,
msg_hdr/0
@@ -150,6 +151,14 @@
%% socket:setopt(Socket, ip, drop_membership, #{multiaddr => Addr,
%% interface => any}).
%%
+
+%% If the integer value is used its up to the caller to ensure its valid!
+-type ip_tos_flag() :: lowdeley |
+ throughput |
+ reliability |
+ mincost |
+ integer().
+
-type ip_mreq() :: #{multiaddr := ip4_address(),
interface := any | ip4_address()}.
%% -type ip_mreqn() :: #{multiaddr := ip4_address(),
@@ -167,6 +176,17 @@
-type ipv6_pmtudisc() :: ip_pmtudisc().
+-type sctp_event_subscribe() :: #{data_in := boolean(),
+ association := boolean(),
+ address := boolean(),
+ send_failure := boolean(),
+ peer_error := boolean(),
+ shutdown := boolean(),
+ partial_delivery := boolean(),
+ adaptation_layer := boolean(),
+ authentication := boolean(),
+ sender_dry := boolean()}.
+
-type sockaddr_un() :: #{family := local,
path := binary() | string()}.
-type sockaddr_in4() :: #{family := inet,
@@ -331,9 +351,9 @@
-type tcp_socket_option() :: congestion |
cork |
info |
+ keepcnt |
keepidle |
keepintvl |
- keepcnt |
maxseg |
md5sig |
nodelay |
@@ -388,13 +408,6 @@
%% sctp_socket_option() |
%% plain_socket_option().
-%% If the integer value is used its up to the caller to ensure its valid!
--type ip_tos_flag() :: lowdeley |
- throughput |
- reliability |
- mincost |
- integer().
-
-type socket_info() :: #{domain => domain(),
type => type(),
protocol => protocol()}.
@@ -609,8 +622,17 @@
-define(SOCKET_OPT_TCP_CONGESTION, 1).
-define(SOCKET_OPT_TCP_CORK, 2).
--define(SOCKET_OPT_TCP_MAXSEG, 3).
--define(SOCKET_OPT_TCP_NODELAY, 4).
+%% -define(SOCKET_OPT_TCP_INFO, 3).
+%% -define(SOCKET_OPT_TCP_KEEPCNT, 4).
+%% -define(SOCKET_OPT_TCP_KEEPIDLE, 5).
+%% -define(SOCKET_OPT_TCP_KEEPINTVL, 6).
+-define(SOCKET_OPT_TCP_MAXSEG, 7).
+%% -define(SOCKET_OPT_TCP_MD5SIG, 8).
+-define(SOCKET_OPT_TCP_NODELAY, 9).
+%% -define(SOCKET_OPT_TCP_NOOPT, 10).
+%% -define(SOCKET_OPT_TCP_NOPUSH, 11).
+%% -define(SOCKET_OPT_TCP_SYNCNT, 12).
+%% -define(SOCKET_OPT_TCP_USER_TIMEOUT, 13).
-define(SOCKET_OPT_UDP_CORK, 1).
@@ -627,24 +649,25 @@
%% -define(SOCKET_OPT_SCTP_DELAYED_ACK_TIME, 11).
%% -define(SOCKET_OPT_SCTP_DISABLE_FRAGMENTS, 12).
%% -define(SOCKET_OPT_SCTP_HMAC_IDENT, 13).
-%% -define(SOCKET_OPT_SCTP_EXPLICIT_EOR, 14).
-%% -define(SOCKET_OPT_SCTP_FRAGMENT_INTERLEAVE, 15).
-%% -define(SOCKET_OPT_SCTP_GET_PEER_ADDR_INFO, 16).
-%% -define(SOCKET_OPT_SCTP_INITMSG, 17).
-%% -define(SOCKET_OPT_SCTP_I_WANT_MAPPED_V4_ADDR, 18).
-%% -define(SOCKET_OPT_SCTP_LOCAL_AUTH_CHUNKS, 19).
-%% -define(SOCKET_OPT_SCTP_MAXSEG, 20).
-%% -define(SOCKET_OPT_SCTP_MAXBURST, 21).
--define(SOCKET_OPT_SCTP_NODELAY, 22).
-%% -define(SOCKET_OPT_SCTP_PARTIAL_DELIVERY_POINT, 23).
-%% -define(SOCKET_OPT_SCTP_PEER_ADDR_PARAMS, 24).
-%% -define(SOCKET_OPT_SCTP_PEER_AUTH_CHUNKS, 25).
-%% -define(SOCKET_OPT_SCTP_PRIMARY_ADDR, 26).
-%% -define(SOCKET_OPT_SCTP_RESET_STREAMS, 27).
-%% -define(SOCKET_OPT_SCTP_RTOINFO, 28).
-%% -define(SOCKET_OPT_SCTP_SET_PEER_PRIMARY_ADDR, 29).
-%% -define(SOCKET_OPT_SCTP_STATUS, 30).
-%% -define(SOCKET_OPT_SCTP_USE_EXT_RECVINFO, 31).
+-define(SOCKET_OPT_SCTP_EVENTS, 14).
+%% -define(SOCKET_OPT_SCTP_EXPLICIT_EOR, 15).
+%% -define(SOCKET_OPT_SCTP_FRAGMENT_INTERLEAVE, 16).
+%% -define(SOCKET_OPT_SCTP_GET_PEER_ADDR_INFO, 17).
+%% -define(SOCKET_OPT_SCTP_INITMSG, 18).
+%% -define(SOCKET_OPT_SCTP_I_WANT_MAPPED_V4_ADDR, 19).
+%% -define(SOCKET_OPT_SCTP_LOCAL_AUTH_CHUNKS, 20).
+%% -define(SOCKET_OPT_SCTP_MAXSEG, 21).
+%% -define(SOCKET_OPT_SCTP_MAXBURST, 22).
+-define(SOCKET_OPT_SCTP_NODELAY, 23).
+%% -define(SOCKET_OPT_SCTP_PARTIAL_DELIVERY_POINT, 24).
+%% -define(SOCKET_OPT_SCTP_PEER_ADDR_PARAMS, 25).
+%% -define(SOCKET_OPT_SCTP_PEER_AUTH_CHUNKS, 26).
+%% -define(SOCKET_OPT_SCTP_PRIMARY_ADDR, 27).
+%% -define(SOCKET_OPT_SCTP_RESET_STREAMS, 28).
+%% -define(SOCKET_OPT_SCTP_RTOINFO, 29).
+%% -define(SOCKET_OPT_SCTP_SET_PEER_PRIMARY_ADDR, 30).
+%% -define(SOCKET_OPT_SCTP_STATUS, 31).
+%% -define(SOCKET_OPT_SCTP_USE_EXT_RECVINFO, 32).
-define(SOCKET_SHUTDOWN_HOW_READ, 0).
-define(SOCKET_SHUTDOWN_HOW_WRITE, 1).
@@ -1736,6 +1759,7 @@ setopt(#socket{info = Info, ref = SockRef}, Level, Key, Value) ->
+
%% ===========================================================================
%%
%% getopt - retrieve individual properties of a socket
@@ -1942,6 +1966,8 @@ enc_setopt_level(tcp) ->
{true, ?SOCKET_OPT_LEVEL_TCP};
enc_setopt_level(udp) ->
{true, ?SOCKET_OPT_LEVEL_UDP};
+enc_setopt_level(sctp) ->
+ {true, ?SOCKET_OPT_LEVEL_SCTP};
%% Any option that is of an plain level must be provided as a binary
%% already fully encoded!
enc_setopt_level(L) when is_integer(L) ->
@@ -2141,20 +2167,38 @@ enc_setopt_value(tcp = L, Opt, V, _D, _T, _P) ->
not_supported({L, Opt, V});
enc_setopt_value(udp, cork, V, _D, T, P)
- when is_boolean(V) andalso
- (T =:= dgram) andalso
- (P =:= udp) ->
+ when is_boolean(V) andalso (T =:= dgram) andalso (P =:= udp) ->
V;
enc_setopt_value(udp = L, Opt, _V, _D, _T, _P) ->
not_supported({L, Opt});
enc_setopt_value(sctp, autoclose, V, _D, _T, P)
- when is_integer(V) andalso
+ when is_integer(V) andalso (P =:= sctp) ->
+ V;
+enc_setopt_value(sctp, events, #{data_in := DataIn,
+ association := Assoc,
+ address := Addr,
+ send_failure := SndFailure,
+ peer_error := PeerError,
+ shutdown := Shutdown,
+ partial_delivery := PartialDelivery,
+ adaptation_layer := AdaptLayer,
+ authentication := Auth,
+ sender_dry := SndDry} = V, _D, _T, P)
+ when is_boolean(DataIn) andalso
+ is_boolean(Assoc) andalso
+ is_boolean(Addr) andalso
+ is_boolean(SndFailure) andalso
+ is_boolean(PeerError) andalso
+ is_boolean(Shutdown) andalso
+ is_boolean(PartialDelivery) andalso
+ is_boolean(AdaptLayer) andalso
+ is_boolean(Auth) andalso
+ is_boolean(SndDry) andalso
(P =:= sctp) ->
V;
enc_setopt_value(sctp, nodelay, V, _D, _T, P)
- when is_boolean(V) andalso
- (P =:= sctp) ->
+ when is_boolean(V) andalso (P =:= sctp) ->
V;
enc_setopt_value(L, Opt, V, _, _, _)
@@ -2572,8 +2616,8 @@ enc_sockopt_key(sctp = L, disable_fragments = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, hmac_ident = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
-enc_sockopt_key(sctp = L, events = Opt, _Dir, _D, _T, _P) ->
- not_supported({L, Opt});
+enc_sockopt_key(sctp = _L, events = _Opt, set = _Dir, _D, _T, _P) ->
+ ?SOCKET_OPT_SCTP_EVENTS;
enc_sockopt_key(sctp = L, explicit_eor = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, fragment_interleave = Opt, _Dir, _D, _T, _P) ->
@@ -2727,7 +2771,6 @@ tdiff(T1, T2) ->
-
%% p(F) ->
%% p(F, []).
diff --git a/lib/kernel/test/socket_server.erl b/lib/kernel/test/socket_server.erl
index 65069df60b..23f30a0d03 100644
--- a/lib/kernel/test/socket_server.erl
+++ b/lib/kernel/test/socket_server.erl
@@ -25,7 +25,8 @@
start_tcp/0, start_tcp/1, start_tcp/2,
start_tcp4/1, start_tcp6/1,
start_udp/0, start_udp/1, start_udp/2,
- start_udp4/1, start_udp6/1
+ start_udp4/1, start_udp6/1,
+ start_sctp/0, start_sctp/1
]).
-define(LIB, socket_lib).
@@ -69,6 +70,13 @@ start_udp6(Peek) ->
start_udp(Domain, Peek) when is_boolean(Peek) ->
start(Domain, dgram, udp, Peek).
+
+start_sctp() ->
+ start_sctp(inet).
+
+start_sctp(Domain) when ((Domain =:= inet) orelse (Domain =:= inet6)) ->
+ start(Domain, seqpacket, sctp, false).
+
start(Domain, Type, Proto, Peek) ->
put(sname, "starter"),
i("try start manager"),
@@ -103,8 +111,11 @@ manager_reply(Pid, Ref, Reply) ->
?LIB:reply(manager, Pid, Ref, Reply).
-manager_init(Domain, stream = Type, Proto, Peek) ->
+manager_init(Domain, Type, Proto, Peek) ->
put(sname, "manager"),
+ do_manager_init(Domain, Type, Proto, Peek).
+
+do_manager_init(Domain, stream = Type, Proto, Peek) ->
i("try start acceptor(s)"),
{Sock, Acceptors} = manager_stream_init(Domain, Type, Proto),
manager_loop(#manager{socket = Sock,
@@ -112,8 +123,7 @@ manager_init(Domain, stream = Type, Proto, Peek) ->
acceptors = Acceptors,
handler_id = 1,
handlers = []});
-manager_init(Domain, dgram = Type, Proto, Peek) ->
- put(sname, "manager"),
+do_manager_init(Domain, dgram = Type, Proto, Peek) ->
i("try open socket"),
case socket:open(Domain, Type, Proto) of
{ok, Sock} ->
@@ -170,9 +180,39 @@ manager_init(Domain, dgram = Type, Proto, Peek) ->
e("Failed open socket: "
"~n ~p", [OReason]),
exit({failed_open_socket, OReason})
+ end;
+do_manager_init(Domain, seqpacket = Type, sctp = Proto, _Peek) ->
+ %% This is as far as I have got with SCTP at the moment...
+ case socket:open(Domain, Type, Proto) of
+ {ok, Sock} ->
+ i("(sctp) socket opened: "
+ "~n ~p", [Sock]),
+ F = fun(_Desc, Expect, Expect) ->
+ Expect;
+ (Desc, Expect, Actual) ->
+ e("Unexpected result ~w: "
+ "~n Expect: ~p"
+ "~n Actual: ~p", [Desc, Expect, Actual]),
+ exit({Desc, Expect, Actual})
+ end,
+ Events = #{data_in => true,
+ association => true,
+ address => true,
+ send_failure => true,
+ peer_error => true,
+ shutdown => true,
+ partial_delivery => true,
+ adaptation_layer => true,
+ authentication => true,
+ sender_dry => true},
+ F(set_sctp_events, ok, socket:setopt(Sock, sctp, events, Events)),
+ F(close_socket, ok, socket:close(Sock));
+ {error, Reason} ->
+ exit({failed_open, Reason})
end.
+
manager_stream_init(Domain, Type, Proto) ->
i("try (socket) open"),
Sock = case socket:open(Domain, Type, Proto) of