From 929ae46220f402d6f36072c46fe27ba39ad48d1b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Thu, 13 Sep 2018 15:44:21 +0200 Subject: [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. --- erts/doc/src/socket.xml | 20 +- erts/emulator/nifs/common/net_nif.c | 27 +-- erts/emulator/nifs/common/socket_nif.c | 326 +++++++++++++++++++++------------ erts/preloaded/ebin/net.beam | Bin 6036 -> 5632 bytes erts/preloaded/ebin/socket.beam | Bin 64588 -> 66000 bytes erts/preloaded/src/Makefile | 29 ++- erts/preloaded/src/net.erl | 42 ++--- erts/preloaded/src/socket.erl | 263 ++++++++++++++++---------- 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 @@ + - + + + + @@ -427,7 +432,7 @@ how much we want to read, it returns when we get a message.

The message will be delivered in the form of a msghdr(), which may contain the source address (if socket not connected), - a list of cmsghdr() (depends on what socket options have + a list of cmsghdr_recv() (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 .

@@ -466,11 +471,11 @@ Send a message on a socket. -

Send a message on a socket. The destination, if needed (socket not - connected) is provided in the MsgHdr, which also - contains the message to send, The MsgHdr may also contain - an list of optional cmsghdr() (depends on what the protocol and - platform supports).

+

Send a message on a socket. The destination, if needed + (socket not connected) is provided in the MsgHdr, + which also contains the message to send, + The MsgHdr may also contain an list of optional cmsghdr_send() + (depends on what the protocol and platform supports).

@@ -492,6 +497,7 @@ + Set options on a socket.

Set options on a socket.

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: * ------------------------------ @@ -454,27 +451,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 * @@ -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) * @@ -2416,27 +2423,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 * @@ -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. - * - * - * - * At the moment, the only data we support is a binary... - * - * */ + + 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 Binary files a/erts/preloaded/ebin/net.beam and b/erts/preloaded/ebin/net.beam differ diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam index 5b14af3ad8..b3f3e385d2 100644 Binary files a/erts/preloaded/ebin/socket.beam and b/erts/preloaded/ebin/socket.beam 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). -- cgit v1.2.3