From 2c08787a53d30bb60d2b604eedb19389dc5a0d9e Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 20 May 2019 15:23:48 +0200 Subject: [esock,kernel] net -> prim_net and add (new) net Renamed the current preloaded net module to prim_net and removed the deprecated functions (call, cast, ...). Introduce a "new" net module (in kernel) as an interface module to the (preloaded) prim_net. This one also contains the deprecated functions (call, cast, ...). OTP-15765 --- erts/emulator/Makefile.in | 7 +- erts/emulator/nifs/common/net_nif.c | 1656 ------------------------------ erts/emulator/nifs/common/prim_net_nif.c | 1656 ++++++++++++++++++++++++++++++ erts/emulator/test/net_SUITE.erl | 3 + erts/preloaded/ebin/erl_init.beam | Bin 2260 -> 2316 bytes erts/preloaded/ebin/net.beam | Bin 6096 -> 0 bytes erts/preloaded/ebin/prim_net.beam | Bin 0 -> 4700 bytes erts/preloaded/src/Makefile | 9 +- erts/preloaded/src/erl_init.erl | 3 +- erts/preloaded/src/net.erl | 353 ------- erts/preloaded/src/prim_net.erl | 289 ++++++ 11 files changed, 1957 insertions(+), 2019 deletions(-) delete mode 100644 erts/emulator/nifs/common/net_nif.c create mode 100644 erts/emulator/nifs/common/prim_net_nif.c delete mode 100644 erts/preloaded/ebin/net.beam create mode 100644 erts/preloaded/ebin/prim_net.beam delete mode 100644 erts/preloaded/src/net.erl create mode 100644 erts/preloaded/src/prim_net.erl (limited to 'erts') diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index a9f3bb8e89..ba5ba8abef 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -636,10 +636,9 @@ GENERATE += $(TTF_DIR)/driver_tab.c ifeq ($(USE_ESOCK), yes) ESOCK_PRELOAD_BEAM = \ $(ERL_TOP)/erts/preloaded/ebin/socket.beam \ - $(ERL_TOP)/erts/preloaded/ebin/net.beam + $(ERL_TOP)/erts/preloaded/ebin/prim_net.beam else -ESOCK_PRELOAD_BEAM = \ - $(ERL_TOP)/erts/preloaded/ebin/net.beam +ESOCK_PRELOAD_BEAM = endif PRELOAD_BEAM = $(ERL_TOP)/erts/preloaded/ebin/erts_code_purger.beam \ @@ -850,7 +849,7 @@ ifeq ($(USE_ESOCK), yes) ESOCK_NIF_OBJS = \ $(OBJDIR)/socket_nif.o \ - $(OBJDIR)/net_nif.o + $(OBJDIR)/prim_net_nif.o ifneq ($(TARGET), win32) # These are *currently* only needed for non-win32, diff --git a/erts/emulator/nifs/common/net_nif.c b/erts/emulator/nifs/common/net_nif.c deleted file mode 100644 index 8a69052935..0000000000 --- a/erts/emulator/nifs/common/net_nif.c +++ /dev/null @@ -1,1656 +0,0 @@ -/* - * %CopyrightBegin% - * - * Copyright Ericsson AB 2018-2019. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * %CopyrightEnd% - * - * ---------------------------------------------------------------------- - * Purpose : The NIF (C) part of the net interface - * This is a module of miscellaneous functions. - * ---------------------------------------------------------------------- - * - */ - -#define STATIC_ERLANG_NIF 1 - - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -/* If we HAVE_SCTP_H and Solaris, we need to define the following in - * order to get SCTP working: - */ -#if (defined(HAVE_SCTP_H) && defined(__sun) && defined(__SVR4)) -#define SOLARIS10 1 -/* WARNING: This is not quite correct, it may also be Solaris 11! */ -#define _XPG4_2 -#define __EXTENSIONS__ -#endif - -#include -#include -#include -#include -#include -#include -#include - -#ifdef HAVE_UNISTD_H -#include -#endif -#ifdef HAVE_SYS_UIO_H -#include -#endif - -#ifdef HAVE_NET_IF_DL_H -#include -#endif - -#ifdef HAVE_IFADDRS_H -#include -#endif - -#ifdef HAVE_NETPACKET_PACKET_H -#include -#endif - -#ifdef HAVE_SYS_UN_H -#include -#endif - -/* SENDFILE STUFF HERE IF WE NEED IT... */ - -#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) -#define __DARWIN__ 1 -#endif - - -#ifdef __WIN32__ -#define STRNCASECMP strncasecmp -#define INCL_WINSOCK_API_TYPEDEFS 1 - -#ifndef WINDOWS_H_INCLUDES_WINSOCK2_H -#include -#endif -#include -#include /* NEED VC 6.0 or higher */ - -/* Visual studio 2008+: NTDDI_VERSION needs to be set for iphlpapi.h - * to define the right structures. It needs to be set to WINXP (or LONGHORN) - * for IPV6 to work and it's set lower by default, so we need to change it. - */ -#ifdef HAVE_SDKDDKVER_H -# include -# ifdef NTDDI_VERSION -# undef NTDDI_VERSION -# endif -# define NTDDI_VERSION NTDDI_WINXP -#endif -#include - -#undef WANT_NONBLOCKING -#include "sys.h" - -#else /* !__WIN32__ */ - -#include -#ifdef NETDB_H_NEEDS_IN_H -#include -#endif -#include - -#include -#include - -#ifdef DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H -#include -#endif - -#include -#include -#include -#include - -#include -#ifdef HAVE_ARPA_NAMESER_H -#include -#endif - -#ifdef HAVE_SYS_SOCKIO_H -#include -#endif - -#ifdef HAVE_SYS_IOCTL_H -#include -#endif - -#include - -#ifdef HAVE_SCHED_H -#include -#endif - -#ifdef HAVE_SETNS_H -#include -#endif - -#define HAVE_UDP - -#ifndef WANT_NONBLOCKING -#define WANT_NONBLOCKING -#endif -#include "sys.h" - -#endif - -#include - -#include "socket_dbg.h" -#include "socket_int.h" -#include "socket_util.h" - - -/* All platforms fail on malloc errors. */ -#define FATAL_MALLOC - - -#ifdef __WIN32__ -#define net_gethostname(__buf__, __bufSz__) gethostname((__buf__), (__bufSz__)) -#else -#define net_gethostname(__buf__, __bufSz__) gethostname((__buf__), (__bufSz__)) -#endif // __WIN32__ - - - -/* *** Misc macros and defines *** */ - -#ifdef __WIN32__ -#define get_errno() WSAGetLastError() -#else -#define get_errno() errno -#endif - - -#define HOSTNAME_LEN 256 -#define SERVICE_LEN 256 - - -/* MAXHOSTNAMELEN could be 64 or 255 depending - * on the platform. Instead, use INET_MAXHOSTNAMELEN - * which is always 255 across all platforms - */ -#define NET_MAXHOSTNAMELEN 255 - - -/* =================================================================== * - * * - * Various enif macros * - * * - * =================================================================== */ - - -#ifdef HAVE_SOCKLEN_T -# define SOCKLEN_T socklen_t -#else -# define SOCKLEN_T size_t -#endif - -/* Debug stuff... */ -#define NET_NIF_DEBUG_DEFAULT FALSE - -#define NDBG( proto ) ESOCK_DBG_PRINTF( data.debug , proto ) - - -typedef struct { - BOOLEAN_T debug; -} NetData; - - - -/* =================================================================== * - * * - * Static data * - * * - * =================================================================== */ - - -static NetData data; - - - -/* ---------------------------------------------------------------------- - * F o r w a r d s - * ---------------------------------------------------------------------- - */ - -/* THIS IS JUST TEMPORARY */ -extern char* erl_errno_id(int error); - -/* All the nif "callback" functions for the net API has - * the exact same API: - * - * nif_(ErlNifEnv* env, - * int argc, - * const ERL_NIF_TERM argv[]); - * - * So, to simplify, use some macro magic to define those. - * - * These are the functions making up the "official" API. - */ - -#define ENET_NIF_FUNCS \ - ENET_NIF_FUNC_DEF(info); \ - ENET_NIF_FUNC_DEF(command); \ - ENET_NIF_FUNC_DEF(gethostname); \ - ENET_NIF_FUNC_DEF(getnameinfo); \ - ENET_NIF_FUNC_DEF(getaddrinfo); \ - ENET_NIF_FUNC_DEF(if_name2index); \ - ENET_NIF_FUNC_DEF(if_index2name); \ - ENET_NIF_FUNC_DEF(if_names); - -#define ENET_NIF_FUNC_DEF(F) \ - static ERL_NIF_TERM nif_##F(ErlNifEnv* env, \ - int argc, \ - const ERL_NIF_TERM argv[]); -ENET_NIF_FUNCS -#undef ENET_NIF_FUNC_DEF - - -/* And here comes the functions that does the actual work (for the most part) */ -static ERL_NIF_TERM ncommand(ErlNifEnv* env, - ERL_NIF_TERM cmd); -static ERL_NIF_TERM ngethostname(ErlNifEnv* env); -static ERL_NIF_TERM ngetnameinfo(ErlNifEnv* env, - const ESockAddress* saP, - SOCKLEN_T saLen, - int flags); -static ERL_NIF_TERM ngetaddrinfo(ErlNifEnv* env, - char* host, - char* serv); -static ERL_NIF_TERM nif_name2index(ErlNifEnv* env, - char* ifn); -static ERL_NIF_TERM nif_index2name(ErlNifEnv* env, - unsigned int id); -static ERL_NIF_TERM nif_names(ErlNifEnv* env); -static unsigned int nif_names_length(struct if_nameindex* p); - -/* -static void net_dtor(ErlNifEnv* env, void* obj); -static void net_stop(ErlNifEnv* env, - void* obj, - int fd, - int is_direct_call); -static void net_down(ErlNifEnv* env, - void* obj, - const ErlNifPid* pid, - const ErlNifMonitor* mon); -*/ - -static BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, - const ERL_NIF_TERM eflags, - int* flags); -static BOOLEAN_T decode_nameinfo_flags_list(ErlNifEnv* env, - const ERL_NIF_TERM eflags, - int* flags); -static -BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, - const ERL_NIF_TERM eString, - char** stringP); -static ERL_NIF_TERM decode_bool(ErlNifEnv* env, - ERL_NIF_TERM eBool, - BOOLEAN_T* bool); -static ERL_NIF_TERM encode_address_infos(ErlNifEnv* env, - struct addrinfo* addrInfo); -static ERL_NIF_TERM encode_address_info(ErlNifEnv* env, - struct addrinfo* addrInfoP); -static unsigned int address_info_length(struct addrinfo* addrInfoP); - -static ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, - int family); -static ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, - int socktype); -static ERL_NIF_TERM encode_address_info_proto(ErlNifEnv* env, - int proto); - -static char* make_address_info(ErlNifEnv* env, - ERL_NIF_TERM fam, - ERL_NIF_TERM sockType, - ERL_NIF_TERM proto, - ERL_NIF_TERM addr, - ERL_NIF_TERM* ai); - -static BOOLEAN_T extract_debug(ErlNifEnv* env, - ERL_NIF_TERM map); -static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); - - -#if HAVE_IN6 -# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY -# if HAVE_DECL_IN6ADDR_ANY_INIT -static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } }; -# else -static const struct in6_addr in6addr_any = - { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; -# endif /* HAVE_IN6ADDR_ANY_INIT */ -# endif /* ! HAVE_DECL_IN6ADDR_ANY */ - -# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK -# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT -static const struct in6_addr in6addr_loopback = - { { IN6ADDR_LOOPBACK_INIT } }; -# else -static const struct in6_addr in6addr_loopback = - { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; -# endif /* HAVE_IN6ADDR_LOOPBACk_INIT */ -# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */ -#endif /* HAVE_IN6 */ - - - -/* *** Local atoms *** */ - -#define LOCAL_ATOMS \ - LOCAL_ATOM_DECL(address_info); \ - LOCAL_ATOM_DECL(debug); \ - LOCAL_ATOM_DECL(host); \ - LOCAL_ATOM_DECL(idn); \ - LOCAL_ATOM_DECL(idna_allow_unassigned); \ - LOCAL_ATOM_DECL(idna_use_std3_ascii_rules); \ - LOCAL_ATOM_DECL(namereqd); \ - LOCAL_ATOM_DECL(name_info); \ - LOCAL_ATOM_DECL(nofqdn); \ - LOCAL_ATOM_DECL(numerichost); \ - LOCAL_ATOM_DECL(numericserv); \ - LOCAL_ATOM_DECL(service); - -#define LOCAL_ERROR_REASON_ATOMS \ - LOCAL_ATOM_DECL(eaddrfamily); \ - LOCAL_ATOM_DECL(ebadflags); \ - LOCAL_ATOM_DECL(efail); \ - LOCAL_ATOM_DECL(efamily); \ - LOCAL_ATOM_DECL(efault); \ - LOCAL_ATOM_DECL(emem); \ - LOCAL_ATOM_DECL(enametoolong); \ - LOCAL_ATOM_DECL(enodata); \ - LOCAL_ATOM_DECL(enoname); \ - LOCAL_ATOM_DECL(enxio); \ - LOCAL_ATOM_DECL(eoverflow); \ - LOCAL_ATOM_DECL(eservice); \ - LOCAL_ATOM_DECL(esocktype); \ - LOCAL_ATOM_DECL(esystem); - -#define LOCAL_ATOM_DECL(A) static ERL_NIF_TERM atom_##A -LOCAL_ATOMS -LOCAL_ERROR_REASON_ATOMS -#undef LOCAL_ATOM_DECL - - -/* *** net *** */ -static ErlNifResourceType* net; -static ErlNifResourceTypeInit netInit = { - NULL, // net_dtor, - NULL, // net_stop, - NULL // (ErlNifResourceDown*) net_down -}; - - - -/* ---------------------------------------------------------------------- - * N I F F u n c t i o n s - * ---------------------------------------------------------------------- - * - * Utility and admin functions: - * ---------------------------- - * nif_info/0 - * nif_command/1 - * - * The "proper" net functions: - * ------------------------------ - * nif_gethostname/0 - * nif_getnameinfo/2 - * nif_getaddrinfo/3 - * nif_if_name2index/1 - * nif_if_index2name/1 - * nif_if_names/0 - * - */ - - -/* ---------------------------------------------------------------------- - * nif_info - * - * Description: - * This is currently just a placeholder... - */ -static -ERL_NIF_TERM nif_info(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM info, tmp; - - NDBG( ("NET", "info -> entry\r\n") ); - - tmp = enif_make_new_map(env); - if (!enif_make_map_put(env, tmp, atom_debug, BOOL2ATOM(data.debug), &info)) - info = tmp; - - NDBG( ("NET", "info -> done: %T\r\n", info) ); - - return info; -#endif -} - - - -/* ---------------------------------------------------------------------- - * nif_command - * - * Description: - * This is a general purpose utility function. - * - * Arguments: - * Command - This is a general purpose command, of any type. - * Currently, the only supported command is: - * - * {debug, boolean()} - */ -static -ERL_NIF_TERM nif_command(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM ecmd, result; - - NDBG( ("NET", "command -> entry (%d)\r\n", argc) ); - - if (argc != 1) - return enif_make_badarg(env); - - ecmd = argv[0]; - - NDBG( ("NET", "command -> ecmd: %T\r\n", ecmd) ); - - result = ncommand(env, ecmd); - - NDBG( ("NET", "command -> result: %T\r\n", result) ); - - return result; -#endif -} - - - -/* - * The command can, in principle, be anything, though currently we only - * support a debug command. - */ -#if !defined(__WIN32__) -static -ERL_NIF_TERM ncommand(ErlNifEnv* env, - ERL_NIF_TERM cmd) -{ - const ERL_NIF_TERM* t; - int tsz; - - if (IS_TUPLE(env, cmd)) { - /* Could be the debug tuple */ - if (!GET_TUPLE(env, cmd, &tsz, &t)) - return esock_make_error(env, esock_atom_einval); - - if (tsz != 2) - return esock_make_error(env, esock_atom_einval); - - /* First element should be the atom 'debug' */ - if (COMPARE(t[0], atom_debug) != 0) - return esock_make_error(env, esock_atom_einval); - - return decode_bool(env, t[1], &data.debug); - - } else { - return esock_make_error(env, esock_atom_einval); - } - -} -#endif - - - -/* ---------------------------------------------------------------------- - * nif_gethostname - * - * Description: - * Access the hostname of the current processor. - * - */ -static -ERL_NIF_TERM nif_gethostname(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM result; - - NDBG( ("NET", "nif_gethostname -> entry (%d)\r\n", argc) ); - - if (argc != 0) - return enif_make_badarg(env); - - result = ngethostname(env); - - NDBG( ("NET", "nif_gethostname -> done when result: %T\r\n", result) ); - - return result; -#endif -} - - -#if !defined(__WIN32__) -static -ERL_NIF_TERM ngethostname(ErlNifEnv* env) -{ - ERL_NIF_TERM result; - char buf[NET_MAXHOSTNAMELEN + 1]; - int res; - - res = net_gethostname(buf, sizeof(buf)); - - NDBG( ("NET", "ngethostname -> gethostname res: %d\r\n", res) ); - - switch (res) { - case 0: - result = esock_make_ok2(env, MKS(env, buf)); - break; - - case EFAULT: - result = esock_make_error(env, atom_efault); - break; - - case EINVAL: - result = esock_make_error(env, esock_atom_einval); - break; - - case ENAMETOOLONG: - result = esock_make_error(env, atom_enametoolong); - break; - - default: - result = esock_make_error(env, MKI(env, res)); - break; - } - - return result; -} -#endif - - - - -/* ---------------------------------------------------------------------- - * nif_getnameinfo - * - * Description: - * Address-to-name translation in protocol-independent manner. - * - * Arguments: - * SockAddr - Socket Address (address and port) - * Flags - The flags argument modifies the behavior of getnameinfo(). - */ - -static -ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM result; - ERL_NIF_TERM eSockAddr, eFlags; - int flags = 0; // Just in case... - ESockAddress sa; - SOCKLEN_T saLen = 0; // Just in case... - char* xres; - - NDBG( ("NET", "nif_getnameinfo -> entry (%d)\r\n", argc) ); - - if (argc != 2) - return enif_make_badarg(env); - eSockAddr = argv[0]; - eFlags = argv[1]; - - NDBG( ("NET", - "nif_getnameinfo -> " - "\r\n SockAddr: %T" - "\r\n Flags: %T" - "\r\n", eSockAddr, eFlags) ); - - if ((xres = esock_decode_sockaddr(env, eSockAddr, &sa, &saLen)) != NULL) { - NDBG( ("NET", "nif_getnameinfo -> failed decode sockaddr: %s\r\n", xres) ); - return esock_make_error_str(env, xres); - } - - NDBG( ("NET", "nif_getnameinfo -> (try) decode flags\r\n") ); - - if (!decode_nameinfo_flags(env, eFlags, &flags)) - return enif_make_badarg(env); - - result = ngetnameinfo(env, &sa, saLen, flags); - - NDBG( ("NET", - "nif_getnameinfo -> done when result: " - "\r\n %T\r\n", result) ); - - return result; -#endif -} - - - -/* Given the provided sock(et) address (and flags), retreive the host and - * service info. - */ -#if !defined(__WIN32__) -static -ERL_NIF_TERM ngetnameinfo(ErlNifEnv* env, - const ESockAddress* saP, - SOCKLEN_T saLen, - int flags) -{ - ERL_NIF_TERM result; - char host[HOSTNAME_LEN]; - SOCKLEN_T hostLen = sizeof(host); - char serv[SERVICE_LEN]; - SOCKLEN_T servLen = sizeof(serv); - - int res = getnameinfo((struct sockaddr*) saP, saLen, - host, hostLen, - serv, servLen, - flags); - - NDBG( ("NET", "ngetnameinfo -> res: %d\r\n", res) ); - - switch (res) { - case 0: - { - ERL_NIF_TERM keys[] = {atom_host, atom_service}; - ERL_NIF_TERM vals[] = {MKS(env, host), MKS(env, serv)}; - ERL_NIF_TERM info; - unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM); - unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM); - - ESOCK_ASSERT( (numKeys == numVals) ); - - if (!MKMA(env, keys, vals, numKeys, &info)) - return enif_make_badarg(env); - - result = esock_make_ok2(env, info); - } - break; - -#if defined(EAI_AGAIN) - case EAI_AGAIN: - result = esock_make_error(env, esock_atom_eagain); - break; -#endif - -#if defined(EAI_BADFLAGS) - case EAI_BADFLAGS: - result = esock_make_error(env, atom_ebadflags); - break; -#endif - -#if defined(EAI_FAIL) - case EAI_FAIL: - result = esock_make_error(env, atom_efail); - break; -#endif - -#if defined(EAI_FAMILY) - case EAI_FAMILY: - result = esock_make_error(env, atom_efamily); - break; -#endif - -#if defined(EAI_MEMORY) - case EAI_MEMORY: - result = esock_make_error(env, atom_emem); - break; -#endif - -#if defined(EAI_NONAME) - case EAI_NONAME: - result = esock_make_error(env, atom_enoname); - break; -#endif - -#if defined(EAI_OVERFLOW) - case EAI_OVERFLOW: - result = esock_make_error(env, atom_eoverflow); - break; -#endif - -#if defined(EAI_SYSTEM) - case EAI_SYSTEM: - result = esock_make_error_errno(env, get_errno()); - break; -#endif - - default: - result = esock_make_error(env, esock_atom_einval); - break; - } - - return result; -} -#endif - - - -/* ---------------------------------------------------------------------- - * nif_getaddrinfo - * - * Description: - * Network address and service translation. - * - * Arguments: - * Host - Host name (either a string or the atom undefined) - * Service - Service name (either a string or the atom undefined) - * Hints - Hints for the lookup (address info record) (currently *ignored*) - */ - -static -ERL_NIF_TERM nif_getaddrinfo(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM result, eHostName, eServName; //, eHints; - char* hostName; - char* servName; - // struct addrinfo* hints; - - NDBG( ("NET", "nif_getaddrinfo -> entry (%d)\r\n", argc) ); - - if (argc != 3) { - return enif_make_badarg(env); - } - eHostName = argv[0]; - eServName = argv[1]; - // eHints = argv[2]; - - NDBG( ("NET", - "nif_getaddrinfo -> " - "\r\n ehost: %T" - "\r\n eservice: %T" - "\r\n ehints: %T" - "\r\n", argv[0], argv[1], argv[2]) ); - - if (!decode_addrinfo_string(env, eHostName, &hostName)) - return enif_make_badarg(env); - - if (!decode_addrinfo_string(env, eServName, &servName)) - return enif_make_badarg(env); - - /* - if (decode_addrinfo_hints(env, eHints, &hints)) - return enif_make_badarg(env); - */ - - if ((hostName == NULL) && (servName == NULL)) - return enif_make_badarg(env); - - result = ngetaddrinfo(env, hostName, servName); - - if (hostName != NULL) - FREE(hostName); - - if (servName != NULL) - FREE(servName); - - /* - if (hints != NULL) - FREE(hints); - */ - - NDBG( ("NET", - "nif_getaddrinfo -> done when result: " - "\r\n %T\r\n", result) ); - - return result; -#endif -} - - -#if !defined(__WIN32__) -static -ERL_NIF_TERM ngetaddrinfo(ErlNifEnv* env, - char* host, - char* serv) -{ - ERL_NIF_TERM result; - struct addrinfo* addrInfoP; - int res; - - NDBG( ("NET", "ngetaddrinfo -> entry with" - "\r\n host: %s" - "\r\n serv: %s" - "\r\n", - ((host == NULL) ? "NULL" : host), - ((serv == NULL) ? "NULL" : serv)) ); - - res = getaddrinfo(host, serv, NULL, &addrInfoP); - - NDBG( ("NET", "ngetaddrinfo -> res: %d\r\n", res) ); - - switch (res) { - case 0: - { - ERL_NIF_TERM addrInfo = encode_address_infos(env, addrInfoP); - freeaddrinfo(addrInfoP); - result = esock_make_ok2(env, addrInfo); - } - break; - -#if defined(EAI_ADDRFAMILY) - case EAI_ADDRFAMILY: - result = esock_make_error(env, atom_eaddrfamily); - break; -#endif - -#if defined(EAI_AGAIN) - case EAI_AGAIN: - result = esock_make_error(env, esock_atom_eagain); - break; -#endif - -#if defined(EAI_BADFLAGS) - case EAI_BADFLAGS: - result = esock_make_error(env, atom_ebadflags); - break; -#endif - -#if defined(EAI_FAIL) - case EAI_FAIL: - result = esock_make_error(env, atom_efail); - break; -#endif - -#if defined(EAI_FAMILY) - case EAI_FAMILY: - result = esock_make_error(env, atom_efamily); - break; -#endif - -#if defined(EAI_MEMORY) - case EAI_MEMORY: - result = esock_make_error(env, atom_emem); - break; -#endif - -#if defined(EAI_NODATA) - case EAI_NODATA: - result = esock_make_error(env, atom_enodata); - break; -#endif - -#if defined(EAI_NONAME) - case EAI_NONAME: - result = esock_make_error(env, atom_enoname); - break; -#endif - -#if defined(EAI_SERVICE) - case EAI_SERVICE: - result = esock_make_error(env, atom_eservice); - break; -#endif - -#if defined(EAI_SOCKTYPE) - case EAI_SOCKTYPE: - result = esock_make_error(env, atom_esocktype); - break; -#endif - -#if defined(EAI_SYSTEM) - case EAI_SYSTEM: - result = esock_make_error(env, atom_esystem); - break; -#endif - - default: - result = esock_make_error(env, esock_atom_einval); - break; - } - - return result; -} -#endif - - - -/* ---------------------------------------------------------------------- - * nif_if_name2index - * - * Description: - * Perform a Interface Name to Interface Index translation. - * - * Arguments: - * Ifn - Interface name to be translated. - */ - -static -ERL_NIF_TERM nif_if_name2index(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM eifn, result; - char ifn[IF_NAMESIZE+1]; - - NDBG( ("NET", "nif_if_name2index -> entry (%d)\r\n", argc) ); - - if (argc != 1) { - return enif_make_badarg(env); - } - eifn = argv[0]; - - NDBG( ("NET", - "nif_if_name2index -> " - "\r\n Ifn: %T" - "\r\n", argv[0]) ); - - if (0 >= GET_STR(env, eifn, ifn, sizeof(ifn))) - return esock_make_error(env, esock_atom_einval); - - result = nif_name2index(env, ifn); - - NDBG( ("NET", "nif_if_name2index -> done when result: %T\r\n", result) ); - - return result; -#endif -} - - - -#if !defined(__WIN32__) -static -ERL_NIF_TERM nif_name2index(ErlNifEnv* env, - char* ifn) -{ - unsigned int idx; - - NDBG( ("NET", "nif_name2index -> entry with ifn: %s\r\n", ifn) ); - - idx = if_nametoindex(ifn); - - NDBG( ("NET", "nif_name2index -> idx: %d\r\n", idx) ); - - if (idx == 0) { - int save_errno = get_errno(); - NDBG( ("NET", "nif_name2index -> failed: %d\r\n", save_errno) ); - return esock_make_error_errno(env, save_errno); - } else { - return esock_make_ok2(env, MKI(env, idx)); - } - -} -#endif - - - -/* ---------------------------------------------------------------------- - * nif_if_index2name - * - * Description: - * Perform a Interface Index to Interface Name translation. - * - * Arguments: - * Idx - Interface index to be translated. - */ - -static -ERL_NIF_TERM nif_if_index2name(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM result; - unsigned int idx; - - NDBG( ("NET", "nif_if_index2name -> entry (%d)\r\n", argc) ); - - if ((argc != 1) || - !GET_UINT(env, argv[0], &idx)) { - return enif_make_badarg(env); - } - - NDBG( ("NET", "nif_index2name -> " - "\r\n Idx: %T" - "\r\n", argv[0]) ); - - result = nif_index2name(env, idx); - - NDBG( ("NET", "nif_if_index2name -> done when result: %T\r\n", result) ); - - return result; -#endif -} - - - -#if !defined(__WIN32__) -static -ERL_NIF_TERM nif_index2name(ErlNifEnv* env, - unsigned int idx) -{ - ERL_NIF_TERM result; - char* ifn = MALLOC(IF_NAMESIZE+1); - - if (ifn == NULL) - return enif_make_badarg(env); // PLACEHOLDER - - if (NULL != if_indextoname(idx, ifn)) { - result = esock_make_ok2(env, MKS(env, ifn)); - } else { - result = esock_make_error(env, atom_enxio); - } - - FREE(ifn); - - return result; -} -#endif - - - -/* ---------------------------------------------------------------------- - * nif_if_names - * - * Description: - * Get network interface names and indexes. - * - */ - -static -ERL_NIF_TERM nif_if_names(ErlNifEnv* env, - int argc, - const ERL_NIF_TERM argv[]) -{ -#if defined(__WIN32__) - return enif_raise_exception(env, MKA(env, "notsup")); -#else - ERL_NIF_TERM result; - - NDBG( ("NET", "nif_if_names -> entry (%d)\r\n", argc) ); - - if (argc != 0) { - return enif_make_badarg(env); - } - - result = nif_names(env); - - NDBG( ("NET", "nif_if_names -> done when result: %T\r\n", result) ); - - return result; -#endif -} - - - -#if !defined(__WIN32__) -static -ERL_NIF_TERM nif_names(ErlNifEnv* env) -{ - ERL_NIF_TERM result; - struct if_nameindex* ifs = if_nameindex(); - - NDBG( ("NET", "nif_names -> ifs: 0x%lX\r\n", ifs) ); - - if (ifs == NULL) { - result = esock_make_error_errno(env, get_errno()); - } else { - /* - * We got some interfaces: - * 1) Calculate how many - the only way is to iterate through the list - * until its end (which is indicated by an entry with index = zero - * and if_name = NULL). - * 2) Allocate an ERL_NIF_TERM array of the calculated length. - * 3) Iterate through the array of interfaces and for each create - * a two tuple: {Idx, If} - * - * Or shall we instead build a list in reverse order and then when - * its done, reverse that? Check - */ - unsigned int len = nif_names_length(ifs); - - NDBG( ("NET", "nif_names -> len: %d\r\n", len) ); - - if (len > 0) { - ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); - unsigned int i; - - for (i = 0; i < len; i++) { - array[i] = MKT2(env, - MKI(env, ifs[i].if_index), - MKS(env, ifs[i].if_name)); - } - - result = esock_make_ok2(env, MKLA(env, array, len)); - FREE(array); - } else { - result = esock_make_ok2(env, enif_make_list(env, 0)); - } - } - - if (ifs != NULL) - if_freenameindex(ifs); - - return result; -} - - -static -unsigned int nif_names_length(struct if_nameindex* p) -{ - unsigned int len = 0; - BOOLEAN_T done = FALSE; - - while (!done) { - - NDBG( ("NET", "nif_names_length -> %d: " - "\r\n if_index: %d" - "\r\n if_name: 0x%lX" - "\r\n", len, p[len].if_index, p[len].if_name) ); - - if ((p[len].if_index == 0) && (p[len].if_name == NULL)) - done = TRUE; - else - len++; - } - - return len; -} -#endif // if !defined(__WIN32__) - - - -/* ---------------------------------------------------------------------- - * U t i l i t y F u n c t i o n s - * ---------------------------------------------------------------------- - */ - -/* The erlang format for a set of flags is a list of atoms. - * A special case is when there is no flags, which is - * represented by the atom undefined. - */ -#if !defined(__WIN32__) -static -BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, - const ERL_NIF_TERM eflags, - int* flags) -{ - BOOLEAN_T result; - - if (IS_ATOM(env, eflags)) { - NDBG( ("NET", "decode_nameinfo_flags -> is atom (%T)\r\n", eflags) ); - if (COMPARE(eflags, esock_atom_undefined) == 0) { - *flags = 0; - result = TRUE; - } else { - result = FALSE; - } - } else if (IS_LIST(env, eflags)) { - NDBG( ("NET", "decode_nameinfo_flags -> is list\r\n") ); - result = decode_nameinfo_flags_list(env, eflags, flags); - } else { - result = FALSE; - } - - NDBG( ("NET", "decode_nameinfo_flags -> result: %s\r\n", B2S(result)) ); - - return result; -} - - - -static -BOOLEAN_T decode_nameinfo_flags_list(ErlNifEnv* env, - const ERL_NIF_TERM eflags, - int* flags) -{ - ERL_NIF_TERM elem, tail, list = eflags; - int tmp = 0; - BOOLEAN_T done = FALSE; - - while (!done) { - if (GET_LIST_ELEM(env, list, &elem, &tail)) { - if (COMPARE(elem, atom_namereqd) == 0) { - tmp |= NI_NAMEREQD; - } else if (COMPARE(elem, esock_atom_dgram) == 0) { - tmp |= NI_DGRAM; - } else if (COMPARE(elem, atom_nofqdn) == 0) { - tmp |= NI_NOFQDN; - } else if (COMPARE(elem, atom_numerichost) == 0) { - tmp |= NI_NUMERICHOST; - } else if (COMPARE(elem, atom_numericserv) == 0) { - tmp |= NI_NUMERICSERV; - - /* Starting with glibc 2.3.4: */ - -#if defined(NI_IDN) - } else if (COMPARE(elem, atom_idn) == 0) { - tmp |= NI_IDN; -#endif - -#if defined(NI_IDN_ALLOW_UNASSIGNED) - } else if (COMPARE(elem, atom_idna_allow_unassigned) == 0) { - tmp |= NI_IDN_ALLOW_UNASSIGNED; -#endif - -#if defined(NI_IDN_USE_STD3_ASCII_RULES) - } else if (COMPARE(elem, atom_idna_use_std3_ascii_rules) == 0) { - tmp |= NI_IDN_USE_STD3_ASCII_RULES; -#endif - - } else { - return FALSE; - } - - list = tail; - - } else { - done = TRUE; - } - } - - *flags = tmp; - - return TRUE; -} - - - -/* Decode the address info string (hostname or service name) - * The string is either the atom undefined or an actual string. - */ -static -BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, - const ERL_NIF_TERM eString, - char** stringP) -{ - BOOLEAN_T result; - - if (IS_ATOM(env, eString)) { - - if (COMPARE(eString, esock_atom_undefined) == 0) { - *stringP = NULL; - result = TRUE; - } else { - *stringP = NULL; - result = FALSE; - } - - } else { - - result = esock_decode_string(env, eString, stringP); - - } - - return result; - -} - - - -static -ERL_NIF_TERM decode_bool(ErlNifEnv* env, - ERL_NIF_TERM eBool, - BOOLEAN_T* bool) -{ - if (COMPARE(eBool, esock_atom_true) == 0) { - *bool = TRUE; - return esock_atom_ok; - } else if (COMPARE(eBool, esock_atom_false) == 0) { - *bool = FALSE; - return esock_atom_ok; - } else { - return esock_make_error(env, esock_atom_einval); - } -} - - - -/* Encode the address info - * The address info is a linked list och address info, which - * will result in the result being a list of zero or more length. - */ -static -ERL_NIF_TERM encode_address_infos(ErlNifEnv* env, - struct addrinfo* addrInfo) -{ - ERL_NIF_TERM result; - unsigned int len = address_info_length(addrInfo); - - NDBG( ("NET", "encode_address_infos -> len: %d\r\n", len) ); - - if (len > 0) { - ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); - unsigned int i = 0; - struct addrinfo* p = addrInfo; - - while (i < len) { - array[i] = encode_address_info(env, p); - p = p->ai_next; - i++; - } - - result = MKLA(env, array, len); - FREE(array); - } else { - result = MKEL(env); - } - - NDBG( ("NET", "encode_address_infos -> result: " - "\r\n %T\r\n", result) ); - - return result; -} - - - -/* Calculate the length of the adress info linked list - * The list is NULL-terminated, so the only way is to - * iterate through the list until we find next = NULL. - */ -static -unsigned int address_info_length(struct addrinfo* addrInfoP) -{ - unsigned int len = 1; - struct addrinfo* tmp; - BOOLEAN_T done = FALSE; - - tmp = addrInfoP; - - while (!done) { - if (tmp->ai_next != NULL) { - len++; - tmp = tmp->ai_next; - } else { - done = TRUE; - } - } - - return len; -} - - - -/* Create one (erlang) instance of the address info record - * Should we have address info as a record or as a map? - * - * {address_info, Fam, Type, Proto, Addr} - */ -static -ERL_NIF_TERM encode_address_info(ErlNifEnv* env, - struct addrinfo* addrInfoP) -{ - ERL_NIF_TERM fam, type, proto, addr, addrInfo; - - fam = encode_address_info_family(env, addrInfoP->ai_family); - type = encode_address_info_type(env, addrInfoP->ai_socktype); - proto = encode_address_info_proto(env, addrInfoP->ai_protocol); - esock_encode_sockaddr(env, - (ESockAddress*) addrInfoP->ai_addr, - addrInfoP->ai_addrlen, - &addr); - - if (make_address_info(env, fam, type, proto, addr, &addrInfo) == NULL) - return addrInfo; - else - return esock_atom_undefined; // We should to better... - -} - - -/* Convert an "native" family to an erlang family (=domain). - * Note that this is not currently exhaustive, but only supports - * inet and inet6. Other values will be returned as is, that is - * in the form of an integer. - */ -static -ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, - int family) -{ - ERL_NIF_TERM efam; - - if (NULL != esock_encode_domain(env, family, &efam)) - efam = MKI(env, family); - - return efam; -} - - - -/* Convert an "native" socket type to an erlang socket type. - * Note that this is not currently exhaustive, but only supports - * stream and dgram. Other values will be returned as is, that is - * in the form of an integer. - */ -static -ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, - int socktype) -{ - ERL_NIF_TERM etype; - - if (NULL != esock_encode_type(env, socktype, &etype)) - etype = MKI(env, socktype); - - return etype; -} - - - -/* Convert an "native" protocol to an erlang protocol. - * Note that this is not currently exhaustive, but only supports - * tcp and udp. Other values will be returned as is, that is - * in the form of an integer. - */ -static -ERL_NIF_TERM encode_address_info_proto(ErlNifEnv* env, - int proto) -{ - ERL_NIF_TERM eproto; - - if (NULL != esock_encode_protocol(env, proto, &eproto)) - eproto = MKI(env, proto); - - return eproto; -} - - - -static -char* make_address_info(ErlNifEnv* env, - ERL_NIF_TERM fam, - ERL_NIF_TERM sockType, - ERL_NIF_TERM proto, - ERL_NIF_TERM addr, - ERL_NIF_TERM* ai) -{ - ERL_NIF_TERM keys[] = {esock_atom_family, - esock_atom_type, - esock_atom_protocol, - esock_atom_addr}; - ERL_NIF_TERM vals[] = {fam, sockType, proto, addr}; - unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM); - unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM); - - ESOCK_ASSERT( (numKeys == numVals) ); - - if (!MKMA(env, keys, vals, numKeys, ai)) { - *ai = esock_atom_undefined; - return ESOCK_STR_EINVAL; - } else { - return NULL; - } -} -#endif // if !defined(__WIN32__) - - - -/* ---------------------------------------------------------------------- - * C a l l b a c k F u n c t i o n s - * ---------------------------------------------------------------------- - */ - -/* ========================================================================= - * net_dtor - Callback function for resource destructor - * - */ -/* -static -void net_dtor(ErlNifEnv* env, void* obj) -{ -} -*/ - - -/* ========================================================================= - * net_stop - Callback function for resource stop - * - */ -/* -static -void net_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call) -{ -} -*/ - - - - -/* ========================================================================= - * net_down - Callback function for resource down (monitored processes) - * - */ -/* -static -void net_down(ErlNifEnv* env, - void* obj, - const ErlNifPid* pid, - const ErlNifMonitor* mon) -{ -} -*/ - - - -/* ---------------------------------------------------------------------- - * L o a d / u n l o a d / u p g r a d e F u n c t i o n s - * ---------------------------------------------------------------------- - */ - -static -ErlNifFunc net_funcs[] = -{ - // Some utility functions - {"nif_info", 0, nif_info, 0}, - {"nif_command", 1, nif_command, 0}, // Shall we let this be dirty? - - /* get/set hostname */ - {"nif_gethostname", 0, nif_gethostname, 0}, - - /* address and name translation in protocol-independent manner */ - {"nif_getnameinfo", 2, nif_getnameinfo, 0}, - {"nif_getaddrinfo", 3, nif_getaddrinfo, 0}, - - /* Network interface (name and/or index) functions */ - {"nif_if_name2index", 1, nif_if_name2index, 0}, - {"nif_if_index2name", 1, nif_if_index2name, 0}, - {"nif_if_names", 0, nif_if_names, 0} -}; - - -#if !defined(__WIN32__) -static -BOOLEAN_T extract_debug(ErlNifEnv* env, - ERL_NIF_TERM map) -{ - /* - * We need to do this here since the "proper" atom has not been - * created when this function is called. - */ - ERL_NIF_TERM debug = MKA(env, "debug"); - - return esock_extract_bool_from_map(env, map, debug, NET_NIF_DEBUG_DEFAULT); -} -#endif - - -/* ======================================================================= - * load_info - A map of misc info (e.g global debug) - */ - -static -int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) -{ -#if !defined(__WIN32__) - // We should make it possible to use load_info to get default values - data.debug = extract_debug(env, load_info); - - NDBG( ("NET", "on_load -> entry\r\n") ); -#endif - -#define LOCAL_ATOM_DECL(A) atom_##A = MKA(env, #A) -LOCAL_ATOMS -LOCAL_ERROR_REASON_ATOMS -#undef LOCAL_ATOM_DECL - - // For storing "global" things... - // data.env = enif_alloc_env(); // We should really check - // data.version = MKA(env, ERTS_VERSION); - // data.buildDate = MKA(env, ERTS_BUILD_DATE); - - net = enif_open_resource_type_x(env, - "net", - &netInit, - ERL_NIF_RT_CREATE, - NULL); - -#if !defined(__WIN32__) - NDBG( ("NET", "on_load -> done\r\n") ); -#endif - - return !net; -} - -ERL_NIF_INIT(net, net_funcs, on_load, NULL, NULL, NULL) diff --git a/erts/emulator/nifs/common/prim_net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c new file mode 100644 index 0000000000..11a8ff724e --- /dev/null +++ b/erts/emulator/nifs/common/prim_net_nif.c @@ -0,0 +1,1656 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2018-2019. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * %CopyrightEnd% + * + * ---------------------------------------------------------------------- + * Purpose : The NIF (C) part of the net interface + * This is a module of miscellaneous functions. + * ---------------------------------------------------------------------- + * + */ + +#define STATIC_ERLANG_NIF 1 + + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/* If we HAVE_SCTP_H and Solaris, we need to define the following in + * order to get SCTP working: + */ +#if (defined(HAVE_SCTP_H) && defined(__sun) && defined(__SVR4)) +#define SOLARIS10 1 +/* WARNING: This is not quite correct, it may also be Solaris 11! */ +#define _XPG4_2 +#define __EXTENSIONS__ +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_UNISTD_H +#include +#endif +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#ifdef HAVE_NET_IF_DL_H +#include +#endif + +#ifdef HAVE_IFADDRS_H +#include +#endif + +#ifdef HAVE_NETPACKET_PACKET_H +#include +#endif + +#ifdef HAVE_SYS_UN_H +#include +#endif + +/* SENDFILE STUFF HERE IF WE NEED IT... */ + +#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__) +#define __DARWIN__ 1 +#endif + + +#ifdef __WIN32__ +#define STRNCASECMP strncasecmp +#define INCL_WINSOCK_API_TYPEDEFS 1 + +#ifndef WINDOWS_H_INCLUDES_WINSOCK2_H +#include +#endif +#include +#include /* NEED VC 6.0 or higher */ + +/* Visual studio 2008+: NTDDI_VERSION needs to be set for iphlpapi.h + * to define the right structures. It needs to be set to WINXP (or LONGHORN) + * for IPV6 to work and it's set lower by default, so we need to change it. + */ +#ifdef HAVE_SDKDDKVER_H +# include +# ifdef NTDDI_VERSION +# undef NTDDI_VERSION +# endif +# define NTDDI_VERSION NTDDI_WINXP +#endif +#include + +#undef WANT_NONBLOCKING +#include "sys.h" + +#else /* !__WIN32__ */ + +#include +#ifdef NETDB_H_NEEDS_IN_H +#include +#endif +#include + +#include +#include + +#ifdef DEF_INADDR_LOOPBACK_IN_RPC_TYPES_H +#include +#endif + +#include +#include +#include +#include + +#include +#ifdef HAVE_ARPA_NAMESER_H +#include +#endif + +#ifdef HAVE_SYS_SOCKIO_H +#include +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include +#endif + +#include + +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_SETNS_H +#include +#endif + +#define HAVE_UDP + +#ifndef WANT_NONBLOCKING +#define WANT_NONBLOCKING +#endif +#include "sys.h" + +#endif + +#include + +#include "socket_dbg.h" +#include "socket_int.h" +#include "socket_util.h" + + +/* All platforms fail on malloc errors. */ +#define FATAL_MALLOC + + +#ifdef __WIN32__ +#define net_gethostname(__buf__, __bufSz__) gethostname((__buf__), (__bufSz__)) +#else +#define net_gethostname(__buf__, __bufSz__) gethostname((__buf__), (__bufSz__)) +#endif // __WIN32__ + + + +/* *** Misc macros and defines *** */ + +#ifdef __WIN32__ +#define get_errno() WSAGetLastError() +#else +#define get_errno() errno +#endif + + +#define HOSTNAME_LEN 256 +#define SERVICE_LEN 256 + + +/* MAXHOSTNAMELEN could be 64 or 255 depending + * on the platform. Instead, use INET_MAXHOSTNAMELEN + * which is always 255 across all platforms + */ +#define NET_MAXHOSTNAMELEN 255 + + +/* =================================================================== * + * * + * Various enif macros * + * * + * =================================================================== */ + + +#ifdef HAVE_SOCKLEN_T +# define SOCKLEN_T socklen_t +#else +# define SOCKLEN_T size_t +#endif + +/* Debug stuff... */ +#define NET_NIF_DEBUG_DEFAULT FALSE + +#define NDBG( proto ) ESOCK_DBG_PRINTF( data.debug , proto ) + + +typedef struct { + BOOLEAN_T debug; +} NetData; + + + +/* =================================================================== * + * * + * Static data * + * * + * =================================================================== */ + + +static NetData data; + + + +/* ---------------------------------------------------------------------- + * F o r w a r d s + * ---------------------------------------------------------------------- + */ + +/* THIS IS JUST TEMPORARY */ +extern char* erl_errno_id(int error); + +/* All the nif "callback" functions for the net API has + * the exact same API: + * + * nif_(ErlNifEnv* env, + * int argc, + * const ERL_NIF_TERM argv[]); + * + * So, to simplify, use some macro magic to define those. + * + * These are the functions making up the "official" API. + */ + +#define ENET_NIF_FUNCS \ + ENET_NIF_FUNC_DEF(info); \ + ENET_NIF_FUNC_DEF(command); \ + ENET_NIF_FUNC_DEF(gethostname); \ + ENET_NIF_FUNC_DEF(getnameinfo); \ + ENET_NIF_FUNC_DEF(getaddrinfo); \ + ENET_NIF_FUNC_DEF(if_name2index); \ + ENET_NIF_FUNC_DEF(if_index2name); \ + ENET_NIF_FUNC_DEF(if_names); + +#define ENET_NIF_FUNC_DEF(F) \ + static ERL_NIF_TERM nif_##F(ErlNifEnv* env, \ + int argc, \ + const ERL_NIF_TERM argv[]); +ENET_NIF_FUNCS +#undef ENET_NIF_FUNC_DEF + + +/* And here comes the functions that does the actual work (for the most part) */ +static ERL_NIF_TERM ncommand(ErlNifEnv* env, + ERL_NIF_TERM cmd); +static ERL_NIF_TERM ngethostname(ErlNifEnv* env); +static ERL_NIF_TERM ngetnameinfo(ErlNifEnv* env, + const ESockAddress* saP, + SOCKLEN_T saLen, + int flags); +static ERL_NIF_TERM ngetaddrinfo(ErlNifEnv* env, + char* host, + char* serv); +static ERL_NIF_TERM nif_name2index(ErlNifEnv* env, + char* ifn); +static ERL_NIF_TERM nif_index2name(ErlNifEnv* env, + unsigned int id); +static ERL_NIF_TERM nif_names(ErlNifEnv* env); +static unsigned int nif_names_length(struct if_nameindex* p); + +/* +static void net_dtor(ErlNifEnv* env, void* obj); +static void net_stop(ErlNifEnv* env, + void* obj, + int fd, + int is_direct_call); +static void net_down(ErlNifEnv* env, + void* obj, + const ErlNifPid* pid, + const ErlNifMonitor* mon); +*/ + +static BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, + const ERL_NIF_TERM eflags, + int* flags); +static BOOLEAN_T decode_nameinfo_flags_list(ErlNifEnv* env, + const ERL_NIF_TERM eflags, + int* flags); +static +BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, + const ERL_NIF_TERM eString, + char** stringP); +static ERL_NIF_TERM decode_bool(ErlNifEnv* env, + ERL_NIF_TERM eBool, + BOOLEAN_T* bool); +static ERL_NIF_TERM encode_address_infos(ErlNifEnv* env, + struct addrinfo* addrInfo); +static ERL_NIF_TERM encode_address_info(ErlNifEnv* env, + struct addrinfo* addrInfoP); +static unsigned int address_info_length(struct addrinfo* addrInfoP); + +static ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, + int family); +static ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, + int socktype); +static ERL_NIF_TERM encode_address_info_proto(ErlNifEnv* env, + int proto); + +static char* make_address_info(ErlNifEnv* env, + ERL_NIF_TERM fam, + ERL_NIF_TERM sockType, + ERL_NIF_TERM proto, + ERL_NIF_TERM addr, + ERL_NIF_TERM* ai); + +static BOOLEAN_T extract_debug(ErlNifEnv* env, + ERL_NIF_TERM map); +static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info); + + +#if HAVE_IN6 +# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY +# if HAVE_DECL_IN6ADDR_ANY_INIT +static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } }; +# else +static const struct in6_addr in6addr_any = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; +# endif /* HAVE_IN6ADDR_ANY_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_ANY */ + +# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK +# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT +static const struct in6_addr in6addr_loopback = + { { IN6ADDR_LOOPBACK_INIT } }; +# else +static const struct in6_addr in6addr_loopback = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; +# endif /* HAVE_IN6ADDR_LOOPBACk_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */ +#endif /* HAVE_IN6 */ + + + +/* *** Local atoms *** */ + +#define LOCAL_ATOMS \ + LOCAL_ATOM_DECL(address_info); \ + LOCAL_ATOM_DECL(debug); \ + LOCAL_ATOM_DECL(host); \ + LOCAL_ATOM_DECL(idn); \ + LOCAL_ATOM_DECL(idna_allow_unassigned); \ + LOCAL_ATOM_DECL(idna_use_std3_ascii_rules); \ + LOCAL_ATOM_DECL(namereqd); \ + LOCAL_ATOM_DECL(name_info); \ + LOCAL_ATOM_DECL(nofqdn); \ + LOCAL_ATOM_DECL(numerichost); \ + LOCAL_ATOM_DECL(numericserv); \ + LOCAL_ATOM_DECL(service); + +#define LOCAL_ERROR_REASON_ATOMS \ + LOCAL_ATOM_DECL(eaddrfamily); \ + LOCAL_ATOM_DECL(ebadflags); \ + LOCAL_ATOM_DECL(efail); \ + LOCAL_ATOM_DECL(efamily); \ + LOCAL_ATOM_DECL(efault); \ + LOCAL_ATOM_DECL(emem); \ + LOCAL_ATOM_DECL(enametoolong); \ + LOCAL_ATOM_DECL(enodata); \ + LOCAL_ATOM_DECL(enoname); \ + LOCAL_ATOM_DECL(enxio); \ + LOCAL_ATOM_DECL(eoverflow); \ + LOCAL_ATOM_DECL(eservice); \ + LOCAL_ATOM_DECL(esocktype); \ + LOCAL_ATOM_DECL(esystem); + +#define LOCAL_ATOM_DECL(A) static ERL_NIF_TERM atom_##A +LOCAL_ATOMS +LOCAL_ERROR_REASON_ATOMS +#undef LOCAL_ATOM_DECL + + +/* *** net *** */ +static ErlNifResourceType* net; +static ErlNifResourceTypeInit netInit = { + NULL, // net_dtor, + NULL, // net_stop, + NULL // (ErlNifResourceDown*) net_down +}; + + + +/* ---------------------------------------------------------------------- + * N I F F u n c t i o n s + * ---------------------------------------------------------------------- + * + * Utility and admin functions: + * ---------------------------- + * nif_info/0 + * nif_command/1 + * + * The "proper" net functions: + * ------------------------------ + * nif_gethostname/0 + * nif_getnameinfo/2 + * nif_getaddrinfo/3 + * nif_if_name2index/1 + * nif_if_index2name/1 + * nif_if_names/0 + * + */ + + +/* ---------------------------------------------------------------------- + * nif_info + * + * Description: + * This is currently just a placeholder... + */ +static +ERL_NIF_TERM nif_info(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM info, tmp; + + NDBG( ("NET", "info -> entry\r\n") ); + + tmp = enif_make_new_map(env); + if (!enif_make_map_put(env, tmp, atom_debug, BOOL2ATOM(data.debug), &info)) + info = tmp; + + NDBG( ("NET", "info -> done: %T\r\n", info) ); + + return info; +#endif +} + + + +/* ---------------------------------------------------------------------- + * nif_command + * + * Description: + * This is a general purpose utility function. + * + * Arguments: + * Command - This is a general purpose command, of any type. + * Currently, the only supported command is: + * + * {debug, boolean()} + */ +static +ERL_NIF_TERM nif_command(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM ecmd, result; + + NDBG( ("NET", "command -> entry (%d)\r\n", argc) ); + + if (argc != 1) + return enif_make_badarg(env); + + ecmd = argv[0]; + + NDBG( ("NET", "command -> ecmd: %T\r\n", ecmd) ); + + result = ncommand(env, ecmd); + + NDBG( ("NET", "command -> result: %T\r\n", result) ); + + return result; +#endif +} + + + +/* + * The command can, in principle, be anything, though currently we only + * support a debug command. + */ +#if !defined(__WIN32__) +static +ERL_NIF_TERM ncommand(ErlNifEnv* env, + ERL_NIF_TERM cmd) +{ + const ERL_NIF_TERM* t; + int tsz; + + if (IS_TUPLE(env, cmd)) { + /* Could be the debug tuple */ + if (!GET_TUPLE(env, cmd, &tsz, &t)) + return esock_make_error(env, esock_atom_einval); + + if (tsz != 2) + return esock_make_error(env, esock_atom_einval); + + /* First element should be the atom 'debug' */ + if (COMPARE(t[0], atom_debug) != 0) + return esock_make_error(env, esock_atom_einval); + + return decode_bool(env, t[1], &data.debug); + + } else { + return esock_make_error(env, esock_atom_einval); + } + +} +#endif + + + +/* ---------------------------------------------------------------------- + * nif_gethostname + * + * Description: + * Access the hostname of the current processor. + * + */ +static +ERL_NIF_TERM nif_gethostname(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM result; + + NDBG( ("NET", "nif_gethostname -> entry (%d)\r\n", argc) ); + + if (argc != 0) + return enif_make_badarg(env); + + result = ngethostname(env); + + NDBG( ("NET", "nif_gethostname -> done when result: %T\r\n", result) ); + + return result; +#endif +} + + +#if !defined(__WIN32__) +static +ERL_NIF_TERM ngethostname(ErlNifEnv* env) +{ + ERL_NIF_TERM result; + char buf[NET_MAXHOSTNAMELEN + 1]; + int res; + + res = net_gethostname(buf, sizeof(buf)); + + NDBG( ("NET", "ngethostname -> gethostname res: %d\r\n", res) ); + + switch (res) { + case 0: + result = esock_make_ok2(env, MKS(env, buf)); + break; + + case EFAULT: + result = esock_make_error(env, atom_efault); + break; + + case EINVAL: + result = esock_make_error(env, esock_atom_einval); + break; + + case ENAMETOOLONG: + result = esock_make_error(env, atom_enametoolong); + break; + + default: + result = esock_make_error(env, MKI(env, res)); + break; + } + + return result; +} +#endif + + + + +/* ---------------------------------------------------------------------- + * nif_getnameinfo + * + * Description: + * Address-to-name translation in protocol-independent manner. + * + * Arguments: + * SockAddr - Socket Address (address and port) + * Flags - The flags argument modifies the behavior of getnameinfo(). + */ + +static +ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM result; + ERL_NIF_TERM eSockAddr, eFlags; + int flags = 0; // Just in case... + ESockAddress sa; + SOCKLEN_T saLen = 0; // Just in case... + char* xres; + + NDBG( ("NET", "nif_getnameinfo -> entry (%d)\r\n", argc) ); + + if (argc != 2) + return enif_make_badarg(env); + eSockAddr = argv[0]; + eFlags = argv[1]; + + NDBG( ("NET", + "nif_getnameinfo -> " + "\r\n SockAddr: %T" + "\r\n Flags: %T" + "\r\n", eSockAddr, eFlags) ); + + if ((xres = esock_decode_sockaddr(env, eSockAddr, &sa, &saLen)) != NULL) { + NDBG( ("NET", "nif_getnameinfo -> failed decode sockaddr: %s\r\n", xres) ); + return esock_make_error_str(env, xres); + } + + NDBG( ("NET", "nif_getnameinfo -> (try) decode flags\r\n") ); + + if (!decode_nameinfo_flags(env, eFlags, &flags)) + return enif_make_badarg(env); + + result = ngetnameinfo(env, &sa, saLen, flags); + + NDBG( ("NET", + "nif_getnameinfo -> done when result: " + "\r\n %T\r\n", result) ); + + return result; +#endif +} + + + +/* Given the provided sock(et) address (and flags), retreive the host and + * service info. + */ +#if !defined(__WIN32__) +static +ERL_NIF_TERM ngetnameinfo(ErlNifEnv* env, + const ESockAddress* saP, + SOCKLEN_T saLen, + int flags) +{ + ERL_NIF_TERM result; + char host[HOSTNAME_LEN]; + SOCKLEN_T hostLen = sizeof(host); + char serv[SERVICE_LEN]; + SOCKLEN_T servLen = sizeof(serv); + + int res = getnameinfo((struct sockaddr*) saP, saLen, + host, hostLen, + serv, servLen, + flags); + + NDBG( ("NET", "ngetnameinfo -> res: %d\r\n", res) ); + + switch (res) { + case 0: + { + ERL_NIF_TERM keys[] = {atom_host, atom_service}; + ERL_NIF_TERM vals[] = {MKS(env, host), MKS(env, serv)}; + ERL_NIF_TERM info; + unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM); + unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM); + + ESOCK_ASSERT( (numKeys == numVals) ); + + if (!MKMA(env, keys, vals, numKeys, &info)) + return enif_make_badarg(env); + + result = esock_make_ok2(env, info); + } + break; + +#if defined(EAI_AGAIN) + case EAI_AGAIN: + result = esock_make_error(env, esock_atom_eagain); + break; +#endif + +#if defined(EAI_BADFLAGS) + case EAI_BADFLAGS: + result = esock_make_error(env, atom_ebadflags); + break; +#endif + +#if defined(EAI_FAIL) + case EAI_FAIL: + result = esock_make_error(env, atom_efail); + break; +#endif + +#if defined(EAI_FAMILY) + case EAI_FAMILY: + result = esock_make_error(env, atom_efamily); + break; +#endif + +#if defined(EAI_MEMORY) + case EAI_MEMORY: + result = esock_make_error(env, atom_emem); + break; +#endif + +#if defined(EAI_NONAME) + case EAI_NONAME: + result = esock_make_error(env, atom_enoname); + break; +#endif + +#if defined(EAI_OVERFLOW) + case EAI_OVERFLOW: + result = esock_make_error(env, atom_eoverflow); + break; +#endif + +#if defined(EAI_SYSTEM) + case EAI_SYSTEM: + result = esock_make_error_errno(env, get_errno()); + break; +#endif + + default: + result = esock_make_error(env, esock_atom_einval); + break; + } + + return result; +} +#endif + + + +/* ---------------------------------------------------------------------- + * nif_getaddrinfo + * + * Description: + * Network address and service translation. + * + * Arguments: + * Host - Host name (either a string or the atom undefined) + * Service - Service name (either a string or the atom undefined) + * Hints - Hints for the lookup (address info record) (currently *ignored*) + */ + +static +ERL_NIF_TERM nif_getaddrinfo(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM result, eHostName, eServName; //, eHints; + char* hostName; + char* servName; + // struct addrinfo* hints; + + NDBG( ("NET", "nif_getaddrinfo -> entry (%d)\r\n", argc) ); + + if (argc != 3) { + return enif_make_badarg(env); + } + eHostName = argv[0]; + eServName = argv[1]; + // eHints = argv[2]; + + NDBG( ("NET", + "nif_getaddrinfo -> " + "\r\n ehost: %T" + "\r\n eservice: %T" + "\r\n ehints: %T" + "\r\n", argv[0], argv[1], argv[2]) ); + + if (!decode_addrinfo_string(env, eHostName, &hostName)) + return enif_make_badarg(env); + + if (!decode_addrinfo_string(env, eServName, &servName)) + return enif_make_badarg(env); + + /* + if (decode_addrinfo_hints(env, eHints, &hints)) + return enif_make_badarg(env); + */ + + if ((hostName == NULL) && (servName == NULL)) + return enif_make_badarg(env); + + result = ngetaddrinfo(env, hostName, servName); + + if (hostName != NULL) + FREE(hostName); + + if (servName != NULL) + FREE(servName); + + /* + if (hints != NULL) + FREE(hints); + */ + + NDBG( ("NET", + "nif_getaddrinfo -> done when result: " + "\r\n %T\r\n", result) ); + + return result; +#endif +} + + +#if !defined(__WIN32__) +static +ERL_NIF_TERM ngetaddrinfo(ErlNifEnv* env, + char* host, + char* serv) +{ + ERL_NIF_TERM result; + struct addrinfo* addrInfoP; + int res; + + NDBG( ("NET", "ngetaddrinfo -> entry with" + "\r\n host: %s" + "\r\n serv: %s" + "\r\n", + ((host == NULL) ? "NULL" : host), + ((serv == NULL) ? "NULL" : serv)) ); + + res = getaddrinfo(host, serv, NULL, &addrInfoP); + + NDBG( ("NET", "ngetaddrinfo -> res: %d\r\n", res) ); + + switch (res) { + case 0: + { + ERL_NIF_TERM addrInfo = encode_address_infos(env, addrInfoP); + freeaddrinfo(addrInfoP); + result = esock_make_ok2(env, addrInfo); + } + break; + +#if defined(EAI_ADDRFAMILY) + case EAI_ADDRFAMILY: + result = esock_make_error(env, atom_eaddrfamily); + break; +#endif + +#if defined(EAI_AGAIN) + case EAI_AGAIN: + result = esock_make_error(env, esock_atom_eagain); + break; +#endif + +#if defined(EAI_BADFLAGS) + case EAI_BADFLAGS: + result = esock_make_error(env, atom_ebadflags); + break; +#endif + +#if defined(EAI_FAIL) + case EAI_FAIL: + result = esock_make_error(env, atom_efail); + break; +#endif + +#if defined(EAI_FAMILY) + case EAI_FAMILY: + result = esock_make_error(env, atom_efamily); + break; +#endif + +#if defined(EAI_MEMORY) + case EAI_MEMORY: + result = esock_make_error(env, atom_emem); + break; +#endif + +#if defined(EAI_NODATA) + case EAI_NODATA: + result = esock_make_error(env, atom_enodata); + break; +#endif + +#if defined(EAI_NONAME) + case EAI_NONAME: + result = esock_make_error(env, atom_enoname); + break; +#endif + +#if defined(EAI_SERVICE) + case EAI_SERVICE: + result = esock_make_error(env, atom_eservice); + break; +#endif + +#if defined(EAI_SOCKTYPE) + case EAI_SOCKTYPE: + result = esock_make_error(env, atom_esocktype); + break; +#endif + +#if defined(EAI_SYSTEM) + case EAI_SYSTEM: + result = esock_make_error(env, atom_esystem); + break; +#endif + + default: + result = esock_make_error(env, esock_atom_einval); + break; + } + + return result; +} +#endif + + + +/* ---------------------------------------------------------------------- + * nif_if_name2index + * + * Description: + * Perform a Interface Name to Interface Index translation. + * + * Arguments: + * Ifn - Interface name to be translated. + */ + +static +ERL_NIF_TERM nif_if_name2index(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM eifn, result; + char ifn[IF_NAMESIZE+1]; + + NDBG( ("NET", "nif_if_name2index -> entry (%d)\r\n", argc) ); + + if (argc != 1) { + return enif_make_badarg(env); + } + eifn = argv[0]; + + NDBG( ("NET", + "nif_if_name2index -> " + "\r\n Ifn: %T" + "\r\n", argv[0]) ); + + if (0 >= GET_STR(env, eifn, ifn, sizeof(ifn))) + return esock_make_error(env, esock_atom_einval); + + result = nif_name2index(env, ifn); + + NDBG( ("NET", "nif_if_name2index -> done when result: %T\r\n", result) ); + + return result; +#endif +} + + + +#if !defined(__WIN32__) +static +ERL_NIF_TERM nif_name2index(ErlNifEnv* env, + char* ifn) +{ + unsigned int idx; + + NDBG( ("NET", "nif_name2index -> entry with ifn: %s\r\n", ifn) ); + + idx = if_nametoindex(ifn); + + NDBG( ("NET", "nif_name2index -> idx: %d\r\n", idx) ); + + if (idx == 0) { + int save_errno = get_errno(); + NDBG( ("NET", "nif_name2index -> failed: %d\r\n", save_errno) ); + return esock_make_error_errno(env, save_errno); + } else { + return esock_make_ok2(env, MKI(env, idx)); + } + +} +#endif + + + +/* ---------------------------------------------------------------------- + * nif_if_index2name + * + * Description: + * Perform a Interface Index to Interface Name translation. + * + * Arguments: + * Idx - Interface index to be translated. + */ + +static +ERL_NIF_TERM nif_if_index2name(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM result; + unsigned int idx; + + NDBG( ("NET", "nif_if_index2name -> entry (%d)\r\n", argc) ); + + if ((argc != 1) || + !GET_UINT(env, argv[0], &idx)) { + return enif_make_badarg(env); + } + + NDBG( ("NET", "nif_index2name -> " + "\r\n Idx: %T" + "\r\n", argv[0]) ); + + result = nif_index2name(env, idx); + + NDBG( ("NET", "nif_if_index2name -> done when result: %T\r\n", result) ); + + return result; +#endif +} + + + +#if !defined(__WIN32__) +static +ERL_NIF_TERM nif_index2name(ErlNifEnv* env, + unsigned int idx) +{ + ERL_NIF_TERM result; + char* ifn = MALLOC(IF_NAMESIZE+1); + + if (ifn == NULL) + return enif_make_badarg(env); // PLACEHOLDER + + if (NULL != if_indextoname(idx, ifn)) { + result = esock_make_ok2(env, MKS(env, ifn)); + } else { + result = esock_make_error(env, atom_enxio); + } + + FREE(ifn); + + return result; +} +#endif + + + +/* ---------------------------------------------------------------------- + * nif_if_names + * + * Description: + * Get network interface names and indexes. + * + */ + +static +ERL_NIF_TERM nif_if_names(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]) +{ +#if defined(__WIN32__) + return enif_raise_exception(env, MKA(env, "notsup")); +#else + ERL_NIF_TERM result; + + NDBG( ("NET", "nif_if_names -> entry (%d)\r\n", argc) ); + + if (argc != 0) { + return enif_make_badarg(env); + } + + result = nif_names(env); + + NDBG( ("NET", "nif_if_names -> done when result: %T\r\n", result) ); + + return result; +#endif +} + + + +#if !defined(__WIN32__) +static +ERL_NIF_TERM nif_names(ErlNifEnv* env) +{ + ERL_NIF_TERM result; + struct if_nameindex* ifs = if_nameindex(); + + NDBG( ("NET", "nif_names -> ifs: 0x%lX\r\n", ifs) ); + + if (ifs == NULL) { + result = esock_make_error_errno(env, get_errno()); + } else { + /* + * We got some interfaces: + * 1) Calculate how many - the only way is to iterate through the list + * until its end (which is indicated by an entry with index = zero + * and if_name = NULL). + * 2) Allocate an ERL_NIF_TERM array of the calculated length. + * 3) Iterate through the array of interfaces and for each create + * a two tuple: {Idx, If} + * + * Or shall we instead build a list in reverse order and then when + * its done, reverse that? Check + */ + unsigned int len = nif_names_length(ifs); + + NDBG( ("NET", "nif_names -> len: %d\r\n", len) ); + + if (len > 0) { + ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); + unsigned int i; + + for (i = 0; i < len; i++) { + array[i] = MKT2(env, + MKI(env, ifs[i].if_index), + MKS(env, ifs[i].if_name)); + } + + result = esock_make_ok2(env, MKLA(env, array, len)); + FREE(array); + } else { + result = esock_make_ok2(env, enif_make_list(env, 0)); + } + } + + if (ifs != NULL) + if_freenameindex(ifs); + + return result; +} + + +static +unsigned int nif_names_length(struct if_nameindex* p) +{ + unsigned int len = 0; + BOOLEAN_T done = FALSE; + + while (!done) { + + NDBG( ("NET", "nif_names_length -> %d: " + "\r\n if_index: %d" + "\r\n if_name: 0x%lX" + "\r\n", len, p[len].if_index, p[len].if_name) ); + + if ((p[len].if_index == 0) && (p[len].if_name == NULL)) + done = TRUE; + else + len++; + } + + return len; +} +#endif // if !defined(__WIN32__) + + + +/* ---------------------------------------------------------------------- + * U t i l i t y F u n c t i o n s + * ---------------------------------------------------------------------- + */ + +/* The erlang format for a set of flags is a list of atoms. + * A special case is when there is no flags, which is + * represented by the atom undefined. + */ +#if !defined(__WIN32__) +static +BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, + const ERL_NIF_TERM eflags, + int* flags) +{ + BOOLEAN_T result; + + if (IS_ATOM(env, eflags)) { + NDBG( ("NET", "decode_nameinfo_flags -> is atom (%T)\r\n", eflags) ); + if (COMPARE(eflags, esock_atom_undefined) == 0) { + *flags = 0; + result = TRUE; + } else { + result = FALSE; + } + } else if (IS_LIST(env, eflags)) { + NDBG( ("NET", "decode_nameinfo_flags -> is list\r\n") ); + result = decode_nameinfo_flags_list(env, eflags, flags); + } else { + result = FALSE; + } + + NDBG( ("NET", "decode_nameinfo_flags -> result: %s\r\n", B2S(result)) ); + + return result; +} + + + +static +BOOLEAN_T decode_nameinfo_flags_list(ErlNifEnv* env, + const ERL_NIF_TERM eflags, + int* flags) +{ + ERL_NIF_TERM elem, tail, list = eflags; + int tmp = 0; + BOOLEAN_T done = FALSE; + + while (!done) { + if (GET_LIST_ELEM(env, list, &elem, &tail)) { + if (COMPARE(elem, atom_namereqd) == 0) { + tmp |= NI_NAMEREQD; + } else if (COMPARE(elem, esock_atom_dgram) == 0) { + tmp |= NI_DGRAM; + } else if (COMPARE(elem, atom_nofqdn) == 0) { + tmp |= NI_NOFQDN; + } else if (COMPARE(elem, atom_numerichost) == 0) { + tmp |= NI_NUMERICHOST; + } else if (COMPARE(elem, atom_numericserv) == 0) { + tmp |= NI_NUMERICSERV; + + /* Starting with glibc 2.3.4: */ + +#if defined(NI_IDN) + } else if (COMPARE(elem, atom_idn) == 0) { + tmp |= NI_IDN; +#endif + +#if defined(NI_IDN_ALLOW_UNASSIGNED) + } else if (COMPARE(elem, atom_idna_allow_unassigned) == 0) { + tmp |= NI_IDN_ALLOW_UNASSIGNED; +#endif + +#if defined(NI_IDN_USE_STD3_ASCII_RULES) + } else if (COMPARE(elem, atom_idna_use_std3_ascii_rules) == 0) { + tmp |= NI_IDN_USE_STD3_ASCII_RULES; +#endif + + } else { + return FALSE; + } + + list = tail; + + } else { + done = TRUE; + } + } + + *flags = tmp; + + return TRUE; +} + + + +/* Decode the address info string (hostname or service name) + * The string is either the atom undefined or an actual string. + */ +static +BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, + const ERL_NIF_TERM eString, + char** stringP) +{ + BOOLEAN_T result; + + if (IS_ATOM(env, eString)) { + + if (COMPARE(eString, esock_atom_undefined) == 0) { + *stringP = NULL; + result = TRUE; + } else { + *stringP = NULL; + result = FALSE; + } + + } else { + + result = esock_decode_string(env, eString, stringP); + + } + + return result; + +} + + + +static +ERL_NIF_TERM decode_bool(ErlNifEnv* env, + ERL_NIF_TERM eBool, + BOOLEAN_T* bool) +{ + if (COMPARE(eBool, esock_atom_true) == 0) { + *bool = TRUE; + return esock_atom_ok; + } else if (COMPARE(eBool, esock_atom_false) == 0) { + *bool = FALSE; + return esock_atom_ok; + } else { + return esock_make_error(env, esock_atom_einval); + } +} + + + +/* Encode the address info + * The address info is a linked list och address info, which + * will result in the result being a list of zero or more length. + */ +static +ERL_NIF_TERM encode_address_infos(ErlNifEnv* env, + struct addrinfo* addrInfo) +{ + ERL_NIF_TERM result; + unsigned int len = address_info_length(addrInfo); + + NDBG( ("NET", "encode_address_infos -> len: %d\r\n", len) ); + + if (len > 0) { + ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); + unsigned int i = 0; + struct addrinfo* p = addrInfo; + + while (i < len) { + array[i] = encode_address_info(env, p); + p = p->ai_next; + i++; + } + + result = MKLA(env, array, len); + FREE(array); + } else { + result = MKEL(env); + } + + NDBG( ("NET", "encode_address_infos -> result: " + "\r\n %T\r\n", result) ); + + return result; +} + + + +/* Calculate the length of the adress info linked list + * The list is NULL-terminated, so the only way is to + * iterate through the list until we find next = NULL. + */ +static +unsigned int address_info_length(struct addrinfo* addrInfoP) +{ + unsigned int len = 1; + struct addrinfo* tmp; + BOOLEAN_T done = FALSE; + + tmp = addrInfoP; + + while (!done) { + if (tmp->ai_next != NULL) { + len++; + tmp = tmp->ai_next; + } else { + done = TRUE; + } + } + + return len; +} + + + +/* Create one (erlang) instance of the address info record + * Should we have address info as a record or as a map? + * + * {address_info, Fam, Type, Proto, Addr} + */ +static +ERL_NIF_TERM encode_address_info(ErlNifEnv* env, + struct addrinfo* addrInfoP) +{ + ERL_NIF_TERM fam, type, proto, addr, addrInfo; + + fam = encode_address_info_family(env, addrInfoP->ai_family); + type = encode_address_info_type(env, addrInfoP->ai_socktype); + proto = encode_address_info_proto(env, addrInfoP->ai_protocol); + esock_encode_sockaddr(env, + (ESockAddress*) addrInfoP->ai_addr, + addrInfoP->ai_addrlen, + &addr); + + if (make_address_info(env, fam, type, proto, addr, &addrInfo) == NULL) + return addrInfo; + else + return esock_atom_undefined; // We should to better... + +} + + +/* Convert an "native" family to an erlang family (=domain). + * Note that this is not currently exhaustive, but only supports + * inet and inet6. Other values will be returned as is, that is + * in the form of an integer. + */ +static +ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, + int family) +{ + ERL_NIF_TERM efam; + + if (NULL != esock_encode_domain(env, family, &efam)) + efam = MKI(env, family); + + return efam; +} + + + +/* Convert an "native" socket type to an erlang socket type. + * Note that this is not currently exhaustive, but only supports + * stream and dgram. Other values will be returned as is, that is + * in the form of an integer. + */ +static +ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, + int socktype) +{ + ERL_NIF_TERM etype; + + if (NULL != esock_encode_type(env, socktype, &etype)) + etype = MKI(env, socktype); + + return etype; +} + + + +/* Convert an "native" protocol to an erlang protocol. + * Note that this is not currently exhaustive, but only supports + * tcp and udp. Other values will be returned as is, that is + * in the form of an integer. + */ +static +ERL_NIF_TERM encode_address_info_proto(ErlNifEnv* env, + int proto) +{ + ERL_NIF_TERM eproto; + + if (NULL != esock_encode_protocol(env, proto, &eproto)) + eproto = MKI(env, proto); + + return eproto; +} + + + +static +char* make_address_info(ErlNifEnv* env, + ERL_NIF_TERM fam, + ERL_NIF_TERM sockType, + ERL_NIF_TERM proto, + ERL_NIF_TERM addr, + ERL_NIF_TERM* ai) +{ + ERL_NIF_TERM keys[] = {esock_atom_family, + esock_atom_type, + esock_atom_protocol, + esock_atom_addr}; + ERL_NIF_TERM vals[] = {fam, sockType, proto, addr}; + unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM); + unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM); + + ESOCK_ASSERT( (numKeys == numVals) ); + + if (!MKMA(env, keys, vals, numKeys, ai)) { + *ai = esock_atom_undefined; + return ESOCK_STR_EINVAL; + } else { + return NULL; + } +} +#endif // if !defined(__WIN32__) + + + +/* ---------------------------------------------------------------------- + * C a l l b a c k F u n c t i o n s + * ---------------------------------------------------------------------- + */ + +/* ========================================================================= + * net_dtor - Callback function for resource destructor + * + */ +/* +static +void net_dtor(ErlNifEnv* env, void* obj) +{ +} +*/ + + +/* ========================================================================= + * net_stop - Callback function for resource stop + * + */ +/* +static +void net_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call) +{ +} +*/ + + + + +/* ========================================================================= + * net_down - Callback function for resource down (monitored processes) + * + */ +/* +static +void net_down(ErlNifEnv* env, + void* obj, + const ErlNifPid* pid, + const ErlNifMonitor* mon) +{ +} +*/ + + + +/* ---------------------------------------------------------------------- + * L o a d / u n l o a d / u p g r a d e F u n c t i o n s + * ---------------------------------------------------------------------- + */ + +static +ErlNifFunc net_funcs[] = +{ + // Some utility functions + {"nif_info", 0, nif_info, 0}, + {"nif_command", 1, nif_command, 0}, // Shall we let this be dirty? + + /* get/set hostname */ + {"nif_gethostname", 0, nif_gethostname, 0}, + + /* address and name translation in protocol-independent manner */ + {"nif_getnameinfo", 2, nif_getnameinfo, 0}, + {"nif_getaddrinfo", 3, nif_getaddrinfo, 0}, + + /* Network interface (name and/or index) functions */ + {"nif_if_name2index", 1, nif_if_name2index, 0}, + {"nif_if_index2name", 1, nif_if_index2name, 0}, + {"nif_if_names", 0, nif_if_names, 0} +}; + + +#if !defined(__WIN32__) +static +BOOLEAN_T extract_debug(ErlNifEnv* env, + ERL_NIF_TERM map) +{ + /* + * We need to do this here since the "proper" atom has not been + * created when this function is called. + */ + ERL_NIF_TERM debug = MKA(env, "debug"); + + return esock_extract_bool_from_map(env, map, debug, NET_NIF_DEBUG_DEFAULT); +} +#endif + + +/* ======================================================================= + * load_info - A map of misc info (e.g global debug) + */ + +static +int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) +{ +#if !defined(__WIN32__) + // We should make it possible to use load_info to get default values + data.debug = extract_debug(env, load_info); + + NDBG( ("NET", "on_load -> entry\r\n") ); +#endif + +#define LOCAL_ATOM_DECL(A) atom_##A = MKA(env, #A) +LOCAL_ATOMS +LOCAL_ERROR_REASON_ATOMS +#undef LOCAL_ATOM_DECL + + // For storing "global" things... + // data.env = enif_alloc_env(); // We should really check + // data.version = MKA(env, ERTS_VERSION); + // data.buildDate = MKA(env, ERTS_BUILD_DATE); + + net = enif_open_resource_type_x(env, + "net", + &netInit, + ERL_NIF_RT_CREATE, + NULL); + +#if !defined(__WIN32__) + NDBG( ("NET", "on_load -> done\r\n") ); +#endif + + return !net; +} + +ERL_NIF_INIT(prim_net, net_funcs, on_load, NULL, NULL, NULL) diff --git a/erts/emulator/test/net_SUITE.erl b/erts/emulator/test/net_SUITE.erl index 6111fc76a5..c6e77a5373 100644 --- a/erts/emulator/test/net_SUITE.erl +++ b/erts/emulator/test/net_SUITE.erl @@ -20,6 +20,8 @@ %% %% This test suite is basically a "placeholder" for a proper test suite... +%% Also we should really call prim_net directly, and not net (since that does +%% not even reside here). %% %% Run the entire test suite: @@ -127,6 +129,7 @@ api_basic_cases() -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% init_per_suite(Config) -> + %% We test on the socket module for simplicity case lists:member(socket, erlang:loaded()) of true -> case os:type() of diff --git a/erts/preloaded/ebin/erl_init.beam b/erts/preloaded/ebin/erl_init.beam index 0c032e8e91..1d54e0cead 100644 Binary files a/erts/preloaded/ebin/erl_init.beam and b/erts/preloaded/ebin/erl_init.beam differ diff --git a/erts/preloaded/ebin/net.beam b/erts/preloaded/ebin/net.beam deleted file mode 100644 index 88d546a3af..0000000000 Binary files a/erts/preloaded/ebin/net.beam and /dev/null differ diff --git a/erts/preloaded/ebin/prim_net.beam b/erts/preloaded/ebin/prim_net.beam new file mode 100644 index 0000000000..9d50b3210f Binary files /dev/null and b/erts/preloaded/ebin/prim_net.beam differ diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 27d450c873..e1bb2ee5c4 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -36,10 +36,9 @@ include $(ERL_TOP)/lib/kernel/vsn.mk ifeq ($(USE_ESOCK), yes) PRE_LOADED_ERL_ESOCK_MODULES = \ socket \ - net + prim_net else -PRE_LOADED_ERL_ESOCK_MODULES = \ - net +PRE_LOADED_ERL_ESOCK_MODULES = endif PRE_LOADED_ERL_MODULES = \ @@ -82,9 +81,9 @@ APP_FILE= erts.app APP_SRC= $(APP_FILE).src APP_TARGET= $(STATIC_EBIN)/$(APP_FILE) ifeq ($(USE_ESOCK), yes) -APP_ESOCK_MODS= net, socket +APP_ESOCK_MODS= prim_net, socket else -APP_ESOCK_MODS= net +APP_ESOCK_MODS= endif diff --git a/erts/preloaded/src/erl_init.erl b/erts/preloaded/src/erl_init.erl index d209c4033b..9fcb3969e4 100644 --- a/erts/preloaded/src/erl_init.erl +++ b/erts/preloaded/src/erl_init.erl @@ -35,7 +35,8 @@ start(Mod, BootArgs) -> erl_tracer:on_load(), prim_buffer:on_load(), prim_file:on_load(), - conditional_load(socket, [socket, net]), % socket:on_load(), net:on_load(), + %% socket:on_load(), prim_net:on_load(), + conditional_load(socket, [socket, prim_net]), %% Proceed to the specified boot module run(Mod, boot, BootArgs). diff --git a/erts/preloaded/src/net.erl b/erts/preloaded/src/net.erl deleted file mode 100644 index 13d2e3a117..0000000000 --- a/erts/preloaded/src/net.erl +++ /dev/null @@ -1,353 +0,0 @@ -%% -%% %CopyrightBegin% -%% -%% Copyright Ericsson AB 2018-2019. All Rights Reserved. -%% -%% Licensed under the Apache License, Version 2.0 (the "License"); -%% you may not use this file except in compliance with the License. -%% You may obtain a copy of the License at -%% -%% http://www.apache.org/licenses/LICENSE-2.0 -%% -%% Unless required by applicable law or agreed to in writing, software -%% distributed under the License is distributed on an "AS IS" BASIS, -%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -%% See the License for the specific language governing permissions and -%% limitations under the License. -%% -%% %CopyrightEnd% -%% - --module(net). - --compile(no_native). - -%% Administrative and "global" utility functions --export([ - on_load/0, on_load/1, - info/0, - command/1 - ]). - --export([ - gethostname/0, - getnameinfo/1, getnameinfo/2, - getaddrinfo/1, getaddrinfo/2, - - if_name2index/1, - if_index2name/1, - if_names/0 - ]). - -%% Deprecated functions from the "old" net module --export([call/4, - cast/4, - broadcast/3, - ping/1, - relay/1, - sleep/1]). - --export_type([ - address_info/0, - name_info/0, - - name_info_flags/0, - name_info_flag/0, - name_info_flag_ext/0, - - network_interface_name/0, - network_interface_index/0 - ]). - --deprecated({call, 4, eventually}). --deprecated({cast, 4, eventually}). --deprecated({broadcast, 3, eventually}). --deprecated({ping, 1, eventually}). --deprecated({relay, 1, eventually}). --deprecated({sleep, 1, eventually}). - - --type name_info_flags() :: [name_info_flag()|name_info_flag_ext()]. --type name_info_flag() :: namereqd | - dgram | - nofqdn | - numerichost | - nomericserv. --type name_info_flag_ext() :: idn | - idna_allow_unassigned | - idna_use_std3_ascii_rules. --type name_info() :: #{host := string(), - service := string()}. --type address_info() :: #{family := socket:domain(), - socktype := socket:type(), - protocol := socket:protocol(), - address := socket:sockaddr()}. --type network_interface_name() :: string(). --type network_interface_index() :: non_neg_integer(). - - -%% =========================================================================== -%% -%% D E P R E C A T E D F U N C T I O N S -%% -%% =========================================================================== - -call(N,M,F,A) -> rpc:call(N,M,F,A). -cast(N,M,F,A) -> rpc:cast(N,M,F,A). -broadcast(M,F,A) -> rpc:eval_everywhere(M,F,A). -ping(Node) -> net_adm:ping(Node). -sleep(T) -> receive after T -> ok end. -relay(X) -> slave:relay(X). - - - -%% =========================================================================== -%% -%% Administrative and utility API -%% -%% =========================================================================== - --spec on_load() -> ok. - -%% Should we require that the Extra arg is a map? -on_load() -> - on_load(#{}). - --spec on_load(Extra) -> ok when - Extra :: map(). - -on_load(Extra) -> - ok = erlang:load_nif(atom_to_list(?MODULE), Extra). - - --spec info() -> list(). - -info() -> - nif_info(). - - --spec command(Cmd :: term()) -> term(). - -command(Cmd) -> - nif_command(Cmd). - - - -%% =========================================================================== -%% -%% The proper net API -%% -%% =========================================================================== - -%% =========================================================================== -%% -%% gethostname - Get the name of the current host. -%% -%% - --spec gethostname() -> {ok, HostName} | {error, Reason} when - HostName :: string(), - Reason :: term(). - -gethostname() -> - nif_gethostname(). - - -%% =========================================================================== -%% -%% getnameinfo - Address-to-name translation in protocol-independent manner. -%% -%% - --spec getnameinfo(SockAddr) -> {ok, Info} | {error, Reason} when - SockAddr :: socket:sockaddr(), - Info :: name_info(), - Reason :: term(). - -getnameinfo(SockAddr) -> - getnameinfo(SockAddr, undefined). - --spec getnameinfo(SockAddr, Flags) -> {ok, Info} | {error, Reason} when - SockAddr :: socket:sockaddr(), - Flags :: name_info_flags() | undefined, - Info :: name_info(), - Reason :: term(). - -getnameinfo(SockAddr, [] = _Flags) -> - getnameinfo(SockAddr, undefined); -getnameinfo(#{family := Fam, addr := _Addr} = SockAddr, Flags) - when ((Fam =:= inet) orelse (Fam =:= inet6)) andalso - (is_list(Flags) orelse (Flags =:= undefined)) -> - nif_getnameinfo((catch ensure_sockaddr(SockAddr)), Flags); -getnameinfo(#{family := Fam, path := _Path} = SockAddr, Flags) - when (Fam =:= local) andalso (is_list(Flags) orelse (Flags =:= undefined)) -> - nif_getnameinfo(SockAddr, Flags). - - -%% This function is intended to "handle" the case when the user -%% has built their (OTP) system with "--disable-esock". -%% That means the socket module does not exist. This is not really -%% a problem since the nif_getnameinfo won't work either (since -%% the nif file is not part of the system). The result of calling -%% getnameinfo will be a undef exception (erlang:nif_error(undef)). -%% -%% The only functions in this module that actually work in this case -%% (--disable-esock) is the depricated stuff (call, cast, ...). -%% -ensure_sockaddr(SockAddr) -> - try socket:ensure_sockaddr(SockAddr) - catch - error:undef:_ -> - undefined - end. - -%% =========================================================================== -%% -%% getaddrinfo - Network address and service translation -%% -%% There is also a "hint" argument that we "at some point" should implement. - --spec getaddrinfo(Host) -> {ok, Info} | {error, Reason} when - Host :: string(), - Info :: [address_info()], - Reason :: term(). - -getaddrinfo(Host) when is_list(Host) -> - getaddrinfo(Host, undefined). - - --spec getaddrinfo(Host, undefined) -> {ok, Info} | {error, Reason} when - Host :: string(), - Info :: [address_info()], - Reason :: term() - ; (undefined, Service) -> {ok, Info} | {error, Reason} when - Service :: string(), - Info :: [address_info()], - Reason :: term() - ; (Host, Service) -> {ok, Info} | {error, Reason} when - Host :: string(), - Service :: string(), - Info :: [address_info()], - Reason :: term(). - -getaddrinfo(Host, Service) - when (is_list(Host) orelse (Host =:= undefined)) andalso - (is_list(Service) orelse (Service =:= undefined)) andalso - (not ((Service =:= undefined) andalso (Host =:= undefined))) -> - nif_getaddrinfo(Host, Service, undefined). - - - -%% =========================================================================== -%% -%% if_name2index - Mappings between network interface names and indexes: -%% name -> idx -%% -%% - --spec if_name2index(Name) -> {ok, Idx} | {error, Reason} when - Name :: network_interface_name(), - Idx :: network_interface_index(), - Reason :: term(). - -if_name2index(If) when is_list(If) -> - nif_if_name2index(If). - - - -%% =========================================================================== -%% -%% if_index2name - Mappings between network interface index and names: -%% idx -> name -%% -%% - --spec if_index2name(Idx) -> {ok, Name} | {error, Reason} when - Idx :: network_interface_index(), - Name :: network_interface_name(), - Reason :: term(). - -if_index2name(Idx) when is_integer(Idx) -> - nif_if_index2name(Idx). - - - -%% =========================================================================== -%% -%% if_names - Get network interface names and indexes -%% -%% - --spec if_names() -> Names | {error, Reason} when - Names :: [{Idx, If}], - Idx :: network_interface_index(), - If :: network_interface_name(), - Reason :: term(). - -if_names() -> - nif_if_names(). - - - -%% =========================================================================== -%% -%% Misc utility functions -%% -%% =========================================================================== - -%% formated_timestamp() -> -%% format_timestamp(os:timestamp()). - -%% format_timestamp(Now) -> -%% N2T = fun(N) -> calendar:now_to_local_time(N) end, -%% format_timestamp(Now, N2T, true). - -%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> -%% FormatExtra = ".~.2.0w", -%% ArgsExtra = [N3 div 10000], -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); -%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> -%% FormatExtra = "", -%% ArgsExtra = [], -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). - -%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> -%% {Date, Time} = N2T(N), -%% {YYYY,MM,DD} = Date, -%% {Hour,Min,Sec} = Time, -%% FormatDate = -%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, -%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), -%% lists:flatten(FormatDate). - - -%% =========================================================================== -%% -%% The actual NIF-functions. -%% -%% =========================================================================== - -nif_info() -> - erlang:nif_error(undef). - -nif_command(_Cmd) -> - erlang:nif_error(undef). - -nif_gethostname() -> - erlang:nif_error(undef). - -nif_getnameinfo(_Addr, _Flags) -> - erlang:nif_error(undef). - -nif_getaddrinfo(_Host, _Service, _Hints) -> - erlang:nif_error(undef). - -nif_if_name2index(_Name) -> - erlang:nif_error(undef). - -nif_if_index2name(_Id) -> - erlang:nif_error(undef). - -nif_if_names() -> - erlang:nif_error(undef). - diff --git a/erts/preloaded/src/prim_net.erl b/erts/preloaded/src/prim_net.erl new file mode 100644 index 0000000000..107043d1aa --- /dev/null +++ b/erts/preloaded/src/prim_net.erl @@ -0,0 +1,289 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2018-2019. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +-module(prim_net). + +-compile(no_native). + +%% Administrative and "global" utility functions +-export([ + on_load/0, on_load/1, + info/0, + command/1 + ]). + +-export([ + gethostname/0, + getnameinfo/2, + getaddrinfo/2, + + if_name2index/1, + if_index2name/1, + if_names/0 + ]). + +-export_type([ + address_info/0, + name_info/0, + + name_info_flags/0, + name_info_flag/0, + name_info_flag_ext/0, + + network_interface_name/0, + network_interface_index/0 + ]). + + +-type name_info_flags() :: [name_info_flag()|name_info_flag_ext()]. +-type name_info_flag() :: namereqd | + dgram | + nofqdn | + numerichost | + nomericserv. +-type name_info_flag_ext() :: idn | + idna_allow_unassigned | + idna_use_std3_ascii_rules. +-type name_info() :: #{host := string(), + service := string()}. +-type address_info() :: #{family := socket:domain(), + socktype := socket:type(), + protocol := socket:protocol(), + address := socket:sockaddr()}. +-type network_interface_name() :: string(). +-type network_interface_index() :: non_neg_integer(). + + +%% =========================================================================== +%% +%% Administrative and utility API +%% +%% =========================================================================== + +-spec on_load() -> ok. + +%% Should we require that the Extra arg is a map? +on_load() -> + on_load(#{}). + +-spec on_load(Extra) -> ok when + Extra :: map(). + +on_load(Extra) -> + ok = erlang:load_nif(atom_to_list(net), Extra). + + +-spec info() -> list(). + +info() -> + nif_info(). + + +-spec command(Cmd :: term()) -> term(). + +command(Cmd) -> + nif_command(Cmd). + + + +%% =========================================================================== +%% +%% The proper net API +%% +%% =========================================================================== + +%% =========================================================================== +%% +%% gethostname - Get the name of the current host. +%% +%% + +-spec gethostname() -> {ok, HostName} | {error, Reason} when + HostName :: string(), + Reason :: term(). + +gethostname() -> + nif_gethostname(). + + +%% =========================================================================== +%% +%% getnameinfo - Address-to-name translation in protocol-independent manner. +%% +%% + +-spec getnameinfo(SockAddr, Flags) -> {ok, Info} | {error, Reason} when + SockAddr :: socket:sockaddr(), + Flags :: name_info_flags() | undefined, + Info :: name_info(), + Reason :: term(). + +getnameinfo(SockAddr, [] = _Flags) -> + getnameinfo(SockAddr, undefined); +getnameinfo(#{family := Fam, addr := _Addr} = SockAddr, Flags) + when ((Fam =:= inet) orelse (Fam =:= inet6)) andalso + (is_list(Flags) orelse (Flags =:= undefined)) -> + nif_getnameinfo(socket:ensure_sockaddr(SockAddr), Flags); +getnameinfo(#{family := Fam, path := _Path} = SockAddr, Flags) + when (Fam =:= local) andalso (is_list(Flags) orelse (Flags =:= undefined)) -> + nif_getnameinfo(SockAddr, Flags). + + +%% =========================================================================== +%% +%% getaddrinfo - Network address and service translation +%% +%% There is also a "hint" argument that we "at some point" should implement. + +-spec getaddrinfo(Host, undefined) -> {ok, Info} | {error, Reason} when + Host :: string(), + Info :: [address_info()], + Reason :: term() + ; (undefined, Service) -> {ok, Info} | {error, Reason} when + Service :: string(), + Info :: [address_info()], + Reason :: term() + ; (Host, Service) -> {ok, Info} | {error, Reason} when + Host :: string(), + Service :: string(), + Info :: [address_info()], + Reason :: term(). + +getaddrinfo(Host, Service) + when (is_list(Host) orelse (Host =:= undefined)) andalso + (is_list(Service) orelse (Service =:= undefined)) andalso + (not ((Service =:= undefined) andalso (Host =:= undefined))) -> + nif_getaddrinfo(Host, Service, undefined). + + + +%% =========================================================================== +%% +%% if_name2index - Mappings between network interface names and indexes: +%% name -> idx +%% +%% + +-spec if_name2index(Name) -> {ok, Idx} | {error, Reason} when + Name :: network_interface_name(), + Idx :: network_interface_index(), + Reason :: term(). + +if_name2index(If) when is_list(If) -> + nif_if_name2index(If). + + + +%% =========================================================================== +%% +%% if_index2name - Mappings between network interface index and names: +%% idx -> name +%% +%% + +-spec if_index2name(Idx) -> {ok, Name} | {error, Reason} when + Idx :: network_interface_index(), + Name :: network_interface_name(), + Reason :: term(). + +if_index2name(Idx) when is_integer(Idx) -> + nif_if_index2name(Idx). + + + +%% =========================================================================== +%% +%% if_names - Get network interface names and indexes +%% +%% + +-spec if_names() -> Names | {error, Reason} when + Names :: [{Idx, If}], + Idx :: network_interface_index(), + If :: network_interface_name(), + Reason :: term(). + +if_names() -> + nif_if_names(). + + + +%% =========================================================================== +%% +%% Misc utility functions +%% +%% =========================================================================== + +%% formated_timestamp() -> +%% format_timestamp(os:timestamp()). + +%% format_timestamp(Now) -> +%% N2T = fun(N) -> calendar:now_to_local_time(N) end, +%% format_timestamp(Now, N2T, true). + +%% format_timestamp({_N1, _N2, N3} = N, N2T, true) -> +%% FormatExtra = ".~.2.0w", +%% ArgsExtra = [N3 div 10000], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra); +%% format_timestamp({_N1, _N2, _N3} = N, N2T, false) -> +%% FormatExtra = "", +%% ArgsExtra = [], +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra). + +%% format_timestamp(N, N2T, FormatExtra, ArgsExtra) -> +%% {Date, Time} = N2T(N), +%% {YYYY,MM,DD} = Date, +%% {Hour,Min,Sec} = Time, +%% FormatDate = +%% io_lib:format("~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w" ++ FormatExtra, +%% [YYYY, MM, DD, Hour, Min, Sec] ++ ArgsExtra), +%% lists:flatten(FormatDate). + + +%% =========================================================================== +%% +%% The actual NIF-functions. +%% +%% =========================================================================== + +nif_info() -> + erlang:nif_error(undef). + +nif_command(_Cmd) -> + erlang:nif_error(undef). + +nif_gethostname() -> + erlang:nif_error(undef). + +nif_getnameinfo(_Addr, _Flags) -> + erlang:nif_error(undef). + +nif_getaddrinfo(_Host, _Service, _Hints) -> + erlang:nif_error(undef). + +nif_if_name2index(_Name) -> + erlang:nif_error(undef). + +nif_if_index2name(_Id) -> + erlang:nif_error(undef). + +nif_if_names() -> + erlang:nif_error(undef). + -- cgit v1.2.3 From 1fe29381876838e26c5ffbd2efaf449a5a9522a9 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 14 Jun 2019 17:41:57 +0200 Subject: Move net.xml from erts to kernel --- erts/doc/src/Makefile | 3 +- erts/doc/src/net.xml | 129 -------------------------------------------------- 2 files changed, 1 insertion(+), 131 deletions(-) delete mode 100644 erts/doc/src/net.xml (limited to 'erts') diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile index bc01919da1..a509f33eac 100644 --- a/erts/doc/src/Makefile +++ b/erts/doc/src/Makefile @@ -56,8 +56,7 @@ XML_REF3_EFILES = \ atomics.xml \ counters.xml \ zlib.xml \ - socket.xml \ - net.xml + socket.xml XML_REF3_FILES = \ $(XML_REF3_EFILES) \ diff --git a/erts/doc/src/net.xml b/erts/doc/src/net.xml deleted file mode 100644 index 6fbc37076c..0000000000 --- a/erts/doc/src/net.xml +++ /dev/null @@ -1,129 +0,0 @@ - - - - -
- - 20182018 - Ericsson AB. All Rights Reserved. - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - - net - - - - - net.xml -
- net - Network interface. - -

This module provides an API for the network interface.

- -

There is currently no support for Windows.

-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - Get hostname. - -

Returns the name of the current host.

-
-
- - - - - Address-to-name transaltion. - -

Address-to-name translation in a protocol-independant manner.

-

This function is the inverse of - getaddrinfo. - It converts a socket address to a corresponding host and service.

-
-
- - - - - - - Network address and service transation. - -

Network address and service translation.

-

This function is the inverse of - getnameinfo. - It converts host and service to a corresponding socket address.

-

One of the Host and Service may be undefined - but not both.

-
-
- - - - Mappings between network interface names and indexes. - -

Mappings between network interface names and indexes.

-
-
- - - - Mappings between network interface index and names. - -

Mappings between network interface index and names.

-
-
- - - - Get network interface names and indexes. - -

Get network interface names and indexes.

-
-
- -
- -
- -- cgit v1.2.3 From fdffb35fc3209e20459a03fc21924295b96becee Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 14 Jun 2019 18:49:52 +0200 Subject: Remove ESOCK stuff from doc build --- erts/doc/src/Makefile | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'erts') diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile index a509f33eac..0e35d7c79f 100644 --- a/erts/doc/src/Makefile +++ b/erts/doc/src/Makefile @@ -47,6 +47,12 @@ XML_REF1_FILES = epmd.xml \ run_erl.xml \ start.xml +ifeq ($(USE_ESOCK), yes) +XML_REF3_ESOCK_EFILES = socket.xml +else +XML_REF3_ESOCK_EFILES = +endif + XML_REF3_EFILES = \ erl_prim_loader.xml \ erlang.xml \ @@ -56,7 +62,7 @@ XML_REF3_EFILES = \ atomics.xml \ counters.xml \ zlib.xml \ - socket.xml + $(XML_REF3_ESOCK_EFILES) XML_REF3_FILES = \ $(XML_REF3_EFILES) \ -- cgit v1.2.3 From 55685630a4c2edccda1954e4bfb2ee590a4467f9 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 17 Jun 2019 18:14:29 +0200 Subject: [esock] Documentation woes Still trying to make --disable-esock to work properly. Now the primary chore is the doc building. OTP-15765 --- erts/doc/src/Makefile | 22 +++++++++++++-- erts/doc/src/part.xml | 49 -------------------------------- erts/doc/src/part.xml.src | 49 ++++++++++++++++++++++++++++++++ erts/doc/src/ref_man.xml | 58 -------------------------------------- erts/doc/src/ref_man.xml.src | 57 +++++++++++++++++++++++++++++++++++++ erts/preloaded/ebin/erl_init.beam | Bin 2316 -> 2336 bytes erts/preloaded/src/erl_init.erl | 4 ++- 7 files changed, 129 insertions(+), 110 deletions(-) delete mode 100644 erts/doc/src/part.xml create mode 100644 erts/doc/src/part.xml.src delete mode 100644 erts/doc/src/ref_man.xml create mode 100644 erts/doc/src/ref_man.xml.src (limited to 'erts') diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile index 0e35d7c79f..735084b345 100644 --- a/erts/doc/src/Makefile +++ b/erts/doc/src/Makefile @@ -49,8 +49,14 @@ XML_REF1_FILES = epmd.xml \ ifeq ($(USE_ESOCK), yes) XML_REF3_ESOCK_EFILES = socket.xml +XML_CHAPTER_ESOCK_EFILES = socket_usage.xml +ESOCK_USE_SOCKET_XML= +ESOCK_USE_SOCKET_USAGE_XML= else XML_REF3_ESOCK_EFILES = +XML_CHAPTER_ESOCK_EFILES = +ESOCK_USE_SOCKET_XML = +ESOCK_USE_SOCKET_USAGE_XML = endif XML_REF3_EFILES = \ @@ -99,7 +105,7 @@ XML_CHAPTER_FILES = \ driver.xml \ absform.xml \ inet_cfg.xml \ - socket_usage.xml \ + $(XML_CHAPTER_ESOCK_EFILES) \ erl_ext_dist.xml \ erl_dist_protocol.xml \ communication.xml \ @@ -164,7 +170,7 @@ $(HTMLDIR)/%.gif: %.gif $(XML_FIGURE_DIR)/%.png: ../../emulator/internal_doc/figures/%.png $(INSTALL_DATA) $< $@ -docs: figures man pdf html $(INFO_FILE) +docs: part ref_man figures man pdf html $(INFO_FILE) $(TOP_PDF_FILE): $(XML_FILES) @@ -174,6 +180,9 @@ html: gifs $(HTML_REF_MAN_FILE) man: $(MAN1_FILES) $(MAN3_FILES) +ref_man: ref_man.xml +part: part.xml + gifs: $(GIF_FILES:%=$(HTMLDIR)/%) $(INFO_FILE): $(INFO_FILE_SRC) $(ERL_TOP)/make/$(TARGET)/otp.mk @@ -201,6 +210,15 @@ $(SPECDIR)/specs_%.xml: $(XMLDIR)/%.xml: ../../emulator/internal_doc/%.md $(ERL_TOP)/make/emd2exml $(ERL_TOP)/make/emd2exml $< $@ +ref_man.xml: ref_man.xml.src + ($(PERL) -p -e 's?%ESOCK_USE_SOCKET_XML%?$(ESOCK_USE_SOCKET_XML)?' \ + $<) > $@ + +part.xml: part.xml.src + ($(PERL) -p -e 's?%ESOCK_USE_SOCKET_USAGE_XML%?$(ESOCK_USE_SOCKET_USAGE_XML)?' \ + $<) > $@ + + # ---------------------------------------------------- # Release Target # ---------------------------------------------------- diff --git a/erts/doc/src/part.xml b/erts/doc/src/part.xml deleted file mode 100644 index f0b8a00b90..0000000000 --- a/erts/doc/src/part.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - -
- - 19962018 - Ericsson AB. All Rights Reserved. - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - - ERTS User's Guide - Catrin Granbom - - 1997-05-15 - 4.5.2 - part.xml -
- - - - - - - - - - - - - - - - -
- diff --git a/erts/doc/src/part.xml.src b/erts/doc/src/part.xml.src new file mode 100644 index 0000000000..9b20beffad --- /dev/null +++ b/erts/doc/src/part.xml.src @@ -0,0 +1,49 @@ + + + + +
+ + 19962019 + Ericsson AB. All Rights Reserved. + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + ERTS User's Guide + Catrin Granbom + + 1997-05-15 + 4.5.2 + part.xml +
+ + + + + + + + + + + + + + %ESOCK_USE_SOCKET_USAGE_XML% + + +
+ diff --git a/erts/doc/src/ref_man.xml b/erts/doc/src/ref_man.xml deleted file mode 100644 index 80cdcf9145..0000000000 --- a/erts/doc/src/ref_man.xml +++ /dev/null @@ -1,58 +0,0 @@ - - - - -
- - 19962018 - Ericsson AB. All Rights Reserved. - - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - - ERTS Reference Manual - Lars Thorsén - - 1997-05-15 - 4.5.2 - application.xml -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- diff --git a/erts/doc/src/ref_man.xml.src b/erts/doc/src/ref_man.xml.src new file mode 100644 index 0000000000..7dd003763c --- /dev/null +++ b/erts/doc/src/ref_man.xml.src @@ -0,0 +1,57 @@ + + + + +
+ + 19962019 + Ericsson AB. All Rights Reserved. + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + + ERTS Reference Manual + Lars Thorsén + + 1997-05-15 + 4.5.2 + application.xml +
+ + + + + + + + + + + + + + + + + + + + %ESOCK_USE_SOCKET_XML% + + + + +
+ diff --git a/erts/preloaded/ebin/erl_init.beam b/erts/preloaded/ebin/erl_init.beam index 1d54e0cead..bc7639781c 100644 Binary files a/erts/preloaded/ebin/erl_init.beam and b/erts/preloaded/ebin/erl_init.beam differ diff --git a/erts/preloaded/src/erl_init.erl b/erts/preloaded/src/erl_init.erl index 9fcb3969e4..dadf7dda6f 100644 --- a/erts/preloaded/src/erl_init.erl +++ b/erts/preloaded/src/erl_init.erl @@ -50,7 +50,9 @@ run(M, F, A) -> end. conditional_load(CondMod, Mods2Load) -> - conditional_load(CondMod, erlang:loaded(), Mods2Load). + Loaded = erlang:loaded(), + %% erlang:display({?MODULE, conditional_load, Loaded}), + conditional_load(CondMod, Loaded, Mods2Load). conditional_load(_CondMod, [], _Mods2LOad) -> ok; -- cgit v1.2.3 From 878741953069a8d0a7d683cf2b7cbbfe957e880d Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 24 Jun 2019 09:43:58 +0200 Subject: [esock] More doc woes Also needed to take care of the specs files (in erts and kernel docs). Also, ifdef'ing the net module adjusted (again). --- erts/doc/src/Makefile | 11 +++++++++-- erts/doc/src/specs.xml | 13 ------------- erts/doc/src/specs.xml.src | 12 ++++++++++++ 3 files changed, 21 insertions(+), 15 deletions(-) delete mode 100644 erts/doc/src/specs.xml create mode 100644 erts/doc/src/specs.xml.src (limited to 'erts') diff --git a/erts/doc/src/Makefile b/erts/doc/src/Makefile index 735084b345..bb96293947 100644 --- a/erts/doc/src/Makefile +++ b/erts/doc/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2018. All Rights Reserved. +# Copyright Ericsson AB 1997-2019. All Rights Reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. @@ -51,11 +51,13 @@ ifeq ($(USE_ESOCK), yes) XML_REF3_ESOCK_EFILES = socket.xml XML_CHAPTER_ESOCK_EFILES = socket_usage.xml ESOCK_USE_SOCKET_XML= +ESOCK_USE_SOCKET_SPECS_XML= ESOCK_USE_SOCKET_USAGE_XML= else XML_REF3_ESOCK_EFILES = XML_CHAPTER_ESOCK_EFILES = ESOCK_USE_SOCKET_XML = +ESOCK_USE_SOCKET_SPECS_XML = ESOCK_USE_SOCKET_USAGE_XML = endif @@ -170,7 +172,7 @@ $(HTMLDIR)/%.gif: %.gif $(XML_FIGURE_DIR)/%.png: ../../emulator/internal_doc/figures/%.png $(INSTALL_DATA) $< $@ -docs: part ref_man figures man pdf html $(INFO_FILE) +docs: part ref_man specs figures man pdf html $(INFO_FILE) $(TOP_PDF_FILE): $(XML_FILES) @@ -182,6 +184,7 @@ man: $(MAN1_FILES) $(MAN3_FILES) ref_man: ref_man.xml part: part.xml +specs: specs.xml gifs: $(GIF_FILES:%=$(HTMLDIR)/%) @@ -218,6 +221,10 @@ part.xml: part.xml.src ($(PERL) -p -e 's?%ESOCK_USE_SOCKET_USAGE_XML%?$(ESOCK_USE_SOCKET_USAGE_XML)?' \ $<) > $@ +specs.xml: specs.xml.src + ($(PERL) -p -e 's?%ESOCK_USE_SOCKET_SPECS_XML%?$(ESOCK_USE_SOCKET_SPECS_XML)?' \ + $<) > $@ + # ---------------------------------------------------- # Release Target diff --git a/erts/doc/src/specs.xml b/erts/doc/src/specs.xml deleted file mode 100644 index 68fab5edf1..0000000000 --- a/erts/doc/src/specs.xml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/erts/doc/src/specs.xml.src b/erts/doc/src/specs.xml.src new file mode 100644 index 0000000000..54224c15f5 --- /dev/null +++ b/erts/doc/src/specs.xml.src @@ -0,0 +1,12 @@ + + + + + + + + %ESOCK_USE_SOCKET_SPECS_XML% + + + + -- cgit v1.2.3