aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/configure.in8
-rw-r--r--erts/doc/src/erl_nif.xml29
-rw-r--r--erts/emulator/beam/beam_emu.c77
-rw-r--r--erts/emulator/beam/erl_bif_port.c2
-rw-r--r--erts/emulator/beam/erl_db_hash.c34
-rw-r--r--erts/emulator/beam/erl_db_hash.h2
-rw-r--r--erts/emulator/beam/erl_nif.c33
-rw-r--r--erts/emulator/beam/erl_nif.h11
-rw-r--r--erts/emulator/beam/erl_nif_api_funcs.h4
-rw-r--r--erts/emulator/beam/erl_process.c2
-rw-r--r--erts/emulator/beam/erl_process_dump.c5
-rw-r--r--erts/emulator/beam/erlang_lttng.h48
-rw-r--r--erts/emulator/beam/lttng-wrapper.h12
-rw-r--r--erts/emulator/beam/sys.h3
-rw-r--r--erts/emulator/drivers/common/inet_drv.c430
-rw-r--r--erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c11
-rw-r--r--erts/emulator/test/lttng_SUITE.erl218
-rw-r--r--erts/emulator/test/process_SUITE.erl6
-rw-r--r--erts/etc/common/heart.c18
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin72544 -> 76348 bytes
-rw-r--r--erts/preloaded/src/prim_inet.erl340
21 files changed, 827 insertions, 466 deletions
diff --git a/erts/configure.in b/erts/configure.in
index a34dfc6dbd..81ecad4f51 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -2116,7 +2116,7 @@ fi
dnl Need by run_erl.
AC_CHECK_FUNCS([openpty])
-AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h)
+AC_CHECK_HEADERS(net/if_dl.h ifaddrs.h netpacket/packet.h sys/un.h)
AC_CHECK_FUNCS([getifaddrs])
dnl Checks for variables in6addr_any and in6addr_loopback,
@@ -3858,15 +3858,15 @@ if test "$enable_lttng_test" = "yes" ; then
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM(
[#include <lttng/tracepoint.h>
- #define TRACEPOINT_PROVIDER com_ericsson_otp
+ #define TRACEPOINT_PROVIDER org_erlang_otp
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
dummy,
TP_ARGS(int, my_int),
TP_FIELDS(ctf_integer(int, my_int, my_int)))
#define TRACEPOINT_CREATE_PROBES
#define TRACEPOINT_DEFINE],
- [if(tracepoint_enabled(com_ericsson_otp,dummy)) do {} while(0)])],
+ [if(tracepoint_enabled(org_erlang_otp,dummy)) do {} while(0)])],
[AC_MSG_RESULT([yes])],
[AC_MSG_ERROR([no (available in lttng-ust v2.7)])])
if test "x$ac_cv_header_lttng_tracepoint_h" = "xyes" \
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml
index 4efd155b09..b2e2254a65 100644
--- a/erts/doc/src/erl_nif.xml
+++ b/erts/doc/src/erl_nif.xml
@@ -1101,15 +1101,6 @@ typedef enum {
Erlang operators <c>=:=</c> and
<c>=/=</c>.</p></desc>
</func>
- <func><name><ret>int</ret><nametext>enif_is_on_dirty_scheduler(ErlNifEnv* env)</nametext></name>
- <fsummary>Check to see if executing on a dirty scheduler thread</fsummary>
- <desc>
- <p>Check to see if the current NIF is executing on a dirty scheduler thread. If
- executing on a dirty scheduler thread true returned; otherwise false.</p>
- <p>This function can only be used from a NIF-calling thread, and with an
- environment corresponding to currently executing processes.</p>
- </desc>
- </func>
<func><name><ret>int</ret><nametext>enif_is_pid(ErlNifEnv* env, ERL_NIF_TERM term)</nametext></name>
<fsummary>Determine if a term is a pid</fsummary>
<desc><p>Return true if <c>term</c> is a pid.</p></desc>
@@ -1820,7 +1811,25 @@ enif_map_iterator_destroy(env, &amp;iter);
<desc><p>Same as <seealso marker="erl_driver#erl_drv_thread_self">erl_drv_thread_self</seealso>.
</p></desc>
</func>
-
+ <func><name><ret>int</ret><nametext>enif_thread_type(void)</nametext></name>
+ <fsummary>Determine type of current thread</fsummary>
+ <desc>
+ <p>Determine the type of currently executing thread. A positive value
+ indicates a scheduler thread while a negative value or zero indicates
+ another type of thread. Currently the following specific types exist
+ (which may be extended in the future):</p>
+ <taglist>
+ <tag><c>ERL_NIF_THR_UNDEFINED</c></tag>
+ <value><p>Undefined thread that is not a scheduler thread.</p></value>
+ <tag><c>ERL_NIF_THR_NORMAL_SCHEDULER</c></tag>
+ <value><p>A normal scheduler thread.</p></value>
+ <tag><c>ERL_NIF_THR_DIRTY_CPU_SCHEDULER</c></tag>
+ <value><p>A dirty CPU scheduler thread.</p></value>
+ <tag><c>ERL_NIF_THR_DIRTY_IO_SCHEDULER</c></tag>
+ <value><p>A dirty I/O scheduler thread.</p></value>
+ </taglist>
+ </desc>
+ </func>
<func>
<name><ret>ErlNifTime</ret><nametext>enif_time_offset(ErlNifTimeUnit time_unit)</nametext></name>
<fsummary>Get current Time Offset</fsummary>
diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c
index 0a59f8785c..4716460a6b 100644
--- a/erts/emulator/beam/beam_emu.c
+++ b/erts/emulator/beam/beam_emu.c
@@ -5318,10 +5318,14 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
ASSERT(BeamOp(op_call_nif) == (BeamInstr *) *I);
- if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p)
- && (ERTS_TRACE_FLAGS(c_p) & F_SENSITIVE) == 0) {
- c_p->fcalls = REDS_IN(c_p) = 0;
- }
+ /*
+ * Set fcalls even though we ignore it, so we don't
+ * confuse code accessing it...
+ */
+ if (ERTS_PROC_GET_SAVED_CALLS_BUF(c_p))
+ c_p->fcalls = 0;
+ else
+ c_p->fcalls = CONTEXT_REDS;
SWAPIN;
@@ -5341,7 +5345,7 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
NULL, fun_buf);
} else {
erts_snprintf(fun_buf, sizeof(DTRACE_CHARBUF_NAME(fun_buf)),
- "<unknown/%p>", next);
+ "<unknown/%p>", *I);
}
}
@@ -5351,8 +5355,10 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
}
{
- Eterm nif_bif_result;
- Eterm bif_nif_arity;
+#ifdef DEBUG
+ Eterm result;
+#endif
+ Eterm arity;
{
/*
@@ -5374,7 +5380,7 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
c_p->current = I-3; /* current and vbf set to please handle_error */
SWAPOUT;
PROCESS_MAIN_CHK_LOCKS(c_p);
- bif_nif_arity = I[-1];
+ arity = I[-1];
ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p);
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
@@ -5383,50 +5389,39 @@ void erts_dirty_process_main(ErtsSchedulerData *esdp)
NifF* fp = vbf = (NifF*) I[1];
struct enif_environment_t env;
ASSERT(!c_p->scheduler_data);
- erts_pre_dirty_nif(esdp, &env, c_p, (struct erl_module_nif*)I[2], NULL);
- nif_bif_result = (*fp)(&env, bif_nif_arity, reg);
- if (env.exception_thrown)
- nif_bif_result = THE_NON_VALUE;
+
+ erts_pre_dirty_nif(esdp, &env, c_p,
+ (struct erl_module_nif*)I[2], NULL);
+
+#ifdef DEBUG
+ result =
+#else
+ (void)
+#endif
+ (*fp)(&env, arity, reg);
+
erts_post_nif(&env);
+
+ ASSERT(!is_value(result));
+ ASSERT(c_p->freason == TRAP);
+ ASSERT(!(c_p->flags & F_HIBERNATE_SCHED));
+
PROCESS_MAIN_CHK_LOCKS(c_p);
+ ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
ERTS_VERIFY_UNUSED_TEMP_ALLOC(c_p);
ERTS_MSACC_SET_STATE_CACHED_M_X(ERTS_MSACC_STATE_EMULATOR);
- if (env.exiting) {
- ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
+ if (env.exiting)
goto do_dirty_schedule;
- }
ASSERT(!ERTS_PROC_IS_EXITING(c_p));
}
+
DTRACE_NIF_RETURN(c_p, (Eterm)I[-3], (Eterm)I[-2], (Uint)I[-1]);
- ERTS_SMP_REQ_PROC_MAIN_LOCK(c_p);
ERTS_HOLE_CHECK(c_p);
- if (ERTS_IS_GC_DESIRED(c_p)) {
- nif_bif_result = erts_gc_after_bif_call(c_p,
- nif_bif_result,
- reg, bif_nif_arity);
- }
- SWAPIN; /* There might have been a garbage collection. */
- if (is_value(nif_bif_result)) {
- r(0) = nif_bif_result;
- CHECK_TERM(r(0));
- I = c_p->cp;
- c_p->cp = 0;
- Goto(*I);
- } else if (c_p->freason == TRAP) {
- I = c_p->i;
- ASSERT(!(c_p->flags & F_HIBERNATE_SCHED));
- goto context_switch;
- }
- I = handle_error(c_p, c_p->cp, reg, vbf);
+ SWAPIN;
+ I = c_p->i;
+ goto context_switch;
}
}
- if (I == 0) {
- goto do_dirty_schedule;
- } else {
- ASSERT(!is_value(r(0)));
- SWAPIN;
- goto context_switch;
- }
#endif /* ERTS_DIRTY_SCHEDULERS */
}
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index 37f4e1de49..fefa9d8391 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -1411,7 +1411,7 @@ BIF_RETTYPE decode_packet_3(BIF_ALIST_3)
trunc_len = val;
goto next_option;
case am_line_delimiter:
- if (type == TCP_PB_LINE_LF && val >= 0 && val <= 255) {
+ if (type == TCP_PB_LINE_LF && val <= 255) {
delimiter = (char)val;
goto next_option;
}
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 74979f984a..074ac6d64e 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -95,7 +95,8 @@
/*
* The following symbols can be manipulated to "tune" the linear hash array
*/
-#define CHAIN_LEN 6 /* Medium bucket chain len */
+#define GROW_LIMIT(NACTIVE) ((NACTIVE)*2)
+#define SHRINK_LIMIT(NACTIVE) ((NACTIVE) / 2)
/* Number of slots per segment */
#define SEGSZ_EXP 8
@@ -463,7 +464,7 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle);
static ERTS_INLINE void try_shrink(DbTableHash* tb)
{
int nactive = NACTIVE(tb);
- if (nactive > SEGSZ && NITEMS(tb) < (nactive * CHAIN_LEN)
+ if (nactive > SEGSZ && NITEMS(tb) < SHRINK_LIMIT(nactive)
&& !IS_FIXED(tb)) {
shrink(tb, nactive);
}
@@ -670,8 +671,8 @@ int db_create_hash(Process *p, DbTable *tbl)
tb->nsegs = NSEG_1;
tb->nslots = SEGSZ;
- erts_smp_atomic_init_nob(&tb->is_resizing, 0);
#ifdef ERTS_SMP
+ erts_smp_atomic_init_nob(&tb->is_resizing, 0);
if (tb->common.type & DB_FINE_LOCKED) {
erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
int i;
@@ -862,7 +863,7 @@ Lnew:
WUNLOCK_HASH(lck);
{
int nactive = NACTIVE(tb);
- if (nitems > nactive * (CHAIN_LEN+1) && !IS_FIXED(tb)) {
+ if (nitems > GROW_LIMIT(nactive) && !IS_FIXED(tb)) {
grow(tb, nactive);
}
}
@@ -2250,12 +2251,12 @@ static int db_free_table_continue_hash(DbTable *tbl)
done /= 2;
while(tb->nslots != 0) {
- free_seg(tb, 1);
+ done += 1 + SEGSZ/64 + free_seg(tb, 1);
/*
* If we have done enough work, get out here.
*/
- if (++done >= (DELETE_RECORD_LIMIT / CHAIN_LEN / SEGSZ)) {
+ if (done >= DELETE_RECORD_LIMIT) {
return 0; /* Not done */
}
}
@@ -2604,23 +2605,22 @@ static Eterm build_term_list(Process* p, HashDbTerm* ptr1, HashDbTerm* ptr2,
static ERTS_INLINE int
begin_resizing(DbTableHash* tb)
{
+#ifdef ERTS_SMP
if (DB_USING_FINE_LOCKING(tb))
- return !erts_smp_atomic_xchg_acqb(&tb->is_resizing, 1);
- else {
- if (erts_smp_atomic_read_nob(&tb->is_resizing))
- return 0;
- erts_smp_atomic_set_nob(&tb->is_resizing, 1);
- return 1;
- }
+ return !erts_atomic_xchg_acqb(&tb->is_resizing, 1);
+ else
+ ERTS_LC_ASSERT(erts_lc_rwmtx_is_rwlocked(&tb->common.rwlock));
+#endif
+ return 1;
}
static ERTS_INLINE void
done_resizing(DbTableHash* tb)
{
+#ifdef ERTS_SMP
if (DB_USING_FINE_LOCKING(tb))
- erts_smp_atomic_set_relb(&tb->is_resizing, 0);
- else
- erts_smp_atomic_set_nob(&tb->is_resizing, 0);
+ erts_atomic_set_relb(&tb->is_resizing, 0);
+#endif
}
/* Grow table with one new bucket.
@@ -2871,7 +2871,7 @@ db_lookup_dbterm_hash(Process *p, DbTable *tbl, Eterm key, Eterm obj,
int nitems = erts_smp_atomic_inc_read_nob(&tb->common.nitems);
int nactive = NACTIVE(tb);
- if (nitems > nactive * (CHAIN_LEN + 1) && !IS_FIXED(tb)) {
+ if (nitems > GROW_LIMIT(nactive) && !IS_FIXED(tb)) {
grow(tb, nactive);
}
}
diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h
index e654363cd5..081ff8fafc 100644
--- a/erts/emulator/beam/erl_db_hash.h
+++ b/erts/emulator/beam/erl_db_hash.h
@@ -60,8 +60,8 @@ typedef struct db_table_hash {
/* List of slots where elements have been deleted while table was fixed */
erts_smp_atomic_t fixdel; /* (FixedDeletion*) */
erts_smp_atomic_t nactive; /* Number of "active" slots */
- erts_smp_atomic_t is_resizing; /* grow/shrink in progress */
#ifdef ERTS_SMP
+ erts_smp_atomic_t is_resizing; /* grow/shrink in progress */
DbTableHashFineLocks* locks;
#endif
#ifdef VALGRIND
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index f1c35cd5a5..039f97ef43 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -803,19 +803,13 @@ ERL_NIF_TERM enif_make_copy(ErlNifEnv* dst_env, ERL_NIF_TERM src_term)
{
Uint sz;
Eterm* hp;
-#ifdef SHCOPY
- erts_shcopy_t info;
- INITIALIZE_SHCOPY(info);
- sz = copy_shared_calculate(src_term, &info);
- hp = alloc_heap(dst_env, sz);
- src_term = copy_shared_perform(src_term, sz, &info, &hp, &MSO(dst_env->proc));
- DESTROY_SHCOPY(info);
- return src_term;
-#else
+ /*
+ * No preserved sharing allowed as long as literals are also preserved.
+ * Process independent environment can not be reached by purge.
+ */
sz = size_object(src_term);
hp = alloc_heap(dst_env, sz);
return copy_struct(src_term, sz, &hp, &MSO(dst_env->proc));
-#endif
}
@@ -2664,18 +2658,21 @@ done:
}
int
-enif_is_on_dirty_scheduler(ErlNifEnv* env)
+enif_thread_type(void)
{
- int scheduler;
- Process *c_p;
+ ErtsSchedulerData *esdp = erts_get_scheduler_data();
- execution_state(env, &c_p, &scheduler);
+ if (!esdp)
+ return ERL_NIF_THR_UNDEFINED;
+
+ if (!ERTS_SCHEDULER_IS_DIRTY(esdp))
+ return ERL_NIF_THR_NORMAL_SCHEDULER;
- if (!c_p || !scheduler)
- erts_exit(ERTS_ABORT_EXIT, "enif_is_on_dirty_scheduler: "
- "Invalid env");
+ if (ERTS_SCHEDULER_IS_DIRTY_CPU(esdp))
+ return ERL_NIF_THR_DIRTY_CPU_SCHEDULER;
- return scheduler < 0;
+ ASSERT(ERTS_SCHEDULER_IS_DIRTY_IO(esdp));
+ return ERL_NIF_THR_DIRTY_IO_SCHEDULER;
}
/* Maps */
diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h
index da7a754757..494971e118 100644
--- a/erts/emulator/beam/erl_nif.h
+++ b/erts/emulator/beam/erl_nif.h
@@ -209,6 +209,17 @@ typedef enum {
ERL_NIF_BIN2TERM_SAFE = 0x20000000
} ErlNifBinaryToTerm;
+/*
+ * Return values from enif_thread_type(). Negative values
+ * reserved for specific types of non-scheduler threads.
+ * Positive values reserved for scheduler thread types.
+ */
+
+#define ERL_NIF_THR_UNDEFINED 0
+#define ERL_NIF_THR_NORMAL_SCHEDULER 1
+#define ERL_NIF_THR_DIRTY_CPU_SCHEDULER 2
+#define ERL_NIF_THR_DIRTY_IO_SCHEDULER 3
+
#if (defined(__WIN32__) || defined(_WIN32) || defined(_WIN32_))
# define ERL_NIF_API_FUNC_DECL(RET_TYPE, NAME, ARGS) RET_TYPE (*NAME) ARGS
typedef struct {
diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h
index b211ab4b16..9a8f216773 100644
--- a/erts/emulator/beam/erl_nif_api_funcs.h
+++ b/erts/emulator/beam/erl_nif_api_funcs.h
@@ -173,7 +173,7 @@ ERL_NIF_API_FUNC_DECL(int, enif_get_local_port, (ErlNifEnv* env, ERL_NIF_TERM, E
ERL_NIF_API_FUNC_DECL(int, enif_term_to_binary, (ErlNifEnv *env, ERL_NIF_TERM term, ErlNifBinary *bin));
ERL_NIF_API_FUNC_DECL(size_t, enif_binary_to_term, (ErlNifEnv *env, const unsigned char* data, size_t sz, ERL_NIF_TERM *term, unsigned int opts));
ERL_NIF_API_FUNC_DECL(int, enif_port_command, (ErlNifEnv *env, const ErlNifPort* to_port, ErlNifEnv *msg_env, ERL_NIF_TERM msg));
-ERL_NIF_API_FUNC_DECL(int,enif_is_on_dirty_scheduler,(ErlNifEnv*));
+ERL_NIF_API_FUNC_DECL(int,enif_thread_type,(void));
ERL_NIF_API_FUNC_DECL(int,enif_snprintf,(char * buffer, size_t size, const char *format, ...));
/*
@@ -330,7 +330,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_snprintf,(char * buffer, size_t size, const char
# define enif_term_to_binary ERL_NIF_API_FUNC_MACRO(enif_term_to_binary)
# define enif_binary_to_term ERL_NIF_API_FUNC_MACRO(enif_binary_to_term)
# define enif_port_command ERL_NIF_API_FUNC_MACRO(enif_port_command)
-# define enif_is_on_dirty_scheduler ERL_NIF_API_FUNC_MACRO(enif_is_on_dirty_scheduler)
+# define enif_thread_type ERL_NIF_API_FUNC_MACRO(enif_thread_type)
# define enif_snprintf ERL_NIF_API_FUNC_MACRO(enif_snprintf)
/*
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index c0b1d7246c..5193be85b4 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -10082,7 +10082,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
}
}
- if (ERTS_IS_GC_DESIRED(p)) {
+ if (ERTS_IS_GC_DESIRED(p) && !ERTS_SCHEDULER_IS_DIRTY_IO(esdp)) {
if (!(state & ERTS_PSFLG_EXITING) && !(p->flags & (F_DELAY_GC|F_DISABLE_GC))) {
int cost = scheduler_gc_proc(p, reds);
calls += cost;
diff --git a/erts/emulator/beam/erl_process_dump.c b/erts/emulator/beam/erl_process_dump.c
index eeaa9a569c..a70dfb8e73 100644
--- a/erts/emulator/beam/erl_process_dump.c
+++ b/erts/emulator/beam/erl_process_dump.c
@@ -560,6 +560,11 @@ dump_externally(int to, void *to_arg, Eterm term)
}
}
+ /* Do not handle maps */
+ if (is_map(term)) {
+ term = am_undefined;
+ }
+
s = p = sbuf;
erts_encode_ext(term, &p);
erts_print(to, to_arg, "E%X:", p-s);
diff --git a/erts/emulator/beam/erlang_lttng.h b/erts/emulator/beam/erlang_lttng.h
index 12f68e477b..4e869671f7 100644
--- a/erts/emulator/beam/erlang_lttng.h
+++ b/erts/emulator/beam/erlang_lttng.h
@@ -20,7 +20,7 @@
#ifdef USE_LTTNG
#undef TRACEPOINT_PROVIDER
-#define TRACEPOINT_PROVIDER com_ericsson_otp
+#define TRACEPOINT_PROVIDER org_erlang_otp
#undef TRACEPOINT_INCLUDE
#define TRACEPOINT_INCLUDE "erlang_lttng.h"
@@ -33,7 +33,7 @@
/* Schedulers */
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
scheduler_poll,
TP_ARGS(
int, id,
@@ -62,7 +62,7 @@ typedef struct {
/* Port and Driver Scheduling */
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_start,
TP_ARGS(
char*, pid,
@@ -77,7 +77,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_init,
TP_ARGS(
char*, driver,
@@ -94,7 +94,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_outputv,
TP_ARGS(
char*, pid,
@@ -111,7 +111,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_output,
TP_ARGS(
char*, pid,
@@ -128,7 +128,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_ready_input,
TP_ARGS(
char*, pid,
@@ -143,7 +143,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_ready_output,
TP_ARGS(
char*, pid,
@@ -158,7 +158,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_event,
TP_ARGS(
char*, pid,
@@ -173,7 +173,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_timeout,
TP_ARGS(
char*, pid,
@@ -188,7 +188,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_stop_select,
TP_ARGS(
char*, driver
@@ -199,7 +199,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_flush,
TP_ARGS(
char*, pid,
@@ -214,7 +214,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_stop,
TP_ARGS(
char*, pid,
@@ -229,7 +229,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_process_exit,
TP_ARGS(
char*, pid,
@@ -244,7 +244,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_ready_async,
TP_ARGS(
char*, pid,
@@ -259,7 +259,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_finish,
TP_ARGS(
char*, driver
@@ -270,7 +270,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_call,
TP_ARGS(
char*, pid,
@@ -289,7 +289,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
driver_control,
TP_ARGS(
char*, pid,
@@ -310,7 +310,7 @@ TRACEPOINT_EVENT(
/* Async pool */
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
aio_pool_get,
TP_ARGS(
char*, port,
@@ -323,7 +323,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
aio_pool_put,
TP_ARGS(
char*, port,
@@ -339,7 +339,7 @@ TRACEPOINT_EVENT(
/* Memory Allocator */
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
carrier_create,
TP_ARGS(
const char*, type,
@@ -365,7 +365,7 @@ TRACEPOINT_EVENT(
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
carrier_destroy,
TP_ARGS(
const char*, type,
@@ -390,7 +390,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
carrier_pool_put,
TP_ARGS(
const char*, name,
@@ -405,7 +405,7 @@ TRACEPOINT_EVENT(
)
TRACEPOINT_EVENT(
- com_ericsson_otp,
+ org_erlang_otp,
carrier_pool_get,
TP_ARGS(
const char*, name,
diff --git a/erts/emulator/beam/lttng-wrapper.h b/erts/emulator/beam/lttng-wrapper.h
index 294872c365..0bc75c1552 100644
--- a/erts/emulator/beam/lttng-wrapper.h
+++ b/erts/emulator/beam/lttng-wrapper.h
@@ -77,23 +77,23 @@
(RQ)->scheduler->no
#define LTTNG_ENABLED(Name) \
- tracepoint_enabled(com_ericsson_otp, Name)
+ tracepoint_enabled(org_erlang_otp, Name)
/* include a special LTTNG_DO for do_tracepoint ? */
#define LTTNG1(Name, Arg1) \
- tracepoint(com_ericsson_otp, Name, (Arg1))
+ tracepoint(org_erlang_otp, Name, (Arg1))
#define LTTNG2(Name, Arg1, Arg2) \
- tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2))
+ tracepoint(org_erlang_otp, Name, (Arg1), (Arg2))
#define LTTNG3(Name, Arg1, Arg2, Arg3) \
- tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3))
+ tracepoint(org_erlang_otp, Name, (Arg1), (Arg2), (Arg3))
#define LTTNG4(Name, Arg1, Arg2, Arg3, Arg4) \
- tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4))
+ tracepoint(org_erlang_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4))
#define LTTNG5(Name, Arg1, Arg2, Arg3, Arg4, Arg5) \
- tracepoint(com_ericsson_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5))
+ tracepoint(org_erlang_otp, Name, (Arg1), (Arg2), (Arg3), (Arg4), (Arg5))
#else /* USE_LTTNG */
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index 9a205d50d3..dfe82cab44 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -154,8 +154,9 @@ typedef ERTS_SYS_FD_TYPE ErtsSysFdType;
# define ERTS_WRITE_UNLIKELY(X) X
#endif
+/* clang may have too low __GNUC__ versions but can handle it */
#ifdef __GNUC__
-# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5)
+# if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 5) || defined(__clang__)
# define ERTS_DECLARE_DUMMY(X) X __attribute__ ((unused))
# else
# define ERTS_DECLARE_DUMMY(X) X
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index e87d141ddb..93ea9f5dcb 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -34,6 +34,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <stddef.h>
#include <ctype.h>
#include <sys/types.h>
#include <errno.h>
@@ -58,6 +59,9 @@
#ifdef HAVE_NETPACKET_PACKET_H
#include <netpacket/packet.h>
#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
/* All platforms fail on malloc errors. */
#define FATAL_MALLOC
@@ -573,7 +577,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#ifdef HAVE_SOCKLEN_T
# define SOCKLEN_T socklen_t
#else
-# define SOCKLEN_T int
+# define SOCKLEN_T size_t
#endif
#include "packet_parser.h"
@@ -587,6 +591,22 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
(((unsigned char*) (s))[1] << 8) | \
(((unsigned char*) (s))[0]))
+/* 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;
+}
+
+/* Check that some character in the buffer != '\0' */
+static int is_nonzero(const char *s, size_t n)
+{
+ size_t i;
+ for (i = 0; i < n; i++) if (s[i] != '\0') return !0;
+ return 0;
+}
#ifdef VALGRIND
# include <valgrind/memcheck.h>
@@ -607,10 +627,13 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
*/
/* general address encode/decode tag */
+#define INET_AF_UNSPEC 0
#define INET_AF_INET 1
#define INET_AF_INET6 2
#define INET_AF_ANY 3 /* INADDR_ANY or IN6ADDR_ANY_INIT */
#define INET_AF_LOOPBACK 4 /* INADDR_LOOPBACK or IN6ADDR_LOOPBACK_INIT */
+#define INET_AF_LOCAL 5
+#define INET_AF_UNDEFINED 6 /* Unknown */
/* open and INET_REQ_GETTYPE enumeration */
#define INET_TYPE_STREAM 1
@@ -633,7 +656,7 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
/* INET_REQ_GETSTATUS enumeration */
#define INET_F_OPEN 0x0001
-#define INET_F_BOUND 0x0002
+/* INET_F_BOUND removed - renumber when there comes a bigger rewrite */
#define INET_F_ACTIVE 0x0004
#define INET_F_LISTEN 0x0008
#define INET_F_CON 0x0010
@@ -831,19 +854,15 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
#define INET_STATE_CLOSED (0)
#define INET_STATE_OPEN (INET_F_OPEN)
-#define INET_STATE_BOUND (INET_STATE_OPEN | INET_F_BOUND)
-#define INET_STATE_CONNECTED (INET_STATE_BOUND | INET_F_ACTIVE)
-#define INET_STATE_LISTENING (INET_STATE_BOUND | INET_F_LISTEN)
-#define INET_STATE_CONNECTING (INET_STATE_BOUND | INET_F_CON)
+#define INET_STATE_CONNECTED (INET_STATE_OPEN | INET_F_ACTIVE)
+#define INET_STATE_LISTENING (INET_STATE_OPEN | INET_F_LISTEN)
+#define INET_STATE_CONNECTING (INET_STATE_OPEN | INET_F_CON)
#define INET_STATE_ACCEPTING (INET_STATE_LISTENING | INET_F_ACC)
#define INET_STATE_MULTI_ACCEPTING (INET_STATE_ACCEPTING | INET_F_MULTI_CLIENT)
#define IS_OPEN(d) \
(((d)->state & INET_F_OPEN) == INET_F_OPEN)
-#define IS_BOUND(d) \
- (((d)->state & INET_F_BOUND) == INET_F_BOUND)
-
#define IS_CONNECTED(d) \
(((d)->state & INET_STATE_CONNECTED) == INET_STATE_CONNECTED)
@@ -896,19 +915,35 @@ typedef union {
#ifdef HAVE_IN6
struct sockaddr_in6 sai6;
#endif
+#ifdef HAVE_SYS_UN_H
+ struct sockaddr_un sal;
+#endif
} inet_address;
-/* for AF_INET & AF_INET6 */
-#define inet_address_port(x) ((x)->sai.sin_port)
+#define inet_address_port(x) \
+ ((((x)->sai.sin_family == AF_INET) || \
+ ((x)->sai.sin_family == AF_INET6)) ? \
+ ((x)->sai.sin_port) : -1)
+
+#ifdef HAVE_SYS_UN_H
+#define localaddrlen(data) \
+ ((((unsigned char*)(data))[0] == INET_AF_LOCAL) ? \
+ (1 + 1 + ((unsigned char*)(data))[1]) : 1)
+#else
+#define localaddrlen(data) (1)
+#endif
#if defined(HAVE_IN6) && defined(AF_INET6)
-#define addrlen(family) \
- ((family == AF_INET) ? sizeof(struct in_addr) : \
- ((family == AF_INET6) ? sizeof(struct in6_addr) : 0))
+#define addrlen(data) \
+ ((((unsigned char*)(data))[0] == INET_AF_INET) ? \
+ (1 + 2 + 4) : \
+ ((((unsigned char*)(data))[0] == INET_AF_INET6) ? \
+ (1 + 2 + 16) : localaddrlen(data)))
#else
-#define addrlen(family) \
- ((family == AF_INET) ? sizeof(struct in_addr) : 0)
+#define addrlen(data) \
+ ((((unsigned char*)(data))[0] == INET_AF_INET) ? \
+ (1 + 2 + 4) : localaddrlen(data))
#endif
typedef struct _multi_timer_data {
@@ -999,8 +1034,10 @@ typedef struct {
inet_address peer_addr; /* fake peer address */
inet_address name_addr; /* fake local address */
- inet_address* peer_ptr; /* fake peername or NULL */
- inet_address* name_ptr; /* fake sockname or NULL */
+ inet_address* peer_ptr; /* fake peername or NULL */
+ inet_address* name_ptr; /* fake sockname or NULL */
+ SOCKLEN_T peer_addr_len; /* fake peername size */
+ SOCKLEN_T name_addr_len; /* fake sockname size */
int bufsz; /* minimum buffer constraint */
unsigned int hsz; /* the list header size, -1 is large !!! */
@@ -1246,6 +1283,8 @@ static int async_ref = 0; /* async reference id generator */
} while (0)
static ErlDrvTermData am_ok;
+static ErlDrvTermData am_undefined;
+static ErlDrvTermData am_unspec;
static ErlDrvTermData am_tcp;
static ErlDrvTermData am_error;
static ErlDrvTermData am_einval;
@@ -1262,6 +1301,7 @@ static ErlDrvTermData am_ssl_tls;
static ErlDrvTermData am_udp;
static ErlDrvTermData am_udp_passive;
static ErlDrvTermData am_udp_error;
+static ErlDrvTermData am_local;
#endif
#ifdef HAVE_SCTP
static ErlDrvTermData am_sctp;
@@ -1471,40 +1511,67 @@ static void *realloc_wrapper(void *current, ErlDrvSizeT size){
#endif
#ifdef HAVE_UDP
-static int load_ip_port(ErlDrvTermData* spec, int i, char* buf)
-{
- spec[i++] = ERL_DRV_INT;
- spec[i++] = (ErlDrvTermData) get_int16(buf);
- return i;
-}
-
-static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf)
+static int load_address(ErlDrvTermData* spec, int i, char* buf)
{
int n;
- if (family == AF_INET) {
- for (n = 0; n < 4; n++) {
+ switch (*buf++) { /* Family */
+ case INET_AF_INET: {
+ for (n = 2; n < 2+4; n++) {
spec[i++] = ERL_DRV_INT;
spec[i++] = (ErlDrvTermData) ((unsigned char)buf[n]);
}
spec[i++] = ERL_DRV_TUPLE;
spec[i++] = 4;
+ spec[i++] = ERL_DRV_INT;
+ spec[i++] = (ErlDrvTermData) get_int16(buf);
+ break;
}
#if defined(HAVE_IN6) && defined(AF_INET6)
- else if (family == AF_INET6) {
- for (n = 0; n < 16; n += 2) {
+ case INET_AF_INET6: {
+ for (n = 2; n < 2+16; n += 2) {
spec[i++] = ERL_DRV_INT;
spec[i++] = (ErlDrvTermData) get_int16(buf+n);
}
spec[i++] = ERL_DRV_TUPLE;
spec[i++] = 8;
+ spec[i++] = ERL_DRV_INT;
+ spec[i++] = (ErlDrvTermData) get_int16(buf);
+ break;
}
#endif
- else {
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL: {
+ int len = *(unsigned char*)buf++;
+ i = LOAD_ATOM(spec, i, am_local);
+ i = LOAD_BUF2BINARY(spec, i, buf, len);
+ spec[i++] = ERL_DRV_TUPLE;
+ spec[i++] = 2;
+ spec[i++] = ERL_DRV_INT;
+ spec[i++] = 0;
+ break;
+ }
+#endif
+ case INET_AF_UNSPEC: {
+ i = LOAD_ATOM(spec, i, am_unspec);
+ i = LOAD_BUF2BINARY(spec, i, buf, 0);
spec[i++] = ERL_DRV_TUPLE;
+ spec[i++] = 2;
+ spec[i++] = ERL_DRV_INT;
spec[i++] = 0;
+ break;
+ }
+ default: { /* INET_AF_UNDEFINED */
+ i = LOAD_ATOM(spec, i, am_undefined);
+ i = LOAD_BUF2BINARY(spec, i, buf, 0);
+ spec[i++] = ERL_DRV_TUPLE;
+ spec[i++] = 2;
+ spec[i++] = ERL_DRV_INT;
+ spec[i++] = 0;
+ break;
+ }
}
return i;
-}
+ }
#endif
@@ -1512,10 +1579,13 @@ static int load_ip_address(ErlDrvTermData* spec, int i, int family, char* buf)
/* For SCTP, we often need to return {IP, Port} tuples: */
static int inet_get_address(char* dst, inet_address* src, unsigned int* len);
-#define LOAD_IP_AND_PORT_CNT \
+/* Max of {{int()*8},int()} | {{int()*4},int()} |
+ * {{'local',binary()},int()}
+ */
+#define LOAD_INET_GET_ADDRESS_CNT \
(8*LOAD_INT_CNT + LOAD_TUPLE_CNT + LOAD_INT_CNT + LOAD_TUPLE_CNT)
-static int load_ip_and_port
+static int load_inet_get_address
(ErlDrvTermData* spec, int i, inet_descriptor* desc,
struct sockaddr_storage* addr)
{
@@ -1533,8 +1603,7 @@ static int load_ip_and_port
/* NB: the following functions are safe to use, as they create tuples
of copied Ints on the "spec", and do not install any String pts --
a ptr to "abuf" would be dangling upon exiting this function: */
- i = load_ip_address(spec, i, desc->sfamily, abuf+3);
- i = load_ip_port (spec, i, abuf+1);
+ i = load_address(spec, i, abuf); /* IP,Port | Family,Addr */
i = LOAD_TUPLE (spec, i, 2);
return i;
}
@@ -2226,7 +2295,6 @@ static ErlDrvTermData am_http_error;
static ErlDrvTermData am_abs_path;
static ErlDrvTermData am_absoluteURI;
static ErlDrvTermData am_star;
-static ErlDrvTermData am_undefined;
static ErlDrvTermData am_http;
static ErlDrvTermData am_https;
static ErlDrvTermData am_scheme;
@@ -2917,7 +2985,7 @@ static int sctp_parse_async_event
ASSERT(sptr->spc_length <= sz); /* No buffer overrun */
i = LOAD_ATOM (spec, i, am_sctp_paddr_change);
- i = load_ip_and_port(spec, i, desc, &sptr->spc_aaddr);
+ i = load_inet_get_address(spec, i, desc, &sptr->spc_aaddr);
switch (sptr->spc_state)
{
@@ -3344,10 +3412,11 @@ static int tcp_error_message(tcp_descriptor* desc, int err)
#ifdef HAVE_UDP
/*
** active mode message:
-** {udp, S, IP, Port, [H1,...Hsz | Data]} or
-** {sctp, S, IP, Port, {[AncilData], Event_or_Data}}
+** {udp, S, IP, Port, [H1,...Hsz | Data]} or
+** {sctp, S, IP, Port, {[AncilData], Event_or_Data}}
** where
** [H1,...,HSz] are msg headers (without IP/Port, UDP only),
+** [AddrLen, H2,...,HSz] are msg headers for UDP AF_UNIX only
** Data : List() | Binary()
*/
static int packet_binary_message
@@ -3357,6 +3426,7 @@ static int packet_binary_message
ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN];
int i = 0;
int alen;
+ char* data = bin->orig_bytes+offs;
DEBUGF(("packet_binary_message(%ld): len = %d\r\n",
(long)desc->port, len));
@@ -3366,13 +3436,12 @@ static int packet_binary_message
i = LOAD_ATOM(spec, i, am_udp ); /* UDP only */
# endif
i = LOAD_PORT(spec, i, desc->dport); /* S */
-
- alen = addrlen(desc->sfamily);
- i = load_ip_address(spec, i, desc->sfamily, bin->orig_bytes+offs+3);
- i = load_ip_port(spec, i, bin->orig_bytes+offs+1); /* IP, Port */
-
- offs += (alen + 3);
- len -= (alen + 3);
+
+ alen = addrlen(data);
+ i = load_address(spec, i, data); /* IP,Port | Family,Addr */
+
+ offs += alen;
+ len -= alen;
# ifdef HAVE_SCTP
if (!IS_SCTP(desc))
@@ -3759,6 +3828,8 @@ static int inet_init()
# endif
INIT_ATOM(ok);
+ INIT_ATOM(undefined);
+ INIT_ATOM(unspec);
INIT_ATOM(tcp);
#ifdef HAVE_UDP
INIT_ATOM(udp);
@@ -3775,6 +3846,7 @@ static int inet_init()
#ifdef HAVE_UDP
INIT_ATOM(udp_passive);
INIT_ATOM(udp_error);
+ INIT_ATOM(local);
#endif
INIT_ATOM(empty_out_q);
INIT_ATOM(ssl_tls);
@@ -3787,7 +3859,6 @@ static int inet_init()
INIT_ATOM(abs_path);
INIT_ATOM(absoluteURI);
am_star = driver_mk_atom("*");
- INIT_ATOM(undefined);
INIT_ATOM(http);
INIT_ATOM(https);
INIT_ATOM(scheme);
@@ -3883,7 +3954,7 @@ static int inet_init()
/*
-** Set a inaddr structure:
+** Set an inaddr structure:
** src = [P1,P0,X1,X2,.....]
** dst points to a structure large enugh to keep any kind
** of inaddr.
@@ -3923,6 +3994,18 @@ static char* inet_set_address(int family, inet_address* dst,
return src + 2+16;
}
#endif
+#ifdef HAVE_SYS_UN_H
+ else if ((family == AF_UNIX) && (*len >= 1)) {
+ int n = *((unsigned char*)src);
+ if ((*len < 1+n) || (sizeof(dst->sal.sun_path) < n+1))
+ return NULL;
+ sys_memzero((char*)dst, sizeof(struct sockaddr_un));
+ dst->sal.sun_family = family;
+ sys_memcpy(dst->sal.sun_path, src+1, n);
+ *len = offsetof(struct sockaddr_un, sun_path) + n;
+ return src + 1 + n;
+ }
+#endif
return NULL;
}
@@ -3931,7 +4014,7 @@ static char* inet_set_address(int family, inet_address* dst,
** or from argument if source data specifies constant address.
**
** src = [TAG,P1,P0] when TAG = INET_AF_ANY | INET_AF_LOOPBACK
-** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6
+** src = [TAG,P1,P0,X1,X2,...] when TAG = INET_AF_INET | INET_AF_INET6 | INET_AF_LOCAL
*/
static char *inet_set_faddress(int family, inet_address* dst,
char *src, ErlDrvSizeT* len) {
@@ -3949,6 +4032,12 @@ static char *inet_set_faddress(int family, inet_address* dst,
family = AF_INET6;
break;
# endif
+# ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL: {
+ family = AF_UNIX;
+ break;
+ }
+# endif
case INET_AF_ANY:
case INET_AF_LOOPBACK: {
int port;
@@ -4012,7 +4101,6 @@ static char *inet_set_faddress(int family, inet_address* dst,
return inet_set_address(family, dst, src, len);
}
-
/* Get a inaddr structure
** src = inaddr structure
** *len is the lenght of structure
@@ -4023,6 +4111,7 @@ static char *inet_set_faddress(int family, inet_address* dst,
*/
static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
{
+ /* Compare the code with inet_address_to_erlang() */
int family;
short port;
@@ -4045,6 +4134,36 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
return 0;
}
#endif
+#ifdef HAVE_SYS_UN_H
+ else if (family == AF_UNIX) {
+ size_t n, m;
+ if (*len < offsetof(struct sockaddr_un, sun_path)) return -1;
+ n = *len - offsetof(struct sockaddr_un, sun_path);
+ if (255 < n) return -1;
+ /* Portability fix: 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 abstract socket address
+ * nonportable extension.
+ */
+ m = my_strnlen(src->sal.sun_path, n);
+ if ((m == 0) && is_nonzero(src->sal.sun_path, n))
+ m = n;
+ dst[0] = INET_AF_LOCAL;
+ dst[1] = (char) ((unsigned char) m);
+ sys_memcpy(dst+2, src->sal.sun_path, m);
+ *len = 1 + 1 + m;
+ return 0;
+ }
+#endif
+ else if (family == AF_UNSPEC) {
+ dst[0] = INET_AF_UNSPEC;
+ *len = 1;
+ }
+ else {
+ dst[0] = INET_AF_UNDEFINED;
+ *len = 1;
+ }
return -1;
}
@@ -4053,7 +4172,9 @@ static int inet_get_address(char* dst, inet_address* src, unsigned int* len)
** according to the size of the current,
** and return the resulting encoded size
*/
-static int inet_address_to_erlang(char *dst, inet_address **src) {
+static int
+inet_address_to_erlang(char *dst, inet_address **src, SOCKLEN_T sz) {
+ /* Compare the code with inet_get_address() */
short port;
switch ((*src)->sa.sa_family) {
@@ -4078,6 +4199,30 @@ static int inet_address_to_erlang(char *dst, inet_address **src) {
(*src) = (inet_address *) (&(*src)->sai6 + 1);
return 1 + 2 + 16;
#endif
+#ifdef HAVE_SYS_UN_H
+ case AF_UNIX: {
+ size_t n, m;
+ if (sz < offsetof(struct sockaddr_un, sun_path)) return -1;
+ n = sz - offsetof(struct sockaddr_un, sun_path);
+ if (255 < n) return -1;
+ /* Portability fix: 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 abstract socket address
+ * nonportable extension.
+ */
+ m = my_strnlen((*src)->sal.sun_path, n);
+ if ((m == 0) && is_nonzero((*src)->sal.sun_path, n))
+ m = n;
+ if (dst) {
+ dst[0] = INET_AF_LOCAL;
+ dst[1] = (char) ((unsigned char) m);
+ sys_memcpy(dst+2, (*src)->sal.sun_path, m);
+ }
+ (*src) = (inet_address *) (&(*src)->sal + 1);
+ return 1 + 1 + m;
+ }
+#endif
default:
return -1;
}
@@ -4086,7 +4231,7 @@ static int inet_address_to_erlang(char *dst, inet_address **src) {
/* Encode n encoded addresses from addrs in the result buffer
*/
static ErlDrvSizeT reply_inet_addrs
-(int n, inet_address *addrs, char **rbuf, ErlDrvSizeT rsize) {
+(int n, inet_address *addrs, char **rbuf, ErlDrvSizeT rsize, SOCKLEN_T sz) {
inet_address *ia;
int i, s;
ErlDrvSizeT rlen;
@@ -4094,11 +4239,19 @@ static ErlDrvSizeT reply_inet_addrs
if (IS_SOCKET_ERROR(n)) return ctl_error(sock_errno(), rbuf, rsize);
if (n == 0) return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
+ /* The sz argument is only used when we have got an actual size
+ * of addrs[0] from e.g getsockname() and then n == 1
+ * so we will loop over 1 element below. Otherwise sz
+ * would be expected to differ between addresses but that
+ * can only happen for AF_UNIX and we will only be called with
+ * n > 1 for SCTP and that will never (?) happen with AF_UNIX
+ */
+
/* Calculate result length */
rlen = 1;
ia = addrs;
for (i = 0; i < n; i++) {
- s = inet_address_to_erlang(NULL, &ia);
+ s = inet_address_to_erlang(NULL, &ia, sz);
if (s < 0) break;
rlen += s;
}
@@ -4109,7 +4262,7 @@ static ErlDrvSizeT reply_inet_addrs
rlen = 1;
ia = addrs;
for (i = 0; i < n; i++) {
- s = inet_address_to_erlang((*rbuf)+rlen, &ia);
+ s = inet_address_to_erlang((*rbuf)+rlen, &ia, sz);
if (s < 0) break;
rlen += s;
}
@@ -4180,6 +4333,7 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
char** rbuf, ErlDrvSizeT rsize)
{
int save_errno;
+ int protocol;
#ifdef HAVE_SETNS
int current_ns, new_ns;
current_ns = new_ns = 0;
@@ -4218,7 +4372,11 @@ static ErlDrvSSizeT inet_ctl_open(inet_descriptor* desc, int domain, int type,
}
}
#endif
- if ((desc->s = sock_open(domain, type, desc->sprotocol)) == INVALID_SOCKET)
+ protocol = desc->sprotocol;
+#ifdef HAVE_SYS_UN_H
+ if (domain == AF_UNIX) protocol = 0;
+#endif
+ if ((desc->s = sock_open(domain, type, protocol)) == INVALID_SOCKET)
save_errno = sock_errno();
#ifdef HAVE_SETNS
if (desc->netns != NULL) {
@@ -4272,10 +4430,12 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
char** rbuf, ErlDrvSizeT rsize)
{
inet_address name;
- unsigned int sz = sizeof(name);
+ unsigned int sz;
if (bound) {
/* check that it is a socket and that the socket is bound */
+ sz = sizeof(name);
+ sys_memzero((char *) &name, sz);
if (IS_SOCKET_ERROR(sock_name(s, (struct sockaddr*) &name, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
if (name.sa.sa_family != domain)
@@ -4290,10 +4450,7 @@ static ErlDrvSSizeT inet_ctl_fdopen(inet_descriptor* desc, int domain, int type,
driver_select(desc->port, desc->event, ERL_DRV_READ, 1);
#endif
- if (bound)
- desc->state = INET_STATE_BOUND;
- else
- desc->state = INET_STATE_OPEN;
+ desc->state = INET_STATE_OPEN;
if (type == SOCK_STREAM) { /* check if connected */
sz = sizeof(name);
@@ -7119,14 +7276,14 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc,
#ifdef HAVE_SCTP
#define LOAD_PADDRINFO_CNT \
- (2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT + LOAD_IP_AND_PORT_CNT + \
+ (2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT + LOAD_INET_GET_ADDRESS_CNT + \
4*LOAD_INT_CNT + LOAD_TUPLE_CNT)
static int load_paddrinfo (ErlDrvTermData * spec, int i,
inet_descriptor* desc, struct sctp_paddrinfo* pai)
{
i = LOAD_ATOM (spec, i, am_sctp_paddrinfo);
i = LOAD_ASSOC_ID (spec, i, pai->spinfo_assoc_id);
- i = load_ip_and_port(spec, i, desc, &pai->spinfo_address);
+ i = load_inet_get_address(spec, i, desc, &pai->spinfo_address);
switch(pai->spinfo_state)
{
case SCTP_ACTIVE:
@@ -7542,7 +7699,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
/* Fill in the response: */
PLACE_FOR(spec, i,
2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT +
- LOAD_IP_AND_PORT_CNT + 2*LOAD_TUPLE_CNT);
+ LOAD_INET_GET_ADDRESS_CNT + 2*LOAD_TUPLE_CNT);
switch (eopt) {
case SCTP_OPT_PRIMARY_ADDR:
i = LOAD_ATOM(spec, i, am_sctp_primary_addr);
@@ -7556,7 +7713,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
ASSERT(0);
}
i = LOAD_ASSOC_ID (spec, i, sp.sspp_assoc_id);
- i = load_ip_and_port(spec, i, desc, &sp.sspp_addr);
+ i = load_inet_get_address(spec, i, desc, &sp.sspp_addr);
i = LOAD_TUPLE (spec, i, 3);
i = LOAD_TUPLE (spec, i, 2);
break;
@@ -7603,11 +7760,11 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc,
/* Fill in the response: */
PLACE_FOR(spec, i,
2*LOAD_ATOM_CNT + LOAD_ASSOC_ID_CNT +
- LOAD_IP_AND_PORT_CNT + 4*LOAD_INT_CNT);
+ LOAD_INET_GET_ADDRESS_CNT + 4*LOAD_INT_CNT);
i = LOAD_ATOM (spec, i, am_sctp_peer_addr_params);
i = LOAD_ATOM (spec, i, am_sctp_paddrparams);
i = LOAD_ASSOC_ID (spec, i, ap.spp_assoc_id);
- i = load_ip_and_port(spec, i, desc, &ap.spp_address);
+ i = load_inet_get_address(spec, i, desc, &ap.spp_address);
i = LOAD_INT (spec, i, ap.spp_hbinterval);
i = LOAD_INT (spec, i, ap.spp_pathmaxrxt);
@@ -8248,6 +8405,11 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
put_int32(INET_AF_INET6, &tbuf[0]);
}
#endif
+#ifdef HAVE_SYS_UN_H
+ else if (desc->sfamily == AF_UNIX) {
+ put_int32(INET_AF_LOCAL, &tbuf[0]);
+ }
+#endif
else
return ctl_error(EINVAL, rbuf, rsize);
@@ -8296,7 +8458,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (len != 4) return ctl_error(EINVAL, rbuf, rsize);
if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc) && p_sctp_getpaddrs) {
@@ -8307,19 +8468,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
assoc_id = get_int32(buf);
n = p_sctp_getpaddrs(desc->s, assoc_id, &sa);
- rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize);
+ rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize, 0);
if (n > 0) p_sctp_freepaddrs(sa);
return rlen;
}
#endif
{ /* Fallback to sock_peer */
inet_address addr;
- unsigned int sz;
+ SOCKLEN_T sz;
int i;
sz = sizeof(addr);
i = sock_peer(desc->s, (struct sockaddr *) &addr, &sz);
- return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize);
+ return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize, sz);
}
}
@@ -8327,15 +8488,21 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
char tbuf[sizeof(inet_address)];
inet_address peer;
inet_address* ptr;
- unsigned int sz = sizeof(peer);
+ unsigned int sz;
DEBUGF(("inet_ctl(%ld): PEER\r\n", (long)desc->port));
if (!(desc->state & INET_F_ACTIVE))
return ctl_error(ENOTCONN, rbuf, rsize);
- if ((ptr = desc->peer_ptr) == NULL) {
+ if ((ptr = desc->peer_ptr) != NULL) {
+ sz = desc->peer_addr_len;
+ }
+ else {
ptr = &peer;
- if (IS_SOCKET_ERROR(sock_peer(desc->s, (struct sockaddr*)ptr,&sz)))
+ sz = sizeof(peer);
+ if (IS_SOCKET_ERROR
+ (sock_peer
+ (desc->s, (struct sockaddr*)ptr, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
}
if (inet_get_address(tbuf, ptr, &sz) < 0)
@@ -8350,11 +8517,12 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
}
else if (len < 2)
return ctl_error(EINVAL, rbuf, rsize);
- else if (inet_set_address(desc->sfamily, &desc->peer_addr,
- buf, &len) == NULL)
+ else if (inet_set_faddress
+ (desc->sfamily, &desc->peer_addr, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
else {
desc->peer_ptr = &desc->peer_addr;
+ desc->peer_addr_len = (SOCKLEN_T) len;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
}
@@ -8365,7 +8533,6 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (len != 4) return ctl_error(EINVAL, rbuf, rsize);
if (! IS_OPEN(desc)) return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (! IS_BOUND(desc)) return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc) && p_sctp_getladdrs) {
@@ -8376,19 +8543,20 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
assoc_id = get_int32(buf);
n = p_sctp_getladdrs(desc->s, assoc_id, &sa);
- rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize);
+ rlen = reply_inet_addrs(n, (inet_address *) sa, rbuf, rsize, 0);
if (n > 0) p_sctp_freeladdrs(sa);
return rlen;
}
#endif
{ /* Fallback to sock_name */
inet_address addr;
- unsigned int sz;
+ SOCKLEN_T sz;
int i;
sz = sizeof(addr);
+ sys_memzero((char *) &addr, sz);
i = sock_name(desc->s, (struct sockaddr *) &addr, &sz);
- return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize);
+ return reply_inet_addrs(i >= 0 ? 1 : i, &addr, rbuf, rsize, sz);
}
}
@@ -8396,16 +8564,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
char tbuf[sizeof(inet_address)];
inet_address name;
inet_address* ptr;
- unsigned int sz = sizeof(name);
+ unsigned int sz;
DEBUGF(("inet_ctl(%ld): NAME\r\n", (long)desc->port));
- if (!IS_BOUND(desc))
- return ctl_error(EINVAL, rbuf, rsize); /* address is not valid */
-
- if ((ptr = desc->name_ptr) == NULL) {
+ if ((ptr = desc->name_ptr) != NULL) {
+ sz = desc->name_addr_len;
+ }
+ else {
ptr = &name;
- if (IS_SOCKET_ERROR(sock_name(desc->s, (struct sockaddr*)ptr, &sz)))
+ sz = sizeof(name);
+ sys_memzero((char *) &name, sz);
+ if (IS_SOCKET_ERROR
+ (sock_name(desc->s, (struct sockaddr*)ptr, &sz)))
return ctl_error(sock_errno(), rbuf, rsize);
}
if (inet_get_address(tbuf, ptr, &sz) < 0)
@@ -8413,18 +8584,19 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
return ctl_reply(INET_REP_OK, tbuf, sz, rbuf, rsize);
}
- case INET_REQ_SETNAME: { /* set fake peername Port Address */
+ case INET_REQ_SETNAME: { /* set fake sockname Port Address */
if (len == 0) {
desc->name_ptr = NULL;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
else if (len < 2)
return ctl_error(EINVAL, rbuf, rsize);
- else if (inet_set_address(desc->sfamily, &desc->name_addr,
- buf, &len) == NULL)
+ else if (inet_set_faddress
+ (desc->sfamily, &desc->name_addr, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
else {
desc->name_ptr = &desc->name_addr;
+ desc->name_addr_len = (SOCKLEN_T) len;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
}
@@ -8432,7 +8604,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
case INET_REQ_BIND: { /* bind socket */
char tbuf[2];
inet_address local;
- short port;
+ int port;
DEBUGF(("inet_ctl(%ld): BIND\r\n", (long)desc->port));
@@ -8447,15 +8619,17 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf,
if (IS_SOCKET_ERROR(sock_bind(desc->s,(struct sockaddr*) &local, len)))
return ctl_error(sock_errno(), rbuf, rsize);
- desc->state = INET_STATE_BOUND;
+ desc->state = INET_STATE_OPEN;
- if ((port = inet_address_port(&local)) == 0) {
+ port = inet_address_port(&local);
+ if (port == 0) {
SOCKLEN_T adrlen = sizeof(local);
+ sys_memzero((char *) &local, adrlen);
sock_name(desc->s, &local.sa, &adrlen);
port = inet_address_port(&local);
}
- port = sock_ntohs(port);
- put_int16(port, tbuf);
+ else if (port == -1) port = 0;
+ put_int16(sock_ntohs((Uint16) port), tbuf);
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
}
@@ -8912,6 +9086,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror("eafnosupport", rbuf, rsize);
break;
#endif
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL:
+ domain = AF_UNIX;
+ break;
+#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
}
@@ -8938,6 +9117,11 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror("eafnosupport", rbuf, rsize);
break;
#endif
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL:
+ domain = AF_UNIX;
+ break;
+#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
}
@@ -8960,8 +9144,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(INETP(desc)))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(INETP(desc)))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (len != 2)
return ctl_error(EINVAL, rbuf, rsize);
backlog = get_int16(buf);
@@ -8984,8 +9166,6 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (IS_CONNECTED(INETP(desc)))
return ctl_error(EISCONN, rbuf, rsize);
- if (!IS_BOUND(INETP(desc)))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (IS_CONNECTING(INETP(desc)))
return ctl_error(EINVAL, rbuf, rsize);
if (len < 6)
@@ -8993,8 +9173,8 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
timeout = get_int32(buf);
buf += 4;
len -= 4;
- if (inet_set_address(desc->inet.sfamily, &desc->inet.remote,
- buf, &len) == NULL)
+ if (inet_set_faddress
+ (desc->inet.sfamily, &desc->inet.remote, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
code = sock_connect(desc->inet.s,
@@ -9086,6 +9266,7 @@ static ErlDrvSSizeT tcp_inet_ctl(ErlDrvData e, unsigned int cmd,
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
} else {
n = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, n);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &n);
if (s == INVALID_SOCKET) {
if (sock_errno() == ERRNO_BLOCK) {
@@ -9971,6 +10152,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
inet_async_op *this_op = desc->inet.opt;
len = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, len);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
/* Just try again, no real error, just a ghost trigger from poll,
@@ -10037,6 +10219,7 @@ static int tcp_inet_input(tcp_descriptor* desc, HANDLE event)
while (desc->inet.state == INET_STATE_MULTI_ACCEPTING) {
len = sizeof(desc->inet.remote);
+ sys_memzero((char *) &remote, len);
s = sock_accept(desc->inet.s, (struct sockaddr*) &remote, &len);
if (s == INVALID_SOCKET && sock_errno() == ERRNO_BLOCK) {
/* Just try again, no real error, keep the last return code */
@@ -10477,7 +10660,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
(struct sockaddr*) &desc->inet.remote, &sz);
if (IS_SOCKET_ERROR(code)) {
- desc->inet.state = INET_STATE_BOUND; /* restore state */
+ desc->inet.state = INET_STATE_OPEN; /* restore state */
ret = async_error(INETP(desc), sock_errno());
goto done;
}
@@ -10490,7 +10673,7 @@ static int tcp_inet_output(tcp_descriptor* desc, HANDLE event)
(void *)&error, &sz);
if ((code < 0) || error) {
- desc->inet.state = INET_STATE_BOUND; /* restore state */
+ desc->inet.state = INET_STATE_OPEN; /* restore state */
ret = async_error(INETP(desc), error);
goto done;
}
@@ -10777,6 +10960,9 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror("eafnosupport", rbuf, rsize);
break;
#endif
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL: af = AF_UNIX; break;
+#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
}
@@ -10827,6 +11013,9 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror("eafnosupport", rbuf, rsize);
break;
#endif
+#ifdef HAVE_SYS_UN_H
+ case INET_AF_LOCAL: af = AF_UNIX; break;
+#endif
default:
return ctl_error(EINVAL, rbuf, rsize);
}
@@ -10893,8 +11082,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
#ifdef HAVE_SCTP
if (IS_SCTP(desc)) {
inet_address remote;
@@ -10909,7 +11096,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
/* For SCTP, we do not set the peer's addr in desc->remote, as
multiple peers are possible: */
- if (inet_set_address(desc->sfamily, &remote, buf, &len) == NULL)
+ if (inet_set_faddress(desc->sfamily, &remote, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
sock_select(desc, FD_CONNECT, 1);
@@ -10949,8 +11136,8 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
/* Ignore timeout */
buf += 4;
len -= 4;
- if (inet_set_address(desc->sfamily,
- &desc->remote, buf, &len) == NULL)
+ if (inet_set_faddress
+ (desc->sfamily, &desc->remote, buf, &len) == NULL)
return ctl_error(EINVAL, rbuf, rsize);
code = sock_connect(desc->s,
@@ -10981,8 +11168,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (len != 2)
return ctl_error(EINVAL, rbuf, rsize);
@@ -11029,7 +11214,7 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_error(sock_errno(), rbuf, rsize);
}
- desc->state = INET_STATE_BOUND;
+ desc->state = INET_STATE_OPEN;
return ctl_reply(INET_REP_OK, NULL, 0, rbuf, rsize);
}
@@ -11046,8 +11231,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_xerror(EXBADPORT, rbuf, rsize);
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_xerror(EXBADSEQ, rbuf, rsize);
if (! p_sctp_peeloff)
return ctl_error(ENOTSUP, rbuf, rsize);
@@ -11088,8 +11271,6 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
/* INPUT: Timeout(4), Length(4) */
if (!IS_OPEN(desc))
return ctl_xerror(EXBADPORT, rbuf, rsize);
- if (!IS_BOUND(desc))
- return ctl_error(EINVAL, rbuf, rsize);
if (desc->active || (len != 8))
return ctl_error(EINVAL, rbuf, rsize);
timeout = get_int32(buf);
@@ -11130,12 +11311,12 @@ static void packet_inet_timeout(ErlDrvData e)
/* THIS IS A "send*" REQUEST; on the Erlang side: "port_command".
-** input should be: P1 P0 Address buffer .
+** input should be: Family Address buffer .
** For UDP, buffer (after Address) is just data to be sent.
** For SCTP, buffer contains a list representing 2 items:
** (1) 6 parms for sctp_sndrcvinfo, as in sctp_get_sendparams();
** (2) 0+ real data bytes.
-** There is no destination address -- SCTYP send is performed over
+** There is no destination address -- SCTP send is performed over
** an existing association, using "sctp_sndrcvinfo" specified.
*/
static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
@@ -11154,10 +11335,6 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
inet_reply_error(desc, EINVAL);
return;
}
- if (!IS_BOUND(desc)) {
- inet_reply_error(desc, EINVAL);
- return;
- }
#ifdef HAVE_SCTP
if (IS_SCTP(desc))
@@ -11210,7 +11387,7 @@ static void packet_inet_command(ErlDrvData e, char* buf, ErlDrvSizeT len)
/* UDP socket. Even if it is connected, there is an address prefix
here -- ignored for connected sockets: */
sz = len;
- qtr = inet_set_address(desc->sfamily, &other, ptr, &sz);
+ qtr = inet_set_faddress(desc->sfamily, &other, ptr, &sz);
if (qtr == NULL) {
inet_reply_error(desc, EINVAL);
return;
@@ -11288,6 +11465,8 @@ static int packet_inet_input(udp_descriptor* udesc, HANDLE event)
while(packet_count--) {
unsigned int len = sizeof(other);
+ sys_memzero((char *) &other, sizeof(other));
+
/* udesc->i_buf is only kept between SCTP fragments */
if (udesc->i_buf == NULL) {
udesc->i_bufsz = desc->bufsz + len;
@@ -11483,7 +11662,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
(struct sockaddr*) &desc->remote, &sz);
if (IS_SOCKET_ERROR(code)) {
- desc->state = INET_STATE_BOUND; /* restore state */
+ desc->state = INET_STATE_OPEN; /* restore state */
ret = async_error(desc, sock_errno());
goto done;
}
@@ -11496,7 +11675,7 @@ static int packet_inet_output(udp_descriptor* udesc, HANDLE event)
(void *)&error, &sz);
if ((code < 0) || error) {
- desc->state = INET_STATE_BOUND; /* restore state */
+ desc->state = INET_STATE_OPEN; /* restore state */
ret = async_error(desc, error);
goto done;
}
@@ -11809,9 +11988,8 @@ int erts_sock_connect(erts_sock_t socket, byte *ip_addr, int len, Uint16 port)
if (!inet_set_address(AF_INET, &addr, buf, &blen))
return 0;
- if (IS_SOCKET_ERROR(sock_connect(s,
- (struct sockaddr *) &addr,
- sizeof(struct sockaddr_in))))
+ if (IS_SOCKET_ERROR
+ (sock_connect(s, (struct sockaddr *) &addr, blen)))
return 0;
return 1;
}
diff --git a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
index e38bececde..d92933a096 100644
--- a/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
+++ b/erts/emulator/test/dirty_nif_SUITE_data/dirty_nif_SUITE.c
@@ -48,7 +48,8 @@ static ERL_NIF_TERM dirty_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[
char s[10];
ErlNifBinary b;
if (have_dirty_schedulers()) {
- assert(enif_is_on_dirty_scheduler(env));
+ assert(ERL_NIF_THR_DIRTY_CPU_SCHEDULER == enif_thread_type()
+ || ERL_NIF_THR_DIRTY_IO_SCHEDULER == enif_thread_type());
}
assert(argc == 3);
enif_get_int(env, argv[0], &n);
@@ -65,7 +66,7 @@ static ERL_NIF_TERM call_dirty_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM
int n;
char s[10];
ErlNifBinary b;
- assert(!enif_is_on_dirty_scheduler(env));
+ assert(ERL_NIF_THR_NORMAL_SCHEDULER == enif_thread_type());
if (argc != 3)
return enif_make_badarg(env);
if (have_dirty_schedulers()) {
@@ -151,7 +152,8 @@ dirty_sleeper(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
ErlNifPid pid;
ErlNifEnv* msg_env = NULL;
- assert(enif_is_on_dirty_scheduler(env));
+ assert(ERL_NIF_THR_DIRTY_CPU_SCHEDULER == enif_thread_type()
+ || ERL_NIF_THR_DIRTY_IO_SCHEDULER == enif_thread_type());
/* If we get a pid argument, it indicates a process involved in the
test wants a message from us. Prior to the sleep we send a 'ready'
@@ -221,7 +223,8 @@ static ERL_NIF_TERM dirty_heap_access_nif(ErlNifEnv* env, int argc, const ERL_NI
{
ERL_NIF_TERM res = enif_make_list(env, 0);
int i;
- assert(enif_is_on_dirty_scheduler(env));
+ assert(ERL_NIF_THR_DIRTY_CPU_SCHEDULER == enif_thread_type()
+ || ERL_NIF_THR_DIRTY_IO_SCHEDULER == enif_thread_type());
for (i = 0; i < 1000; i++)
res = enif_make_list_cell(env, enif_make_copy(env, argv[0]), res);
diff --git a/erts/emulator/test/lttng_SUITE.erl b/erts/emulator/test/lttng_SUITE.erl
index c64ddc40da..6b7ad836f5 100644
--- a/erts/emulator/test/lttng_SUITE.erl
+++ b/erts/emulator/test/lttng_SUITE.erl
@@ -44,6 +44,7 @@ suite() ->
all() ->
[t_lttng_list,
+ t_memory_carrier,
t_carrier_pool,
t_async_io_pool,
t_driver_start_stop,
@@ -52,8 +53,7 @@ all() ->
t_driver_timeout,
t_driver_caller,
t_driver_flush,
- t_scheduler_poll,
- t_memory_carrier].
+ t_scheduler_poll].
init_per_suite(Config) ->
@@ -80,34 +80,34 @@ end_per_testcase(Case, _Config) ->
ok.
%% Not tested yet
-%% com_ericsson_otp:driver_process_exit
-%% com_ericsson_otp:driver_event
+%% org_erlang_otp:driver_process_exit
+%% org_erlang_otp:driver_event
%% tracepoints
%%
-%% com_ericsson_otp:carrier_pool_get
-%% com_ericsson_otp:carrier_pool_put
-%% com_ericsson_otp:carrier_destroy
-%% com_ericsson_otp:carrier_create
-%% com_ericsson_otp:aio_pool_put
-%% com_ericsson_otp:aio_pool_get
-%% com_ericsson_otp:driver_control
-%% com_ericsson_otp:driver_call
-%% com_ericsson_otp:driver_finish
-%% com_ericsson_otp:driver_ready_async
-%% com_ericsson_otp:driver_process_exit
-%% com_ericsson_otp:driver_stop
-%% com_ericsson_otp:driver_flush
-%% com_ericsson_otp:driver_stop_select
-%% com_ericsson_otp:driver_timeout
-%% com_ericsson_otp:driver_event
-%% com_ericsson_otp:driver_ready_output
-%% com_ericsson_otp:driver_ready_input
-%% com_ericsson_otp:driver_output
-%% com_ericsson_otp:driver_outputv
-%% com_ericsson_otp:driver_init
-%% com_ericsson_otp:driver_start
-%% com_ericsson_otp:scheduler_poll
+%% org_erlang_otp:carrier_pool_get
+%% org_erlang_otp:carrier_pool_put
+%% org_erlang_otp:carrier_destroy
+%% org_erlang_otp:carrier_create
+%% org_erlang_otp:aio_pool_put
+%% org_erlang_otp:aio_pool_get
+%% org_erlang_otp:driver_control
+%% org_erlang_otp:driver_call
+%% org_erlang_otp:driver_finish
+%% org_erlang_otp:driver_ready_async
+%% org_erlang_otp:driver_process_exit
+%% org_erlang_otp:driver_stop
+%% org_erlang_otp:driver_flush
+%% org_erlang_otp:driver_stop_select
+%% org_erlang_otp:driver_timeout
+%% org_erlang_otp:driver_event
+%% org_erlang_otp:driver_ready_output
+%% org_erlang_otp:driver_ready_input
+%% org_erlang_otp:driver_output
+%% org_erlang_otp:driver_outputv
+%% org_erlang_otp:driver_init
+%% org_erlang_otp:driver_start
+%% org_erlang_otp:scheduler_poll
%%
%% Testcases
@@ -117,48 +117,48 @@ t_lttng_list(_Config) ->
{ok, _} = cmd("lttng list -u"),
ok.
-%% com_ericsson_otp:carrier_pool_get
-%% com_ericsson_otp:carrier_pool_put
+%% org_erlang_otp:carrier_pool_get
+%% org_erlang_otp:carrier_pool_put
t_carrier_pool(Config) ->
case have_carriers(ets_alloc) of
false ->
{skip, "No Memory Carriers configured on system."};
true ->
- ok = lttng_start_event("com_ericsson_otp:carrier_pool*", Config),
+ ok = lttng_start_event("org_erlang_otp:carrier_pool*", Config),
ok = ets_load(),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:carrier_pool_get", Res),
- ok = check_tracepoint("com_ericsson_otp:carrier_pool_put", Res),
+ ok = check_tracepoint("org_erlang_otp:carrier_pool_get", Res),
+ ok = check_tracepoint("org_erlang_otp:carrier_pool_put", Res),
ok
end.
-%% com_ericsson_otp:carrier_destroy
-%% com_ericsson_otp:carrier_create
+%% org_erlang_otp:carrier_destroy
+%% org_erlang_otp:carrier_create
t_memory_carrier(Config) ->
case have_carriers(ets_alloc) of
false ->
{skip, "No Memory Carriers configured on system."};
true ->
- ok = lttng_start_event("com_ericsson_otp:carrier_*", Config),
+ ok = lttng_start_event("org_erlang_otp:carrier_*", Config),
ok = ets_load(),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:carrier_destroy", Res),
- ok = check_tracepoint("com_ericsson_otp:carrier_create", Res),
+ ok = check_tracepoint("org_erlang_otp:carrier_destroy", Res),
+ ok = check_tracepoint("org_erlang_otp:carrier_create", Res),
ok
end.
-%% com_ericsson_otp:aio_pool_put
-%% com_ericsson_otp:aio_pool_get
+%% org_erlang_otp:aio_pool_put
+%% org_erlang_otp:aio_pool_get
t_async_io_pool(Config) ->
case have_async_threads() of
false ->
{skip, "No Async Threads configured on system."};
true ->
- ok = lttng_start_event("com_ericsson_otp:aio_pool_*", Config),
+ ok = lttng_start_event("org_erlang_otp:aio_pool_*", Config),
Path1 = proplists:get_value(priv_dir, Config),
{ok, [[Path2]]} = init:get_argument(home),
@@ -168,51 +168,54 @@ t_async_io_pool(Config) ->
{ok, _} = file:list_dir(Path2),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:aio_pool_put", Res),
- ok = check_tracepoint("com_ericsson_otp:aio_pool_get", Res),
+ ok = check_tracepoint("org_erlang_otp:aio_pool_put", Res),
+ ok = check_tracepoint("org_erlang_otp:aio_pool_get", Res),
ok
end.
-%% com_ericsson_otp:driver_start
-%% com_ericsson_otp:driver_stop
+%% org_erlang_otp:driver_start
+%% org_erlang_otp:driver_stop
t_driver_start_stop(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_*", Config),
+ timer:sleep(500),
Path = proplists:get_value(priv_dir, Config),
Name = filename:join(Path, "sometext.txt"),
Bin = txt(),
ok = file:write_file(Name, Bin),
{ok, Bin} = file:read_file(Name),
+ timer:sleep(500),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_start", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_stop", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_control", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_outputv", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_ready_async", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_start", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_stop", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_control", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_outputv", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_ready_async", Res),
ok.
-%% com_ericsson_otp:driver_control
-%% com_ericsson_otp:driver_outputv
-%% com_ericsson_otp:driver_ready_async
+%% org_erlang_otp:driver_control
+%% org_erlang_otp:driver_outputv
+%% org_erlang_otp:driver_ready_async
t_driver_control_ready_async(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_control", Config),
- ok = lttng_start_event("com_ericsson_otp:driver_outputv", Config),
- ok = lttng_start_event("com_ericsson_otp:driver_ready_async", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_control", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_outputv", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_ready_async", Config),
Path = proplists:get_value(priv_dir, Config),
Name = filename:join(Path, "sometext.txt"),
Bin = txt(),
ok = file:write_file(Name, Bin),
{ok, Bin} = file:read_file(Name),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_control", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_outputv", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_ready_async", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_control", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_outputv", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_ready_async", Res),
ok.
-%% com_ericsson_otp:driver_ready_input
-%% com_ericsson_otp:driver_ready_output
+%% org_erlang_otp:driver_ready_input
+%% org_erlang_otp:driver_ready_output
t_driver_ready_input_output(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_ready_*", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_ready_*", Config),
+ timer:sleep(500),
Me = self(),
Pid = spawn_link(fun() -> tcp_server(Me, active) end),
receive {Pid, accept} -> ok end,
@@ -225,16 +228,17 @@ t_driver_ready_input_output(Config) ->
ok = gen_tcp:close(Sock),
receive {Pid, done} -> ok end,
+ timer:sleep(500),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_ready_input", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_ready_output", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_ready_input", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_ready_output", Res),
ok.
-%% com_ericsson_otp:driver_stop_select
-%% com_ericsson_otp:driver_timeout
+%% org_erlang_otp:driver_stop_select
+%% org_erlang_otp:driver_timeout
t_driver_timeout(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_*", Config),
Me = self(),
Pid = spawn_link(fun() -> tcp_server(Me, timeout) end),
receive {Pid, accept} -> ok end,
@@ -243,16 +247,16 @@ t_driver_timeout(Config) ->
receive {Pid, done} -> ok end,
ok = gen_tcp:close(Sock),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_timeout", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_stop_select", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_timeout", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_stop_select", Res),
ok.
-%% com_ericsson_otp:driver_call
-%% com_ericsson_otp:driver_output
-%% com_ericsson_otp:driver_init
-%% com_ericsson_otp:driver_finish
+%% org_erlang_otp:driver_call
+%% org_erlang_otp:driver_output
+%% org_erlang_otp:driver_init
+%% org_erlang_otp:driver_finish
t_driver_caller(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_*", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_*", Config),
Drv = 'caller_drv',
os:putenv("CALLER_DRV_USE_OUTPUTV", "false"),
@@ -278,25 +282,25 @@ t_driver_caller(Config) ->
erl_ddll:unload_driver(Drv),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_call", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_output", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_init", Res),
- ok = check_tracepoint("com_ericsson_otp:driver_finish", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_call", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_output", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_init", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_finish", Res),
ok.
-%% com_ericsson_otp:scheduler_poll
+%% org_erlang_otp:scheduler_poll
t_scheduler_poll(Config) ->
- ok = lttng_start_event("com_ericsson_otp:scheduler_poll", Config),
+ ok = lttng_start_event("org_erlang_otp:scheduler_poll", Config),
ok = memory_load(),
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:scheduler_poll", Res),
+ ok = check_tracepoint("org_erlang_otp:scheduler_poll", Res),
ok.
-%% com_ericsson_otp:driver_flush
+%% org_erlang_otp:driver_flush
t_driver_flush(Config) ->
- ok = lttng_start_event("com_ericsson_otp:driver_flush", Config),
+ ok = lttng_start_event("org_erlang_otp:driver_flush", Config),
Me = self(),
Pid = spawn_link(fun() -> tcp_server(Me, passive_no_read) end),
@@ -320,7 +324,7 @@ t_driver_flush(Config) ->
receive {Pid, done} -> ok end,
Res = lttng_stop_and_view(Config),
- ok = check_tracepoint("com_ericsson_otp:driver_flush", Res),
+ ok = check_tracepoint("org_erlang_otp:driver_flush", Res),
ok.
%%
@@ -412,29 +416,29 @@ tcp_server(Pid, Type) ->
txt() ->
<<"%% tracepoints\n"
"%%\n"
- "%% com_ericsson_otp:carrier_pool_get\n"
- "%% com_ericsson_otp:carrier_pool_put\n"
- "%% com_ericsson_otp:carrier_destroy\n"
- "%% com_ericsson_otp:carrier_create\n"
- "%% com_ericsson_otp:aio_pool_put\n"
- "%% com_ericsson_otp:aio_pool_get\n"
- "%% com_ericsson_otp:driver_control\n"
- "%% com_ericsson_otp:driver_call\n"
- "%% com_ericsson_otp:driver_finish\n"
- "%% com_ericsson_otp:driver_ready_async\n"
- "%% com_ericsson_otp:driver_process_exit\n"
- "%% com_ericsson_otp:driver_stop\n"
- "%% com_ericsson_otp:driver_flush\n"
- "%% com_ericsson_otp:driver_stop_select\n"
- "%% com_ericsson_otp:driver_timeout\n"
- "%% com_ericsson_otp:driver_event\n"
- "%% com_ericsson_otp:driver_ready_output\n"
- "%% com_ericsson_otp:driver_ready_input\n"
- "%% com_ericsson_otp:driver_output\n"
- "%% com_ericsson_otp:driver_outputv\n"
- "%% com_ericsson_otp:driver_init\n"
- "%% com_ericsson_otp:driver_start\n"
- "%% com_ericsson_otp:scheduler_poll">>.
+ "%% org_erlang_otp:carrier_pool_get\n"
+ "%% org_erlang_otp:carrier_pool_put\n"
+ "%% org_erlang_otp:carrier_destroy\n"
+ "%% org_erlang_otp:carrier_create\n"
+ "%% org_erlang_otp:aio_pool_put\n"
+ "%% org_erlang_otp:aio_pool_get\n"
+ "%% org_erlang_otp:driver_control\n"
+ "%% org_erlang_otp:driver_call\n"
+ "%% org_erlang_otp:driver_finish\n"
+ "%% org_erlang_otp:driver_ready_async\n"
+ "%% org_erlang_otp:driver_process_exit\n"
+ "%% org_erlang_otp:driver_stop\n"
+ "%% org_erlang_otp:driver_flush\n"
+ "%% org_erlang_otp:driver_stop_select\n"
+ "%% org_erlang_otp:driver_timeout\n"
+ "%% org_erlang_otp:driver_event\n"
+ "%% org_erlang_otp:driver_ready_output\n"
+ "%% org_erlang_otp:driver_ready_input\n"
+ "%% org_erlang_otp:driver_output\n"
+ "%% org_erlang_otp:driver_outputv\n"
+ "%% org_erlang_otp:driver_init\n"
+ "%% org_erlang_otp:driver_start\n"
+ "%% org_erlang_otp:scheduler_poll">>.
load_driver(Dir, Driver) ->
case erl_ddll:load_driver(Dir, Driver) of
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index eaa4026a8a..4ebc1f5782 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -147,11 +147,7 @@ spawn_with_binaries(Config) when is_list(Config) ->
TwoMeg = lists:duplicate(1024, L),
Fun = fun() -> spawn(?MODULE, binary_owner, [list_to_binary(TwoMeg)]),
receive after 1 -> ok end end,
- Iter = case test_server:purify_is_running() of
- true -> 10;
- false -> 150
- end,
- test_server:do_times(Iter, Fun),
+ test_server:do_times(150, Fun),
ok.
binary_owner(Bin) when is_binary(Bin) ->
diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c
index e931ae4641..a4008186c4 100644
--- a/erts/etc/common/heart.c
+++ b/erts/etc/common/heart.c
@@ -119,6 +119,8 @@
#define HEART_COMMAND_ENV "HEART_COMMAND"
#define ERL_CRASH_DUMP_SECONDS_ENV "ERL_CRASH_DUMP_SECONDS"
#define HEART_KILL_SIGNAL "HEART_KILL_SIGNAL"
+#define HEART_NO_KILL "HEART_NO_KILL"
+
#define MSG_HDR_SIZE (2)
#define MSG_HDR_PLUS_OP_SIZE (3)
@@ -524,6 +526,12 @@ static void
kill_old_erlang(void){
HANDLE erlh;
DWORD exit_code;
+ char* envvar = NULL;
+
+ envvar = get_env(HEART_NO_KILL);
+ if (!envvar || strcmp(envvar, "TRUE") == 0)
+ return;
+
if(heart_beat_kill_pid != 0){
if((erlh = OpenProcess(PROCESS_TERMINATE |
SYNCHRONIZE |
@@ -555,10 +563,14 @@ kill_old_erlang(void){
pid_t pid;
int i, res;
int sig = SIGKILL;
- char *sigenv = NULL;
+ char *envvar = NULL;
+
+ envvar = get_env(HEART_NO_KILL);
+ if (!envvar || strcmp(envvar, "TRUE") == 0)
+ return;
- sigenv = get_env(HEART_KILL_SIGNAL);
- if (sigenv && strcmp(sigenv, "SIGABRT") == 0) {
+ envvar = get_env(HEART_KILL_SIGNAL);
+ if (envvar && strcmp(envvar, "SIGABRT") == 0) {
print_error("kill signal SIGABRT requested");
sig = SIGABRT;
}
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 0521060e34..fdf8bbf4e2 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 4872ffd00c..560810d222 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -70,11 +70,13 @@ open(Protocol, Family, Type) ->
open(Protocol, Family, Type, Opts) ->
open(Protocol, Family, Type, Opts, ?INET_REQ_OPEN, []).
+%% FDOPEN(tcp|udp|sctp, inet|inet6|local, stream|dgram|seqpacket, integer())
+
fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) ->
fdopen(Protocol, Family, Type, Fd, true).
fdopen(Protocol, Family, Type, Fd, Bound)
- when is_integer(Fd), Bound == true orelse Bound == false ->
+ when is_integer(Fd), is_boolean(Bound) ->
open(Protocol, Family, Type, [], ?INET_REQ_FDOPEN,
[?int32(Fd), enc_value_2(bool, Bound)]).
@@ -104,8 +106,9 @@ open(Protocol, Family, Type, Opts, Req, Data) ->
error:system_limit -> {error, system_limit}
end.
-enc_family(inet) -> ?INET_AF_INET;
-enc_family(inet6) -> ?INET_AF_INET6.
+enc_family(inet) -> ?INET_AF_INET;
+enc_family(inet6) -> ?INET_AF_INET6;
+enc_family(local) -> ?INET_AF_LOCAL.
enc_type(stream) -> ?INET_TYPE_STREAM;
enc_type(dgram) -> ?INET_TYPE_DGRAM;
@@ -189,41 +192,52 @@ close_port(S) ->
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-bind(S,IP,Port) when is_port(S), is_integer(Port), Port >= 0, Port =< 65535 ->
- case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, {IP,Port})) of
- {ok, [P1,P0]} -> {ok, ?u16(P1, P0)};
- {error,_}=Error -> Error
- end;
-
%% Multi-homed "bind": sctp_bindx(). The Op is 'add' or 'remove'.
%% If no addrs are specified, it just does nothing.
%% Function returns {ok, S} on success, unlike TCP/UDP "bind":
-bind(S, Op, Addrs) when is_port(S), is_list(Addrs) ->
- case Op of
- add ->
- bindx(S, 1, Addrs);
- remove ->
- bindx(S, 0, Addrs);
- _ -> {error, einval}
+bind(S, add, Addrs) when is_port(S), is_list(Addrs) ->
+ bindx(S, 1, Addrs);
+bind(S, remove, Addrs) when is_port(S), is_list(Addrs) ->
+ bindx(S, 0, Addrs);
+bind(S, Addr, _) when is_port(S), tuple_size(Addr) =:= 2 ->
+ case type_value(set, addr, Addr) of
+ true ->
+ case ctl_cmd(S,?INET_REQ_BIND,enc_value(set, addr, Addr)) of
+ {ok, [P1,P0]} -> {ok, ?u16(P1, P0)};
+ {error, _} = Error -> Error
+ end;
+ false ->
+ {error, einval}
end;
-bind(_, _, _) -> {error, einval}.
+bind(S, IP, Port) ->
+ bind(S, {IP, Port}, 0).
bindx(S, AddFlag, Addrs) ->
case getprotocol(S) of
sctp ->
- %% Really multi-homed "bindx". Stringified args:
- %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]:
- Args =
- [?int8(AddFlag)|
- [enc_value(set, addr, {IP,Port}) ||
- {IP, Port} <- Addrs]],
- case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
- {ok,_} -> {ok, S};
- {error,_}=Error -> Error
+ case bindx_check_addrs(Addrs) of
+ true ->
+ %% Really multi-homed "bindx". Stringified args:
+ %% [AddFlag, (AddrBytes see enc_value_2(addr,X))+]:
+ Args =
+ [?int8(AddFlag)|
+ [enc_value(set, addr, Addr) || Addr <- Addrs]],
+ case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of
+ {ok, _} -> {ok, S};
+ {error, _}=Error -> Error
+ end;
+ false ->
+ {error, einval}
end;
- _ -> {error, einval}
+ _ ->
+ {error, einval}
end.
+bindx_check_addrs([Addr|Addrs]) ->
+ type_value(set, addr, Addr) andalso bindx_check_addrs(Addrs);
+bindx_check_addrs([]) ->
+ true.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
%% CONNECT(insock(), IP, Port [,Timeout]) -> ok | {error, Reason}
@@ -242,14 +256,24 @@ bindx(S, AddFlag, Addrs) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% For TCP, UDP or SCTP sockets.
%%
-connect(S, IP, Port) -> connect0(S, IP, Port, -1).
-connect(S, IP, Port, infinity) -> connect0(S, IP, Port, -1);
-connect(S, IP, Port, Time) -> connect0(S, IP, Port, Time).
+connect(S, IP, Port) ->
+ connect(S, IP, Port, infinity).
+%%
+connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
+ case type_value(set, addr, Addr) of
+ true when Time =:= infinity ->
+ connect0(S, Addr, -1);
+ true when is_integer(Time) ->
+ connect0(S, Addr, Time);
+ false ->
+ {error, einval}
+ end;
+connect(S, IP, Port, Time) ->
+ connect(S, {IP, Port}, 0, Time).
-connect0(S, IP, Port, Time) when is_port(S), Port > 0, Port =< 65535,
- is_integer(Time) ->
- case async_connect(S, IP, Port, Time) of
+connect0(S, Addr, Time) ->
+ case async_connect0(S, Addr, Time) of
{ok, S, Ref} ->
receive
{inet_async, S, Ref, Status} ->
@@ -258,11 +282,27 @@ connect0(S, IP, Port, Time) when is_port(S), Port > 0, Port =< 65535,
Error -> Error
end.
+
+async_connect(S, Addr, _, Time) when is_port(S), tuple_size(Addr) =:= 2 ->
+ case type_value(set, addr, Addr) of
+ true when Time =:= infinity ->
+ async_connect0(S, Addr, -1);
+ true when is_integer(Time) ->
+ async_connect0(S, Addr, Time);
+ false ->
+ {error, einval}
+ end;
+%%
async_connect(S, IP, Port, Time) ->
- case ctl_cmd(S, ?INET_REQ_CONNECT,
- [enc_time(Time),?int16(Port),ip_to_bytes(IP)]) of
+ async_connect(S, {IP, Port}, 0, Time).
+
+async_connect0(S, Addr, Time) ->
+ case ctl_cmd(
+ S, ?INET_REQ_CONNECT,
+ [enc_time(Time),enc_value(set, addr, Addr)])
+ of
{ok, [R1,R0]} -> {ok, S, ?u16(R1,R0)};
- {error,_}=Error -> Error
+ {error, _}=Error -> Error
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -400,20 +440,34 @@ send(S, Data) ->
%% "sendto" is for UDP. IP and Port are set by the caller to 0 if the socket
%% is known to be connected.
-sendto(S, IP, Port, Data) when is_port(S), Port >= 0, Port =< 65535 ->
- ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p, ~p)~n", [S,IP,Port,Data]),
- try erlang:port_command(S, [?int16(Port),ip_to_bytes(IP),Data]) of
- true ->
- receive
- {inet_reply,S,Reply} ->
- ?DBG_FORMAT("prim_inet:sendto() -> ~p~n", [Reply]),
- Reply
- end
- catch
- error:_ ->
- ?DBG_FORMAT("prim_inet:sendto() -> {error,einval}~n", []),
- {error,einval}
- end.
+sendto(S, Addr, _, Data) when is_port(S), tuple_size(Addr) =:= 2 ->
+ case type_value(set, addr, Addr) of
+ true ->
+ ?DBG_FORMAT("prim_inet:sendto(~p, ~p, ~p)~n", [S,Addr,Data]),
+ try
+ erlang:port_command(S, [enc_value(set, addr, Addr),Data])
+ of
+ true ->
+ receive
+ {inet_reply,S,Reply} ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> ~p~n", [Reply]),
+ Reply
+ end
+ catch
+ error:_ ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> {error,einval}~n", []),
+ {error,einval}
+ end;
+ false ->
+ ?DBG_FORMAT(
+ "prim_inet:sendto() -> {error,einval}~n", []),
+ {error,einval}
+ end;
+sendto(S, IP, Port, Data) ->
+ sendto(S, {IP, Port}, 0, Data).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%
@@ -484,29 +538,37 @@ async_recv(S, Length, Time) ->
%% oriented: preserved here only for API compatibility.
%%
recvfrom(S, Length) ->
- recvfrom0(S, Length, -1).
+ recvfrom(S, Length, infinity).
-recvfrom(S, Length, infinity) ->
+recvfrom(S, Length, infinity) when is_port(S) ->
recvfrom0(S, Length, -1);
-recvfrom(S, Length, Time) when is_integer(Time), Time < 16#ffffffff ->
- recvfrom0(S, Length, Time);
-recvfrom(_, _, _) -> {error,einval}.
+recvfrom(S, Length, Time) when is_port(S) ->
+ if
+ is_integer(Time), 0 =< Time, Time < 16#ffffffff ->
+ recvfrom0(S, Length, Time);
+ true ->
+ {error, einval}
+ end.
recvfrom0(S, Length, Time)
- when is_port(S), is_integer(Length), Length >= 0, Length =< 16#ffffffff ->
+ when is_integer(Length), 0 =< Length, Length =< 16#ffffffff ->
case ctl_cmd(S, ?PACKET_REQ_RECV,[enc_time(Time),?int32(Length)]) of
{ok,[R1,R0]} ->
Ref = ?u16(R1,R0),
receive
% Success, UDP:
- {inet_async, S, Ref, {ok, [F,P1,P0 | AddrData]}} ->
- {IP,Data} = get_ip(F, AddrData),
- {ok, {IP, ?u16(P1,P0), Data}};
+ {inet_async, S, Ref, {ok, [F | AddrData]}} ->
+ case get_addr(F, AddrData) of
+ {{Family, _} = Addr, Data} when is_atom(Family) ->
+ {ok, {Addr, 0, Data}};
+ {{IP, Port}, Data} ->
+ {ok, {IP, Port, Data}}
+ end;
% Success, SCTP:
{inet_async, S, Ref, {ok, {[F,P1,P0 | Addr], AncData, DE}}} ->
- {IP, _} = get_ip(F, Addr),
- {ok, {IP, ?u16(P1,P0), AncData, DE}};
+ {IP, _} = get_ip(F, Addr),
+ {ok, {IP, ?u16(P1, P0), AncData, DE}};
% Back-end error:
{inet_async, S, Ref, Error={error, _}} ->
@@ -525,21 +587,26 @@ recvfrom0(_, _, _) -> {error,einval}.
peername(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_PEER, []) of
- {ok, [F, P1,P0 | Addr]} ->
- {IP, _} = get_ip(F, Addr),
- {ok, { IP, ?u16(P1, P0) }};
- {error,_}=Error -> Error
+ {ok, [F | Addr]} ->
+ {A, _} = get_addr(F, Addr),
+ {ok, A};
+ {error, _} = Error -> Error
end.
-setpeername(S, {IP,Port}) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_SETPEER, [?int16(Port),ip_to_bytes(IP)]) of
- {ok,[]} -> ok;
- {error,_}=Error -> Error
- end;
setpeername(S, undefined) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_SETPEER, []) of
- {ok,[]} -> ok;
- {error,_}=Error -> Error
+ {ok, []} -> ok;
+ {error, _} = Error -> Error
+ end;
+setpeername(S, Addr) when is_port(S) ->
+ case type_value(set, addr, Addr) of
+ true ->
+ case ctl_cmd(S, ?INET_REQ_SETPEER, enc_value(set, addr, Addr)) of
+ {ok, []} -> ok;
+ {error, _} = Error -> Error
+ end;
+ false ->
+ {error, einval}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -580,21 +647,28 @@ peernames(S, AssocId)
sockname(S) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_NAME, []) of
- {ok, [F, P1, P0 | Addr]} ->
- {IP, _} = get_ip(F, Addr),
- {ok, { IP, ?u16(P1, P0) }};
- {error,_}=Error -> Error
+ {ok, [F | Addr]} ->
+ {A, _} = get_addr(F, Addr),
+ {ok, A};
+ {error, _} = Error -> Error
end.
-setsockname(S, {IP,Port}) when is_port(S) ->
- case ctl_cmd(S, ?INET_REQ_SETNAME, [?int16(Port),ip_to_bytes(IP)]) of
- {ok,[]} -> ok;
- {error,_}=Error -> Error
- end;
setsockname(S, undefined) when is_port(S) ->
case ctl_cmd(S, ?INET_REQ_SETNAME, []) of
- {ok,[]} -> ok;
- {error,_}=Error -> Error
+ {ok, []} -> ok;
+ {error, _} = Error -> Error
+ end;
+setsockname(S, Addr) when is_port(S) ->
+ case type_value(set, addr, Addr) of
+ true ->
+ case
+ ctl_cmd(S, ?INET_REQ_SETNAME, enc_value(set, addr, Addr))
+ of
+ {ok, []} -> ok;
+ {error, _} = Error -> Error
+ end;
+ false ->
+ {error, einval}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -1496,14 +1570,49 @@ type_value_2(uint8, X) when X band 16#ff =:= X -> true;
type_value_2(time, infinity) -> true;
type_value_2(time, X) when is_integer(X), X >= 0 -> true;
type_value_2(ip,{A,B,C,D}) when ?ip(A,B,C,D) -> true;
+%%
type_value_2(addr, {any,Port}) ->
type_value_2(uint16, Port);
type_value_2(addr, {loopback,Port}) ->
type_value_2(uint16, Port);
-type_value_2(addr, {{A,B,C,D},Port}) when ?ip(A,B,C,D) ->
+type_value_2(addr, {IP,_} = Addr) when tuple_size(IP) =:= 4 ->
+ type_value_2(addr, {inet,Addr});
+type_value_2(addr, {IP,_} = Addr) when tuple_size(IP) =:= 8 ->
+ type_value_2(addr, {inet6,Addr});
+type_value_2(addr, {Local,_}) when is_list(Local); is_binary(Local) ->
+ type_value_2(addr, {local,Local});
+%%
+type_value_2(addr, {Family,{Tag,Port}})
+ when (Family =:= inet orelse Family =:= inet6) andalso
+ (Tag =:= any orelse Tag =:= loopback) ->
+ type_value_2(uint16, Port);
+type_value_2(addr, {inet,{{A,B,C,D},Port}})
+ when ?ip(A,B,C,D) ->
type_value_2(uint16, Port);
-type_value_2(addr, {{A,B,C,D,E,F,G,H},Port}) when ?ip6(A,B,C,D,E,F,G,H) ->
+type_value_2(addr, {inet6,{{A,B,C,D,E,F,G,H},Port}})
+ when ?ip6(A,B,C,D,E,F,G,H) ->
type_value_2(uint16, Port);
+type_value_2(addr, {local,Addr}) ->
+ if
+ is_binary(Addr) ->
+ byte_size(Addr) =< 255;
+ true ->
+ try
+ %% We either get a badarg from byte_size
+ %% or from characters_to_binary
+ byte_size(
+ unicode:characters_to_binary(
+ Addr, file:native_name_encoding()))
+ of
+ N when N =< 255 ->
+ true;
+ _ ->
+ false
+ catch error:badarg ->
+ false
+ end
+ end;
+%%
type_value_2(ether,[X1,X2,X3,X4,X5,X6])
when ?ether(X1,X2,X3,X4,X5,X6) -> true;
type_value_2({enum,List}, Enum) ->
@@ -1611,6 +1720,7 @@ enc_value_2(time, Val) -> ?int32(Val);
enc_value_2(ip,{A,B,C,D}) -> [A,B,C,D];
enc_value_2(ip, any) -> [0,0,0,0];
enc_value_2(ip, loopback) -> [127,0,0,1];
+%%
enc_value_2(addr, {any,Port}) ->
[?INET_AF_ANY|?int16(Port)];
enc_value_2(addr, {loopback,Port}) ->
@@ -1619,6 +1729,35 @@ enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 ->
[?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 ->
[?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
+enc_value_2(addr, {File,_}) when is_list(File); is_binary(File) ->
+ [?INET_AF_LOCAL,iolist_size(File)|File];
+%%
+enc_value_2(addr, {inet,{any,Port}}) ->
+ [?INET_AF_INET,?int16(Port),0,0,0,0];
+enc_value_2(addr, {inet,{loopback,Port}}) ->
+ [?INET_AF_INET,?int16(Port),127,0,0,1];
+enc_value_2(addr, {inet,{IP,Port}}) ->
+ [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)];
+enc_value_2(addr, {inet6,{any,Port}}) ->
+ [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,0];
+enc_value_2(addr, {inet6,{loopback,Port}}) ->
+ [?INET_AF_INET6,?int16(Port),0,0,0,0,0,0,0,1];
+enc_value_2(addr, {inet6,{IP,Port}}) ->
+ [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)];
+enc_value_2(addr, {local,Addr}) ->
+ %% A binary is passed as is, but anything else will be
+ %% regarded as a filename and therefore encoded according to
+ %% the current system filename encoding mode.
+ Bin =
+ if
+ is_binary(Addr) ->
+ Addr;
+ true ->
+ unicode:characters_to_binary(
+ Addr, file:native_name_encoding())
+ end,
+ [?INET_AF_LOCAL,byte_size(Bin),Bin];
+%%
enc_value_2(ether, [_,_,_,_,_,_]=Xs) -> Xs;
enc_value_2(sockaddr, any) ->
[?INET_AF_ANY];
@@ -2249,9 +2388,6 @@ utf8_to_characters(Bs, U, 0) ->
utf8_to_characters([B|Bs], U, N) when ((B band 16#3F) bor 16#80) =:= B ->
utf8_to_characters(Bs, (U bsl 6) bor (B band 16#3F), N-1).
-ip_to_bytes(IP) when tuple_size(IP) =:= 4 -> ip4_to_bytes(IP);
-ip_to_bytes(IP) when tuple_size(IP) =:= 8 -> ip6_to_bytes(IP).
-
ip4_to_bytes({A,B,C,D}) ->
[A band 16#ff, B band 16#ff, C band 16#ff, D band 16#ff].
@@ -2261,18 +2397,32 @@ ip6_to_bytes({A,B,C,D,E,F,G,H}) ->
get_addrs([]) ->
[];
-get_addrs([F,P1,P0|Addr]) ->
- {IP,Addrs} = get_ip(F, Addr),
- [{IP,?u16(P1, P0)}|get_addrs(Addrs)].
-
-get_ip(?INET_AF_INET, Addr) -> get_ip4(Addr);
-get_ip(?INET_AF_INET6, Addr) -> get_ip6(Addr).
+get_addrs([F|Addrs]) ->
+ {Addr,Rest} = get_addr(F, Addrs),
+ [Addr|get_addrs(Rest)].
+
+get_addr(?INET_AF_LOCAL, [0]) ->
+ {{local,<<>>},[]};
+get_addr(?INET_AF_LOCAL, [N|Addr]) ->
+ {A,Rest} = lists:split(N, Addr),
+ {{local,iolist_to_binary(A)},Rest};
+get_addr(?INET_AF_UNDEFINED, Rest) ->
+ {{undefined,0},Rest};
+get_addr(Family, [P1,P0|Addr]) ->
+ {IP,Rest} = get_ip(Family, Addr),
+ {{IP,?u16(P1, P0)},Rest}.
+
+get_ip(?INET_AF_INET, Addr) ->
+ get_ip4(Addr);
+get_ip(?INET_AF_INET6, Addr) ->
+ get_ip6(Addr).
get_ip4([A,B,C,D | T]) -> {{A,B,C,D},T}.
get_ip6([X1,X2,X3,X4,X5,X6,X7,X8,X9,X10,X11,X12,X13,X14,X15,X16 | T]) ->
{ { ?u16(X1,X2),?u16(X3,X4),?u16(X5,X6),?u16(X7,X8),
- ?u16(X9,X10),?u16(X11,X12),?u16(X13,X14),?u16(X15,X16)}, T}.
+ ?u16(X9,X10),?u16(X11,X12),?u16(X13,X14),?u16(X15,X16)},
+ T }.
%% Control command