From cc08971508f3515f9f3b6c406ff0f6a186b24f6b Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Mon, 11 Jun 2018 12:34:23 +0200 Subject: [net-nif] Added debugging Added a command function, which is currently only used to enable and disable debug, which is also added. --- erts/emulator/nifs/common/net_nif.c | 285 +++++++++++++++++++++++++++++++++++- erts/preloaded/ebin/net.beam | Bin 4792 -> 5000 bytes erts/preloaded/src/net.erl | 12 +- 3 files changed, 289 insertions(+), 8 deletions(-) diff --git a/erts/emulator/nifs/common/net_nif.c b/erts/emulator/nifs/common/net_nif.c index edcf944c66..134b02d178 100644 --- a/erts/emulator/nifs/common/net_nif.c +++ b/erts/emulator/nifs/common/net_nif.c @@ -63,6 +63,7 @@ #include #include #include +#include #ifdef HAVE_UNISTD_H #include @@ -317,6 +318,12 @@ typedef unsigned long long llu_t; # define SOCKLEN_T size_t #endif +#define NDEBUG( ___COND___ , proto ) \ + if ( ___COND___ ) { \ + dbg_printf proto; \ + fflush(stdout); \ + } +#define NDBG( proto ) NDEBUG( data.debug , proto ) /* The general purpose socket address */ typedef union { @@ -330,6 +337,12 @@ typedef union { } SockAddress; +typedef struct { + BOOLEAN_T debug; +} NetData; + + +static NetData data; /* ---------------------------------------------------------------------- @@ -347,6 +360,9 @@ static ERL_NIF_TERM nif_is_loaded(ErlNifEnv* env, static ERL_NIF_TERM nif_info(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM nif_command(ErlNifEnv* env, + int argc, + const ERL_NIF_TERM argv[]); static ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env, int argc, @@ -366,6 +382,8 @@ static ERL_NIF_TERM nif_if_names(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]); +static ERL_NIF_TERM ncommand(ErlNifEnv* env, + ERL_NIF_TERM cmd); static ERL_NIF_TERM ngetnameinfo(ErlNifEnv* env, const SockAddress* saP, SOCKLEN_T saLen, @@ -415,6 +433,9 @@ 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_info(ErlNifEnv* env, struct addrinfo* addrInfo); static unsigned int address_info_length(struct addrinfo* addrInfoP); @@ -437,6 +458,10 @@ static ERL_NIF_TERM make_error(ErlNifEnv* env, ERL_NIF_TERM reason); static ERL_NIF_TERM make_error1(ErlNifEnv* env, char* reason); static ERL_NIF_TERM make_error2(ErlNifEnv* env, int err); +static void dbg_printf( const char* format, ... ); +static int dbg_realtime(struct timespec* tsP); +static int dbg_timespec2str(char *buf, unsigned int len, struct timespec *ts); + /* static void xabort(const char* expr, const char* func, @@ -472,8 +497,10 @@ static const struct in6_addr in6addr_loopback = /* *** String constants *** */ static char str_address_info[] = "address_info"; +static char str_debug[] = "debug"; static char str_dgram[] = "dgram"; static char str_error[] = "error"; +static char str_false[] = "false"; static char str_idn[] = "idn"; static char str_idna_allow_unassigned[] = "idna_allow_unassigned"; static char str_idna_use_std3_ascii_rules[] = "idna_use_std3_ascii_rules"; @@ -526,8 +553,10 @@ static char str_esystem[] = "esystem"; /* *** Atoms *** */ static ERL_NIF_TERM atom_address_info; +static ERL_NIF_TERM atom_debug; static ERL_NIF_TERM atom_dgram; static ERL_NIF_TERM atom_error; +static ERL_NIF_TERM atom_false; static ERL_NIF_TERM atom_idn; static ERL_NIF_TERM atom_idna_allow_unassigned; static ERL_NIF_TERM atom_idna_use_std3_ascii_rules; @@ -640,12 +669,90 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM info = enif_make_new_map(env); + ERL_NIF_TERM info; + + NDBG( ("info -> entry\r\n") ); + + info = enif_make_new_map(env); + + NDBG( ("info -> done\r\n") ); + return info; } +/* ---------------------------------------------------------------------- + * 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[]) +{ + ERL_NIF_TERM ecmd, result; + + NDBG( ("command -> entry (%d)\r\n", argc) ); + + if (argc != 1) + return enif_make_badarg(env); + + ecmd = argv[0]; + + NDBG( ("command -> ecmd: %T\r\n", ecmd) ); + + result = ncommand(env, ecmd); + + NDBG( ("command -> result: %T\r\n", result) ); + + return result; +} + + + +/* + * The command can, in principle, be anything, though currently we only + * support a debug command. + */ +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 make_error(env, atom_einval); + + if (tsz != 2) + return make_error(env, atom_einval); + + /* First element should be the atom 'debug' */ + if (COMPARE(t[0], atom_debug) != 0) + return make_error(env, atom_einval); + + return decode_bool(env, t[1], &data.debug); + + } else { + return make_error(env, atom_einval); + } + +} + + + + /* ---------------------------------------------------------------------- * nif_getnameinfo * @@ -663,25 +770,36 @@ ERL_NIF_TERM nif_getnameinfo(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM eSockAddr; + ERL_NIF_TERM result, eSockAddr; unsigned int eFlags; int flags = 0; // Just in case... SockAddress sa; SOCKLEN_T saLen = 0; // Just in case... + NDBG( ("nif_getnameinfo -> entry (%d)\r\n", argc) ); + if ((argc != 2) || !GET_UINT(env, argv[1], &eFlags)) { return enif_make_badarg(env); } eSockAddr = argv[0]; + NDBG( ("nif_getnameinfo -> " + "\r\n SockAddr: %T" + "\r\n Flags: %T" + "\r\n", argv[0], argv[1]) ); + if (!decode_nameinfo_flags(env, eFlags, &flags)) return enif_make_badarg(env); if (decode_in_sockaddr(env, eSockAddr, &sa, &saLen)) return enif_make_badarg(env); - return ngetnameinfo(env, &sa, saLen, flags); + result = ngetnameinfo(env, &sa, saLen, flags); + + NDBG( ("nif_getnameinfo -> done when result: %T\r\n", result) ); + + return result; } @@ -781,6 +899,8 @@ ERL_NIF_TERM nif_getaddrinfo(ErlNifEnv* env, char* servName; // struct addrinfo* hints; + NDBG( ("nif_getaddrinfo -> entry (%d)\r\n", argc) ); + if (argc != 3) { return enif_make_badarg(env); } @@ -788,6 +908,12 @@ ERL_NIF_TERM nif_getaddrinfo(ErlNifEnv* env, eServName = argv[1]; // eHints = argv[2]; + NDBG( ("nif_getaddrinfo -> " + "\r\n Host: %T" + "\r\n Service: %T" + "\r\n Hints: %T" + "\r\n", argv[0], argv[1], argv[2]) ); + if (!decode_addrinfo_string(env, eHostName, &hostName)) return enif_make_badarg(env); @@ -815,6 +941,8 @@ ERL_NIF_TERM nif_getaddrinfo(ErlNifEnv* env, FREE(hints); */ + NDBG( ("nif_getaddrinfo -> done when result: %T\r\n", result) ); + return result; } @@ -907,18 +1035,28 @@ ERL_NIF_TERM nif_if_name2index(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { - ERL_NIF_TERM eifn; + ERL_NIF_TERM eifn, result; char ifn[IF_NAMESIZE+1]; + NDBG( ("nif_if_name2index -> entry (%d)\r\n", argc) ); + if (argc != 1) { return enif_make_badarg(env); } eifn = argv[0]; + NDBG( ("nif_name2index -> " + "\r\n Ifn: %T" + "\r\n", argv[0]) ); + if (0 >= GET_STR(env, eifn, ifn, sizeof(ifn))) return make_error2(env, atom_einval); - return nif_name2index(env, ifn); + result = nif_name2index(env, ifn); + + NDBG( ("nif_if_name2index -> done when result: %T\r\n", result) ); + + return result; } @@ -953,14 +1091,25 @@ ERL_NIF_TERM nif_if_index2name(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + ERL_NIF_TERM result; unsigned int idx; + NDBG( ("nif_if_index2name -> entry (%d)\r\n", argc) ); + if ((argc != 1) || !GET_UINT(env, argv[0], &idx)) { return enif_make_badarg(env); } - return nif_index2name(env, idx); + NDBG( ("nif_index2name -> " + "\r\n Idx: %T" + "\r\n", argv[0]) ); + + result = nif_index2name(env, idx); + + NDBG( ("nif_if_index2name -> done when result: %T\r\n", result) ); + + return result; } @@ -1001,11 +1150,19 @@ ERL_NIF_TERM nif_if_names(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) { + ERL_NIF_TERM result; + + NDBG( ("nif_if_names -> entry (%d)\r\n", argc) ); + if (argc != 0) { return enif_make_badarg(env); } - return nif_names(env); + result = nif_names(env); + + NDBG( ("nif_if_names -> done when result: %T\r\n", result) ); + + return result; } @@ -1016,6 +1173,8 @@ ERL_NIF_TERM nif_names(ErlNifEnv* env) ERL_NIF_TERM result; struct if_nameindex* ifs = if_nameindex(); + NDBG( ("nif_names -> ifs: 0x%lX\r\n", ifs) ); + if (ifs == NULL) { result = make_error2(env, get_errno()); } else { @@ -1033,6 +1192,8 @@ ERL_NIF_TERM nif_names(ErlNifEnv* env) */ unsigned int len = nif_names_length(ifs); + NDBG( ("nif_names -> len: %d\r\n", len) ); + if (len > 0) { ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); unsigned int i; @@ -1395,6 +1556,24 @@ BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, +static +ERL_NIF_TERM decode_bool(ErlNifEnv* env, + ERL_NIF_TERM eBool, + BOOLEAN_T* bool) +{ + if (COMPARE(eBool, atom_true) == 0) { + *bool = TRUE; + return atom_ok; + } else if (COMPARE(eBool, atom_false) == 0) { + *bool = FALSE; + return atom_ok; + } else { + return make_error(env, 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. @@ -1753,6 +1932,88 @@ void net_down(ErlNifEnv* env, +/* ---------------------------------------------------------------------- + * D e b u g F u n c t i o n s + * ---------------------------------------------------------------------- + */ + +/* + * Print a debug format string *with* both a timestamp and the + * the name of the *current* thread. + */ +static +void dbg_printf( const char* format, ... ) +{ + va_list args; + char f[512 + sizeof(format)]; // This has to suffice... + char stamp[30]; + struct timespec ts; + int res; + + /* + * We should really include self in the printout, so we can se which process + * are executing the code. But then I must change the API.... + * ....something for later. + */ + + if (!dbg_realtime(&ts)) { + if (dbg_timespec2str(stamp, sizeof(stamp), &ts) != 0) { + // res = enif_snprintf(f, sizeof(f), "NET [%s] %s", TSNAME(), format); + res = enif_snprintf(f, sizeof(f), "NET [%s]", format); + } else { + // res = enif_snprintf(f, sizeof(f), "NET[%s] [%s] %s", stamp, TSNAME(), format); + res = enif_snprintf(f, sizeof(f), "NET [%s] %s", stamp, format); + } + + if (res > 0) { + va_start (args, format); + erts_vfprintf (stdout, f, args); // TMP: use enif_vfprintf + va_end (args); + fflush(stdout); + } + } + + return; +} + + +static +int dbg_realtime(struct timespec* tsP) +{ + return clock_gettime(CLOCK_REALTIME, tsP); +} + + + + +/* + * Convert a timespec struct into a readable/printable string + */ +static +int dbg_timespec2str(char *buf, unsigned int len, struct timespec *ts) +{ + int ret, buflen; + struct tm t; + + tzset(); + if (localtime_r(&(ts->tv_sec), &t) == NULL) + return 1; + + ret = strftime(buf, len, "%F %T", &t); + if (ret == 0) + return 2; + len -= ret - 1; + buflen = strlen(buf); + + ret = snprintf(&buf[buflen], len, ".%06ld", ts->tv_nsec/1000); + if (ret >= len) + return 3; + + return 0; +} + + + /* ---------------------------------------------------------------------- * 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 * ---------------------------------------------------------------------- @@ -1764,6 +2025,7 @@ ErlNifFunc net_funcs[] = // Some utility functions {"nif_is_loaded", 0, nif_is_loaded, 0}, {"nif_info", 0, nif_info, 0}, + {"nif_command", 1, nif_command, 0}, // Shall we let this be dirty? /* address and name translation in protocol-independent manner */ {"nif_getnameinfo", 2, nif_getnameinfo, 0}, @@ -1784,10 +2046,17 @@ ErlNifFunc net_funcs[] = static int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) { + // We should make it possible to use load_info to get default values + data.debug = FALSE; + + // NDBG( ("on_load -> entry\r\n") ); + /* +++ Misc atoms +++ */ atom_address_info = MKA(env, str_address_info); + atom_debug = MKA(env, str_debug); atom_dgram = MKA(env, str_dgram); atom_error = MKA(env, str_error); + atom_false = MKA(env, str_false); atom_idn = MKA(env, str_idn); atom_idna_allow_unassigned = MKA(env, str_idna_allow_unassigned); atom_idna_use_std3_ascii_rules = MKA(env, str_idna_use_std3_ascii_rules); @@ -1849,6 +2118,8 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) ERL_NIF_RT_CREATE, NULL); + // NDBG( ("on_load -> done\r\n") ); + return !net; } diff --git a/erts/preloaded/ebin/net.beam b/erts/preloaded/ebin/net.beam index a5746fb8c9..89f14a86d1 100644 Binary files a/erts/preloaded/ebin/net.beam and b/erts/preloaded/ebin/net.beam differ diff --git a/erts/preloaded/src/net.erl b/erts/preloaded/src/net.erl index f145797b97..3c010871c0 100644 --- a/erts/preloaded/src/net.erl +++ b/erts/preloaded/src/net.erl @@ -23,7 +23,8 @@ %% Administrative and "global" utility functions -export([ on_load/0, on_load/1, on_load/2, - info/0 + info/0, + command/1 ]). -export([ @@ -141,6 +142,12 @@ info() -> nif_info(). +-spec command(Cmd :: term()) -> term(). + +command(Cmd) -> + nif_command(Cmd). + + %% =========================================================================== %% @@ -292,6 +299,9 @@ nif_is_loaded() -> nif_info() -> erlang:error(badarg). +nif_command(_Cmd) -> + erlang:error(badarg). + nif_getnameinfo(_Addr, _Flags) -> erlang:error(badarg). -- cgit v1.2.3