aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMicael Karlberg <[email protected]>2018-09-13 15:44:21 +0200
committerMicael Karlberg <[email protected]>2018-09-18 14:50:18 +0200
commit929ae46220f402d6f36072c46fe27ba39ad48d1b (patch)
treeb51ba588683a452a13603294f3e2990526b30538
parentee2eadd1c61d4237ee4044260665c82edf559228 (diff)
downloadotp-929ae46220f402d6f36072c46fe27ba39ad48d1b.tar.gz
otp-929ae46220f402d6f36072c46fe27ba39ad48d1b.tar.bz2
otp-929ae46220f402d6f36072c46fe27ba39ad48d1b.zip
[socket-nif] CMsgHdr and various doc related changes
Updated the (send) cmsghdr type and the handling of it (in the nif code). Still not tested! Removed the is_loaded nif function. Tried to get fix the doc build problem (socket.erl *i think*), which causes socket.html generation to fail with: "cannot find module exporting type" To solve this I tried to run dialyzer on preloaded, and ran into problems with enc_setopt_value. Update various specs and types to "solve" this (which did not work). Updated the nif-stub functions to make dialyzer happy.
-rw-r--r--erts/doc/src/socket.xml20
-rw-r--r--erts/emulator/nifs/common/net_nif.c27
-rw-r--r--erts/emulator/nifs/common/socket_nif.c326
-rw-r--r--erts/preloaded/ebin/net.beambin6036 -> 5632 bytes
-rw-r--r--erts/preloaded/ebin/socket.beambin64588 -> 66000 bytes
-rw-r--r--erts/preloaded/src/Makefile29
-rw-r--r--erts/preloaded/src/net.erl42
-rw-r--r--erts/preloaded/src/socket.erl263
8 files changed, 430 insertions, 277 deletions
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index b11b68cba5..35f7e8502d 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -176,11 +176,16 @@
<datatype>
<name name="cmsghdr_type"/>
</datatype>
+ <!--
<datatype>
<name name="cmsghdr_data"/>
</datatype>
+ -->
<datatype>
- <name name="cmsghdr"/>
+ <name name="cmsghdr_recv"/>
+ </datatype>
+ <datatype>
+ <name name="cmsghdr_send"/>
</datatype>
<datatype>
<name name="uint8"/>
@@ -427,7 +432,7 @@
how much we want to read, it returns when we get a message.</p>
<p>The message will be delivered in the form of a <c>msghdr()</c>,
which may contain the source address (if socket not connected),
- a list of <c>cmsghdr()</c> (depends on what socket options have
+ a list of <c>cmsghdr_recv()</c> (depends on what socket options have
been set and what the protocol and platform supports) and
also a set of flags, providing further info about the read . </p>
@@ -466,11 +471,11 @@
<name name="sendmsg" arity="4"/>
<fsummary>Send a message on a socket.</fsummary>
<desc>
- <p>Send a message on a socket. The destination, if needed (socket not
- connected) is provided in the <c>MsgHdr</c>, which also
- contains the message to send, The <c>MsgHdr</c> may also contain
- an list of optional <c>cmsghdr()</c> (depends on what the protocol and
- platform supports).</p>
+ <p>Send a message on a socket. The destination, if needed
+ (socket <em>not</em> connected) is provided in the <c>MsgHdr</c>,
+ which also contains the message to send,
+ The <c>MsgHdr</c> may also contain an list of optional <c>cmsghdr_send()</c>
+ (depends on what the protocol and platform supports).</p>
</desc>
</func>
@@ -492,6 +497,7 @@
<name name="setopt" arity="4" clause_i="5"/>
<name name="setopt" arity="4" clause_i="6"/>
<name name="setopt" arity="4" clause_i="7"/>
+ <name name="setopt" arity="4" clause_i="8"/>
<fsummary>Set options on a socket.</fsummary>
<desc>
<p>Set options on a socket.</p>
diff --git a/erts/emulator/nifs/common/net_nif.c b/erts/emulator/nifs/common/net_nif.c
index 309ad05a36..9905d99a04 100644
--- a/erts/emulator/nifs/common/net_nif.c
+++ b/erts/emulator/nifs/common/net_nif.c
@@ -241,9 +241,6 @@ static NetData data;
extern char* erl_errno_id(int error);
-static ERL_NIF_TERM nif_is_loaded(ErlNifEnv* env,
- int argc,
- const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM nif_info(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[]);
@@ -439,8 +436,8 @@ static ErlNifResourceTypeInit netInit = {
*
* Utility and admin functions:
* ----------------------------
- * nif_is_loaded/0
* nif_info/0
+ * nif_command/1
*
* The "proper" net functions:
* ------------------------------
@@ -455,27 +452,6 @@ static ErlNifResourceTypeInit netInit = {
/* ----------------------------------------------------------------------
- * nif_is_loaded
- *
- * Description:
- * This functions only purpose is to return the atom 'true'.
- * This will happen *if* the (socket) nif library is loaded.
- * If its not, the erlang (nif_is_loaded) will instead return
- * 'false'.
- */
-static
-ERL_NIF_TERM nif_is_loaded(ErlNifEnv* env,
- int argc,
- const ERL_NIF_TERM argv[])
-{
- if (argc != 0)
- return enif_make_badarg(env);
-
- return esock_atom_true;
-}
-
-
-/* ----------------------------------------------------------------------
* nif_info
*
* Description:
@@ -1522,7 +1498,6 @@ static
ErlNifFunc net_funcs[] =
{
// Some utility functions
- {"nif_is_loaded", 0, nif_is_loaded, 0},
{"nif_info", 0, nif_info, 0},
{"nif_command", 1, nif_command, 0}, // Shall we let this be dirty?
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index f7e59678bb..68a9730d0c 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -848,9 +848,6 @@ typedef struct {
-static ERL_NIF_TERM nif_is_loaded(ErlNifEnv* env,
- int argc,
- const ERL_NIF_TERM argv[]);
static ERL_NIF_TERM nif_info(ErlNifEnv* env,
int argc,
const ERL_NIF_TERM argv[]);
@@ -1973,7 +1970,18 @@ extern char* encode_msghdr_flags(ErlNifEnv* env,
SocketDescriptor* descP,
int msgFlags,
ERL_NIF_TERM* flags);
-
+static char* decode_cmsghdr_data(ErlNifEnv* env,
+ void** bufP,
+ size_t* rem,
+ int level,
+ int type,
+ ERL_NIF_TERM eData);
+static char* decode_cmsghdr_final(void** bufP,
+ size_t* rem,
+ int level,
+ int type,
+ char* data,
+ int sz);
static BOOLEAN_T decode_sock_linger(ErlNifEnv* env,
ERL_NIF_TERM eVal,
struct linger* valP);
@@ -2380,7 +2388,6 @@ static SocketData data;
*
* Utility and admin functions:
* ----------------------------
- * nif_is_loaded/0
* nif_info/0
* (nif_debug/1)
*
@@ -2417,27 +2424,6 @@ static SocketData data;
/* ----------------------------------------------------------------------
- * nif_is_loaded
- *
- * Description:
- * This functions only purpose is to return the atom 'true'.
- * This will happen *if* the (socket) nif library is loaded.
- * If its not, the erlang (nif_is_loaded) will instead return
- * 'false'.
- */
-static
-ERL_NIF_TERM nif_is_loaded(ErlNifEnv* env,
- int argc,
- const ERL_NIF_TERM argv[])
-{
- if (argc != 0)
- return enif_make_badarg(env);
-
- return atom_true;
-}
-
-
-/* ----------------------------------------------------------------------
* nif_info
*
* Description:
@@ -11046,7 +11032,7 @@ char* encode_msghdr(ErlNifEnv* env,
*
* The cmsgHdrP arguments points to the start of the control data buffer,
* an actual binary. Its the only way to create sub-binaries. So, what we
- * need to continue processing this is to tern that into an binary erlang
+ * need to continue processing this is to turn that into an binary erlang
* term (which can then in turn be turned into sub-binaries).
*
* We need the cmsgBufP (even though cmsgHdrP points to it) to be able
@@ -11171,7 +11157,7 @@ char* encode_cmsghdrs(ErlNifEnv* env,
*
* Decode a list of cmsghdr(). There can be 0 or more cmsghdr "blocks".
*
- * Each element can either be a (erlang) map that needds to be decoded,
+ * Each element can either be a (erlang) map that needs to be decoded,
* or a (erlang) binary that just needs to be appended to the control
* buffer.
*
@@ -11267,46 +11253,121 @@ char* decode_cmsghdr(ErlNifEnv* env,
/* And finally data
* If its a binary, we are done. Otherwise, we need to check
* level and type to know what kind of data to expect.
- *
- * <KOLLA>
- *
- * At the moment, the only data we support is a binary...
- *
- * </KOLLA>
*/
+
+ return decode_cmsghdr_data(env, bufP, rem, level, type, eData);
+
+ } else {
+ return ESOCK_STR_EINVAL;
+ }
+
+ return NULL;
+}
+
+
+/* *** decode_cmsghdr_data ***
+ *
+ * For all combinations of level and type we accept a binary as data,
+ * so we begin by testing for that. If its not a binary, then we check
+ * level (ip) and type (tos or ttl), in which case the data *must* be
+ * an integer (we have already taken care of the binary).
+ */
+static
+char* decode_cmsghdr_data(ErlNifEnv* env,
+ void** bufP,
+ size_t* rem,
+ int level,
+ int type,
+ ERL_NIF_TERM eData)
+{
+ char* xres = ESOCK_STR_EINVAL;
+
+ if (IS_BIN(env, eData)) {
+ ErlNifBinary bin;
- if (IS_BIN(env, eData)) {
- ErlNifBinary bin;
- size_t currentRem = *rem;
+ if (GET_BIN(env, eData, &bin)) {
+ return decode_cmsghdr_final(bufP, rem, level, type,
+ (char*) bin.data, bin.size);
+ }
+ } else {
- if (!GET_BIN(env, eData, &bin)) {
- return ESOCK_STR_EINVAL;
- } else {
- int len = CMSG_LEN(bin.size); // The cmsghdr
- int space = CMSG_SPACE(bin.size); // With padding
- /* Make sure it fits before we copy */
- if (currentRem >= space) {
- struct cmsghdr* cmsgP = (struct cmsghdr*) bufP;
-
- /* The header */
- cmsgP->cmsg_len = len;
- cmsgP->cmsg_level = level;
- cmsgP->cmsg_type = type;
-
- /* And the data */
- sys_memcpy(CMSG_DATA(cmsgP), bin.data, bin.size);
- *bufP += space;
- *rem -= space;
- } else {
- return ESOCK_STR_EINVAL;
+ /* Its *not* a binary so we need to look at what level and type
+ * we have and treat them individually.
+ */
+
+ switch (level) {
+#if defined(SOL_IP)
+ case SOL_IP:
+#else
+ case IPPROTO_IP:
+#endif
+ switch (type) {
+#if defined(IP_TOS)
+ case IP_TOS:
+ {
+ int data;
+ if (decode_ip_tos(env, eData, &data)) {
+ return decode_cmsghdr_final(bufP, rem, level, type,
+ (char*) &data,
+ sizeof(data));
+ }
+ }
+ break;
+#endif
+
+#if defined(IP_TTL)
+ case IP_TTL:
+ {
+ int data;
+ if (GET_INT(env, eData, &data)) {
+ return decode_cmsghdr_final(bufP, rem, level, type,
+ (char*) &data,
+ sizeof(data));
+ }
}
+ break;
+#endif
+
}
- } else {
+ break;
+
+ default:
+ break;
+ }
- /* Here is where we should have the proper data decode */
+ }
- return ESOCK_STR_EINVAL;
- }
+ return xres;
+}
+
+
+/* *** decode_cmsghdr_final ***
+ *
+ * This does the final create of the cmsghdr (including the data copy).
+ */
+static
+char* decode_cmsghdr_final(void** bufP,
+ size_t* rem,
+ int level,
+ int type,
+ char* data,
+ int sz)
+{
+ int currentRem = *rem;
+ int len = CMSG_LEN(sz);
+ int space = CMSG_SPACE(sz);
+
+ if (currentRem >= space) {
+ struct cmsghdr* cmsgP = (struct cmsghdr*) bufP;
+
+ /* The header */
+ cmsgP->cmsg_len = len;
+ cmsgP->cmsg_level = level;
+ cmsgP->cmsg_type = type;
+
+ sys_memcpy(CMSG_DATA(cmsgP), &data, sz);
+ *bufP += space;
+ *rem -= space;
} else {
return ESOCK_STR_EINVAL;
}
@@ -11334,8 +11395,30 @@ char* encode_cmsghdr_level(ErlNifEnv* env,
xres = NULL;
break;
+#if defined(SOL_IP)
+ case SOL_IP:
+#else
+ case IPPROTO_IP:
+#endif
+ *eLevel = esock_atom_ip;
+ xres = NULL;
+ break;
+
+#if defined(SOL_IPV6)
+ case SOL_IPV6:
+ *eLevel = esock_atom_ip;
+ xres = NULL;
+ break;
+#endif
+
+ case IPPROTO_UDP:
+ *eLevel = esock_atom_udp;
+ xres = NULL;
+ break;
+
default:
- xres = esock_encode_protocol(env, level, eLevel);
+ *eLevel = MKI(env, level);
+ xres = NULL;
break;
}
@@ -11358,17 +11441,35 @@ char* decode_cmsghdr_level(ErlNifEnv* env,
char* xres = NULL;
if (IS_ATOM(env, eLevel)) {
+
if (COMPARE(eLevel, esock_atom_socket) == 0) {
*level = SOL_SOCKET;
xres = NULL;
+ } else if (COMPARE(eLevel, esock_atom_ip) == 0) {
+#if defined(SOL_IP)
+ *level = SOL_IP;
+#else
+ *level = IPPROTO_IP;
+#endif
+ xres = NULL;
+#if defined(SOL_IPV6)
+ } else if (COMPARE(eLevel, esock_atom_ipv6) == 0) {
+ *level = SOL_IPV6;
+ xres = NULL;
+#endif
+ } else if (COMPARE(eLevel, esock_atom_udp) == 0) {
+ *level = IPPROTO_UDP;
+ xres = NULL;
} else {
- xres = esock_decode_protocol(env, eLevel, level);
+ *level = -1;
+ xres = ESOCK_STR_EINVAL;
}
} else if (IS_NUM(env, eLevel)) {
if (!GET_INT(env, eLevel, level))
xres = ESOCK_STR_EINVAL;
} else {
- xres = ESOCK_STR_EINVAL;
+ *level = -1;
+ xres = ESOCK_STR_EINVAL;
}
return xres;
@@ -11521,25 +11622,13 @@ char* decode_cmsghdr_type(ErlNifEnv* env,
switch (level) {
case SOL_SOCKET:
- if (COMPARE(eType, esock_atom_timestamp) == 0) {
-#if defined(SO_TIMESTAMP)
- *type = SO_TIMESTAMP;
-#else
- xres = ESOCK_STR_EINVAL;
-#endif
- } else if (COMPARE(eType, esock_atom_rights) == 0) {
-#if defined(SCM_RIGHTS)
- *type = SCM_RIGHTS;
-#else
- xres = ESOCK_STR_EINVAL;
-#endif
- } else if (COMPARE(eType, esock_atom_credentials) == 0) {
-#if defined(SCM_CREDENTIALS)
- *type = SCM_CREDENTIALS;
-#else
- xres = ESOCK_STR_EINVAL;
-#endif
+ if (IS_NUM(env, eType)) {
+ if (!GET_INT(env, eType, type)) {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
} else {
+ *type = -1;
xres = ESOCK_STR_EINVAL;
}
break;
@@ -11550,60 +11639,62 @@ char* decode_cmsghdr_type(ErlNifEnv* env,
#else
case IPPROTO_IP:
#endif
- if (COMPARE(eType, esock_atom_tos) == 0) {
+ if (IS_ATOM(env, eType)) {
+ if (COMPARE(eType, esock_atom_tos) == 0) {
#if defined(IP_TOS)
- *type = IP_TOS;
+ *type = IP_TOS;
#else
- xres = ESOCK_STR_EINVAL;
+ xres = ESOCK_STR_EINVAL;
#endif
- } else if (COMPARE(eType, esock_atom_ttl) == 0) {
+ } else if (COMPARE(eType, esock_atom_ttl) == 0) {
#if defined(IP_TTL)
- *type = IP_TTL;
+ *type = IP_TTL;
#else
- xres = ESOCK_STR_EINVAL;
-#endif
- } else if (COMPARE(eType, esock_atom_pktinfo) == 0) {
-#if defined(IP_PKTINFO)
- *type = IP_PKTINFO;
-#else
- xres = ESOCK_STR_EINVAL;
-#endif
- } else if (COMPARE(eType, esock_atom_origdstaddr) == 0) {
-#if defined(IP_ORIGDSTADDR)
- *type = IP_ORIGDSTADDR;
-#else
- xres = ESOCK_STR_EINVAL;
+ xres = ESOCK_STR_EINVAL;
#endif
+ } else {
+ xres = ESOCK_STR_EINVAL;
+ }
+ } else if (IS_NUM(env, eType)) {
+ if (!GET_INT(env, eType, type)) {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
} else {
- xres = ESOCK_STR_EINVAL;
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
}
break;
#if defined(SOL_IPV6)
case SOL_IPV6:
- xres = ESOCK_STR_EINVAL;
+ if (IS_NUM(env, eType)) {
+ if (!GET_INT(env, eType, type)) {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
+ } else {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
break;
#endif
- case IPPROTO_TCP:
- xres = ESOCK_STR_EINVAL;
- break;
- break;
-
case IPPROTO_UDP:
- xres = ESOCK_STR_EINVAL;
- break;
- break;
-
-#if defined(HAVE_SCTP)
- case IPPROTO_SCTP:
- xres = ESOCK_STR_EINVAL;
- break;
+ if (IS_NUM(env, eType)) {
+ if (!GET_INT(env, eType, type)) {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
+ } else {
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
+ }
break;
-#endif
default:
- xres = ESOCK_STR_EINVAL;
+ *type = -1;
+ xres = ESOCK_STR_EINVAL;
break;
}
@@ -13481,7 +13572,6 @@ static
ErlNifFunc socket_funcs[] =
{
// Some utility functions
- {"nif_is_loaded", 0, nif_is_loaded, 0},
{"nif_info", 0, nif_info, 0},
// {"nif_debug", 1, nif_debug_, 0},
diff --git a/erts/preloaded/ebin/net.beam b/erts/preloaded/ebin/net.beam
index b52fa01b07..e7a393391a 100644
--- a/erts/preloaded/ebin/net.beam
+++ b/erts/preloaded/ebin/net.beam
Binary files differ
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 5b14af3ad8..b3f3e385d2 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index fae60a4491..2a80837719 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -78,6 +78,10 @@ STDLIB_INCLUDE=$(ERL_TOP)/lib/stdlib/include
ERL_COMPILE_FLAGS += +debug_info -I$(KERNEL_SRC) -I$(KERNEL_INCLUDE)
+DIA_PLT = erts-preloaded.plt
+DIA_ANALYSIS = $(basename $(DIA_PLT)).dialyzer_analysis
+
+
debug opt: $(TARGET_FILES)
clean:
@@ -89,7 +93,6 @@ copy:
$(APP_TARGET): $(APP_SRC) $(ERL_TOP)/erts/vsn.mk
$(vsn_verbose)sed -e 's;%VSN%;$(VSN);' $< > $@
-
include $(ERL_TOP)/make/otp_release_targets.mk
release_spec: $(APP_TARGET)
@@ -104,6 +107,30 @@ release_docs_spec:
list_preloaded:
@echo $(PRE_LOADED_MODULES)
+dclean:
+ rm -f $(DIA_PLT)
+ rm -f $(DIA_ANALYSIS)
+
+dialyzer_plt: $(DIA_PLT)
+
+$(DIA_PLT): $(ERL_FILES)
+ @echo "Building ($(basename $(DIA_PLT))) plt file"
+ @dialyzer --build_plt \
+ --output_plt $@ \
+ -r ../ebin \
+ ../../../lib/kernel/ebin \
+ ../../../lib/stdlib/ebin \
+ ../../../lib/crypto/ebin \
+ ../../../lib/compiler/ebin \
+ --output $(DIA_ANALYSIS) \
+ --verbose
+
+dialyzer: $(DIA_PLT)
+ @echo "Running dialyzer on $(basename $(DIA_PLT))"
+ @dialyzer --plt $< \
+ ../ebin \
+ --verbose
+
#
# Combine a BEAM assembly script file a stub Erlang file into a BEAM file.
# See add_abstract_chunk script.
diff --git a/erts/preloaded/src/net.erl b/erts/preloaded/src/net.erl
index 01b12696e9..0183a69ddb 100644
--- a/erts/preloaded/src/net.erl
+++ b/erts/preloaded/src/net.erl
@@ -20,9 +20,11 @@
-module(net).
+-compile(no_native).
+
%% Administrative and "global" utility functions
-export([
- on_load/0, on_load/1, on_load/2,
+ on_load/0, on_load/1,
info/0,
command/1
]).
@@ -105,23 +107,10 @@ on_load() ->
on_load(#{}).
-spec on_load(Extra) -> ok when
- Extra :: maps:map().
-
-on_load(Extra) when is_map(Extra) ->
- on_load(atom_to_list(?MODULE), Extra).
-
--spec on_load(Path, Extra) -> ok when
- Path :: string(),
- Extra :: maps:map().
-
-on_load(Path, Extra) when is_list(Path) andalso is_map(Extra) ->
- on_load(nif_is_loaded(), Path, Extra).
-
-on_load(true, _Path, _Extra) ->
- ok;
-on_load(false, Path, Extra) ->
- ok = erlang:load_nif(Path, Extra).
+ Extra :: map().
+on_load(Extra) ->
+ ok = erlang:load_nif(atom_to_list(?MODULE), Extra).
-spec info() -> list().
@@ -315,29 +304,26 @@ if_names() ->
%%
%% ===========================================================================
-nif_is_loaded() ->
- false.
-
nif_info() ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_command(_Cmd) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_gethostname() ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_getnameinfo(_Addr, _Flags) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_getaddrinfo(_Host, _Service, _Hints) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_if_name2index(_Name) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_if_index2name(_Id) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_if_names() ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 8af052e149..d1053d88f9 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -20,11 +20,12 @@
-module(socket).
+-compile(no_native).
-compile({no_auto_import,[error/1]}).
%% Administrative and "global" utility functions
-export([
- on_load/0, on_load/1, on_load/2,
+ on_load/0, on_load/1,
info/0,
ensure_sockaddr/1
]).
@@ -112,8 +113,8 @@
msghdr/0,
cmsghdr_level/0,
cmsghdr_type/0,
- cmsghdr_data/0,
- cmsghdr/0,
+ %% cmsghdr_data/0,
+ cmsghdr_recv/0, cmsghdr_send/0,
uint8/0,
uint16/0,
@@ -311,7 +312,7 @@
%% Int - Raw level, sent down and used "as is".
-type sockopt_level() :: otp |
socket |
- ip | ipv6 | tcp | udp | sctp | raw |
+ ip | ipv6 | tcp | udp | sctp |
non_neg_integer().
%% There are some options that are 'read-only'.
@@ -546,7 +547,7 @@
%% The maximum size of the control buffer is platform
%% specific. It is the users responsibility to ensure
%% that its not exceeded.
- ctrl := [cmsghdr()],
+ ctrl := [cmsghdr_recv()] | [cmsghdr_send()],
%% Only valid with recvmsg
flags := msghdr_flags()
@@ -555,7 +556,7 @@
%% Even if we are able to decode both level and type, we may not be
%% able to decode the data, in which case it will be a binary.
--type cmsghdr_level() :: socket | protocol() | integer().
+-type cmsghdr_level() :: socket | ip | ipv6 | integer().
-type cmsghdr_type() :: timestamp |
pktinfo |
tos |
@@ -564,18 +565,44 @@
credentials |
origdstaddr |
integer().
--type cmsghdr_data() :: timeval() | % if level = socket and type = timstamp
- ip_pktinfo() | % if level = ip and type = pktinfo
- ipv6_pktinfo() | % if level = ipv6 and type = pktinfo
- ip_tos() | % if level = ip and type = tos
- integer() | % if level = ip and type = ttl
- sockaddr_in4() | % if level = ip and type = origdstaddr
- binary().
--type cmsghdr() :: #{
- level := cmsghdr_level(),
- type := cmsghdr_type(),
- data := cmsghdr_data()
- }.
+%% Do we need this? See cmsghdr()
+%% -type cmsghdr_data() :: timeval() | % if level = socket and type = timstamp
+%% ip_pktinfo() | % if level = ip and type = pktinfo
+%% ipv6_pktinfo() | % if level = ipv6 and type = pktinfo
+%% ip_tos() | % if level = ip and type = tos
+%% integer() | % if level = ip and type = ttl
+%% sockaddr_in4() | % if level = ip and type = origdstaddr
+%% binary().
+%% -type cmsghdr() :: #{
+%% level := cmsghdr_level(),
+%% type := cmsghdr_type(),
+%% data := cmsghdr_data()
+%% }.
+
+-type cmsghdr_recv() ::
+ #{level := socket, type := timestamp, data := timeval()} |
+ #{level := socket, type := rights, data := binary()} |
+ #{level := socket, type := credentials, data := binary()} |
+ #{level := socket, type := integer(), data := binary()} |
+ #{level := ip, type := tos, data := ip_tos()} |
+ #{level := ip, type := ttl, data := integer()} |
+ #{level := ip, type := pktinfo, data := ip_pktinfo()} |
+ #{level := ip, type := origdstaddr, data := sockaddr_in4()} |
+ #{level := ip, type := integer(), data := binary()} |
+ #{level := ipv6, type := pktinfo, data := ipv6_pktinfo()} |
+ #{level := ipv6, type := integer(), data := binary()} |
+ #{level := integer(), type := integer(), data := binary()}.
+
+
+-type cmsghdr_send() ::
+ #{level := socket, type := integer(), data := binary()} |
+ #{level := ip, type := tos, data := ip_tos() | binary()} |
+ #{level := ip, type := ttl, data := integer() | binary()} |
+ #{level := ip, type := integer(), data := binary()} |
+ #{level := ipv6, type := integer(), data := binary()} |
+ #{level := udp, type := integer(), data := binary()} |
+ #{level := integer(), type := integer(), data := binary()}.
+
-define(SOCKET_DOMAIN_LOCAL, 1).
-define(SOCKET_DOMAIN_UNIX, ?SOCKET_DOMAIN_LOCAL).
@@ -630,10 +657,12 @@
-define(SOCKET_OPT_LEVEL_UDP, 5).
-define(SOCKET_OPT_LEVEL_SCTP, 6).
+%% *** OTP (socket) options
-define(SOCKET_OPT_OTP_DEBUG, 1).
-define(SOCKET_OPT_OTP_IOW, 2).
-define(SOCKET_OPT_OTP_CTRL_PROC, 3).
+%% *** SOCKET (socket) options
-define(SOCKET_OPT_SOCK_ACCEPTCONN, 1).
%% -define(SOCKET_OPT_SOCK_ACCEPTFILTER, 2). % FreeBSD
-define(SOCKET_OPT_SOCK_BINDTODEVICE, 3).
@@ -667,6 +696,7 @@
-define(SOCKET_OPT_SOCK_TIMESTAMP, 31).
-define(SOCKET_OPT_SOCK_TYPE, 32).
+%% *** IP (socket) options
-define(SOCKET_OPT_IP_ADD_MEMBERSHIP, 1).
-define(SOCKET_OPT_IP_ADD_SOURCE_MEMBERSHIP, 2).
-define(SOCKET_OPT_IP_BLOCK_SOURCE, 3).
@@ -701,6 +731,7 @@
-define(SOCKET_OPT_IP_TTL, 32).
-define(SOCKET_OPT_IP_UNBLOCK_SOURCE, 33).
+%% *** IPv6 (socket) options
-define(SOCKET_OPT_IPV6_ADDRFORM, 1).
-define(SOCKET_OPT_IPV6_ADD_MEMBERSHIP, 2).
-define(SOCKET_OPT_IPV6_AUTHHDR, 3). % Obsolete?
@@ -734,6 +765,7 @@
%% -define(SOCKET_OPT_IPV6_USE_MIN_MTU, 31). % FreeBSD
-define(SOCKET_OPT_IPV6_V6ONLY, 32).
+%% *** TCP (socket) options
-define(SOCKET_OPT_TCP_CONGESTION, 1).
-define(SOCKET_OPT_TCP_CORK, 2).
%% -define(SOCKET_OPT_TCP_INFO, 3).
@@ -748,8 +780,10 @@
%% -define(SOCKET_OPT_TCP_SYNCNT, 12).
%% -define(SOCKET_OPT_TCP_USER_TIMEOUT, 13).
+%% *** UDP (socket) options
-define(SOCKET_OPT_UDP_CORK, 1).
+%% *** SCTP (socket) options
%% -define(SOCKET_OPT_SCTP_ADAPTION_LAYER, 1).
-define(SOCKET_OPT_SCTP_ASSOCINFO, 2).
%% -define(SOCKET_OPT_SCTP_AUTH_ACTIVE_KEY, 3).
@@ -802,23 +836,10 @@ on_load() ->
on_load(#{}).
-spec on_load(Extra) -> ok when
- Extra :: maps:map().
-
-on_load(Extra) when is_map(Extra) ->
- on_load(atom_to_list(?MODULE), Extra).
-
--spec on_load(Path, Extra) -> ok when
- Path :: string(),
- Extra :: maps:map().
+ Extra :: map().
-on_load(Path, Extra) when is_list(Path) andalso is_map(Extra) ->
- on_load(nif_is_loaded(), Path, Extra).
-
-on_load(true, _Path, _Extra) ->
- ok;
-on_load(false, Path, Extra) ->
- %% ok = erlang:load_nif(Path, maps:put(timestamp, formated_timestamp(), Extra)).
- ok = erlang:load_nif(Path, Extra).
+on_load(Extra) ->
+ ok = erlang:load_nif(atom_to_list(?MODULE), Extra).
@@ -1022,8 +1043,8 @@ bind(#socket{ref = SockRef}, Addrs, Action)
when is_list(Addrs) andalso ((Action =:= add) orelse (Action =:= remove)) ->
try
begin
- ensure_type(seqpacket, which_type(SockRef)),
- ensure_proto(sctp, which_protocol(SockRef)),
+ ensure_type(SockRef, seqpacket),
+ ensure_proto(SockRef, sctp),
validate_addrs(which_domain(SockRef), Addrs),
nif_bind(SockRef, Addrs, Action)
end
@@ -1508,38 +1529,6 @@ ensure_msghdr(_) ->
einval().
-
-%% send(Sock, #{ctrl = Ctrl} = MsgHdr, Flags) when is_list(Ctrl) ->
-%% case encode_cmsghdrs(Ctrl) of
-%% undefined ->
-%% send(Sock, maps:remove(ctrl, MsgHdr), Flags);
-%% Ctrl2 ->
-%% send(Sock, MsgHdr#{ctrl = Ctrl2}, Flags)
-%% end.
-
-%% encode_cmsghdrs([]) ->
-%% undefined;
-%% encode_cmsghdrs(Hdrs) ->
-%% encode_cmsghdrs(Hdrs, []).
-
-%% encode_cmsghdrs([], Acc) ->
-%% list_to_binary(lists:reverse(Acc));
-%% encode_cmsghdrs([H|T], Acc) when is_binary(H) ->
-%% encode_cmsghdrs(T, [H|Acc]);
-%% encode_cmsghdrs([#{level := Level,
-%% type := Type,
-%% data := Data} | T], Acc) ->
-%% case nif_encode_cmsghdr(Level, Type, Data) of
-%% {ok, Bin} when is_binary(Bin) ->
-%% encode_cmsghdrs(T, [Bin | Acc]);
-%% {error, _} = ERROR ->
-%% ERROR
-%% end.
-
-
-
-
-
%% ===========================================================================
%%
%% writev - write data into multiple buffers
@@ -1924,7 +1913,8 @@ do_recvfrom(SockRef, BufSz, EFlags, Timeout) ->
Reason :: term().
recvmsg(Socket) ->
- recvmsg(Socket, 0, 0, ?SOCKET_RECV_FLAGS_DEFAULT, ?SOCKET_RECV_TIMEOUT_DEFAULT).
+ recvmsg(Socket, 0, 0,
+ ?SOCKET_RECV_FLAGS_DEFAULT, ?SOCKET_RECV_TIMEOUT_DEFAULT).
-spec recvmsg(Socket, Flags) -> {ok, MsgHdr} | {error, Reason} when
Socket :: socket(),
@@ -2118,6 +2108,12 @@ shutdown(#socket{ref = SockRef}, How) ->
; (Socket, sctp, sctp_socket_option(), Value) -> ok | {error, Reason} when
Socket :: socket(),
Value :: term(),
+ Reason :: term()
+ ; (Socket, Level, Key, Value) -> ok | {error, Reason} when
+ Socket :: socket(),
+ Level :: non_neg_integer(),
+ Key :: non_neg_integer(),
+ Value :: binary(),
Reason :: term().
setopt(#socket{ref = SockRef}, Level, Key, Value) ->
@@ -2223,6 +2219,11 @@ getopt(#socket{ref = SockRef}, Level, Key) ->
%% These are internal "shortcut" functions for the options
%% domain, type and protocol.
+
+-spec which_domain(SockRef) -> Domain when
+ SockRef :: reference(),
+ Domain :: domain().
+
which_domain(SockRef) ->
case nif_getopt(SockRef, true,
?SOCKET_OPT_LEVEL_SOCKET, ?SOCKET_OPT_SOCK_DOMAIN) of
@@ -2233,6 +2234,10 @@ which_domain(SockRef) ->
end.
+-spec which_type(SockRef) -> Type when
+ SockRef :: reference(),
+ Type :: type().
+
which_type(SockRef) ->
case nif_getopt(SockRef, true,
?SOCKET_OPT_LEVEL_SOCKET, ?SOCKET_OPT_SOCK_TYPE) of
@@ -2242,6 +2247,10 @@ which_type(SockRef) ->
throw(ERROR)
end.
+-spec which_protocol(SockRef) -> Protocol when
+ SockRef :: reference(),
+ Protocol :: protocol().
+
which_protocol(SockRef) ->
case nif_getopt(SockRef, true,
?SOCKET_OPT_LEVEL_SOCKET, ?SOCKET_OPT_SOCK_PROTOCOL) of
@@ -2409,6 +2418,57 @@ enc_setopt_key(Level, Opt, Domain, Type, Protocol) ->
%% encode the value into an more "manageable" type.
%% It also handles "aliases" (see linger).
+-spec enc_setopt_value(otp, otp_socket_option(),
+ Value, Domain, Type, Protocol) -> term() when
+ Value :: term(),
+ Domain :: domain(),
+ Type :: type(),
+ Protocol :: protocol()
+ ; (socket, socket_option(),
+ Value, Domain, Type, Protocol) -> term() when
+ Value :: term(),
+ Domain :: domain(),
+ Type :: type(),
+ Protocol :: protocol()
+ ; (ip, ip_socket_option(),
+ Value, Domain, Type, Protocol) -> term() when
+ Value :: term(),
+ Domain :: domain(),
+ Type :: type(),
+ Protocol :: protocol()
+ ; (ipv6, ipv6_socket_option(),
+ Value, Domain, Type, Protocol) -> term() when
+ Value :: term(),
+ Domain :: domain(),
+ Type :: type(),
+ Protocol :: protocol()
+ ; (tcp, tcp_socket_option(),
+ Value, Domain, Type, Protocol) -> term() when
+ Value :: term(),
+ Domain :: domain(),
+ Type :: type(),
+ Protocol :: protocol()
+ ; (udp, udp_socket_option(),
+ Value, Domain, Type, Protocol) -> term() when
+ Value :: term(),
+ Domain :: domain(),
+ Type :: type(),
+ Protocol :: protocol()
+ ; (sctp, sctp_socket_option(),
+ Value, Domain, Type, Protocol) -> term() when
+ Value :: term(),
+ Domain :: domain(),
+ Type :: type(),
+ Protocol :: protocol()
+ ; (Level, Opt,
+ Value, Domain, Type, Protocol) -> term() when
+ Level :: integer(),
+ Opt :: integer(),
+ Value :: binary(),
+ Domain :: domain(),
+ Type :: type(),
+ Protocol :: protocol().
+
enc_setopt_value(otp, debug, V, _, _, _) when is_boolean(V) ->
V;
enc_setopt_value(otp, iow, V, _, _, _) when is_boolean(V) ->
@@ -2762,8 +2822,8 @@ enc_setopt_value(sctp, rtoinfo, #{assoc_id := AssocId,
enc_setopt_value(sctp = L, Opt, V, _D, _T, _P) ->
not_supported({L, Opt, V});
-enc_setopt_value(raw = L, Opt, _V, _D, _T, _P) ->
- not_supported({L, Opt});
+%% enc_setopt_value(raw = L, Opt, _V, _D, _T, _P) ->
+%% not_supported({L, Opt});
%% Is this correct? What about getopt?
enc_setopt_value(L, Opt, V, _, _, _)
@@ -2788,10 +2848,10 @@ enc_getopt_key(Level, Opt, Domain, Type, Protocol) ->
%% +++ Decode getopt value +++
%%
%% For the most part, we simply let the value pass through, but for some
-%% values we do an actual decode.
+%% values we may need to do an actual decode.
%%
-%% Let the user deal with this...
+%% Let the user deal with this for now...
dec_getopt_value(_L, _Opt, V, _D, _T, _P) ->
V.
@@ -3361,15 +3421,26 @@ tdiff(T1, T2) ->
%%
%% ===========================================================================
+-spec not_supported(What) -> no_return() when
+ What :: term().
+
not_supported(What) ->
error({not_supported, What}).
+-spec unknown(What) -> no_return() when
+ What :: term().
+
unknown(What) ->
error({unknown, What}).
+-spec einval() -> no_return().
+
einval() ->
error(einval).
+-spec error(Reason) -> no_return() when
+ Reason :: term().
+
error(Reason) ->
throw({error, Reason}).
@@ -3380,71 +3451,69 @@ error(Reason) ->
%%
%% ===========================================================================
-nif_is_loaded() -> false.
-
nif_info() ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_open(_Domain, _Type, _Protocol, _Extra) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_bind(_SRef, _SockAddr) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_bind(_SRef, _SockAddrs, _Action) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_connect(_SRef, _SockAddr) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_finalize_connection(_SRef) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_listen(_SRef, _Backlog) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_accept(_SRef, _Ref) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_send(_SockRef, _SendRef, _Data, _Flags) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_sendto(_SRef, _SendRef, _Data, _Dest, _Flags) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_sendmsg(_SRef, _SendRef, _MsgHdr, _Flags) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_recv(_SRef, _RecvRef, _Length, _Flags) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_recvfrom(_SRef, _RecvRef, _Length, _Flags) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_recvmsg(_SRef, _RecvRef, _BufSz, _CtrlSz, _Flags) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_cancel(_SRef, _Op, _Ref) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_close(_SRef) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_shutdown(_SRef, _How) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_finalize_close(_SRef) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_setopt(_Ref, _IsEnc, _Lev, _Key, _Val) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_getopt(_Ref, _IsEnc, _Lev, _Key) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_sockname(_Ref) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).
nif_peername(_Ref) ->
- erlang:error(badarg).
+ erlang:nif_error(undef).