From 1b31432a2c60364dc3e7b2a18fa8494475344271 Mon Sep 17 00:00:00 2001 From: Micael Karlberg Date: Fri, 15 Jun 2018 18:51:48 +0200 Subject: [socket+net-nif] Introduced a couple of common files Started to move the common stuff, such as common utility functions, debug and encode / decode of basic types. OTP-14831 --- erts/emulator/Makefile.in | 7 +- erts/emulator/nifs/common/net_nif.c | 511 ++++++++++---- erts/emulator/nifs/common/socket_dbg.c | 116 ++++ erts/emulator/nifs/common/socket_dbg.h | 41 ++ erts/emulator/nifs/common/socket_int.h | 193 ++++++ erts/emulator/nifs/common/socket_nif.c | 1100 +++++++++++++++++++------------ erts/emulator/nifs/common/socket_util.c | 659 ++++++++++++++++++ erts/emulator/nifs/common/socket_util.h | 108 +++ erts/preloaded/src/Makefile | 2 +- erts/preloaded/src/net.erl | 87 +-- erts/preloaded/src/socket.erl | 209 ++++-- 11 files changed, 2372 insertions(+), 661 deletions(-) create mode 100644 erts/emulator/nifs/common/socket_dbg.c create mode 100644 erts/emulator/nifs/common/socket_dbg.h create mode 100644 erts/emulator/nifs/common/socket_int.h create mode 100644 erts/emulator/nifs/common/socket_util.c create mode 100644 erts/emulator/nifs/common/socket_util.h diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 3bfe393a12..60f9b36491 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -637,12 +637,12 @@ GENERATE += $(TTF_DIR)/driver_tab.c PRELOAD_BEAM = $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \ $(ERL_TOP)/erts/preloaded/ebin/erts_code_purger.beam \ $(ERL_TOP)/erts/preloaded/ebin/init.beam \ - $(ERL_TOP)/erts/preloaded/ebin/net.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_buffer.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_eval.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \ $(ERL_TOP)/erts/preloaded/ebin/socket.beam \ + $(ERL_TOP)/erts/preloaded/ebin/net.beam \ $(ERL_TOP)/erts/preloaded/ebin/zlib.beam \ $(ERL_TOP)/erts/preloaded/ebin/prim_zip.beam \ $(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \ @@ -863,7 +863,7 @@ RUN_OBJS += \ $(OBJDIR)/register.o $(OBJDIR)/break.o \ $(OBJDIR)/erl_async.o $(OBJDIR)/erl_lock_check.o \ $(OBJDIR)/erl_gc.o $(OBJDIR)/erl_lock_count.o \ - $(OBJDIR)/erl_posix_str.o \ + $(OBJDIR)/erl_posix_str.o \ $(OBJDIR)/erl_bits.o $(OBJDIR)/erl_math.o \ $(OBJDIR)/erl_fun.o $(OBJDIR)/erl_bif_port.o \ $(OBJDIR)/erl_term.o $(OBJDIR)/erl_node_tables.o \ @@ -877,7 +877,8 @@ RUN_OBJS += \ $(OBJDIR)/erl_thr_queue.o $(OBJDIR)/erl_sched_spec_pre_alloc.o \ $(OBJDIR)/erl_ptab.o $(OBJDIR)/erl_map.o \ $(OBJDIR)/erl_msacc.o $(OBJDIR)/erl_lock_flags.o \ - $(OBJDIR)/erl_io_queue.o + $(OBJDIR)/erl_io_queue.o \ + $(OBJDIR)/socket_dbg.o $(OBJDIR)/socket_util.o LTTNG_OBJS = $(OBJDIR)/erlang_lttng.o NIF_OBJS = \ diff --git a/erts/emulator/nifs/common/net_nif.c b/erts/emulator/nifs/common/net_nif.c index e0129aec69..90263d11c2 100644 --- a/erts/emulator/nifs/common/net_nif.c +++ b/erts/emulator/nifs/common/net_nif.c @@ -174,6 +174,9 @@ #include +#include "socket_dbg.h" +#include "socket_int.h" + /* All platforms fail on malloc errors. */ #define FATAL_MALLOC @@ -263,66 +266,67 @@ typedef unsigned long long llu_t; * * * =================================================================== */ -#define MALLOC(SZ) enif_alloc((SZ)) -#define FREE(P) enif_free((P)) - -#define MKA(E,S) enif_make_atom((E), (S)) -#define MKBIN(E,B) enif_make_binary((E), (B)) -#define MKI(E,I) enif_make_int((E), (I)) -#define MKLA(E,A,L) enif_make_list_from_array((E), (A), (L)) -#define MKEL(E) enif_make_list((E), 0) -#define MKREF(E) enif_make_ref((E)) -#define MKS(E,S) enif_make_string((E), (S), ERL_NIF_LATIN1) -#define MKSL(E,S,L) enif_make_string_len((E), (S), (L), ERL_NIF_LATIN1) -#define MKSBIN(E,B,ST,SZ) enif_make_sub_binary((E), (B), (ST), (SZ)) -#define MKT2(E,E1,E2) enif_make_tuple2((E), (E1), (E2)) -#define MKT3(E,E1,E2,E3) enif_make_tuple3((E), (E1), (E2), (E3)) -#define MKT4(E,E1,E2,E3,E4) enif_make_tuple4((E), (E1), (E2), (E3), (E4)) -#define MKT5(E,E1,E2,E3,E4,E5) \ - enif_make_tuple5((E), (E1), (E2), (E3), (E4), (E5)) -#define MKT8(E,E1,E2,E3,E4,E5,E6,E7,E8) \ - enif_make_tuple8((E), (E1), (E2), (E3), (E4), (E5), (E6), (E7), (E8)) - -#define MCREATE(N) enif_mutex_create((N)) -#define MDESTROY(M) enif_mutex_destroy((M)) -#define MLOCK(M) enif_mutex_lock((M)) -#define MUNLOCK(M) enif_mutex_unlock((M)) - -#define MONP(E,D,P,M) enif_monitor_process((E), (D), (P), (M)) -#define DEMONP(E,D,M) enif_demonitor_process((E), (D), (M)) - -#define SELECT(E,FD,M,O,P,R) \ - enif_select((E), (FD), (M), (O), (P), (R)) -#define SELECT_READ(E, DP, P, R) \ - SELECT((E), (DP)->sock, (ERL_NIF_SELECT_READ), (DP), (P), (R)) -#define SELECT_WRITE(E, DP, P, R) \ - SELECT((E), (DP)->sock, (ERL_NIF_SELECT_WRITE), (DP), (P), (R)) -#define SELECT_STOP(E, DP) \ - enif_select((E), (DP)->sock, (ERL_NIF_SELECT_STOP), (DP), NULL, atom_undefined) - -#define IS_ATOM(E, TE) enif_is_atom((E), (TE)) -#define IS_BIN(E, TE) enif_is_binary((E), (TE)) -#define IS_NUM(E, TE) enif_is_number((E), (TE)) -#define IS_TUPLE(E, TE) enif_is_tuple((E), (TE)) -#define IS_LIST(E, TE) enif_is_list((E), (TE)) - -#define COMPARE(L, R) enif_compare((L), (R)) - -#define GET_ATOM_LEN(E, TE, LP) \ - enif_get_atom_length((E), (TE), (LP), ERL_NIF_LATIN1) -#define GET_ATOM(E, TE, BP, MAX) \ - enif_get_atom((E), (TE), (BP), (MAX), ERL_NIF_LATIN1) -#define GET_BIN(E, TE, BP) enif_inspect_iolist_as_binary((E), (TE), (BP)) -#define GET_INT(E, TE, IP) enif_get_int((E), (TE), (IP)) -#define GET_LIST_ELEM(E, L, HP, TP) enif_get_list_cell((E), (L), (HP), (TP)) -#define GET_LIST_LEN(E, L, LP) enif_get_list_length((E), (L), (LP)) -#define GET_STR(E, L, B, SZ) \ - enif_get_string((E), (L), (B), (SZ), ERL_NIF_LATIN1) -#define GET_UINT(E, TE, IP) enif_get_uint((E), (TE), (IP)) -#define GET_TUPLE(E, TE, TSZ, TA) enif_get_tuple((E), (TE), (TSZ), (TA)) - -#define ALLOC_BIN(SZ, BP) enif_alloc_binary((SZ), (BP)) -#define REALLOC_BIN(SZ, BP) enif_realloc_binary((SZ), (BP)) +/* #define MALLOC(SZ) enif_alloc((SZ)) */ +/* #define FREE(P) enif_free((P)) */ + +/* #define MKA(E,S) enif_make_atom((E), (S)) */ +/* #define MKBIN(E,B) enif_make_binary((E), (B)) */ +/* #define MKI(E,I) enif_make_int((E), (I)) */ +/* #define MKLA(E,A,L) enif_make_list_from_array((E), (A), (L)) */ +/* #define MKEL(E) enif_make_list((E), 0) */ +/* #define MKREF(E) enif_make_ref((E)) */ +/* #define MKS(E,S) enif_make_string((E), (S), ERL_NIF_LATIN1) */ +/* #define MKSL(E,S,L) enif_make_string_len((E), (S), (L), ERL_NIF_LATIN1) */ +/* #define MKSBIN(E,B,ST,SZ) enif_make_sub_binary((E), (B), (ST), (SZ)) */ +/* #define MKT2(E,E1,E2) enif_make_tuple2((E), (E1), (E2)) */ +/* #define MKT3(E,E1,E2,E3) enif_make_tuple3((E), (E1), (E2), (E3)) */ +/* #define MKT4(E,E1,E2,E3,E4) enif_make_tuple4((E), (E1), (E2), (E3), (E4)) */ +/* #define MKT5(E,E1,E2,E3,E4,E5) \ */ +/* enif_make_tuple5((E), (E1), (E2), (E3), (E4), (E5)) */ +/* #define MKT8(E,E1,E2,E3,E4,E5,E6,E7,E8) \ */ +/* enif_make_tuple8((E), (E1), (E2), (E3), (E4), (E5), (E6), (E7), (E8)) */ +/* #define MKTA(E, A, AL) enif_make_tuple_from_array((E), (A), (AL)) */ + +/* #define MCREATE(N) enif_mutex_create((N)) */ +/* #define MDESTROY(M) enif_mutex_destroy((M)) */ +/* #define MLOCK(M) enif_mutex_lock((M)) */ +/* #define MUNLOCK(M) enif_mutex_unlock((M)) */ + +/* #define MONP(E,D,P,M) enif_monitor_process((E), (D), (P), (M)) */ +/* #define DEMONP(E,D,M) enif_demonitor_process((E), (D), (M)) */ + +/* #define SELECT(E,FD,M,O,P,R) \ */ +/* enif_select((E), (FD), (M), (O), (P), (R)) */ +/* #define SELECT_READ(E, DP, P, R) \ */ +/* SELECT((E), (DP)->sock, (ERL_NIF_SELECT_READ), (DP), (P), (R)) */ +/* #define SELECT_WRITE(E, DP, P, R) \ */ +/* SELECT((E), (DP)->sock, (ERL_NIF_SELECT_WRITE), (DP), (P), (R)) */ +/* #define SELECT_STOP(E, DP) \ */ +/* enif_select((E), (DP)->sock, (ERL_NIF_SELECT_STOP), (DP), NULL, atom_undefined) */ + +/* #define IS_ATOM(E, TE) enif_is_atom((E), (TE)) */ +/* #define IS_BIN(E, TE) enif_is_binary((E), (TE)) */ +/* #define IS_NUM(E, TE) enif_is_number((E), (TE)) */ +/* #define IS_TUPLE(E, TE) enif_is_tuple((E), (TE)) */ +/* #define IS_LIST(E, TE) enif_is_list((E), (TE)) */ + +/* #define COMPARE(L, R) enif_compare((L), (R)) */ + +/* #define GET_ATOM_LEN(E, TE, LP) \ */ +/* enif_get_atom_length((E), (TE), (LP), ERL_NIF_LATIN1) */ +/* #define GET_ATOM(E, TE, BP, MAX) \ */ +/* enif_get_atom((E), (TE), (BP), (MAX), ERL_NIF_LATIN1) */ +/* #define GET_BIN(E, TE, BP) enif_inspect_iolist_as_binary((E), (TE), (BP)) */ +/* #define GET_INT(E, TE, IP) enif_get_int((E), (TE), (IP)) */ +/* #define GET_LIST_ELEM(E, L, HP, TP) enif_get_list_cell((E), (L), (HP), (TP)) */ +/* #define GET_LIST_LEN(E, L, LP) enif_get_list_length((E), (L), (LP)) */ +/* #define GET_STR(E, L, B, SZ) \ */ +/* enif_get_string((E), (L), (B), (SZ), ERL_NIF_LATIN1) */ +/* #define GET_UINT(E, TE, IP) enif_get_uint((E), (TE), (IP)) */ +/* #define GET_TUPLE(E, TE, TSZ, TA) enif_get_tuple((E), (TE), (TSZ), (TA)) */ + +/* #define ALLOC_BIN(SZ, BP) enif_alloc_binary((SZ), (BP)) */ +/* #define REALLOC_BIN(SZ, BP) enif_realloc_binary((SZ), (BP)) */ #ifdef HAVE_SOCKLEN_T @@ -342,12 +346,16 @@ typedef unsigned long long llu_t; typedef union { struct sockaddr sa; - struct sockaddr_in in; + struct sockaddr_in in4; #ifdef HAVE_IN6 struct sockaddr_in6 in6; #endif +#ifdef HAVE_SYS_UN_H + struct sockaddr_un un; +#endif + } SockAddress; typedef struct { @@ -440,6 +448,22 @@ static BOOLEAN_T decode_in6_sockaddr(ErlNifEnv* env, SockAddress* saP, SOCKLEN_T* saLen); #endif +static ERL_NIF_TERM encode_in_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP, + SOCKLEN_T addrLen); +static ERL_NIF_TERM encode_in4_sockaddr(ErlNifEnv* env, + struct sockaddr_in* addrP, + SOCKLEN_T addrLen); +#if defined(HAVE_IN6) && defined(AF_INET6) +static ERL_NIF_TERM encode_in6_sockaddr(ErlNifEnv* env, + struct sockaddr_in6* addrP, + SOCKLEN_T addrLen); +#endif +#ifdef HAVE_SYS_UN_H +static ERL_NIF_TERM encode_un_sockaddr(ErlNifEnv* env, + struct sockaddr_un* addrP, + SOCKLEN_T addrLen); +#endif static BOOLEAN_T decode_nameinfo_flags(ErlNifEnv* env, const ERL_NIF_TERM eflags, int* flags); @@ -453,28 +477,50 @@ BOOLEAN_T decode_addrinfo_string(ErlNifEnv* env, 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* addrInfo); + struct addrinfo* addrInfoP); static unsigned int address_info_length(struct addrinfo* addrInfoP); -static ERL_NIF_TERM make_address_info(ErlNifEnv* env, - struct addrinfo* addrInfoP); -static ERL_NIF_TERM make_addrinfo_family(ErlNifEnv* env, +static ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, int family); -static ERL_NIF_TERM make_addrinfo_type(ErlNifEnv* env, +static ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, int socktype); -static ERL_NIF_TERM make_addrinfo_proto(ErlNifEnv* env, +static ERL_NIF_TERM encode_address_info_proto(ErlNifEnv* env, int proto); -static ERL_NIF_TERM make_addrinfo_addr(ErlNifEnv* env, - struct sockaddr* addrP, - SOCKLEN_T addrLen); +/* static ERL_NIF_TERM make_address_info(ErlNifEnv* env, */ +/* struct addrinfo* addrInfoP); */ +/* static ERL_NIF_TERM make_addrinfo_addr(ErlNifEnv* env, */ +/* struct sockaddr* addrP, */ +/* SOCKLEN_T addrLen); */ + +static ERL_NIF_TERM make_in4_sockaddr(ErlNifEnv* env, + ERL_NIF_TERM port, + ERL_NIF_TERM addr); +#if defined(HAVE_IN6) && defined(AF_INET6) +static ERL_NIF_TERM make_in6_sockaddr(ErlNifEnv* env, + ERL_NIF_TERM port, + ERL_NIF_TERM addr, + ERL_NIF_TERM flowInfo, + ERL_NIF_TERM scopeId); +#endif +static ERL_NIF_TERM make_address_info(ErlNifEnv* env, + ERL_NIF_TERM fam, + ERL_NIF_TERM sockType, + ERL_NIF_TERM proto, + ERL_NIF_TERM addr); static ERL_NIF_TERM make_ok2(ErlNifEnv* env, ERL_NIF_TERM val); // static ERL_NIF_TERM make_ok3(ErlNifEnv* env, ERL_NIF_TERM val1, ERL_NIF_TERM val2); 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); +#if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE) +static size_t my_strnlen(const char *s, size_t maxlen); +#endif + 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); @@ -522,9 +568,12 @@ 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"; +static char str_in4_sockaddr[] = "in4_sockaddr"; +static char str_in6_sockaddr[] = "in6_sockaddr"; static char str_inet[] = "inet"; static char str_inet6[] = "inet6"; static char str_ip[] = "ip"; +static char str_ipv6[] = "ipv6"; static char str_namereqd[] = "namereqd"; static char str_name_info[] = "name_info"; static char str_nofqdn[] = "nofqdn"; @@ -585,9 +634,12 @@ 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; +static ERL_NIF_TERM atom_in4_sockaddr; +static ERL_NIF_TERM atom_in6_sockaddr; static ERL_NIF_TERM atom_inet; static ERL_NIF_TERM atom_inet6; static ERL_NIF_TERM atom_ip; +static ERL_NIF_TERM atom_ipv6; static ERL_NIF_TERM atom_namereqd; static ERL_NIF_TERM atom_name_info; static ERL_NIF_TERM atom_nofqdn; @@ -1009,9 +1061,9 @@ ERL_NIF_TERM nif_getaddrinfo(ErlNifEnv* env, // eHints = argv[2]; NDBG( ("nif_getaddrinfo -> " - "\r\n Host: %T" - "\r\n Service: %T" - "\r\n Hints: %T" + "\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)) @@ -1071,7 +1123,7 @@ ERL_NIF_TERM ngetaddrinfo(ErlNifEnv* env, switch (res) { case 0: { - ERL_NIF_TERM addrInfo = encode_address_info(env, addrInfoP); + ERL_NIF_TERM addrInfo = encode_address_infos(env, addrInfoP); freeaddrinfo(addrInfoP); result = make_ok2(env, addrInfo); } @@ -1454,14 +1506,14 @@ BOOLEAN_T decode_in4_sockaddr(ErlNifEnv* env, /* And finally initialize the sockaddr structure (and size) */ sys_memzero((char*)saP, sizeof(struct sockaddr_in)); - saP->in.sin_family = AF_INET; - saP->in.sin_port = htons(port); + saP->in4.sin_family = AF_INET; + saP->in4.sin_port = htons(port); for (a = 0; a < 4; a++) { if (!GET_INT(env, ipAddrT[a], &v)) return FALSE; addr[a] = v; } - sys_memcpy(&saP->in.sin_addr, &addr, sizeof(addr)); + sys_memcpy(&saP->in4.sin_addr, &addr, sizeof(addr)); *saLen = sizeof(struct sockaddr_in); return TRUE; } @@ -1552,6 +1604,168 @@ BOOLEAN_T decode_in6_sockaddr(ErlNifEnv* env, +static +ERL_NIF_TERM encode_in_sockaddr(ErlNifEnv* env, + struct sockaddr* addrP, + SOCKLEN_T addrLen) +{ + SockAddress* sockAddrP = (SockAddress*) addrP; + ERL_NIF_TERM sockAddr; + + switch (sockAddrP->sa.sa_family) { + case AF_INET: + sockAddr = encode_in4_sockaddr(env, &sockAddrP->in4, addrLen); + break; + +#if defined(HAVE_IN6) && defined(AF_INET6) + case AF_INET6: + sockAddr = encode_in6_sockaddr(env, &sockAddrP->in6, addrLen); + break; +#endif + +#ifdef HAVE_SYS_UN_H + case AF_UNIX: + sockAddr = encode_un_sockaddr(env, &sockAddrP->un, addrLen); + break; +#endif + + default: + sockAddr = atom_undefined; + break; + } + + return sockAddr; +} + + + +/* Encode an IPv4 socket address; in4_sockaddr */ +static +ERL_NIF_TERM encode_in4_sockaddr(ErlNifEnv* env, + struct sockaddr_in* addrP, + SOCKLEN_T addrLen) +{ + ERL_NIF_TERM sockAddr; + short port; + ERL_NIF_TERM ePort, eAddr; + + + if (addrLen >= sizeof(struct sockaddr_in)) { + unsigned int i; + ERL_NIF_TERM at[4]; + unsigned int atLen = sizeof(at) / sizeof(ERL_NIF_TERM); + unsigned char* a = (unsigned char*) &addrP->sin_addr; + + /* The port */ + port = ntohs(addrP->sin_port); + ePort = MKI(env, port); + + /* The address */ + for (i = 0; i < atLen; i++) { + at[i] = MKI(env, a[i]); + } + eAddr = MKTA(env, at, atLen); + // eAddr = MKT4(env, at[0], at[1], at[2], at[3]); + + /* And finally construct the in4_sockaddr record */ + sockAddr = make_in4_sockaddr(env, ePort, eAddr); + + } else { + sockAddr = atom_undefined; + } + + return sockAddr; +} + + + +/* Encode an IPv6 socket address; in6_sockaddr */ +#if defined(HAVE_IN6) && defined(AF_INET6) +static +ERL_NIF_TERM encode_in6_sockaddr(ErlNifEnv* env, + struct sockaddr_in6* addrP, + SOCKLEN_T addrLen) +{ + ERL_NIF_TERM sockAddr; + short port; + ERL_NIF_TERM ePort, eAddr, eFlowInfo, eScopeId; + + + if (addrLen >= sizeof(struct sockaddr_in6)) { + unsigned int i; + ERL_NIF_TERM at[8]; + unsigned int atLen = sizeof(at) / sizeof(ERL_NIF_TERM); + unsigned char* a = (unsigned char*) &addrP->sin6_addr; + + /* The port */ + port = ntohs(addrP->sin6_port); + ePort = MKI(env, port); + + /* The address */ + for (i = 0; i < atLen; i++) { + at[i] = MKI(env, get_int16(a + i*2)); + } + eAddr = MKTA(env, at, atLen); + + /* The flowInfo */ + eFlowInfo = MKI(env, addrP->sin6_flowinfo); + + /* The scopeId */ + eScopeId = MKI(env, addrP->sin6_scope_id); + + /* And finally construct the in6_sockaddr record */ + sockAddr = make_in6_sockaddr(env, ePort, eAddr, eFlowInfo, eScopeId); + + } else { + sockAddr = atom_undefined; + } + + return sockAddr; +} +#endif + + + +/* Encode an Unix Domain socket address: string() */ +#ifdef HAVE_SYS_UN_H +static +ERL_NIF_TERM encode_un_sockaddr(ErlNifEnv* env, + struct sockaddr_un* addrP, + SOCKLEN_T addrLen) +{ + ERL_NIF_TERM sockAddr; + size_t n, m; + + if (addrLen >= offsetof(struct sockaddr_un, sun_path)) { + n = addrLen - offsetof(struct sockaddr_un, sun_path); + if (255 < n) { + sockAddr = atom_undefined; + } else { + m = my_strnlen(addrP->sun_path, n); +#ifdef __linux__ + /* Assume that the address is a zero terminated string, + * except when the first byte is \0 i.e the string length is 0, + * then use the reported length instead. + * This fix handles Linux's nonportable + * abstract socket address extension. + */ + if (m == 0) { + m = n; + } +#endif + + sockAddr = MKSL(env, addrP->sun_path, m); + } + } else { + sockAddr = atom_undefined; + } + + return sockAddr; +} +#endif + + + /* 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. @@ -1710,13 +1924,13 @@ ERL_NIF_TERM decode_bool(ErlNifEnv* env, * will result in the result being a list of zero or more length. */ static -ERL_NIF_TERM encode_address_info(ErlNifEnv* env, - struct addrinfo* addrInfo) +ERL_NIF_TERM encode_address_infos(ErlNifEnv* env, + struct addrinfo* addrInfo) { ERL_NIF_TERM result; unsigned int len = address_info_length(addrInfo); - NDBG( ("encode_address_info -> len: %d\r\n", len) ); + NDBG( ("encode_address_infos -> len: %d\r\n", len) ); if (len > 0) { ERL_NIF_TERM* array = MALLOC(len * sizeof(ERL_NIF_TERM)); @@ -1724,22 +1938,17 @@ ERL_NIF_TERM encode_address_info(ErlNifEnv* env, struct addrinfo* p = addrInfo; while (i < len) { - array[i] = make_address_info(env, p); + array[i] = encode_address_info(env, p); p = p->ai_next; i++; } - /* - for (i = 0; i < len; i++) { - array[i] = make_address_info(env, &addrInfo[i]); - } - */ result = MKLA(env, array, len); } else { result = MKEL(env); } - NDBG( ("encode_address_info -> result: " + NDBG( ("encode_address_infos -> result: " "\r\n %T\r\n", result) ); return result; @@ -1780,28 +1989,17 @@ unsigned int address_info_length(struct addrinfo* addrInfoP) * {address_info, Fam, Type, Proto, Addr} */ static -ERL_NIF_TERM make_address_info(ErlNifEnv* env, - struct addrinfo* addrInfoP) +ERL_NIF_TERM encode_address_info(ErlNifEnv* env, + struct addrinfo* addrInfoP) { ERL_NIF_TERM result, fam, type, proto, addr; - fam = make_addrinfo_family(env, addrInfoP->ai_family); - // NDBG( ("make_address_info -> fam: %T\r\n", fam) ); - type = make_addrinfo_type(env, addrInfoP->ai_socktype); - // NDBG( ("make_address_info -> type: %T\r\n", type) ); - proto = make_addrinfo_proto(env, addrInfoP->ai_protocol); - // NDBG( ("make_address_info -> proto: %T\r\n", proto) ); - addr = make_addrinfo_addr(env, - addrInfoP->ai_addr, - addrInfoP->ai_addrlen); - // NDBG( ("make_address_info -> addr: %T\r\n", addr) ); + 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); + addr = encode_in_sockaddr(env, addrInfoP->ai_addr, addrInfoP->ai_addrlen); - result = MKT5(env, atom_address_info, fam, type, proto, addr); - - /* - NDBG( ("make_address_info -> result: " - "\r\n %T\r\n", result) ); - */ + result = make_address_info(env, fam, type, proto, addr); return result; @@ -1814,23 +2012,29 @@ ERL_NIF_TERM make_address_info(ErlNifEnv* env, * in the form of an integer. */ static -ERL_NIF_TERM make_addrinfo_family(ErlNifEnv* env, - int family) +ERL_NIF_TERM encode_address_info_family(ErlNifEnv* env, + int family) { ERL_NIF_TERM efam; switch (family) { case AF_INET: - efam = atom_inet; + efam = esock_atom_inet; break; #if defined(HAVE_IN6) && defined(AF_INET6) case AF_INET6: - efam = atom_inet6; + efam = esock_atom_inet6; break; #endif - default: + #ifdef HAVE_SYS_UN_H + case AF_UNIX: + efam = esock_atom_local; + break; +#endif + + default: efam = MKI(env, family); break; } @@ -1846,8 +2050,8 @@ ERL_NIF_TERM make_addrinfo_family(ErlNifEnv* env, * in the form of an integer. */ static -ERL_NIF_TERM make_addrinfo_type(ErlNifEnv* env, - int socktype) +ERL_NIF_TERM encode_address_info_type(ErlNifEnv* env, + int socktype) { ERL_NIF_TERM etype; @@ -1872,10 +2076,6 @@ ERL_NIF_TERM make_addrinfo_type(ErlNifEnv* env, etype = atom_seqpacket; break; - case SOCK_DCCP: - etype = atom_dccp; - break; - default: etype = MKI(env, socktype); break; @@ -1892,8 +2092,8 @@ ERL_NIF_TERM make_addrinfo_type(ErlNifEnv* env, * in the form of an integer. */ static -ERL_NIF_TERM make_addrinfo_proto(ErlNifEnv* env, - int proto) +ERL_NIF_TERM encode_address_info_proto(ErlNifEnv* env, + int proto) { ERL_NIF_TERM eproto; @@ -1906,6 +2106,12 @@ ERL_NIF_TERM make_addrinfo_proto(ErlNifEnv* env, eproto = atom_ip; break; +#if defined(SOL_IPV6) + case SOL_IPV6: + eproto = atom_ipv6; + break; +#endif + case IPPROTO_TCP: eproto = atom_tcp; break; @@ -1914,6 +2120,12 @@ ERL_NIF_TERM make_addrinfo_proto(ErlNifEnv* env, eproto = atom_udp; break; +#if defined(HAVE_SCTP) + case IPPROTO_SCTP: + eproto = atom_sctp; + break; +#endif + default: eproto = MKI(env, proto); break; @@ -1929,15 +2141,16 @@ ERL_NIF_TERM make_addrinfo_proto(ErlNifEnv* env, * IPv4 and IPv6 addresses. Values of other families will be * returned as an undefined. */ +/* static -ERL_NIF_TERM make_addrinfo_addr(ErlNifEnv* env, - struct sockaddr* addrP, - SOCKLEN_T addrLen) +ERL_NIF_TERM encode_address_info_addr(ErlNifEnv* env, + struct sockaddr* addrP, + SOCKLEN_T addrLen) { ERL_NIF_TERM port, addr, eaddr; SockAddress* p = (SockAddress*) addrP; - NDBG( ("make_addrinfo_addr -> entry with" + NDBG( ("encode_address_info_addr -> entry with" "\r\n family: %d" "\r\n addrLen: %d" "\r\n", addrP->sa_family, addrLen) ); @@ -1985,6 +2198,57 @@ ERL_NIF_TERM make_addrinfo_addr(ErlNifEnv* env, return eaddr; } +*/ + + + +#if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE) +/* strnlen doesn't exist everywhere */ +static +size_t my_strnlen(const char *s, size_t maxlen) +{ + size_t i = 0; + while (i < maxlen && s[i] != '\0') + i++; + return i; +} +#endif + + + +/* Construct the IPv4 socket address record: in4_sockaddr */ +static +ERL_NIF_TERM make_in4_sockaddr(ErlNifEnv* env, + ERL_NIF_TERM port, + ERL_NIF_TERM addr) +{ + return MKT3(env, atom_in4_sockaddr, port, addr); +} + + + +/* Construct the IPv6 socket address record: in6_sockaddr */ +static +ERL_NIF_TERM make_in6_sockaddr(ErlNifEnv* env, + ERL_NIF_TERM port, + ERL_NIF_TERM addr, + ERL_NIF_TERM flowInfo, + ERL_NIF_TERM scopeId) +{ + return MKT5(env, atom_in6_sockaddr, port, addr, flowInfo, scopeId); +} + + + +static +ERL_NIF_TERM make_address_info(ErlNifEnv* env, + ERL_NIF_TERM fam, + ERL_NIF_TERM sockType, + ERL_NIF_TERM proto, + ERL_NIF_TERM addr) +{ + return MKT5(env, atom_address_info, fam, sockType, proto, addr); +} @@ -2248,9 +2512,12 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) 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); + atom_in4_sockaddr = MKA(env, str_in4_sockaddr); + atom_in6_sockaddr = MKA(env, str_in6_sockaddr); atom_inet = MKA(env, str_inet); atom_inet6 = MKA(env, str_inet6); atom_ip = MKA(env, str_ip); + atom_ipv6 = MKA(env, str_ipv6); atom_namereqd = MKA(env, str_namereqd); atom_name_info = MKA(env, str_name_info); atom_nofqdn = MKA(env, str_nofqdn); diff --git a/erts/emulator/nifs/common/socket_dbg.c b/erts/emulator/nifs/common/socket_dbg.c new file mode 100644 index 0000000000..dd11fbca9b --- /dev/null +++ b/erts/emulator/nifs/common/socket_dbg.c @@ -0,0 +1,116 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2018-2018. 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 : Debug functions for the socket and net NIF(s). + * ---------------------------------------------------------------------- + * + */ + +#include +#include +#include +#include +#include + +#include +#include "socket_dbg.h" + +#define TSELF() enif_thread_self() +#define TNAME(__T__) enif_thread_name( __T__ ) +#define TSNAME() TNAME(TSELF()) + +static int realtime(struct timespec* tsP); +static int timespec2str(char *buf, unsigned int len, struct timespec *ts); + + +/* + * Print a debug format string *with* both a timestamp and the + * the name of the *current* thread. + */ +extern +void esock_dbg_printf( const char* prefix, 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 (!realtime(&ts)) { + if (timespec2str(stamp, sizeof(stamp), &ts) != 0) { + res = enif_snprintf(f, sizeof(f), "%s [%s] %s", prefix, TSNAME(), format); + // res = enif_snprintf(f, sizeof(f), "%s [%s]", prefix, format); + } else { + res = enif_snprintf(f, sizeof(f), "%s [%s] [%s] %s", prefix, stamp, TSNAME(), format); + // res = enif_snprintf(f, sizeof(f), "%s [%s] %s", prefix, stamp, format); + } + + if (res > 0) { + va_start (args, format); + enif_vfprintf (stdout, f, args); + va_end (args); + fflush(stdout); + } + } + + return; +} + + +static +int realtime(struct timespec* tsP) +{ + return clock_gettime(CLOCK_REALTIME, tsP); +} + + + + +/* + * Convert a timespec struct into a readable/printable string + */ +static +int 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; +} diff --git a/erts/emulator/nifs/common/socket_dbg.h b/erts/emulator/nifs/common/socket_dbg.h new file mode 100644 index 0000000000..36e2be1679 --- /dev/null +++ b/erts/emulator/nifs/common/socket_dbg.h @@ -0,0 +1,41 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2018-2018. 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 : Defines and macros for the debug util of the socket and + * net NIF(s). + * ---------------------------------------------------------------------- + * + */ + +#ifndef SOCKET_DBG_H__ +#define SOCKET_DBG_H__ + + +#define ESOCK_DBG_PRINTF( ___COND___ , proto ) \ + if ( ___COND___ ) { \ + esock_dbg_printf proto; \ + fflush(stdout); \ + } + + +extern +void esock_dbg_printf( const char* prefix, const char* format, ... ); + +#endif // SOCKET_DBG_H__ diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h new file mode 100644 index 0000000000..83794f0b95 --- /dev/null +++ b/erts/emulator/nifs/common/socket_int.h @@ -0,0 +1,193 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2018-2018. 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 : Utility "stuff" for socket and net. + * ---------------------------------------------------------------------- + * + */ + +#ifndef SOCKET_INT_H__ +#define SOCKET_INT_H__ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#ifdef __WIN32__ + +/* All this just to replace sys/socket.h, netinet/in.h and sys/un.h??? */ +#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 + +#else /* !__WIN32__ */ + +#include +#include +#ifdef HAVE_SYS_UN_H +#include +#endif + +#endif + +#include + +/* The general purpose sockaddr */ +typedef union { + /* General sockaddr */ + struct sockaddr in; + + /* IPv4 sockaddr */ + struct sockaddr_in in4; + + /* IPv6 sockaddr */ +#if defined(HAVE_IN6) && defined(AF_INET6) + struct sockaddr_in6 in6; +#endif + + /* Unix Domain Socket sockaddr */ +#if defined(HAVE_SYS_UN_H) + struct sockaddr_un un; +#endif + +} SocketAddress; + + +typedef unsigned int BOOLEAN_T; +#define TRUE 1 +#define FALSE 0 + + +/* Misc error strings */ +#define ESOCK_STR_EINVAL "einval" +#define ESOCK_STR_EAFNOSUPPORT "eafnosupport" + + +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * Misc atoms + */ +extern ERL_NIF_TERM esock_atom_addr; +extern ERL_NIF_TERM esock_atom_any; +extern ERL_NIF_TERM esock_atom_dgram; +extern ERL_NIF_TERM esock_atom_error; +extern ERL_NIF_TERM esock_atom_family; +extern ERL_NIF_TERM esock_atom_flowinfo; +extern ERL_NIF_TERM esock_atom_inet; +extern ERL_NIF_TERM esock_atom_inet6; +extern ERL_NIF_TERM esock_atom_local; +extern ERL_NIF_TERM esock_atom_loopback; +extern ERL_NIF_TERM esock_atom_ok; +extern ERL_NIF_TERM esock_atom_path; +extern ERL_NIF_TERM esock_atom_port; +extern ERL_NIF_TERM esock_atom_raw; +extern ERL_NIF_TERM esock_atom_scope_id; +extern ERL_NIF_TERM esock_atom_seqpacket; +extern ERL_NIF_TERM esock_atom_stream; +extern ERL_NIF_TERM esock_atom_undefined; + + +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * Error value (=reason) atoms + */ +extern ERL_NIF_TERM esock_atom_eagain; +extern ERL_NIF_TERM esock_atom_eafnosupport; +extern ERL_NIF_TERM esock_atom_einval; + + +/* ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + * Various wrapper macros for enif functions + */ +#define MALLOC(SZ) enif_alloc((SZ)) +#define FREE(P) enif_free((P)) + +#define MKA(E,S) enif_make_atom((E), (S)) +#define MKBIN(E,B) enif_make_binary((E), (B)) +#define MKI(E,I) enif_make_int((E), (I)) +#define MKLA(E,A,L) enif_make_list_from_array((E), (A), (L)) +#define MKEL(E) enif_make_list((E), 0) +#define MKMA(E,KA,VA,L,M) enif_make_map_from_arrays((E), (KA), (VA), (L), (M)) +#define MKREF(E) enif_make_ref((E)) +#define MKS(E,S) enif_make_string((E), (S), ERL_NIF_LATIN1) +#define MKSL(E,S,L) enif_make_string_len((E), (S), (L), ERL_NIF_LATIN1) +#define MKSBIN(E,B,ST,SZ) enif_make_sub_binary((E), (B), (ST), (SZ)) +#define MKT2(E,E1,E2) enif_make_tuple2((E), (E1), (E2)) +#define MKT3(E,E1,E2,E3) enif_make_tuple3((E), (E1), (E2), (E3)) +#define MKT4(E,E1,E2,E3,E4) enif_make_tuple4((E), (E1), (E2), (E3), (E4)) +#define MKT5(E,E1,E2,E3,E4,E5) \ + enif_make_tuple5((E), (E1), (E2), (E3), (E4), (E5)) +#define MKT8(E,E1,E2,E3,E4,E5,E6,E7,E8) \ + enif_make_tuple8((E), (E1), (E2), (E3), (E4), (E5), (E6), (E7), (E8)) +#define MKTA(E, A, AL) enif_make_tuple_from_array((E), (A), (AL)) + +#define MCREATE(N) enif_mutex_create((N)) +#define MDESTROY(M) enif_mutex_destroy((M)) +#define MLOCK(M) enif_mutex_lock((M)) +#define MUNLOCK(M) enif_mutex_unlock((M)) + +#define MONP(E,D,P,M) enif_monitor_process((E), (D), (P), (M)) +#define DEMONP(E,D,M) enif_demonitor_process((E), (D), (M)) + +#define SELECT(E,FD,M,O,P,R) \ + if (enif_select((E), (FD), (M), (O), (P), (R)) < 0) \ + return enif_make_badarg((E)); + +#define COMPARE(A, B) enif_compare((A), (B)) + +#define IS_ATOM(E, TE) enif_is_atom((E), (TE)) +#define IS_BIN(E, TE) enif_is_binary((E), (TE)) +#define IS_LIST(E, TE) enif_is_list((E), (TE)) +#define IS_MAP(E, TE) enif_is_map((E), (TE)) +#define IS_NUM(E, TE) enif_is_number((E), (TE)) +#define IS_TUPLE(E, TE) enif_is_tuple((E), (TE)) + +#define GET_ATOM_LEN(E, TE, LP) \ + enif_get_atom_length((E), (TE), (LP), ERL_NIF_LATIN1) +#define GET_ATOM(E, TE, BP, MAX) \ + enif_get_atom((E), (TE), (BP), (MAX), ERL_NIF_LATIN1) +#define GET_BIN(E, TE, BP) enif_inspect_iolist_as_binary((E), (TE), (BP)) +#define GET_INT(E, TE, IP) enif_get_int((E), (TE), (IP)) +#define GET_LIST_ELEM(E, L, HP, TP) enif_get_list_cell((E), (L), (HP), (TP)) +#define GET_LIST_LEN(E, L, LP) enif_get_list_length((E), (L), (LP)) +#define GET_STR(E, L, B, SZ) \ + enif_get_string((E), (L), (B), (SZ), ERL_NIF_LATIN1) +#define GET_UINT(E, TE, IP) enif_get_uint((E), (TE), (IP)) +#define GET_TUPLE(E, TE, TSZ, TA) enif_get_tuple((E), (TE), (TSZ), (TA)) +#define GET_MAP_VAL(E, M, K, V) enif_get_map_value((E), (M), (K), (V)) + +#define ALLOC_BIN(SZ, BP) enif_alloc_binary((SZ), (BP)) +#define REALLOC_BIN(SZ, BP) enif_realloc_binary((SZ), (BP)) + + +#endif // SOCKET_INT_H__ diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c index badaa8d988..335d773f89 100644 --- a/erts/emulator/nifs/common/socket_nif.c +++ b/erts/emulator/nifs/common/socket_nif.c @@ -173,6 +173,9 @@ #include +#include "socket_dbg.h" +#include "socket_int.h" +#include "socket_util.h" /* All platforms fail on malloc errors. */ #define FATAL_MALLOC @@ -399,66 +402,61 @@ typedef union { * * * =================================================================== */ -#define MALLOC(SZ) enif_alloc((SZ)) -#define FREE(P) enif_free((P)) - -#define MKA(E,S) enif_make_atom((E), (S)) -#define MKBIN(E,B) enif_make_binary((E), (B)) -#define MKI(E,I) enif_make_int((E), (I)) -#define MKLA(E,A,L) enif_make_list_from_array((E), (A), (L)) -#define MKMA(E,KA,VA,L,M) enif_make_map_from_arrays((E), (KA), (VA), (L), (M)) -#define MKREF(E) enif_make_ref((E)) -#define MKS(E,S) enif_make_string((E), (S), ERL_NIF_LATIN1) -#define MKSL(E,S,L) enif_make_string_len((E), (S), (L), ERL_NIF_LATIN1) -#define MKSBIN(E,B,ST,SZ) enif_make_sub_binary((E), (B), (ST), (SZ)) -#define MKT2(E,E1,E2) enif_make_tuple2((E), (E1), (E2)) -#define MKT3(E,E1,E2,E3) enif_make_tuple3((E), (E1), (E2), (E3)) -#define MKT4(E,E1,E2,E3,E4) enif_make_tuple4((E), (E1), (E2), (E3), (E4)) -#define MKT8(E,E1,E2,E3,E4,E5,E6,E7,E8) \ - enif_make_tuple8((E), (E1), (E2), (E3), (E4), (E5), (E6), (E7), (E8)) - -#define MCREATE(N) enif_mutex_create((N)) -#define MDESTROY(M) enif_mutex_destroy((M)) -#define MLOCK(M) enif_mutex_lock((M)) -#define MUNLOCK(M) enif_mutex_unlock((M)) - -#define MONP(E,D,P,M) enif_monitor_process((E), (D), (P), (M)) -#define DEMONP(E,D,M) enif_demonitor_process((E), (D), (M)) - -#define SELECT(E,FD,M,O,P,R) \ - if (enif_select((E), (FD), (M), (O), (P), (R)) < 0) \ - return enif_make_badarg((E)); - -#define COMPARE(A, B) enif_compare((A), (B)) - -#define IS_ATOM(E, TE) enif_is_atom((E), (TE)) -#define IS_BIN(E, TE) enif_is_binary((E), (TE)) -#define IS_MAP(E, TE) enif_is_map((E), (TE)) -#define IS_NUM(E, TE) enif_is_number((E), (TE)) -#define IS_TUPLE(E, TE) enif_is_tuple((E), (TE)) - -#define GET_ATOM_LEN(E, TE, LP) \ - enif_get_atom_length((E), (TE), (LP), ERL_NIF_LATIN1) -#define GET_ATOM(E, TE, BP, MAX) \ - enif_get_atom((E), (TE), (BP), (MAX), ERL_NIF_LATIN1) -#define GET_BIN(E, TE, BP) enif_inspect_iolist_as_binary((E), (TE), (BP)) -#define GET_INT(E, TE, IP) enif_get_int((E), (TE), (IP)) -#define GET_STR(E, L, B, SZ) \ - enif_get_string((E), (L), (B), (SZ), ERL_NIF_LATIN1) -#define GET_UINT(E, TE, IP) enif_get_uint((E), (TE), (IP)) -#define GET_TUPLE(E, TE, TSZ, TA) enif_get_tuple((E), (TE), (TSZ), (TA)) - -#define ALLOC_BIN(SZ, BP) enif_alloc_binary((SZ), (BP)) -#define REALLOC_BIN(SZ, BP) enif_realloc_binary((SZ), (BP)) - - -#define SDEBUG( ___COND___ , proto ) \ - if ( ___COND___ ) { \ - dbg_printf proto; \ - fflush(stdout); \ - } -#define SGDBG( proto ) SDEBUG( data.dbg , proto ) -#define SSDBG( __D__ , proto ) SDEBUG( (__D__)->dbg , proto ) +/* #define MALLOC(SZ) enif_alloc((SZ)) */ +/* #define FREE(P) enif_free((P)) */ + +/* #define MKA(E,S) enif_make_atom((E), (S)) */ +/* #define MKBIN(E,B) enif_make_binary((E), (B)) */ +/* #define MKI(E,I) enif_make_int((E), (I)) */ +/* #define MKLA(E,A,L) enif_make_list_from_array((E), (A), (L)) */ +/* #define MKMA(E,KA,VA,L,M) enif_make_map_from_arrays((E), (KA), (VA), (L), (M)) */ +/* #define MKREF(E) enif_make_ref((E)) */ +/* #define MKS(E,S) enif_make_string((E), (S), ERL_NIF_LATIN1) */ +/* #define MKSL(E,S,L) enif_make_string_len((E), (S), (L), ERL_NIF_LATIN1) */ +/* #define MKSBIN(E,B,ST,SZ) enif_make_sub_binary((E), (B), (ST), (SZ)) */ +/* #define MKT2(E,E1,E2) enif_make_tuple2((E), (E1), (E2)) */ +/* #define MKT3(E,E1,E2,E3) enif_make_tuple3((E), (E1), (E2), (E3)) */ +/* #define MKT4(E,E1,E2,E3,E4) enif_make_tuple4((E), (E1), (E2), (E3), (E4)) */ +/* #define MKT8(E,E1,E2,E3,E4,E5,E6,E7,E8) \ */ +/* enif_make_tuple8((E), (E1), (E2), (E3), (E4), (E5), (E6), (E7), (E8)) */ + +/* #define MCREATE(N) enif_mutex_create((N)) */ +/* #define MDESTROY(M) enif_mutex_destroy((M)) */ +/* #define MLOCK(M) enif_mutex_lock((M)) */ +/* #define MUNLOCK(M) enif_mutex_unlock((M)) */ + +/* #define MONP(E,D,P,M) enif_monitor_process((E), (D), (P), (M)) */ +/* #define DEMONP(E,D,M) enif_demonitor_process((E), (D), (M)) */ + +/* #define SELECT(E,FD,M,O,P,R) \ */ +/* if (enif_select((E), (FD), (M), (O), (P), (R)) < 0) \ */ +/* return enif_make_badarg((E)); */ + +/* #define COMPARE(A, B) enif_compare((A), (B)) */ + +/* #define IS_ATOM(E, TE) enif_is_atom((E), (TE)) */ +/* #define IS_BIN(E, TE) enif_is_binary((E), (TE)) */ +/* #define IS_MAP(E, TE) enif_is_map((E), (TE)) */ +/* #define IS_NUM(E, TE) enif_is_number((E), (TE)) */ +/* #define IS_TUPLE(E, TE) enif_is_tuple((E), (TE)) */ + +/* #define GET_ATOM_LEN(E, TE, LP) \ */ +/* enif_get_atom_length((E), (TE), (LP), ERL_NIF_LATIN1) */ +/* #define GET_ATOM(E, TE, BP, MAX) \ */ +/* enif_get_atom((E), (TE), (BP), (MAX), ERL_NIF_LATIN1) */ +/* #define GET_BIN(E, TE, BP) enif_inspect_iolist_as_binary((E), (TE), (BP)) */ +/* #define GET_INT(E, TE, IP) enif_get_int((E), (TE), (IP)) */ +/* #define GET_STR(E, L, B, SZ) \ */ +/* enif_get_string((E), (L), (B), (SZ), ERL_NIF_LATIN1) */ +/* #define GET_UINT(E, TE, IP) enif_get_uint((E), (TE), (IP)) */ +/* #define GET_TUPLE(E, TE, TSZ, TA) enif_get_tuple((E), (TE), (TSZ), (TA)) */ + +/* #define ALLOC_BIN(SZ, BP) enif_alloc_binary((SZ), (BP)) */ +/* #define REALLOC_BIN(SZ, BP) enif_realloc_binary((SZ), (BP)) */ + + +#define SGDBG( proto ) ESOCK_DBG_PRINTF( data.dbg , proto ) +#define SSDBG( __D__ , proto ) ESOCK_DBG_PRINTF( (__D__)->dbg , proto ) /* =================================================================== * @@ -548,24 +546,28 @@ static unsigned long one_value = 1; #define SOCKOPTLEN_T SOCKLEN_T #endif -/* The general purpose sockaddr */ +/* The general purpose sockaddr * / typedef union { - struct sockaddr sa; - struct sockaddr_in sai; + struct sockaddr in; + struct sockaddr_in in4; #ifdef HAVE_IN6 - struct sockaddr_in6 sai6; + struct sockaddr_in6 in6; #endif #ifdef HAVE_SYS_UN_H - struct sockaddr_un sal; + struct sockaddr_un un; #endif + } SocketAddress; +*/ +/* We can use the IPv4 def for this since the beginning + * is the same for INET and INET6 */ #define which_address_port(sap) \ - ((((sap)->sai.sin_family == AF_INET) || \ - ((sap)->sai.sin_family == AF_INET6)) ? \ - ((sap)->sai.sin_port) : -1) + ((((sap)->in4.sin_family == AF_INET) || \ + ((sap)->in4.sin_family == AF_INET6)) ? \ + ((sap)->in4.sin_port) : -1) typedef struct { @@ -706,8 +708,6 @@ typedef struct { * ---------------------------------------------------------------------- */ -/* THIS IS JUST TEMPORARY */ -extern char* erl_errno_id(int error); static ERL_NIF_TERM nif_is_loaded(ErlNifEnv* env, @@ -1313,12 +1313,6 @@ static void socket_down(ErlNifEnv* env, const ErlNifPid* pid, const ErlNifMonitor* mon); -static ERL_NIF_TERM make_ok2(ErlNifEnv* env, ERL_NIF_TERM val); -static ERL_NIF_TERM make_ok3(ErlNifEnv* env, ERL_NIF_TERM val1, ERL_NIF_TERM val2); -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 char* send_msg_error_closed(ErlNifEnv* env, ErlNifPid* pid); @@ -1341,10 +1335,6 @@ static void xabort(const char* expr, const char* file, int line); -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 BOOLEAN_T extract_item_on_load(ErlNifEnv* env, ERL_NIF_TERM map, ERL_NIF_TERM key, @@ -1384,20 +1374,18 @@ static const struct in6_addr in6addr_loopback = /* *** String constants *** */ -static char str_any[] = "any"; +// static char str_any[] = "any"; static char str_close[] = "close"; static char str_closed[] = "closed"; static char str_closing[] = "closing"; static char str_debug[] = "debug"; -static char str_error[] = "error"; static char str_false[] = "false"; static char str_global_counters[] = "global_counters"; static char str_in4_sockaddr[] = "in4_sockaddr"; static char str_in6_sockaddr[] = "in6_sockaddr"; static char str_iow[] = "iow"; -static char str_loopback[] = "loopback"; +// static char str_loopback[] = "loopback"; static char str_nif_abort[] = "nif_abort"; -static char str_ok[] = "ok"; static char str_select[] = "select"; static char str_num_dlocal[] = "num_domain_local"; static char str_num_dinet[] = "num_domain_inet"; @@ -1412,7 +1400,6 @@ static char str_num_tseqpkgs[] = "num_type_seqpacket"; static char str_num_tstreams[] = "num_type_stream"; static char str_timeout[] = "timeout"; static char str_true[] = "true"; -static char str_undefined[] = "undefined"; static char str_lowdelay[] = "lowdelay"; static char str_throughput[] = "throughput"; @@ -1434,19 +1421,37 @@ static char str_exself[] = "exself"; // failed self static char str_exsend[] = "exsend"; // failed send +/* *** "Global" Atoms *** */ +ERL_NIF_TERM esock_atom_addr; +ERL_NIF_TERM esock_atom_any; +ERL_NIF_TERM esock_atom_dgram; +ERL_NIF_TERM esock_atom_error; +ERL_NIF_TERM esock_atom_family; +ERL_NIF_TERM esock_atom_flowinfo; +ERL_NIF_TERM esock_atom_inet; +ERL_NIF_TERM esock_atom_inet6; +ERL_NIF_TERM esock_atom_local; +ERL_NIF_TERM esock_atom_loopback; +ERL_NIF_TERM esock_atom_ok; +ERL_NIF_TERM esock_atom_path; +ERL_NIF_TERM esock_atom_port; +ERL_NIF_TERM esock_atom_raw; +ERL_NIF_TERM esock_atom_scope_id; +ERL_NIF_TERM esock_atom_seqpacket; +ERL_NIF_TERM esock_atom_stream; +ERL_NIF_TERM esock_atom_undefined; + + /* *** Atoms *** */ -static ERL_NIF_TERM atom_any; static ERL_NIF_TERM atom_close; static ERL_NIF_TERM atom_closed; static ERL_NIF_TERM atom_closing; static ERL_NIF_TERM atom_debug; -static ERL_NIF_TERM atom_error; static ERL_NIF_TERM atom_false; static ERL_NIF_TERM atom_global_counters; static ERL_NIF_TERM atom_in4_sockaddr; static ERL_NIF_TERM atom_in6_sockaddr; static ERL_NIF_TERM atom_iow; -static ERL_NIF_TERM atom_loopback; static ERL_NIF_TERM atom_nif_abort; static ERL_NIF_TERM atom_num_dinet; static ERL_NIF_TERM atom_num_dinet6; @@ -1459,11 +1464,9 @@ static ERL_NIF_TERM atom_num_sockets; static ERL_NIF_TERM atom_num_tdgrams; static ERL_NIF_TERM atom_num_tseqpkgs; static ERL_NIF_TERM atom_num_tstreams; -static ERL_NIF_TERM atom_ok; static ERL_NIF_TERM atom_select; static ERL_NIF_TERM atom_timeout; static ERL_NIF_TERM atom_true; -static ERL_NIF_TERM atom_undefined; static ERL_NIF_TERM atom_lowdelay; static ERL_NIF_TERM atom_throughput; @@ -1629,7 +1632,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, ERL_NIF_TERM emap; ERL_NIF_TERM result; - SGDBG( ("nif_open -> entry with %d args\r\n", argc) ); + SGDBG( ("SOCKET", "nif_open -> entry with %d args\r\n", argc) ); /* Extract arguments and perform preliminary validation */ @@ -1642,7 +1645,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, } emap = argv[3]; - SGDBG( ("nif_open -> " + SGDBG( ("SOCKET", "nif_open -> " "\r\n edomain: %T" "\r\n etype: %T" "\r\n eproto: %T" @@ -1668,7 +1671,7 @@ ERL_NIF_TERM nif_open(ErlNifEnv* env, result = nopen(env, domain, type, proto, netns); - SGDBG( ("nif_open -> done with result: " + SGDBG( ("SOCKET", "nif_open -> done with result: " "\r\n %T" "\r\n", result) ); @@ -1698,7 +1701,7 @@ ERL_NIF_TERM nopen(ErlNifEnv* env, int current_ns; #endif - SGDBG( ("nopen -> entry with" + SGDBG( ("SOCKET", "nopen -> entry with" "\r\n domain: %d" "\r\n type: %d" "\r\n protocol: %d" @@ -1708,16 +1711,16 @@ ERL_NIF_TERM nopen(ErlNifEnv* env, #ifdef HAVE_SETNS if ((netns != NULL) && !change_network_namespace(netns, ¤t_ns, &save_errno)) - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); #endif if ((sock = sock_open(domain, type, protocol)) == INVALID_SOCKET) - return make_error2(env, sock_errno()); + return esock_make_error_errno(env, sock_errno()); #ifdef HAVE_SETNS if ((netns != NULL) && !restore_network_namespace(current_ns, sock, &save_errno)) - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); if (netns != NULL) FREE(netns); @@ -1727,7 +1730,7 @@ ERL_NIF_TERM nopen(ErlNifEnv* env, if ((event = sock_create_event(sock)) == INVALID_EVENT) { save_errno = sock_errno(); while ((sock_close(sock) == INVALID_SOCKET) && (sock_errno() == EINTR)); - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); } @@ -1756,12 +1759,12 @@ ERL_NIF_TERM nopen(ErlNifEnv* env, * of environment... */ if (enif_self(env, &descP->ctrlPid) == NULL) - return make_error(env, atom_exself); + return esock_make_error(env, atom_exself); if (MONP(env, descP, &descP->ctrlPid, &descP->ctrlMon) > 0) - return make_error(env, atom_exmon); + return esock_make_error(env, atom_exmon); #ifdef __WIN32__ @@ -1779,11 +1782,11 @@ ERL_NIF_TERM nopen(ErlNifEnv* env, SELECT(env, event, (ERL_NIF_SELECT_READ), - descP, NULL, atom_undefined); + descP, NULL, esock_atom_undefined); #endif - return make_ok2(env, res); + return esock_make_ok2(env, res); } @@ -1802,7 +1805,7 @@ BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err) int current_ns = 0; int new_ns = 0; - SGDBG( ("change_network_namespace -> entry with" + SGDBG( ("SOCKET", "change_network_namespace -> entry with" "\r\n new ns: %s", netns) ); if (netns != NULL) { @@ -1853,7 +1856,7 @@ BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err) { int save_errno; - SGDBG( ("restore_network_namespace -> entry with" + SGDBG( ("SOCKET", "restore_network_namespace -> entry with" "\r\n ns: %d", ns) ); if (ns != INVALID_SOCKET) { @@ -1920,7 +1923,7 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, } SSDBG( descP, - ("nif_bind -> " + ("SOCKET", "nif_bind -> " "\r\n Socket: %T" "\r\n Addr: %T" "\r\n", argv[0], argv[1]) ); @@ -1943,7 +1946,7 @@ ERL_NIF_TERM nif_bind(ErlNifEnv* env, */ /* WHY NOT !IS_OPEN(...) */ if (descP->state != SOCKET_STATE_OPEN) - return make_error(env, atom_exbadstate); + return esock_make_error(env, atom_exbadstate); return nbind(env, descP, argv[1]); } @@ -1960,34 +1963,34 @@ ERL_NIF_TERM nbind(ErlNifEnv* env, int port; SSDBG( descP, - ("nbind -> entry with" + ("SOCKET", "nbind -> entry with" "\r\n addr: %T" "\r\n", addr) ); if ((xerr = decode_laddress(env, descP->domain, addr, &local, &addrLen)) != NULL) - return make_error1(env, xerr); + return esock_make_error_str(env, xerr); - SSDBG( descP, ("nbind -> try bind\r\n") ); + SSDBG( descP, ("SOCKET", "nbind -> try bind\r\n") ); if (IS_SOCKET_ERROR(sock_bind(descP->sock, (struct sockaddr*) &local, addrLen))) { - return make_error2(env, sock_errno()); + return esock_make_error_errno(env, sock_errno()); } port = which_address_port(&local); if (port == 0) { SOCKLEN_T len = sizeof(local); sys_memzero((char *) &local, len); - sock_name(descP->sock, &local.sa, &len); + sock_name(descP->sock, &local.in, &len); port = which_address_port(&local); } else if (port == -1) { port = 0; } - SSDBG( descP, ("nbind -> done with port = %d\r\n", port) ); + SSDBG( descP, ("SOCKET", "nbind -> done with port = %d\r\n", port) ); - return make_ok2(env, MKI(env, port)); + return esock_make_ok2(env, MKI(env, port)); } @@ -2050,15 +2053,15 @@ char* decode_laddress_binary(ErlNifEnv* env, #else 1 #endif - ) > sizeof(localP->sal.sun_path)) + ) > sizeof(localP->un.sun_path)) return str_einval; sys_memzero((char*)localP, sizeof(struct sockaddr_un)); - localP->sal.sun_family = domain; - sys_memcpy(localP->sal.sun_path, bin.data, bin.size); + localP->un.sun_family = domain; + sys_memcpy(localP->un.sun_path, bin.data, bin.size); addrLen = offsetof(struct sockaddr_un, sun_path) + bin.size; #ifndef NO_SA_LEN - localP->u.sal.sun_len = addrLen; + localP->un.sun_len = addrLen; #endif *addrLenP = addrLen; return NULL; @@ -2103,7 +2106,7 @@ ERL_NIF_TERM nif_connect(ErlNifEnv* env, if ((xres = decode_in_sockaddr(env, eSockAddr, &descP->remote, &descP->addrLen)) != NULL) { - return make_error1(env, xres); + return esock_make_error_str(env, xres); } return nconnect(env, descP); @@ -2119,13 +2122,13 @@ ERL_NIF_TERM nconnect(ErlNifEnv* env, /* Verify that we are where in the proper state */ if (!IS_OPEN(descP)) - return make_error(env, atom_exbadstate); + return esock_make_error(env, atom_exbadstate); if (IS_CONNECTED(descP)) - return make_error(env, atom_eisconn); + return esock_make_error(env, atom_eisconn); if (IS_CONNECTING(descP)) - return make_error(env, atom_einval); + return esock_make_error(env, atom_einval); code = sock_connect(descP->sock, (struct sockaddr*) &descP->remote, @@ -2140,15 +2143,15 @@ ERL_NIF_TERM nconnect(ErlNifEnv* env, descP->sock, (ERL_NIF_SELECT_WRITE), descP, NULL, ref); - return make_ok2(env, ref); + return esock_make_ok2(env, ref); } else if (code == 0) { /* ok we are connected */ descP->state = SOCKET_STATE_CONNECTED; /* Do we need to do somthing for "active" mode? * Is there even such a thing *here*? */ - return atom_ok; + return esock_atom_ok; } else { - return make_error2(env, sock_errno()); + return esock_make_error_errno(env, sock_errno()); } } @@ -2192,16 +2195,16 @@ ERL_NIF_TERM nfinalize_connection(ErlNifEnv* env, int error; if (descP->state != SOCKET_STATE_CONNECTING) - return make_error(env, atom_enotconn); + return esock_make_error(env, atom_enotconn); if (!verify_is_connected(descP, &error)) { descP->state = SOCKET_STATE_OPEN; /* restore state */ - return make_error2(env, error); + return esock_make_error_errno(env, error); } descP->state = SOCKET_STATE_CONNECTED; - return atom_ok; + return esock_atom_ok; } @@ -2294,17 +2297,17 @@ ERL_NIF_TERM nlisten(ErlNifEnv* env, int backlog) { if (descP->state == SOCKET_STATE_CLOSED) - return make_error(env, atom_exbadstate); + return esock_make_error(env, atom_exbadstate); if (!IS_OPEN(descP)) - return make_error(env, atom_exbadstate); + return esock_make_error(env, atom_exbadstate); if (IS_SOCKET_ERROR(sock_listen(descP->sock, backlog))) - return make_error2(env, sock_errno()); + return esock_make_error_errno(env, sock_errno()); descP->state = SOCKET_STATE_LISTENING; - return atom_ok; + return esock_atom_ok; } @@ -2361,7 +2364,7 @@ ERL_NIF_TERM naccept(ErlNifEnv* env, break; default: - res = make_error(env, atom_einval); + res = esock_make_error(env, atom_einval); break; } @@ -2385,7 +2388,7 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env, ErlNifPid caller; if (enif_self(env, &caller) == NULL) - return make_error(env, atom_exself); + return esock_make_error(env, atom_exself); n = sizeof(remote); sys_memzero((char *) &remote, n); @@ -2400,7 +2403,7 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env, if (MONP(env, descP, &descP->currentAcceptor.pid, &descP->currentAcceptor.mon) > 0) - return make_error(env, atom_exmon); + return esock_make_error(env, atom_exmon); descP->currentAcceptor.ref = ref; @@ -2434,10 +2437,10 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env, descP->state = SOCKET_STATE_ACCEPTING; - return make_error(env, atom_eagain); + return esock_make_error(env, atom_eagain); } else { - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); } } else { @@ -2452,7 +2455,7 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env, save_errno = sock_errno(); while ((sock_close(accSock) == INVALID_SOCKET) && (sock_errno() == EINTR)); - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); } if ((accDescP = alloc_descriptor(accSock, accEvent)) == NULL) { @@ -2472,7 +2475,7 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env, &accDescP->ctrlPid, &accDescP->ctrlMon) > 0) { sock_close(accSock); - return make_error(env, atom_exmon); + return esock_make_error(env, atom_exmon); } accDescP->remote = remote; @@ -2483,12 +2486,12 @@ ERL_NIF_TERM naccept_listening(ErlNifEnv* env, SELECT(env, descP->sock, (ERL_NIF_SELECT_READ), - descP, NULL, atom_undefined); + descP, NULL, esock_atom_undefined); #endif accDescP->state = SOCKET_STATE_CONNECTED; - return make_ok2(env, accRef); + return esock_make_ok2(env, accRef); } } @@ -2510,7 +2513,7 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env, int save_errno; if (enif_self(env, &caller) == NULL) - return make_error(env, atom_exself); + return esock_make_error(env, atom_exself); if (compare_pids(env, &descP->currentAcceptor.pid, &caller) != 0) { /* This will have to do until we implement the queue. @@ -2518,7 +2521,7 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env, * and instead return with eagain (the caller will then wait * for the select message). */ - return make_error(env, atom_exbusy); + return esock_make_error(env, atom_exbusy); } n = sizeof(descP->remote); @@ -2537,9 +2540,9 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env, (ERL_NIF_SELECT_READ), descP, NULL, ref); - return make_error(env, atom_eagain); + return esock_make_error(env, atom_eagain); } else { - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); } } else { SocketDescriptor* accDescP; @@ -2553,7 +2556,7 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env, save_errno = sock_errno(); while ((sock_close(accSock) == INVALID_SOCKET) && (sock_errno() == EINTR)); - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); } if ((accDescP = alloc_descriptor(accSock, accEvent)) == NULL) { @@ -2573,7 +2576,7 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env, &accDescP->ctrlPid, &accDescP->ctrlMon) > 0) { sock_close(accSock); - return make_error(env, atom_exmon); + return esock_make_error(env, atom_exmon); } accDescP->remote = remote; @@ -2584,7 +2587,7 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env, SELECT(env, descP->sock, (ERL_NIF_SELECT_READ), - descP, NULL, atom_undefined); + descP, NULL, esock_atom_undefined); #endif accDescP->state = SOCKET_STATE_CONNECTED; @@ -2596,7 +2599,7 @@ ERL_NIF_TERM naccept_accepting(ErlNifEnv* env, */ descP->state = SOCKET_STATE_LISTENING; - return make_ok2(env, accRef); + return esock_make_ok2(env, accRef); } } @@ -2638,7 +2641,7 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env, sendRef = argv[1]; if (!IS_CONNECTED(descP)) - return make_error(env, atom_enotconn); + return esock_make_error(env, atom_enotconn); if (!esendflags2sendflags(eflags, &flags)) return enif_make_badarg(env); @@ -2739,15 +2742,15 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env, /* THIS TEST IS NOT CORRECT!!! */ if (!IS_OPEN(descP)) - return make_error(env, atom_einval); + return esock_make_error(env, atom_einval); if (!esendflags2sendflags(eflags, &flags)) - return make_error(env, atom_einval); + return esock_make_error(env, atom_einval); if ((xres = decode_in_sockaddr(env, eSockAddr, &remoteAddr, &remoteAddrLen)) != NULL) - return make_error1(env, xres); + return esock_make_error_str(env, xres); return nsendto(env, descP, sendRef, &data, flags, &remoteAddr, remoteAddrLen); } @@ -2775,7 +2778,7 @@ ERL_NIF_TERM nsendto(ErlNifEnv* env, if (toAddrP != NULL) { written = sock_sendto(descP->sock, dataP->data, dataP->size, flags, - &toAddrP->sa, toAddrLen); + &toAddrP->in, toAddrLen); } else { written = sock_sendto(descP->sock, dataP->data, dataP->size, flags, @@ -2893,7 +2896,7 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env, recvRef = argv[1]; if (!IS_CONNECTED(descP)) - return make_error(env, atom_enotconn); + return esock_make_error(env, atom_enotconn); if (!erecvflags2recvflags(eflags, &flags)) return enif_make_badarg(env); @@ -2945,7 +2948,7 @@ ERL_NIF_TERM nrecv(ErlNifEnv* env, * size (what has been configured). */ if (!ALLOC_BIN((len ? len : descP->rBufSz), &buf)) - return make_error(env, atom_exalloc); + return esock_make_error(env, atom_exalloc); /* We ignore the wrap for the moment. * Maybe we should issue a wrap-message to controlling process... @@ -2999,7 +3002,7 @@ ERL_NIF_TERM nif_recvfrom(ErlNifEnv* env, recvRef = argv[1]; /* if (IS_OPEN(descP)) */ - /* return make_error(env, atom_enotconn); */ + /* return esock_make_error(env, atom_enotconn); */ if (!erecvflags2recvflags(eflags, &flags)) return enif_make_badarg(env); @@ -3055,7 +3058,7 @@ ERL_NIF_TERM nrecvfrom(ErlNifEnv* env, * size (what has been configured). */ if (!ALLOC_BIN((bufSz ? bufSz : descP->rBufSz), &buf)) - return make_error(env, atom_exalloc); + return esock_make_error(env, atom_exalloc); /* We ignore the wrap for the moment. * Maybe we should issue a wrap-message to controlling process... @@ -3066,7 +3069,7 @@ ERL_NIF_TERM nrecvfrom(ErlNifEnv* env, sys_memzero((char*) &fromAddr, addrLen); read = sock_recvfrom(descP->sock, buf.data, buf.size, flags, - &fromAddr.sa, &addrLen); + &fromAddr.in, &addrLen); return recvfrom_check_result(env, descP, read, @@ -3129,7 +3132,7 @@ ERL_NIF_TERM nclose(ErlNifEnv* env, if (enif_self(env, &descP->closerPid) == NULL) { MUNLOCK(descP->closeMtx); - return make_error(env, atom_exself); + return esock_make_error(env, atom_exself); } /* Monitor the caller, since we should complete this operation even if @@ -3140,7 +3143,7 @@ ERL_NIF_TERM nclose(ErlNifEnv* env, &descP->closerPid, &descP->closerMon) > 0) { MUNLOCK(descP->closeMtx); - return make_error(env, atom_exmon); + return esock_make_error(env, atom_exmon); } descP->closeLocal = TRUE; @@ -3156,11 +3159,11 @@ ERL_NIF_TERM nclose(ErlNifEnv* env, descP, NULL, descP->closeRef); if (selectRes & ERL_NIF_SELECT_STOP_CALLED) { /* Prep done - inform the caller it can finalize (close) directly */ - reply = atom_ok; + reply = esock_atom_ok; } else if (selectRes & ERL_NIF_SELECT_STOP_SCHEDULED) { /* The stop callback function has been *scheduled* which means that we * have to wait for it to complete. */ - reply = make_ok2(env, descP->closeRef); + reply = esock_make_ok2(env, descP->closeRef); } else { /* * @@ -3172,10 +3175,10 @@ ERL_NIF_TERM nclose(ErlNifEnv* env, * */ reason = MKT2(env, atom_select, MKI(env, selectRes)); - reply = make_error(env, reason); + reply = esock_make_error(env, reason); } } else { - reply = make_error(env, reason); + reply = esock_make_error(env, reason); } return reply; @@ -3222,10 +3225,10 @@ ERL_NIF_TERM nfinalize_close(ErlNifEnv* env, ERL_NIF_TERM reply; if (descP->state == SOCKET_STATE_CLOSED) - return atom_ok; + return esock_atom_ok; if (descP->state != SOCKET_STATE_CLOSING) - return make_error(env, atom_enotclosing); + return esock_make_error(env, atom_enotclosing); /* This nif is executed in a dirty scheduler just so that * it can "hang" (whith minumum effect on the VM) while the @@ -3242,12 +3245,12 @@ ERL_NIF_TERM nfinalize_close(ErlNifEnv* env, /* Not all data in the buffers where sent, * make sure the caller gets this. */ - reply = make_error(env, atom_timeout); + reply = esock_make_error(env, atom_timeout); } else { - reply = make_error2(env, save_errno); + reply = esock_make_error_errno(env, save_errno); } } else { - reply = atom_ok; + reply = esock_atom_ok; } sock_close_event(descP->event); @@ -3315,9 +3318,9 @@ ERL_NIF_TERM nshutdown(ErlNifEnv* env, descP->isWritable = FALSE; break; } - reply = atom_ok; + reply = esock_atom_ok; } else { - reply = make_error2(env, sock_errno()); + reply = esock_make_error_errno(env, sock_errno()); } return reply; @@ -3366,10 +3369,10 @@ ERL_NIF_TERM nif_setopt(ErlNifEnv* env, eVal = argv[4]; if (!decode_bool(env, eIsEncoded, &isEncoded)) - return make_error(env, atom_einval); + return esock_make_error(env, atom_einval); if (!elevel2level(isEncoded, eLevel, &isOTP, &level)) - return make_error(env, atom_einval); + return esock_make_error(env, atom_einval); return nsetopt(env, descP, isEncoded, isOTP, level, eOpt, eVal); } @@ -3422,7 +3425,7 @@ ERL_NIF_TERM nsetopt_otp(ErlNifEnv* env, break; default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -3440,9 +3443,9 @@ ERL_NIF_TERM nsetopt_otp_debug(ErlNifEnv* env, ERL_NIF_TERM result; if (decode_bool(env, eVal, &descP->dbg)) { - result = atom_ok; + result = esock_atom_ok; } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } return result; @@ -3459,9 +3462,9 @@ ERL_NIF_TERM nsetopt_otp_iow(ErlNifEnv* env, ERL_NIF_TERM result; if (decode_bool(env, eVal, &descP->iow)) { - result = atom_ok; + result = esock_atom_ok; } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } return result; @@ -3486,11 +3489,11 @@ ERL_NIF_TERM nsetopt_native(ErlNifEnv* env, int res = socket_setopt(descP->sock, level, opt, val.data, val.size); if (res != 0) - result = make_error2(env, res); + result = esock_make_error_errno(env, res); else - result = atom_ok; + result = esock_atom_ok; } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } return result; @@ -3543,7 +3546,7 @@ ERL_NIF_TERM nsetopt_level(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -3612,7 +3615,7 @@ ERL_NIF_TERM nsetopt_lvl_socket(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -3667,11 +3670,11 @@ ERL_NIF_TERM nsetopt_lvl_sock_linger(ErlNifEnv* env, int res = socket_setopt(descP->sock, SOL_SOCKET, SO_LINGER, (void*) &val, optLen); if (res != 0) - result = make_error2(env, res); + result = esock_make_error_errno(env, res); else - result = atom_ok; + result = esock_atom_ok; } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } return result; @@ -3760,7 +3763,7 @@ ERL_NIF_TERM nsetopt_lvl_ip(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -3826,12 +3829,12 @@ ERL_NIF_TERM nsetopt_lvl_ip_tos(ErlNifEnv* env, int res = socket_setopt(descP->sock, level, IP_TOS, &val, sizeof(val)); if (res != 0) - result = make_error2(env, res); + result = esock_make_error_errno(env, res); else - result = atom_ok; + result = esock_atom_ok; } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } return result; @@ -3878,7 +3881,7 @@ ERL_NIF_TERM nsetopt_lvl_ipv6(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -3931,7 +3934,7 @@ ERL_NIF_TERM nsetopt_lvl_tcp(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -3999,7 +4002,7 @@ ERL_NIF_TERM nsetopt_lvl_udp(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -4047,7 +4050,7 @@ ERL_NIF_TERM nsetopt_lvl_sctp(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -4105,12 +4108,12 @@ ERL_NIF_TERM nsetopt_str_opt(ErlNifEnv* env, int res = socket_setopt(descP->sock, level, opt, &val, optLen); if (res != 0) - result = make_error2(env, res); + result = esock_make_error_errno(env, res); else - result = atom_ok; + result = esock_atom_ok; } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } FREE(val); @@ -4136,12 +4139,12 @@ ERL_NIF_TERM nsetopt_bool_opt(ErlNifEnv* env, int res = socket_setopt(descP->sock, level, opt, &ival, sizeof(ival)); if (res != 0) - result = make_error2(env, res); + result = esock_make_error_errno(env, res); else - result = atom_ok; + result = esock_atom_ok; } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } return result; @@ -4164,12 +4167,12 @@ ERL_NIF_TERM nsetopt_int_opt(ErlNifEnv* env, int res = socket_setopt(descP->sock, level, opt, &val, sizeof(val)); if (res != 0) - result = make_error2(env, res); + result = esock_make_error_errno(env, res); else - result = atom_ok; + result = esock_atom_ok; } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } return result; @@ -4376,10 +4379,10 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env, eIsEncoded = argv[1]; if (!decode_bool(env, eIsEncoded, &isEncoded)) - return make_error(env, atom_einval); + return esock_make_error(env, atom_einval); if (!elevel2level(isEncoded, eLevel, &isOTP, &level)) - return make_error(env, atom_einval); + return esock_make_error(env, atom_einval); return ngetopt(env, descP, isEncoded, isOTP, level, eOpt); } @@ -4431,7 +4434,7 @@ ERL_NIF_TERM ngetopt_otp(ErlNifEnv* env, break; default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -4449,7 +4452,7 @@ ERL_NIF_TERM ngetopt_otp_debug(ErlNifEnv* env, encode_bool(descP->dbg, &eVal); - return make_ok2(env, eVal); + return esock_make_ok2(env, eVal); } @@ -4463,7 +4466,7 @@ ERL_NIF_TERM ngetopt_otp_iow(ErlNifEnv* env, encode_bool(descP->iow, &eVal); - return make_ok2(env, eVal); + return esock_make_ok2(env, eVal); } @@ -4501,11 +4504,11 @@ ERL_NIF_TERM ngetopt_native(ErlNifEnv* env, result = ngetopt_bool_opt(env, descP, level, opt); break; default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } } else { - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); } return result; @@ -4525,20 +4528,20 @@ ERL_NIF_TERM ngetopt_native_unspec(ErlNifEnv* env, if (valueSz == 0) { res = sock_getopt(descP->sock, level, opt, NULL, NULL); if (res != 0) - result = make_error2(env, res); + result = esock_make_error_errno(env, res); else - result = atom_ok; + result = esock_atom_ok; } else { ErlNifBinary val; if (ALLOC_BIN(valueSz, &val)) { res = sock_getopt(descP->sock, level, opt, val.data, &valueSz); if (res != 0) { - result = make_error2(env, res); + result = esock_make_error_errno(env, res); } else { if (valueSz < val.size) { if (REALLOC_BIN(&val, valueSz)) { - result = make_ok2(env, MKBIN(env, &val)); + result = esock_make_ok2(env, MKBIN(env, &val)); } else { result = enif_make_badarg(env); } @@ -4598,7 +4601,7 @@ ERL_NIF_TERM ngetopt_level(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -4665,7 +4668,7 @@ ERL_NIF_TERM ngetopt_lvl_socket(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -4719,13 +4722,13 @@ ERL_NIF_TERM ngetopt_lvl_sock_linger(ErlNifEnv* env, &val, &valSz); if (res != 0) { - result = make_error2(env, res); + result = esock_make_error_errno(env, res); } else { ERL_NIF_TERM lOnOff = MKI(env, val.l_onoff); ERL_NIF_TERM lSecs = MKI(env, val.l_linger); ERL_NIF_TERM linger = MKT2(env, lOnOff, lSecs); - result = make_ok2(env, linger); + result = esock_make_ok2(env, linger); } return result; @@ -4808,7 +4811,7 @@ ERL_NIF_TERM ngetopt_lvl_ip(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -4872,7 +4875,7 @@ ERL_NIF_TERM ngetopt_lvl_ip_tos(ErlNifEnv* env, res = sock_getopt(descP->sock, level, IP_TOS, &val, &valSz); if (res != 0) { - result = make_error2(env, res); + result = esock_make_error_errno(env, res); } else { result = encode_ip_tos(env, val); } @@ -4919,7 +4922,7 @@ ERL_NIF_TERM ngetopt_lvl_ipv6(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -4970,7 +4973,7 @@ ERL_NIF_TERM ngetopt_lvl_tcp(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -5034,7 +5037,7 @@ ERL_NIF_TERM ngetopt_lvl_udp(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -5079,7 +5082,7 @@ ERL_NIF_TERM ngetopt_lvl_sctp(ErlNifEnv* env, #endif default: - result = make_error(env, atom_einval); + result = esock_make_error(env, atom_einval); break; } @@ -5132,11 +5135,11 @@ ERL_NIF_TERM ngetopt_str_opt(ErlNifEnv* env, res = sock_getopt(descP->sock, level, opt, &val, &valSz); if (res != 0) { - result = make_error2(env, res); + result = esock_make_error_errno(env, res); } else { ERL_NIF_TERM sval = MKSL(env, val, valSz); - result = make_ok2(env, sval); + result = esock_make_ok2(env, sval); } FREE(val); @@ -5161,11 +5164,11 @@ ERL_NIF_TERM ngetopt_bool_opt(ErlNifEnv* env, res = sock_getopt(descP->sock, level, opt, &val, &valSz); if (res != 0) { - result = make_error2(env, res); + result = esock_make_error_errno(env, res); } else { ERL_NIF_TERM bval = ((val) ? atom_true : atom_false); - result = make_ok2(env, bval); + result = esock_make_ok2(env, bval); } return result; @@ -5188,9 +5191,9 @@ ERL_NIF_TERM ngetopt_int_opt(ErlNifEnv* env, res = sock_getopt(descP->sock, level, opt, &val, &valSz); if (res != 0) { - result = make_error2(env, res); + result = esock_make_error_errno(env, res); } else { - result = make_ok2(env, MKI(env, val)); + result = esock_make_ok2(env, MKI(env, val)); } return result; @@ -5215,7 +5218,7 @@ ERL_NIF_TERM send_check_result(ErlNifEnv* env, cnt_inc(&descP->writePkgCnt, 1); cnt_inc(&descP->writeByteCnt, written); - return atom_ok; + return esock_atom_ok; } else if (written < 0) { @@ -5226,7 +5229,7 @@ ERL_NIF_TERM send_check_result(ErlNifEnv* env, cnt_inc(&descP->writeFails, 1); - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); } else { @@ -5251,7 +5254,7 @@ ERL_NIF_TERM send_check_result(ErlNifEnv* env, SELECT(env, descP->sock, (ERL_NIF_SELECT_WRITE), descP, NULL, sendRef); - return make_ok2(env, enif_make_int(env, written)); + return esock_make_ok2(env, enif_make_int(env, written)); } @@ -5295,7 +5298,7 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env, data = MKBIN(env, bufP); - return make_ok3(env, atom_false, data); + return esock_make_ok3(env, atom_false, data); } else { @@ -5308,7 +5311,7 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env, data = MKBIN(env, bufP); - return make_ok3(env, atom_true, data); + return esock_make_ok3(env, atom_true, data); } @@ -5345,13 +5348,13 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env, (ERL_NIF_SELECT_STOP), descP, NULL, recvRef); - return make_error(env, atom_closed); + return esock_make_error(env, atom_closed); } else if ((save_errno == ERRNO_BLOCK) || (save_errno == EAGAIN)) { - return make_error(env, atom_eagain); + return esock_make_error(env, atom_eagain); } else { - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); } } else { @@ -5369,14 +5372,14 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env, data = MKBIN(env, bufP); data = MKSBIN(env, data, 0, read); - return make_ok3(env, atom_true, data); + return esock_make_ok3(env, atom_true, data); } else { /* +++ We got only a part of what was expected +++ * +++ => receive more later. +++ */ - return make_ok3(env, atom_false, MKBIN(env, bufP)); + return esock_make_ok3(env, atom_false, MKBIN(env, bufP)); } } } @@ -5430,13 +5433,13 @@ ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, (ERL_NIF_SELECT_STOP), descP, NULL, recvRef); - return make_error(env, atom_closed); + return esock_make_error(env, atom_closed); } else if ((save_errno == ERRNO_BLOCK) || (save_errno == EAGAIN)) { - return make_error(env, atom_eagain); + return esock_make_error(env, atom_eagain); } else { - return make_error2(env, save_errno); + return esock_make_error_errno(env, save_errno); } } else { @@ -5463,7 +5466,7 @@ ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env, data = MKSBIN(env, data, 0, read); } - return make_ok2(env, MKT3(env, fromDomainT, fromSourceT, data)); + return esock_make_ok2(env, MKT3(env, fromDomainT, fromSourceT, data)); } } @@ -5663,9 +5666,9 @@ char* decode_in4_sockaddr_atomaddr(ErlNifEnv* env, { struct in_addr addr; - if (COMPARE(atom_loopback, eAddr) == 0) { + if (COMPARE(esock_atom_loopback, eAddr) == 0) { addr.s_addr = sock_htonl(INADDR_LOOPBACK); - } else if (COMPARE(atom_any, eAddr) == 0) { + } else if (COMPARE(esock_atom_any, eAddr) == 0) { addr.s_addr = sock_htonl(INADDR_ANY); } else { return str_einval; @@ -5673,11 +5676,11 @@ char* decode_in4_sockaddr_atomaddr(ErlNifEnv* env, sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in)); #ifndef NO_SA_LEN - sockAddrP->sai.sin_len = sizeof(struct sockaddr_in6); + sockAddrP->sai.sin_len = sizeof(struct sockaddr_in); #endif - sockAddrP->sai.sin_family = AF_INET; - sockAddrP->sai.sin_port = sock_htons(port); - sockAddrP->sai.sin_addr.s_addr = addr.s_addr; + sockAddrP->in4.sin_family = AF_INET; + sockAddrP->in4.sin_port = sock_htons(port); + sockAddrP->in4.sin_addr.s_addr = addr.s_addr; *addrLenP = sizeof(struct sockaddr_in); return NULL; @@ -5708,16 +5711,16 @@ char* decode_in4_sockaddr_addr(ErlNifEnv* env, sys_memzero((char*)sockAddrP, sizeof(struct sockaddr_in)); #ifndef NO_SA_LEN - sockAddrP->sai.sin_len = sizeof(struct sockaddr_in); + sockAddrP->in4.sin_len = sizeof(struct sockaddr_in); #endif - sockAddrP->sai.sin_family = AF_INET; - sockAddrP->sai.sin_port = sock_htons(port); + sockAddrP->in4.sin_family = AF_INET; + sockAddrP->in4.sin_port = sock_htons(port); for (a = 0; a < 4; a++) { if (!GET_INT(env, ip4AddrT[a], &v)) return str_einval; addr[a] = v; } - sys_memcpy(&sockAddrP->sai.sin_addr, &addr, sizeof(addr)); + sys_memcpy(&sockAddrP->in4.sin_addr, &addr, sizeof(addr)); *addrLenP = sizeof(struct sockaddr_in); return NULL; @@ -5789,9 +5792,9 @@ char* decode_in6_sockaddr_atomaddr(ErlNifEnv* env, { const struct in6_addr* addr; - if (COMPARE(atom_loopback, eAddr) == 0) { + if (COMPARE(esock_atom_loopback, eAddr) == 0) { addr = &in6addr_loopback; - } else if (COMPARE(atom_any, eAddr) == 0) { + } else if (COMPARE(esock_atom_any, eAddr) == 0) { addr = &in6addr_any; } else { return str_einval; @@ -5799,13 +5802,13 @@ char* decode_in6_sockaddr_atomaddr(ErlNifEnv* env, sys_memzero((char*)sockAddrP, sizeof(struct sockaddr_in6)); #ifndef NO_SA_LEN - sockAddrP->sai6.sin6_len = sizeof(struct sockaddr_in6); + sockAddrP->in6.sin6_len = sizeof(struct sockaddr_in6); #endif - sockAddrP->sai6.sin6_family = AF_INET6; - sockAddrP->sai6.sin6_port = sock_htons(port); - sockAddrP->sai6.sin6_flowinfo = flowInfo; - sockAddrP->sai6.sin6_scope_id = scopeId; - sockAddrP->sai6.sin6_addr = *addr; + sockAddrP->in6.sin6_family = AF_INET6; + sockAddrP->in6.sin6_port = sock_htons(port); + sockAddrP->in6.sin6_flowinfo = flowInfo; + sockAddrP->in6.sin6_scope_id = scopeId; + sockAddrP->in6.sin6_addr = *addr; *addrLenP = sizeof(struct sockaddr_in6); return NULL; @@ -5839,12 +5842,12 @@ char* decode_in6_sockaddr_addr(ErlNifEnv* env, sys_memzero((char*)sockAddrP, sizeof(struct sockaddr_in6)); #ifndef NO_SA_LEN - sockAddrP->sai6.sin6_len = sizeof(struct sockaddr_in6); + sockAddrP->in6.sin6_len = sizeof(struct sockaddr_in6); #endif - sockAddrP->sai6.sin6_family = AF_INET6; - sockAddrP->sai6.sin6_port = sock_htons(port); - sockAddrP->sai6.sin6_flowinfo = flowInfo; - sockAddrP->sai6.sin6_scope_id = scopeId; + sockAddrP->in6.sin6_family = AF_INET6; + sockAddrP->in6.sin6_port = sock_htons(port); + sockAddrP->in6.sin6_flowinfo = flowInfo; + sockAddrP->in6.sin6_scope_id = scopeId; /* The address tuple is of size 8 * and each element is a two byte integer */ @@ -5854,7 +5857,7 @@ char* decode_in6_sockaddr_addr(ErlNifEnv* env, addr[a*2 ] = ((v >> 8) & 0xFF); addr[a*2+1] = (v & 0xFF); } - sys_memcpy(&sockAddrP->sai6.sin6_addr, &addr, sizeof(addr)); + sys_memcpy(&sockAddrP->in6.sin6_addr, &addr, sizeof(addr)); *addrLenP = sizeof(struct sockaddr_in6); return NULL; @@ -5960,7 +5963,7 @@ void encode_address(ErlNifEnv* env, { short port; - switch (addrP->sa.sa_family) { + switch (addrP->in.sa_family) { /* +++ inet (IPv4) +++ */ @@ -5969,9 +5972,9 @@ void encode_address(ErlNifEnv* env, ERL_NIF_TERM addrT, portT; unsigned int i; ERL_NIF_TERM at4[4]; - char* a4 = (char*) &addrP->sai.sin_addr; + char* a4 = (char*) &addrP->in4.sin_addr; - port = sock_ntohs(addrP->sai.sin_port); + port = sock_ntohs(addrP->in4.sin_port); for (i = 0; i < 4; i++) { at4[i] = MKI(env, a4[i]); } @@ -5981,8 +5984,8 @@ void encode_address(ErlNifEnv* env, portT = MKI(env, port); *sourceT = MKT2(env, addrT, portT); } else { - *domainT = atom_undefined; - *sourceT = atom_undefined; + *domainT = esock_atom_undefined; + *sourceT = esock_atom_undefined; } break; @@ -5995,9 +5998,9 @@ void encode_address(ErlNifEnv* env, ERL_NIF_TERM addrT, portT; unsigned int i; ERL_NIF_TERM at6[8]; - char* a16 = (char*) &addrP->sai6.sin6_addr; + char* a16 = (char*) &addrP->in6.sin6_addr; - port = sock_ntohs(addrP->sai6.sin6_port); + port = sock_ntohs(addrP->in6.sin6_port); /* The address tuple is of size 8 * and each element is a two byte integer */ @@ -6013,8 +6016,8 @@ void encode_address(ErlNifEnv* env, portT = MKI(env, port); *sourceT = MKT2(env, addrT, portT); } else { - *domainT = atom_undefined; - *sourceT = atom_undefined; + *domainT = esock_atom_undefined; + *sourceT = esock_atom_undefined; } break; #endif @@ -6028,13 +6031,13 @@ void encode_address(ErlNifEnv* env, *domainT = MKA(env, "local"); if (addrLen < offsetof(struct sockaddr_un, sun_path)) { - *sourceT = atom_undefined; + *sourceT = esock_atom_undefined; } else { n = addrLen - offsetof(struct sockaddr_un, sun_path); if (255 < n) { - *sourceT = atom_undefined; + *sourceT = esock_atom_undefined; } else { - m = my_strnlen(addrP->sal.sun_path, n); + m = my_strnlen(addrP->un.sun_path, n); #ifdef __linux__ /* Assume that the address is a zero terminated string, * except when the first byte is \0 i.e the string length is 0, @@ -6047,7 +6050,7 @@ void encode_address(ErlNifEnv* env, } #endif - *sourceT = MKSL(env, addrP->sal.sun_path, m); + *sourceT = MKSL(env, addrP->un.sun_path, m); } } } @@ -6055,8 +6058,8 @@ void encode_address(ErlNifEnv* env, #endif default: - *domainT = atom_undefined; - *sourceT = atom_undefined; + *domainT = esock_atom_undefined; + *sourceT = esock_atom_undefined; break; } /* switch (addrP->sa.sa_family) */ @@ -6369,23 +6372,23 @@ ERL_NIF_TERM encode_ip_tos(ErlNifEnv* env, int val) switch (val) { case IPTOS_LOWDELAY: - result = make_ok2(env, atom_lowdelay); + result = esock_make_ok2(env, atom_lowdelay); break; case IPTOS_THROUGHPUT: - result = make_ok2(env, atom_throughput); + result = esock_make_ok2(env, atom_throughput); break; case IPTOS_RELIABILITY: - result = make_ok2(env, atom_reliability); + result = esock_make_ok2(env, atom_reliability); break; case IPTOS_MINCOST: - result = make_ok2(env, atom_mincost); + result = esock_make_ok2(env, atom_mincost); break; default: - result = make_ok2(env, MKI(env, val)); + result = esock_make_ok2(env, MKI(env, val)); break; } @@ -6468,6 +6471,11 @@ int compare_pids(ErlNifEnv* env, } +/* ---------------------------------------------------------------------- + * D e c o d e / E n c o d e F u n c t i o n s + * ---------------------------------------------------------------------- + */ + /* edomain2domain - convert internal (erlang) domain to (proper) domain * * Note that only a subset is supported. @@ -6587,7 +6595,7 @@ BOOLEAN_T emap2netns(ErlNifEnv* env, ERL_NIF_TERM map, char** netns) /* The currently only supported extra option is: netns */ key = enif_make_atom(env, "netns"); - if (!enif_get_map_value(env, map, key, &value)) { + if (!GET_MAP_VAL(env, map, key, &value)) { *netns = NULL; // Just in case... return FALSE; } @@ -6737,77 +6745,409 @@ BOOLEAN_T ehow2how(unsigned int ehow, int* how) } return TRUE; - } +} -#if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE) -/* strnlen doesn't exist everywhere */ + +/* +++ decode_sockaddr +++ + * + * Decode a socket address - sockaddr. In erlang its represented by + * a map, which has a specific set of attributes, depending on one + * mandatory attribute; family. So depending on the value of the family + * attribute: + * + * local - sockaddr_un: path + * inet - sockaddr_in4: port, addr + * inet6 - sockaddr_in6: port, addr, flowinfo, scope_id + */ +/* static -size_t my_strnlen(const char *s, size_t maxlen) +char* decode_sockaddr(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + SocketAddress* sockAddrP, + unsigned int* addrLen) { - size_t i = 0; - while (i < maxlen && s[i] != '\0') - i++; - return i; -} + ERL_NIF_TERM efam; + int fam; + char* res; + + if (!IS_MAP(env, eSockAddr)) + return str_einval; + + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_family, &efam)) + return str_einval; + + if (!decode_domain(env, efam, &fam)) + return str_einval; + + switch (fam) { + case AF_INET: + res = decode_sockaddr_in4(env, eSockAddr, &sockAddrP->in6, addrLen); + break; + +#if defined(HAVE_IN6) && defined(AF_INET6) + case AF_INET6: + res = decode_sockaddr_in6(env, eSockAddr, &sockAddrP->in6, addrLen); + break; #endif +#ifdef HAVE_SYS_UN_H + case AF_UNIX: + res = decode_sockaddr_un(env, eSockAddr, &sockAddrP->un, addrLen); + break; +#endif + + default: + result = str_eafnosupport; + break; -/* Create an ok two (2) tuple in the form: {ok, Any}. - * The second element (Any) is already in the form of an - * ERL_NIF_TERM so all we have to do is create the tuple. + } + + return res; +} +*/ + + + +/* +++ decode_sockaddr_in4 +++ + * + * Decode a IPv4 socket address - sockaddr_in4. In erlang its represented by + * a map, which has a specific set of attributes: + * + * port :: port_numbber() + * addr :: ip4_address() + * + * The erlang module ensures that both of these has values exist, so there + * is no need for any elaborate error handling. */ +/* static -ERL_NIF_TERM make_ok2(ErlNifEnv* env, ERL_NIF_TERM any) +char* decode_sockaddr_in4(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_in* sockAddrP, + unsigned int* addrLen) { - return MKT2(env, atom_ok, any); + ERL_NIF_TERM eport, eaddr; + short port; + + / * Basic init * / + sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in)); + +#ifndef NO_SA_LEN + sockAddrP->sin_len = sizeof(struct sockaddr_in); +#endif + + sockAddrP->sin_family = AF_INET; + + / * Extract (e) port number from map * / + if (!GET_MAP_VAL(env, eSockAddr, atom_port, &eport)) + return str_einval; + + / * Decode port number * / + if (!GET_INT(env, eport, &port)) + return str_einval; + sockAddrP->sin_port = sock_htons(port); + + / * Extract (e) address from map * / + if (!GET_MAP_VAL(env, eSockAddr, atom_addr, &eaddr)) + return str_einval; + + / * Decode address * / + if (!decode_ip4_address(env, eaddr, sockAddrP, addrLen)) + return str_einval; + + return NULL; } +*/ -/* Create an ok three (3) tuple in the form: {ok, Val1, Val2}. - * The second (Val1) and third (Val2) elements are already in - * the form of an ERL_NIF_TERM so all we have to do is create - * the tuple. + +/* +++ decode_sockaddr_in6 +++ + * + * Decode a IPv6 socket address - sockaddr_in6. In erlang its represented by + * a map, which has a specific set of attributes: + * + * port :: port_numbber() (integer) + * addr :: ip6_address() (tuple) + * flowinfo :: in6_flow_info() (integer) + * scope_id :: in6_scope_id() (integer) + * + * The erlang module ensures that all of these has values exist, so there + * is no need for any elaborate error handling. */ +/* +#if defined(HAVE_IN6) && defined(AF_INET6) static -ERL_NIF_TERM make_ok3(ErlNifEnv* env, ERL_NIF_TERM val1, ERL_NIF_TERM val2) +char* decode_sockaddr_in6(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_in6* sockAddrP, + unsigned int* addrLen) { - return MKT3(env, atom_ok, val1, val2); + ERL_NIF_TERM eport, eaddr; + short port; + + / * Basic init * / + sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in6)); +#ifndef NO_SA_LEN + sockAddrP->sin6_len = sizeof(struct sockaddr_in); +#endif + + sockAddrP->sin6_family = AF_INET6; + + / * *** Extract (e) port number from map *** * / + if (!GET_MAP_VAL(env, eSockAddr, atom_port, &eport)) + return str_einval; + + / * Decode port number * / + if (!GET_INT(env, eport, &port)) + return str_einval; + + sockAddrP->sin6_port = sock_htons(port); + + / * *** Extract (e) flowinfo from map *** * / + if (!GET_MAP_VAL(env, eSockAddr, atom_flowinfo, &eflowInfo)) + return str_einval; + + / * 4: Get the flowinfo * / + if (!GET_UINT(env, eflowInfo, &flowInfo)) + return str_einval; + + sockAddrP->sin6_flowinfo = flowInfo; + + / * *** Extract (e) scope_id from map *** * / + if (!GET_MAP_VAL(env, eSockAddr, atom_scope_id, &escopeId)) + return str_einval; + + / * *** Get the scope_id *** * / + if (!GET_UINT(env, escopeId, &scopeId)) + return str_einval; + + sockAddrP->sin6_scope_id = scopeId; + + / * *** Extract (e) address from map *** * / + if (!GET_MAP_VAL(env, eSockAddr, atom_addr, &eaddr)) + return str_einval; + + / * Decode address * / + if (!decode_ip6_address(env, eaddr, sockAddrP, addrLen)) + return str_einval; + + return NULL; } +#endif +*/ -/* Create an error two (2) tuple in the form: {error, Reason}. - * The second element (Reason) is already in the form of an - * ERL_NIF_TERM so all we have to do is create the tuple. + + +/* +++ decode_sockaddr_un +++ + * + * Decode a Unix Domain socket address - sockaddr_un. In erlang its represented by + * a map, which has a specific set of attributes: + * + * path :: binary() + * + * The erlang module ensures that this value exist, so there + * is no need for any elaborate error handling. */ +/* +#ifdef HAVE_SYS_UN_H static -ERL_NIF_TERM make_error(ErlNifEnv* env, ERL_NIF_TERM reason) +char* decode_sockaddr_un(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_un* sockAddrP, + unsigned int* addrLen) { - return MKT2(env, atom_error, reason); + ErlNifBinary bin; + ERL_NIF_TERM epath; + unsigned int len; + + / * *** Extract (e) path (a binary) from map *** * / + if (!GET_MAP_VAL(env, eSockAddr, atom_port, &epath)) + return str_einval; + + / * Get the path * / + if (!GET_BIN(env, epath, &bin)) + return str_einval; + + if ((bin.size + +#ifdef __linux__ + / * Make sure the address gets zero terminated + * except when the first byte is \0 because then it is + * sort of zero terminated although the zero termination + * comes before the address... + * This fix handles Linux's nonportable + * abstract socket address extension. + * / + (bin.data[0] == '\0' ? 0 : 1) +#else + 1 +#endif + ) > sizeof(sockaAddrP->sun_path)) + return str_einval; + + + sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_un)); + sockAddrP->sun_family = AF_UNIX; + + sys_memcpy(sockAddrP->sun_path, bin.data, bin.size); + len = offsetof(struct sockaddr_un, sun_path) + bin.size; + +#ifndef NO_SA_LEN + sockAddrP->sun_len = len; +#endif + *addrLen = len: + + return NULL; } +#endif +*/ -/* Create an error two (2) tuple in the form: {error, Reason}. - * The second element, Reason, is a string to be converted into - * an atom. + +/* +++ decode_ip4_address +++ + * + * Decode a IPv4 address. This can be three things: + * + * + Then atom 'any' + * + Then atom 'loopback' + * + An ip4_address() (4 tuple) + * + * Note that this *only* decodes the "address" part of a + * (IPv4) socket address. There are several other things (port). */ +/* static -ERL_NIF_TERM make_error1(ErlNifEnv* env, char* reason) +char* decode_ip4_address(ErlNifEnv* env, + ERL_NIF_TERM eAddr, + struct sockaddr_in* sockAddrP, + unsigned int* addrLen) { - return make_error(env, MKA(env, reason)); + if (IS_ATOM(env, eAddr)) { + / * This is either 'any' or 'loopback' * / + struct in_addr addr; + + if (COMPARE(esock_atom_loopback, eAddr) == 0) { + addr.s_addr = sock_htonl(INADDR_LOOPBACK); + } else if (COMPARE(esock_atom_any, eAddr) == 0) { + addr.s_addr = sock_htonl(INADDR_ANY); + } else { + return str_einval; + } + + sockAddrP->sin_addr.s_addr = addr.s_addr; + *addrLen = sizeof(struct sockaddr_in); + + } else { + / * This is a 4-tuple * / + + const ERL_NIF_TERM* addrt; + int addrtSz; + int a, v; + char addr[4]; + + if (!GET_TUPLE(env, eAddr, &addrtSz, &addrt)) + return str_einval; + + if (addrtSz != 4) + return str_einval; + + for (a = 0; a < 4; a++) { + if (!GET_INT(env, addrt[a], &v)) + return str_einval; + addr[a] = v; + } + + sys_memcpy(&sockAddrP->sin_addr, &addr, sizeof(addr)); + *addrLenP = sizeof(struct sockaddr_in); + + } + + return NULL; } +*/ + -/* Create an error two (2) tuple in the form: {error, Reason}. - * The second element, Reason, is the errno value in its - * basic form (integer) which will (eventually) be converted - * into an atom. +/* +++ decode_ip6_address +++ + * + * Decode a IPv6 address. This can be three things: + * + * + Then atom 'any' + * + Then atom 'loopback' + * + An ip6_address() (8 tuple) + * + * Note that this *only* decodes the "address" part of a + * (IPv6) socket address. There are several other things + * (port, flowinfo and scope_id) that are handled elsewhere). */ +/* +#if defined(HAVE_IN6) && defined(AF_INET6) +static +char* decode_ip6_address(ErlNifEnv* env, + ERL_NIF_TERM eAddr, + struct sockaddr_in6* sockAddrP, + unsigned int* addrLen) +{ + if (IS_ATOM(env, eAddr)) { + / * This is either 'any' or 'loopback' * / + const struct in6_addr* addr; + + if (COMPARE(esock_atom_loopback, eAddr) == 0) { + addr = &in6addr_loopback; + } else if (COMPARE(esock_atom_any, eAddr) == 0) { + addr = &in6addr_any; + } else { + return str_einval; + } + + sockAddrP->sin6_addr = *addr; + *addrLen = sizeof(struct sockaddr_in6); + + } else { + / * This is a 8-tuple * / + + const ERL_NIF_TERM* addrt; + int addrtSz; + int a, v; + char addr[16]; + + if (!GET_TUPLE(env, eAddr, &addrtSz, &addrt)) + return str_einval; + + if (addrtSz != 8) + return str_einval; + + for (a = 0; a < 8; a++) { + if (!GET_INT(env, addrt[a], &v)) + return str_einval; + addr[a*2 ] = ((v >> 8) & 0xFF); + addr[a*2+1] = (v & 0xFF); + } + + sys_memcpy(&sockAddrP->sin6_addr, &addr, sizeof(addr)); + *addrLen = sizeof(struct sockaddr_in6); + + } + + return NULL; +} +#endif +*/ + + + +#if defined(HAVE_SYS_UN_H) || defined(SO_BINDTODEVICE) +/* strnlen doesn't exist everywhere */ static -ERL_NIF_TERM make_error2(ErlNifEnv* env, int err) +size_t my_strnlen(const char *s, size_t maxlen) { - return make_error1(env, erl_errno_id(err)); + size_t i = 0; + while (i < maxlen && s[i] != '\0') + i++; + return i; } +#endif /* Send an error closed message to the specified process: @@ -6893,6 +7233,7 @@ void xabort(const char* expr, } + /* ---------------------------------------------------------------------- * C o u n t e r F u n c t i o n s * ---------------------------------------------------------------------- @@ -7137,89 +7478,6 @@ void socket_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), "SOCKET [%s] %s", TSNAME(), format); - res = enif_snprintf(f, sizeof(f), "SOCKET [%s]", format); - } else { - // res = enif_snprintf(f, sizeof(f), "SOCKET [%s] [%s] %s", stamp, TSNAME(), format); - res = enif_snprintf(f, sizeof(f), "SOCKET [%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 * ---------------------------------------------------------------------- @@ -7271,7 +7529,7 @@ BOOLEAN_T extract_item_on_load(ErlNifEnv* env, if (!enif_is_map(env, map)) return FALSE; - if (!enif_get_map_value(env, map, key, val)) + if (!GET_MAP_VAL(env, map, key, val)) return FALSE; return TRUE; @@ -7373,18 +7631,15 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) data.numProtoSCTP = 0; /* +++ Misc atoms +++ */ - atom_any = MKA(env, str_any); atom_close = MKA(env, str_close); atom_closed = MKA(env, str_closed); atom_closing = MKA(env, str_closing); atom_debug = MKA(env, str_debug); - atom_error = MKA(env, str_error); atom_false = MKA(env, str_false); atom_global_counters = MKA(env, str_global_counters); atom_in4_sockaddr = MKA(env, str_in4_sockaddr); atom_in6_sockaddr = MKA(env, str_in6_sockaddr); atom_iow = MKA(env, str_iow); - atom_loopback = MKA(env, str_loopback); atom_nif_abort = MKA(env, str_nif_abort); atom_num_dinet = MKA(env, str_num_dinet); atom_num_dinet6 = MKA(env, str_num_dinet6); @@ -7397,11 +7652,28 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info) atom_num_tdgrams = MKA(env, str_num_tdgrams); atom_num_tseqpkgs = MKA(env, str_num_tseqpkgs); atom_num_tstreams = MKA(env, str_num_tstreams); - atom_ok = MKA(env, str_ok); atom_select = MKA(env, str_select); atom_timeout = MKA(env, str_timeout); atom_true = MKA(env, str_true); - atom_undefined = MKA(env, str_undefined); + + esock_atom_addr = MKA(env, "addr"); + esock_atom_any = MKA(env, "any"); + esock_atom_dgram = MKA(env, "dgram"); + esock_atom_error = MKA(env, "error"); + esock_atom_family = MKA(env, "family"); + esock_atom_flowinfo = MKA(env, "flowinfo"); + esock_atom_inet = MKA(env, "inet"); + esock_atom_inet6 = MKA(env, "inet6"); + esock_atom_local = MKA(env, "local"); + esock_atom_loopback = MKA(env, "loopback"); + esock_atom_ok = MKA(env, "ok"); + esock_atom_path = MKA(env, "path"); + esock_atom_port = MKA(env, "port"); + esock_atom_raw = MKA(env, "raw"); + esock_atom_scope_id = MKA(env, "scope_id"); + esock_atom_seqpacket = MKA(env, "seqpacket"); + esock_atom_stream = MKA(env, "stream"); + esock_atom_undefined = MKA(env, "undefined"); atom_lowdelay = MKA(env, str_lowdelay); atom_throughput = MKA(env, str_throughput); diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c new file mode 100644 index 0000000000..818e259ae8 --- /dev/null +++ b/erts/emulator/nifs/common/socket_util.c @@ -0,0 +1,659 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2018-2018. 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 : Utility functions for the socket and net NIF(s). + * ---------------------------------------------------------------------- + * + */ + +#include +#include "socket_int.h" +#include "socket_util.h" +#include "sys.h" + + +/* THIS IS JUST TEMPORARY */ +extern char* erl_errno_id(int error); + + +/* +++ esock_decode_sockaddr +++ + * + * Decode a socket address - sockaddr. In erlang its represented as + * a map, which has a specific set of attributes, depending on one + * mandatory attribute; family. So depending on the value of the family + * attribute: + * + * local - sockaddr_un: path + * inet - sockaddr_in4: port, addr + * inet6 - sockaddr_in6: port, addr, flowinfo, scope_id + */ + +extern +char* esock_decode_sockaddr(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + SocketAddress* sockAddrP, + unsigned int* addrLen) +{ + ERL_NIF_TERM efam; + int fam; + char* xres; + + if (!IS_MAP(env, eSockAddr)) + return ESOCK_STR_EINVAL; + + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_family, &efam)) + return ESOCK_STR_EINVAL; + + if ((xres = esock_decode_domain(env, efam, &fam)) != NULL) + return xres; + + switch (fam) { + case AF_INET: + xres = esock_decode_sockaddr_in4(env, eSockAddr, + &sockAddrP->in4, addrLen); + break; + +#if defined(HAVE_IN6) && defined(AF_INET6) + case AF_INET6: + xres = esock_decode_sockaddr_in6(env, eSockAddr, + &sockAddrP->in6, addrLen); + break; +#endif + +#ifdef HAVE_SYS_UN_H + case AF_UNIX: + xres = esock_decode_sockaddr_un(env, eSockAddr, + &sockAddrP->un, addrLen); + break; +#endif + + default: + xres = ESOCK_STR_EAFNOSUPPORT; + break; + + } + + return xres; +} + + + +/* +++ esock_decode_sockaddr_in4 +++ + * + * Decode a IPv4 socket address - sockaddr_in4. In erlang its represented as + * a map, which has a specific set of attributes: + * + * port :: port_numbber() + * addr :: ip4_address() + * + * The erlang module ensures that both of these has values exist, so there + * is no need for any elaborate error handling. + */ + +extern +char* esock_decode_sockaddr_in4(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_in* sockAddrP, + unsigned int* addrLen) +{ + ERL_NIF_TERM eport, eaddr; + int port; + + /* Basic init */ + sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in)); + +#ifndef NO_SA_LEN + sockAddrP->sin_len = sizeof(struct sockaddr_in); +#endif + + sockAddrP->sin_family = AF_INET; + + /* Extract (e) port number from map */ + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_port, &eport)) + return ESOCK_STR_EINVAL; + + /* Decode port number */ + if (!GET_INT(env, eport, &port)) + return ESOCK_STR_EINVAL; + + sockAddrP->sin_port = htons(port); + + /* Extract (e) address from map */ + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_addr, &eaddr)) + return ESOCK_STR_EINVAL; + + /* Decode address */ + if (!esock_decode_ip4_address(env, eaddr, sockAddrP, addrLen)) + return ESOCK_STR_EINVAL; + + return NULL; +} + + +/* +++ decode_sockaddr_in6 +++ + * + * Decode a IPv6 socket address - sockaddr_in6. In erlang its represented as + * a map, which has a specific set of attributes: + * + * port :: port_numbber() (integer) + * addr :: ip6_address() (tuple) + * flowinfo :: in6_flow_info() (integer) + * scope_id :: in6_scope_id() (integer) + * + * The erlang module ensures that all of these has values exist, so there + * is no need for any elaborate error handling here. + */ + +#if defined(HAVE_IN6) && defined(AF_INET6) +extern +char* esock_decode_sockaddr_in6(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_in6* sockAddrP, + unsigned int* addrLen) +{ + ERL_NIF_TERM eport, eaddr, eflowInfo, escopeId; + int port; + unsigned int flowInfo, scopeId; + + /* Basic init */ + sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_in6)); +#ifndef NO_SA_LEN + sockAddrP->sin6_len = sizeof(struct sockaddr_in); +#endif + + sockAddrP->sin6_family = AF_INET6; + + /* *** Extract (e) port number from map *** */ + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_port, &eport)) + return ESOCK_STR_EINVAL; + + /* Decode port number */ + if (!GET_INT(env, eport, &port)) + return ESOCK_STR_EINVAL; + + sockAddrP->sin6_port = htons(port); + + /* *** Extract (e) flowinfo from map *** */ + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_flowinfo, &eflowInfo)) + return ESOCK_STR_EINVAL; + + /* 4: Get the flowinfo */ + if (!GET_UINT(env, eflowInfo, &flowInfo)) + return ESOCK_STR_EINVAL; + + sockAddrP->sin6_flowinfo = flowInfo; + + /* *** Extract (e) scope_id from map *** */ + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_scope_id, &escopeId)) + return ESOCK_STR_EINVAL; + + /* *** Get the scope_id *** */ + if (!GET_UINT(env, escopeId, &scopeId)) + return ESOCK_STR_EINVAL; + + sockAddrP->sin6_scope_id = scopeId; + + /* *** Extract (e) address from map *** */ + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_addr, &eaddr)) + return ESOCK_STR_EINVAL; + + /* Decode address */ + if (!esock_decode_ip6_address(env, eaddr, sockAddrP, addrLen)) + return ESOCK_STR_EINVAL; + + return NULL; +} +#endif + + + +/* +++ esock_decode_sockaddr_un +++ + * + * Decode a Unix Domain socket address - sockaddr_un. In erlang its + * represented as a map, which has a specific set of attributes: + * + * path :: binary() + * + * The erlang module ensures that this value exist, so there + * is no need for any elaborate error handling here. + */ + +#ifdef HAVE_SYS_UN_H +extern +char* esock_decode_sockaddr_un(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_un* sockAddrP, + unsigned int* addrLen) +{ + ErlNifBinary bin; + ERL_NIF_TERM epath; + unsigned int len; + + /* *** Extract (e) path (a binary) from map *** */ + if (!GET_MAP_VAL(env, eSockAddr, esock_atom_path, &epath)) + return ESOCK_STR_EINVAL; + + /* Get the path */ + if (!GET_BIN(env, epath, &bin)) + return ESOCK_STR_EINVAL; + + if ((bin.size + +#ifdef __linux__ + /* Make sure the address gets zero terminated + * except when the first byte is \0 because then it is + * sort of zero terminated although the zero termination + * comes before the address... + * This fix handles Linux's nonportable + * abstract socket address extension. + */ + (bin.data[0] == '\0' ? 0 : 1) +#else + 1 +#endif + ) > sizeof(sockAddrP->sun_path)) + return ESOCK_STR_EINVAL; + + + sys_memzero((char*) sockAddrP, sizeof(struct sockaddr_un)); + sockAddrP->sun_family = AF_UNIX; + + sys_memcpy(sockAddrP->sun_path, bin.data, bin.size); + len = offsetof(struct sockaddr_un, sun_path) + bin.size; + +#ifndef NO_SA_LEN + sockAddrP->sun_len = len; +#endif + *addrLen = len; + + return NULL; +} +#endif + + + +/* +++ decode_ip4_address +++ + * + * Decode a IPv4 address. This can be three things: + * + * + Then atom 'any' + * + Then atom 'loopback' + * + An ip4_address() (4 tuple) + * + * Note that this *only* decodes the "address" part of a + * (IPv4) socket address. There are several other things (port). + */ + +extern +char* esock_decode_ip4_address(ErlNifEnv* env, + ERL_NIF_TERM eAddr, + struct sockaddr_in* sockAddrP, + unsigned int* addrLen) +{ + if (IS_ATOM(env, eAddr)) { + /* This is either 'any' or 'loopback' */ + struct in_addr addr; + + if (COMPARE(esock_atom_loopback, eAddr) == 0) { + addr.s_addr = htonl(INADDR_LOOPBACK); + } else if (COMPARE(esock_atom_any, eAddr) == 0) { + addr.s_addr = htonl(INADDR_ANY); + } else { + return ESOCK_STR_EINVAL; + } + + sockAddrP->sin_addr.s_addr = addr.s_addr; + *addrLen = sizeof(struct sockaddr_in); + + } else { + /* This is a 4-tuple */ + + const ERL_NIF_TERM* addrt; + int addrtSz; + int a, v; + char addr[4]; + + if (!GET_TUPLE(env, eAddr, &addrtSz, &addrt)) + return ESOCK_STR_EINVAL; + + if (addrtSz != 4) + return ESOCK_STR_EINVAL; + + for (a = 0; a < 4; a++) { + if (!GET_INT(env, addrt[a], &v)) + return ESOCK_STR_EINVAL; + addr[a] = v; + } + + sys_memcpy(&sockAddrP->sin_addr, &addr, sizeof(addr)); + *addrLen = sizeof(struct sockaddr_in); + + } + + return NULL; +} + + + +/* +++ decode_ip6_address +++ + * + * Decode a IPv6 address. This can be three things: + * + * + Then atom 'any' + * + Then atom 'loopback' + * + An ip6_address() (8 tuple) + * + * Note that this *only* decodes the "address" part of a + * (IPv6) socket address. There are several other things + * (port, flowinfo and scope_id) that are handled elsewhere). + */ + +#if defined(HAVE_IN6) && defined(AF_INET6) +extern +char* esock_decode_ip6_address(ErlNifEnv* env, + ERL_NIF_TERM eAddr, + struct sockaddr_in6* sockAddrP, + unsigned int* addrLen) +{ + if (IS_ATOM(env, eAddr)) { + /* This is either 'any' or 'loopback' */ + const struct in6_addr* addr; + + if (COMPARE(esock_atom_loopback, eAddr) == 0) { + addr = &in6addr_loopback; + } else if (COMPARE(esock_atom_any, eAddr) == 0) { + addr = &in6addr_any; + } else { + return ESOCK_STR_EINVAL; + } + + sockAddrP->sin6_addr = *addr; + *addrLen = sizeof(struct sockaddr_in6); + + } else { + /* This is a 8-tuple */ + + const ERL_NIF_TERM* addrt; + int addrtSz; + int a, v; + char addr[16]; + + if (!GET_TUPLE(env, eAddr, &addrtSz, &addrt)) + return ESOCK_STR_EINVAL; + + if (addrtSz != 8) + return ESOCK_STR_EINVAL; + + for (a = 0; a < 8; a++) { + if (!GET_INT(env, addrt[a], &v)) + return ESOCK_STR_EINVAL; + addr[a*2 ] = ((v >> 8) & 0xFF); + addr[a*2+1] = (v & 0xFF); + } + + sys_memcpy(&sockAddrP->sin6_addr, &addr, sizeof(addr)); + *addrLen = sizeof(struct sockaddr_in6); + + } + + return NULL; +} +#endif + + +/* +++ esock_decode_domain +++ + * + * Decode the Erlang form of the 'domain' type, that is: + * + * inet => AF_INET + * inet6 => AF_INET6 + * local => AF_UNIX + * + */ +extern +char* esock_decode_domain(ErlNifEnv* env, + ERL_NIF_TERM eDomain, + int* domain) +{ + char* xres = NULL; + + if (COMPARE(esock_atom_inet, eDomain) == 0) { + *domain = AF_INET; + +#if defined(HAVE_IN6) && defined(AF_INET6) + } else if (COMPARE(esock_atom_inet6, eDomain) == 0) { + *domain = AF_INET6; +#endif + +#ifdef HAVE_SYS_UN_H + } else if (COMPARE(esock_atom_local, eDomain) == 0) { + *domain = AF_UNIX; +#endif + + } else { + *domain = -1; + xres = ESOCK_STR_EAFNOSUPPORT; + } + + return xres; +} + + + +/* +++ esock_encode_domain +++ + * + * Encode the native domain to the Erlang form, that is: + * + * AF_INET => inet + * AF_INET6 => inet6 + * AF_UNIX => local + * + */ +extern +char* esock_encode_domain(ErlNifEnv* env, + int domain, + ERL_NIF_TERM* eDomain) +{ + char* xres = NULL; + + switch (domain) { + case AF_INET: + *eDomain = esock_atom_inet; + break; + +#if defined(HAVE_IN6) && defined(AF_INET6) + case AF_INET6: + *eDomain = esock_atom_inet6; + break; +#endif + +#ifdef HAVE_SYS_UN_H + case AF_UNIX: + *eDomain = esock_atom_local; + break; +#endif + + default: + *eDomain = esock_atom_undefined; // Just in case + xres = ESOCK_STR_EAFNOSUPPORT; + } + + return xres; +} + + + +/* +++ esock_decode_type +++ + * + * Decode the Erlang form of the 'type' type, that is: + * + * stream => SOCK_STREAM + * dgram => SOCK_DGRAM + * raw => SOCK_RAW + * seqpacket => SOCK_SEQPACKET + * + */ +extern +char* esock_decode_type(ErlNifEnv* env, + ERL_NIF_TERM eType, + int* type) +{ + char* xres = NULL; + + if (COMPARE(esock_atom_stream, eType) == 0) { + *type = SOCK_STREAM; + } else if (COMPARE(esock_atom_dgram, eType) == 0) { + *type = SOCK_DGRAM; + } else if (COMPARE(esock_atom_raw, eType) == 0) { + *type = SOCK_RAW; + +#if defined(HAVE_SCTP) + } else if (COMPARE(esock_atom_seqpacket, eType) == 0) { + *type = SOCK_SEQPACKET; +#endif + + } else { + *type = -1; + xres = ESOCK_STR_EAFNOSUPPORT; + } + + return xres; +} + + + +/* +++ esock_decode_domain +++ + * + * Encode the native type to the Erlang form, that is: + * + * SOCK_STREAM => stream + * SOCK_DGRAM => dgram + * SOCK_RAW => raw + * SOCK_SEQPACKET => seqpacket + * + */ +extern +char* esock_encode_type(ErlNifEnv* env, + int type, + ERL_NIF_TERM* eType) +{ + char* xres = NULL; + + switch (type) { + case SOCK_STREAM: + *eType = esock_atom_stream; + break; + + case SOCK_DGRAM: + *eType = esock_atom_dgram; + break; + + case SOCK_RAW: + *eType = esock_atom_raw; + break; + +#if defined(HAVE_SCTP) + case SOCK_SEQPACKET: + *eType = esock_atom_seqpacket; + break; +#endif + + default: + *eType = esock_atom_undefined; // Just in case + xres = ESOCK_STR_EAFNOSUPPORT; + } + + return xres; +} + + + +/* Create an ok two (2) tuple in the form: + * + * {ok, Any} + * + * The second element (Any) is already in the form of an + * ERL_NIF_TERM so all we have to do is create the tuple. + */ +extern +ERL_NIF_TERM esock_make_ok2(ErlNifEnv* env, ERL_NIF_TERM any) +{ + return MKT2(env, esock_atom_ok, any); +} + + +/* Create an ok three (3) tuple in the form: + * + * {ok, Val1, Val2} + * + * The second (Val1) and third (Val2) elements are already in + * the form of an ERL_NIF_TERM so all we have to do is create + * the tuple. + */ +extern +ERL_NIF_TERM esock_make_ok3(ErlNifEnv* env, ERL_NIF_TERM val1, ERL_NIF_TERM val2) +{ + return MKT3(env, esock_atom_ok, val1, val2); +} + + + +/* Create an error two (2) tuple in the form: + * + * {error, Reason} + * + * The second element (Reason) is already in the form of an + * ERL_NIF_TERM so all we have to do is create the tuple. + */ +extern +ERL_NIF_TERM esock_make_error(ErlNifEnv* env, ERL_NIF_TERM reason) +{ + return MKT2(env, esock_atom_error, reason); +} + + + +/* Create an error two (2) tuple in the form: {error, Reason}. + * + * {error, Reason} + * + * The second element, Reason, is the reason string that has + * converted into an atom. + */ +extern +ERL_NIF_TERM esock_make_error_str(ErlNifEnv* env, char* reason) +{ + return esock_make_error(env, MKA(env, reason)); +} + + +/* Create an error two (2) tuple in the form: + * + * {error, Reason} + * + * The second element, Reason, is the errno value in its + * basic form (integer) which has been converted into an atom. + */ +extern +ERL_NIF_TERM esock_make_error_errno(ErlNifEnv* env, int err) +{ + return esock_make_error_str(env, erl_errno_id(err)); +} + + diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h new file mode 100644 index 0000000000..babfebc17b --- /dev/null +++ b/erts/emulator/nifs/common/socket_util.h @@ -0,0 +1,108 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2018-2018. 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 : Utility "stuff" for socket and net. + * ---------------------------------------------------------------------- + * + */ + +#ifndef SOCKET_UTIL_H__ +#define SOCKET_UTIL_H__ + +#include +#include "socket_int.h" + +extern +char* esock_decode_sockaddr(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + SocketAddress* sockAddrP, + unsigned int* addrLen); + +extern +char* esock_decode_sockaddr_in4(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_in* sockAddrP, + unsigned int* addrLen); + +#if defined(HAVE_IN6) && defined(AF_INET6) +extern +char* esock_decode_sockaddr_in6(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_in6* sockAddrP, + unsigned int* addrLen); +#endif + +#ifdef HAVE_SYS_UN_H +extern +char* esock_decode_sockaddr_un(ErlNifEnv* env, + ERL_NIF_TERM eSockAddr, + struct sockaddr_un* sockAddrP, + unsigned int* addrLen); +#endif + +extern +char* esock_decode_ip4_address(ErlNifEnv* env, + ERL_NIF_TERM eAddr, + struct sockaddr_in* sockAddrP, + unsigned int* addrLen); + +#if defined(HAVE_IN6) && defined(AF_INET6) +extern +char* esock_decode_ip6_address(ErlNifEnv* env, + ERL_NIF_TERM eAddr, + struct sockaddr_in6* sockAddrP, + unsigned int* addrLen); +#endif + +extern +char* esock_decode_domain(ErlNifEnv* env, + ERL_NIF_TERM eDomain, + int* domain); + +extern +char* esock_encode_domain(ErlNifEnv* env, + int domain, + ERL_NIF_TERM* eDomain); + +extern +char* esock_decode_type(ErlNifEnv* env, + ERL_NIF_TERM eType, + int* type); + +extern +char* esock_encode_type(ErlNifEnv* env, + int type, + ERL_NIF_TERM* eType); + + +extern +ERL_NIF_TERM esock_make_ok2(ErlNifEnv* env, ERL_NIF_TERM any); +extern +ERL_NIF_TERM esock_make_ok3(ErlNifEnv* env, ERL_NIF_TERM val1, ERL_NIF_TERM val2); + +extern +ERL_NIF_TERM esock_make_error(ErlNifEnv* env, ERL_NIF_TERM reason); +extern +ERL_NIF_TERM esock_make_error_str(ErlNifEnv* env, char* reason); +extern +ERL_NIF_TERM esock_make_error_errno(ErlNifEnv* env, int err); + + +#endif // SOCKET_UTIL_H__ diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 213dc2a1a2..fae60a4491 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -36,11 +36,11 @@ include $(ERL_TOP)/lib/kernel/vsn.mk PRE_LOADED_ERL_MODULES = \ erl_prim_loader \ init \ - net \ prim_buffer \ prim_file \ prim_inet \ socket \ + net \ zlib \ prim_zip \ otp_ring0 \ diff --git a/erts/preloaded/src/net.erl b/erts/preloaded/src/net.erl index 29739f4510..6abfc22d3f 100644 --- a/erts/preloaded/src/net.erl +++ b/erts/preloaded/src/net.erl @@ -30,7 +30,7 @@ -export([ gethostname/0, getnameinfo/1, getnameinfo/2, - getaddrinfo/2, + getaddrinfo/1, getaddrinfo/2, if_name2index/1, if_index2name/1, @@ -46,14 +46,6 @@ sleep/1]). -export_type([ - ip_address/0, - ip4_address/0, - ip6_address/0, - in_sockaddr/0, - in4_sockaddr/0, - in6_sockaddr/0, - port_number/0, - address_info/0, name_info/0, @@ -66,35 +58,6 @@ ]). -%% Many of these should be moved to the socket module. --type ip_address() :: ip4_address() | ip6_address(). --type ip4_address() :: {0..255, 0..255, 0..255, 0..255}. --type ip6_address() :: - {0..65535, - 0..65535, - 0..65535, - 0..65535, - 0..65535, - 0..65535, - 0..65535, - 0..65535}. --type uint20() :: 0..16#FFFFF. --type uint32() :: 0..16#FFFFFFFF. --type in6_flow_info() :: uint20(). --type in6_scope_id() :: uint32(). --record(in4_sockaddr, {port = 0 :: port_number(), - addr = any :: any | loopback | ip4_address()}). --type in4_sockaddr() :: #in4_sockaddr{}. --record(in6_sockaddr, {port = 0 :: port_number(), - addr = any :: any | loopback | ip6_address(), - flowinfo = 0 :: in6_flow_info(), - scope_id = 0 :: in6_scope_id()}). --type in6_sockaddr() :: #in6_sockaddr{}. - --type in_sockaddr() :: in4_sockaddr() | in6_sockaddr(). - --type port_number() :: 0..65535. - -type name_info_flags() :: [name_info_flag()|name_info_flag_ext()]. -type name_info_flag() :: namereqd | dgram | @@ -104,10 +67,19 @@ -type name_info_flag_ext() :: idn | idna_allow_unassigned | idna_use_std3_ascii_rules. --record(name_info, {host, service}). --type name_info() :: #name_info{}. --record(address_info, {family, socktype, protocol, addr}). --type address_info() :: #address_info{}. +-type name_info() :: #{host := string(), + service := string()}. +%% -record(name_info, {host, service}). +%% -type name_info() :: #name_info{}. +-type address_info() :: #{family := socket:domain(), + socktype := socket:type(), + protocol := socket:protocol(), + address := socket:sockaddr()}. +%% -record(address_info, {family :: socket:domain(), +%% socktype :: socket:type(), +%% protocol :: socket:protocol(), +%% addr :: undefined | socket:in_sockaddr() | string()}). +%% -type address_info() :: #address_info{}. -type network_interface_name() :: string(). -type network_interface_index() :: non_neg_integer(). @@ -199,38 +171,51 @@ gethostname() -> %% -spec getnameinfo(SockAddr) -> {ok, Info} | {error, Reason} when - SockAddr :: in_sockaddr(), + SockAddr :: socket:sockaddr(), Info :: name_info(), Reason :: term(). -getnameinfo(SockAddr) - when is_record(SockAddr, in4_sockaddr) orelse - is_record(SockAddr, in6_sockaddr) -> +getnameinfo(SockAddr) -> getnameinfo(SockAddr, undefined). -spec getnameinfo(SockAddr, Flags) -> {ok, Info} | {error, Reason} when - SockAddr :: in_sockaddr(), + SockAddr :: socket:sockaddr(), Flags :: name_info_flags() | undefined, Info :: name_info(), Reason :: term(). getnameinfo(SockAddr, [] = _Flags) -> getnameinfo(SockAddr, undefined); -getnameinfo(SockAddr, Flags) - when (is_record(SockAddr, in4_sockaddr) orelse - is_record(SockAddr, in6_sockaddr)) andalso +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, Service) -> {ok, Info} | {error, Reason} when +-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(). diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl index 5a0748e8fb..b89fa06da8 100644 --- a/erts/preloaded/src/socket.erl +++ b/erts/preloaded/src/socket.erl @@ -25,7 +25,8 @@ %% Administrative and "global" utility functions -export([ on_load/0, on_load/1, on_load/2, - info/0 + info/0, + ensure_sockaddr/1 ]). -export([ @@ -58,13 +59,14 @@ protocol/0, socket/0, + port_number/0, ip_address/0, ip4_address/0, ip6_address/0, - in_sockaddr/0, - in4_sockaddr/0, - in6_sockaddr/0, - port_number/0, + sockaddr/0, + sockaddr_in4/0, + sockaddr_in6/0, + sockaddr_un/0, accept_flags/0, accept_flag/0, @@ -95,6 +97,8 @@ %% We support only a subset of all protocols: -type protocol() :: ip | tcp | udp | sctp. +-type port_number() :: 0..65535. + -type ip_address() :: ip4_address() | ip6_address(). -type ip4_address() :: {0..255, 0..255, 0..255, 0..255}. @@ -115,22 +119,39 @@ 0..65535}. %% +%% %% Should we do these as maps instead? %% If we do we may need to include the family (domain) in the %% map (as the native type do. See struct sockaddr_in6). +%% +%% What about default values? Such as for port (=0) and addr (=any)? +%% %% --type in_sockaddr() :: in4_sockaddr() | in6_sockaddr(). --record(in4_sockaddr, {port = 0 :: port_number(), - addr = any :: any | loopback | ip4_address()}). --type in4_sockaddr() :: #in4_sockaddr{}. --record(in6_sockaddr, {port = 0 :: port_number(), - addr = any :: any | loopback | ip6_address(), - flowinfo = 0 :: in6_flow_info(), - scope_id = 0 :: in6_scope_id()}). --type in6_sockaddr() :: #in6_sockaddr{}. - --type port_number() :: 0..65535. +-type sockaddr_un() :: #{family := local, + path := binary() | string()}. +-type sockaddr_in4() :: #{family := inet, + port := port_number(), + addr := any | loopback | ip4_address()}. +-type sockaddr_in6() :: #{family := inet6, + port := port_number(), + addr := any | loopback | ip6_address(), + flowinfo := in6_flow_info(), + scope_id := in6_scope_id()}. +-type sockaddr() :: sockaddr_in4() | + sockaddr_in6() | + sockaddr_un(). + +-define(SOCKADDR_IN4_DEFAULTS(A), #{port => 0, + addr => A}). +-define(SOCKADDR_IN4_DEFAULTS, ?SOCKADDR_IN4_DEFAULTS(any)). +-define(SOCKADDR_IN4_DEFAULT(A), (?SOCKADDR_IN4_DEFAULTS(A))#{family => inet}). +-define(SOCKADDR_IN6_DEFAULTS(A), #{port => 0, + addr => A, + flowinfo => 0, + scope_id => 0}). +-define(SOCKADDR_IN6_DEFAULTS, ?SOCKADDR_IN6_DEFAULTS(any)). +-define(SOCKADDR_IN6_DEFAULT(A), (?SOCKADDR_IN6_DEFAULTS(A))#{family => inet6}). %% otp - The option is internal to our (OTP) imeplementation. %% socket - The socket layer (SOL_SOCKET). @@ -651,40 +672,61 @@ default_protocol(Protocol, _) -> Protocol. %% bind - bind a name to a socket %% --spec bind(Socket, FileOrAddr) -> ok | {error, Reason} when - Socket :: socket(), - FileOrAddr :: binary() | string() | in_sockaddr() | any | loopback, - Reason :: term(). +-spec bind(Socket, Addr) -> ok | {error, Reason} when + Socket :: socket(), + Addr :: any | loopback | sockaddr(), + Reason :: term(). -bind(Socket, File) when is_binary(File) -> - if - byte_size(File) =:= 0 -> - {error, einval}; - byte_size(File) =< 255 -> - nif_bind(Socket, File); - true -> - {error, einval} - end; -bind(Socket, File) when is_list(File) andalso (File =/= []) -> - Bin = unicode:characters_to_binary(File, file:native_name_encoding()), - if - byte_size(Bin) =< 255 -> - nif_bind(Socket, Bin); - true -> - {error, einval} - end; bind(#socket{info = #{domain := inet}} = Socket, Addr) when ((Addr =:= any) orelse (Addr =:= loopback)) -> - bind(Socket, #in4_sockaddr{addr = Addr}); + bind(Socket, ?SOCKADDR_IN4_DEFAULT(Addr)); bind(#socket{info = #{domain := inet6}} = Socket, Addr) when ((Addr =:= any) orelse (Addr =:= loopback)) -> - bind(Socket, #in6_sockaddr{addr = Addr}); -bind(#socket{info = #{domain := inet}, ref = SockRef} = _Socket, SockAddr) - when is_record(SockAddr, in4_sockaddr) -> - nif_bind(SockRef, SockAddr); -bind(#socket{info = #{domain := inet6}, ref = SockRef} = _Socket, SockAddr) - when is_record(SockAddr, in6_sockaddr) -> - nif_bind(SockRef, SockAddr). + bind(Socket, ?SOCKADDR_IN6_DEFAULT(Addr)); +bind(Socket, Addr) -> + try + begin + nif_bind(Socket, ensure_sockaddr(Addr)) + end + catch + throw:ERROR -> + ERROR + end. + +%% -spec bind(Socket, FileOrAddr) -> ok | {error, Reason} when +%% Socket :: socket(), +%% FileOrAddr :: binary() | string() | in_sockaddr() | any | loopback, +%% Reason :: term(). + +%% bind(Socket, File) when is_binary(File) -> +%% if +%% byte_size(File) =:= 0 -> +%% {error, einval}; +%% byte_size(File) =< 255 -> +%% nif_bind(Socket, File); +%% true -> +%% {error, einval} +%% end; +%% bind(Socket, File) when is_list(File) andalso (File =/= []) -> +%% Bin = unicode:characters_to_binary(File, file:native_name_encoding()), +%% if +%% byte_size(Bin) =< 255 -> +%% nif_bind(Socket, Bin); +%% true -> +%% {error, einval} +%% end; +%% bind(#socket{info = #{domain := inet}} = Socket, Addr) +%% when ((Addr =:= any) orelse (Addr =:= loopback)) -> +%% bind(Socket, #in4_sockaddr{addr = Addr}); +%% bind(#socket{info = #{domain := inet6}} = Socket, Addr) +%% when ((Addr =:= any) orelse (Addr =:= loopback)) -> +%% bind(Socket, #in6_sockaddr{addr = Addr}); +%% bind(#socket{info = #{domain := inet}, ref = SockRef} = _Socket, SockAddr) +%% when is_record(SockAddr, in4_sockaddr) -> +%% nif_bind(SockRef, SockAddr); +%% bind(#socket{info = #{domain := inet6}, ref = SockRef} = _Socket, SockAddr) +%% when is_record(SockAddr, in6_sockaddr) -> +%% nif_bind(SockRef, SockAddr). @@ -695,7 +737,7 @@ bind(#socket{info = #{domain := inet6}, ref = SockRef} = _Socket, SockAddr) -spec connect(Socket, SockAddr) -> ok | {error, Reason} when Socket :: socket(), - SockAddr :: in_sockaddr(), + SockAddr :: sockaddr(), Reason :: term(). connect(Socket, SockAddr) -> @@ -703,16 +745,15 @@ connect(Socket, SockAddr) -> -spec connect(Socket, SockAddr, Timeout) -> ok | {error, Reason} when Socket :: socket(), - SockAddr :: in_sockaddr(), + SockAddr :: sockaddr(), Timeout :: timeout(), Reason :: term(). connect(_Socket, _SockAddr, Timeout) when (is_integer(Timeout) andalso (Timeout =< 0)) -> {error, timeout}; -connect(#socket{ref = SockRef}, SockAddr, Timeout) - when (is_record(SockAddr, in4_sockaddr) orelse - is_record(SockAddr, in6_sockaddr)) andalso +connect(#socket{ref = SockRef}, #{family := Fam} = SockAddr, Timeout) + when ((Fam =:= inet) orelse (Fam =:= inet6) orelse (Fam =:= local)) andalso ((Timeout =:= infinity) orelse is_integer(Timeout)) -> TS = timestamp(Timeout), case nif_connect(SockRef, SockAddr) of @@ -917,35 +958,40 @@ do_send(SockRef, Data, EFlags, Timeout) -> %% --------------------------------------------------------------------------- %% -sendto(Socket, Data, Flags, DestSockAddr) -> - sendto(Socket, Data, Flags, DestSockAddr, ?SOCKET_SENDTO_TIMEOUT_DEFAULT). +sendto(Socket, Data, Flags, Dest) -> + sendto(Socket, Data, Flags, Dest, ?SOCKET_SENDTO_TIMEOUT_DEFAULT). --spec sendto(Socket, Data, Flags, DestSockAddr, Timeout) -> +-spec sendto(Socket, Data, Flags, Dest, Timeout) -> ok | {error, Reason} when - Socket :: socket(), - Data :: binary(), - Flags :: send_flags(), - DestSockAddr :: null | in_sockaddr(), - Timeout :: timeout(), - Reason :: term(). + Socket :: socket(), + Data :: binary(), + Flags :: send_flags(), + Dest :: null | sockaddr(), + Timeout :: timeout(), + Reason :: term(). sendto(Socket, Data, Flags, DestSockAddr, Timeout) when is_list(Data) -> Bin = erlang:list_to_binary(Data), sendto(Socket, Bin, Flags, DestSockAddr, Timeout); -sendto(#socket{ref = SockRef}, Data, Flags, DestSockAddr, Timeout) +sendto(#socket{ref = SockRef}, Data, Flags, Dest, Timeout) + when is_binary(Data) andalso + is_list(Flags) andalso + (Dest =:= null) andalso + (is_integer(Timeout) orelse (Timeout =:= infinity)) -> + EFlags = enc_send_flags(Flags), + do_sendto(SockRef, Data, EFlags, Dest, Timeout); +sendto(#socket{ref = SockRef}, Data, Flags, #{family := Fam} = Dest, Timeout) when is_binary(Data) andalso is_list(Flags) andalso - (is_record(DestSockAddr, in4_sockaddr) orelse - is_record(DestSockAddr, in6_sockaddr) orelse - (DestSockAddr =:= null)) andalso + ((Fam =:= inet) orelse (Fam =:= inet6) orelse (Fam =:= local)) andalso (is_integer(Timeout) orelse (Timeout =:= infinity)) -> EFlags = enc_send_flags(Flags), - do_sendto(SockRef, Data, EFlags, DestSockAddr, Timeout). + do_sendto(SockRef, Data, EFlags, Dest, Timeout). -do_sendto(SockRef, Data, EFlags, DestSockAddr, Timeout) -> +do_sendto(SockRef, Data, EFlags, Dest, Timeout) -> TS = timestamp(Timeout), SendRef = make_ref(), - case nif_sendto(SockRef, SendRef, Data, EFlags, DestSockAddr) of + case nif_sendto(SockRef, SendRef, Data, EFlags, Dest) of ok -> %% We are done ok; @@ -955,10 +1001,10 @@ do_sendto(SockRef, Data, EFlags, DestSockAddr, Timeout) -> receive {select, SockRef, SendRef, ready_output} when (Written > 0) -> <<_:Written/binary, Rest/binary>> = Data, - do_sendto(SockRef, Rest, EFlags, DestSockAddr, + do_sendto(SockRef, Rest, EFlags, Dest, next_timeout(TS, Timeout)); {select, SockRef, SendRef, ready_output} -> - do_sendto(SockRef, Data, EFlags, DestSockAddr, + do_sendto(SockRef, Data, EFlags, Dest, next_timeout(TS, Timeout)); {nif_abort, SendRef, Reason} -> @@ -973,7 +1019,7 @@ do_sendto(SockRef, Data, EFlags, DestSockAddr, Timeout) -> {error, eagain} -> receive {select, SockRef, SendRef, ready_output} -> - do_sendto(SockRef, Data, EFlags, DestSockAddr, + do_sendto(SockRef, Data, EFlags, Dest, next_timeout(TS, Timeout)) after Timeout -> nif_cancel(SockRef, sendto, SendRef), @@ -1256,7 +1302,7 @@ recvfrom(Socket, BufSz, Timeout) -> BufSz :: non_neg_integer(), Flags :: recv_flags(), Timeout :: timeout(), - Source :: in_sockaddr() | string() | undefined, + Source :: sockaddr() | undefined, Data :: binary(), Reason :: term(). @@ -2061,6 +2107,26 @@ enc_shutdown_how(read_write) -> %% %% =========================================================================== +ensure_sockaddr(#{family := inet} = SockAddr) -> + maps:merge(?SOCKADDR_IN4_DEFAULTS, SockAddr); +ensure_sockaddr(#{family := inet6} = SockAddr) -> + maps:merge(?SOCKADDR_IN6_DEFAULTS, SockAddr); +ensure_sockaddr(#{family := local, path := Path} = SockAddr) + when is_list(Path) andalso + (length(Path) > 0) andalso + (length(Path) =< 255) -> + BinPath = unicode:characters_to_binary(Path, file:native_name_encoding()), + ensure_sockaddr(SockAddr#{path => BinPath}); +ensure_sockaddr(#{family := local, path := Path} = SockAddr) + when is_binary(Path) andalso + (byte_size(Path) > 0) andalso + (byte_size(Path) =< 255) -> + SockAddr; +ensure_sockaddr(_SockAddr) -> + einval(). + + + flush_select_msgs(LSRef, Ref) -> receive {select, LSRef, Ref, _} -> @@ -2136,6 +2202,9 @@ not_supported(What) -> unknown(What) -> error({unknown, What}). +einval() -> + error(einval). + error(Reason) -> throw({error, Reason}). -- cgit v1.2.3