diff options
161 files changed, 2476 insertions, 1203 deletions
diff --git a/HOWTO/INSTALL.md b/HOWTO/INSTALL.md index 0b78f4ca56..a823d5abbc 100644 --- a/HOWTO/INSTALL.md +++ b/HOWTO/INSTALL.md @@ -381,7 +381,7 @@ Some of the available `configure` options are: if different than specified by `--with-ssl=PATH` * `--with-ssl-rpath=yes|no|PATHS` - Runtime library path for OpenSSL. Default is `yes`, which equates to a number of standard locations. If - `no`, then no runtime library paths wil be used. Anything else should be + `no`, then no runtime library paths will be used. Anything else should be a comma separated list of paths. * `--with-libatomic_ops=PATH` - Use the `libatomic_ops` library for atomic memory accesses. If `configure` should inform you about no native atomic diff --git a/configure.in b/configure.in index 64b0bdac6d..40498f2ff9 100644 --- a/configure.in +++ b/configure.in @@ -271,7 +271,7 @@ AC_ARG_WITH(ssl-rpath, AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS], [runtime library path for OpenSSL. Default is 'yes', which equates to a number of standard locations. If 'no', then no runtime - library paths wil be used. Anything else should be a + library paths will be used. Anything else should be a comma separated list of paths.])) AC_ARG_ENABLE(dynamic-ssl-lib, diff --git a/erts/configure.in b/erts/configure.in index 4fb725ff00..4ade3b3086 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -468,7 +468,7 @@ case $host_os in win32) # The ethread library requires _WIN32_WINNT of at least 0x0403. # -D_WIN32_WINNT=* from CPPFLAGS is saved in ETHR_DEFS. - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0501 -DWINVER=0x0501" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" ;; darwin*) CPPFLAGS="$CPPFLAGS -D_XOPEN_SOURCE" @@ -4111,7 +4111,7 @@ AC_ARG_WITH(ssl-rpath, AS_HELP_STRING([--with-ssl-rpath=yes|no|PATHS], [runtime library path for OpenSSL. Default is "yes", which equates to a number of standard locations. If "no", then no runtime - library paths wil be used. Anything else should be a + library paths will be used. Anything else should be a comma separated list of paths.]), [ case X$with_ssl in diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml index 28fcc8f7af..7f61804bea 100644 --- a/erts/doc/src/epmd.xml +++ b/erts/doc/src/epmd.xml @@ -37,7 +37,7 @@ <comsummary> <p>Erlang Port Mapper Daemon</p> <taglist> - <tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag> + <tag><c><![CDATA[epmd [-d|-debug] [DbgExtra...] [-address Addresses] [-port No] [-daemon] [-relaxed_command_check]]]></c></tag> <item> <p>Starts the port mapper daemon</p> </item> diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index e8621fecc3..ed3e7e34c4 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -387,6 +387,28 @@ <p>Replaces the path specified in the boot script. See <seealso marker="sasl:script">script(4)</seealso>.</p> </item> + <tag><c><![CDATA[-proto_dist Proto]]></c></tag> + <item> + <p>Specify a protocol for Erlang distribution.</p> + <taglist> + <tag><c>inet_tcp</c></tag> + <item> + <p>TCP over IPv4 (the default)</p> + </item> + <tag><c>inet_tls</c></tag> + <item> + <p>distribution over TLS/SSL</p> + </item> + <tag><c>inet6_tcp</c></tag> + <item> + <p>TCP over IPv6</p> + </item> + </taglist> + <p>For example, to start up IPv6 distributed nodes:</p> +<pre> +% <input>erl -name [email protected] -proto_dist inet6_tcp</input> +</pre> + </item> <tag><c><![CDATA[-remsh Node]]></c></tag> <item> <p>Starts Erlang with a remote shell connected to <c><![CDATA[Node]]></c>.</p> diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml index e4d5e6e77a..30e6751f41 100644 --- a/erts/doc/src/erlang.xml +++ b/erts/doc/src/erlang.xml @@ -1794,7 +1794,8 @@ os_prompt% </pre> </item> </taglist> <note><p>On many platforms, the OS supports only status - codes 0-255.</p></note> + codes 0-255. A too large status code will be truncated by clearing + the high bits.</p></note> <p>For integer <c><anno>Status</anno></c>, the Erlang runtime system closes all ports and allows async threads to finish their operations before exiting. To exit without such flushing, use diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 07f6492948..cb6d294a41 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -269,6 +269,7 @@ atom getenv atom gather_gc_info_result atom gather_io_bytes atom gather_sched_wall_time_result +atom gather_system_check_result atom getting_linked atom getting_unlinked atom global diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index c1fd17c65d..7a1f4901aa 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -143,7 +143,7 @@ BeamInstr *beam_catches_car(unsigned i) struct bc_pool* p = &bccix[erts_active_code_ix()]; if (i >= p->tabsize ) { - erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); + erts_exit(ERTS_ERROR_EXIT, "beam_catches_delmod: index %#x is out of range\r\n", i); } return p->beam_catches[i].cp; } @@ -157,10 +157,10 @@ void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, ASSERT((code_ix == erts_active_code_ix()) != bccix[erts_staging_code_ix()].is_staging); for(i = head; i != (unsigned)-1;) { if (i >= p->tabsize) { - erl_exit(1, "beam_catches_delmod: index %#x is out of range\r\n", i); + erts_exit(ERTS_ERROR_EXIT, "beam_catches_delmod: index %#x is out of range\r\n", i); } if( (char*)p->beam_catches[i].cp - (char*)code >= code_bytes ) { - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "beam_catches_delmod: item %#x has cp %p which is not " "in module's range [%p,%p[\r\n", i, p->beam_catches[i].cp, code, ((char*)code + code_bytes)); diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 73292885ce..1fe4cc9374 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -5018,7 +5018,7 @@ do { \ #ifdef NO_FPE_SIGNALS OpCase(fclearerror): OpCase(i_fcheckerror): - erl_exit(1, "fclearerror/i_fcheckerror without fpe signals (beam_emu)"); + erts_exit(ERTS_ERROR_EXIT, "fclearerror/i_fcheckerror without fpe signals (beam_emu)"); # define ERTS_NO_FPE_CHECK_INIT ERTS_FP_CHECK_INIT # define ERTS_NO_FPE_ERROR ERTS_FP_ERROR #else @@ -5176,7 +5176,7 @@ do { \ I = handle_error(c_p, I, reg, NULL); goto post_error_handling; default: - erl_exit(1, "hipe_mode_switch: result %u\n", c_p->def_arg_reg[3]); + erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: result %u\n", c_p->def_arg_reg[3]); } } OpCase(hipe_call_count): { @@ -5256,7 +5256,7 @@ do { \ OpCase(label_L): OpCase(on_load): OpCase(line_I): - erl_exit(1, "meta op\n"); + erts_exit(ERTS_ERROR_EXIT, "meta op\n"); /* * One-time initialization of Beam emulator. @@ -5310,7 +5310,7 @@ do { \ } #ifdef NO_JUMP_TABLE default: - erl_exit(1, "unexpected op code %d\n",Go); + erts_exit(ERTS_ERROR_EXIT, "unexpected op code %d\n",Go); } #endif return; /* Never executed */ @@ -5355,7 +5355,7 @@ translate_gc_bif(void* gcf) } else if (gcf == erts_gc_binary_part_3) { return binary_part_3; } else { - erl_exit(1, "bad gc bif"); + erts_exit(ERTS_ERROR_EXIT, "bad gc bif"); } } @@ -5420,7 +5420,7 @@ handle_error(Process* c_p, BeamInstr* pc, Eterm* reg, BifFunction bf) Eterm* hp; Eterm Value = c_p->fvalue; Eterm Args = am_true; - c_p->i = pc; /* In case we call erl_exit(). */ + c_p->i = pc; /* In case we call erts_exit(). */ ASSERT(c_p->freason != TRAP); /* Should have been handled earlier. */ @@ -5484,7 +5484,7 @@ handle_error(Process* c_p, BeamInstr* pc, Eterm* reg, BifFunction bf) c_p->cp = 0; /* To avoid keeping stale references. */ return new_pc; } - if (c_p->catches > 0) erl_exit(1, "Catch not found"); + if (c_p->catches > 0) erts_exit(ERTS_ERROR_EXIT, "Catch not found"); } ERTS_SMP_UNREQ_PROC_MAIN_LOCK(c_p); terminate_proc(c_p, Value); diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index a8cc19ee1f..66c2853534 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -2216,7 +2216,7 @@ BIF_RETTYPE send_3(BIF_ALIST_3) erts_dsend_export_trap_context(p, ctx)); break; default: - erl_exit(ERTS_ABORT_EXIT, "send_3 invalid result %d\n", (int)result); + erts_exit(ERTS_ABORT_EXIT, "send_3 invalid result %d\n", (int)result); break; } @@ -2260,7 +2260,7 @@ static BIF_RETTYPE dsend_continue_trap_1(BIF_ALIST_1) BIF_TRAP1(&dsend_continue_trap_export, BIF_P, BIF_ARG_1); } default: - erl_exit(ERTS_ABORT_EXIT, "dsend_continue_trap invalid result %d\n", (int)result); + erts_exit(ERTS_ABORT_EXIT, "dsend_continue_trap invalid result %d\n", (int)result); break; } ASSERT(! "Can not arrive here"); @@ -2332,7 +2332,7 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg) erts_dsend_export_trap_context(p, ctx)); break; default: - erl_exit(ERTS_ABORT_EXIT, "invalid send result %d\n", (int)result); + erts_exit(ERTS_ABORT_EXIT, "invalid send result %d\n", (int)result); break; } @@ -3883,7 +3883,7 @@ BIF_RETTYPE erts_debug_display_1(BIF_ALIST_1) erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(64); pres = erts_dsprintf(dsbufp, "%.*T\n", INT_MAX, BIF_ARG_1); if (pres < 0) - erl_exit(1, "Failed to convert term to string: %d (%s)\n", + erts_exit(ERTS_ERROR_EXIT, "Failed to convert term to string: %d (%s)\n", -pres, erl_errno_id(-pres)); hp = HAlloc(BIF_P, 2*dsbufp->str_len); /* we need length * 2 heap words */ res = buf_to_intlist(&hp, dsbufp->str, dsbufp->str_len, NIL); @@ -3905,7 +3905,7 @@ BIF_RETTYPE display_string_1(BIF_ALIST_1) } str = (char *) erts_alloc(ERTS_ALC_T_TMP, sizeof(char)*(len + 1)); if (intlist_to_buf(string, str, len) != len) - erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); str[len] = '\0'; erts_fprintf(stderr, "%s", str); erts_free(ERTS_ALC_T_TMP, (void *) str); @@ -3925,7 +3925,7 @@ BIF_RETTYPE display_nl_0(BIF_ALIST_0) BIF_RETTYPE halt_0(BIF_ALIST_0) { VERBOSE(DEBUG_SYSTEM,("System halted by BIF halt()\n")); - erl_halt(0); + erts_halt(0); ERTS_BIF_YIELD1(bif_export[BIF_halt_1], BIF_P, am_undefined); } @@ -3938,17 +3938,18 @@ static char halt_msg[HALT_MSG_SIZE]; /* ARGSUSED */ BIF_RETTYPE halt_1(BIF_ALIST_1) { - Sint code; + Uint code; - if (is_small(BIF_ARG_1) && (code = signed_val(BIF_ARG_1)) >= 0) { + if (term_to_Uint_mask(BIF_ARG_1, &code)) { + int pos_int_code = (int) (code & INT_MAX); VERBOSE(DEBUG_SYSTEM,("System halted by BIF halt(%T)\n", BIF_ARG_1)); - erl_halt((int)(- code)); + erts_halt(pos_int_code); ERTS_BIF_YIELD1(bif_export[BIF_halt_1], BIF_P, am_undefined); } else if (ERTS_IS_ATOM_STR("abort", BIF_ARG_1)) { VERBOSE(DEBUG_SYSTEM,("System halted by BIF halt(%T)\n", BIF_ARG_1)); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit(ERTS_ABORT_EXIT, ""); + erts_exit(ERTS_ABORT_EXIT, ""); } else if (is_string(BIF_ARG_1) || BIF_ARG_1 == NIL) { int i; @@ -3959,11 +3960,11 @@ BIF_RETTYPE halt_1(BIF_ALIST_1) halt_msg[i] = '\0'; VERBOSE(DEBUG_SYSTEM,("System halted by BIF halt(%T)\n", BIF_ARG_1)); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit(ERTS_DUMP_EXIT, "%s\n", halt_msg); + erts_exit(ERTS_DUMP_EXIT, "%s\n", halt_msg); } else goto error; - return NIL; /* Pedantic (lint does not know about erl_exit) */ + return NIL; /* Pedantic (lint does not know about erts_exit) */ error: BIF_ERROR(BIF_P, BADARG); } @@ -3974,7 +3975,7 @@ BIF_RETTYPE halt_1(BIF_ALIST_1) /* ARGSUSED */ BIF_RETTYPE halt_2(BIF_ALIST_2) { - Sint code; + Uint code; Eterm optlist = BIF_ARG_2; int flush = 1; @@ -4001,23 +4002,24 @@ BIF_RETTYPE halt_2(BIF_ALIST_2) if (is_not_nil(optlist)) goto error; - if (is_small(BIF_ARG_1) && (code = signed_val(BIF_ARG_1)) >= 0) { + if (term_to_Uint_mask(BIF_ARG_1, &code)) { + int pos_int_code = (int) (code & INT_MAX); VERBOSE(DEBUG_SYSTEM, ("System halted by BIF halt(%T, %T)\n", BIF_ARG_1, BIF_ARG_2)); if (flush) { - erl_halt((int)(- code)); + erts_halt(pos_int_code); ERTS_BIF_YIELD1(bif_export[BIF_halt_1], BIF_P, am_undefined); } else { erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit((int)(- code), ""); + erts_exit(pos_int_code, ""); } } else if (ERTS_IS_ATOM_STR("abort", BIF_ARG_1)) { VERBOSE(DEBUG_SYSTEM, ("System halted by BIF halt(%T, %T)\n", BIF_ARG_1, BIF_ARG_2)); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit(ERTS_ABORT_EXIT, ""); + erts_exit(ERTS_ABORT_EXIT, ""); } else if (is_string(BIF_ARG_1) || BIF_ARG_1 == NIL) { int i; @@ -4029,11 +4031,11 @@ BIF_RETTYPE halt_2(BIF_ALIST_2) VERBOSE(DEBUG_SYSTEM, ("System halted by BIF halt(%T, %T)\n", BIF_ARG_1, BIF_ARG_2)); erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN); - erl_exit(ERTS_DUMP_EXIT, "%s\n", halt_msg); + erts_exit(ERTS_DUMP_EXIT, "%s\n", halt_msg); } else goto error; - return NIL; /* Pedantic (lint does not know about erl_exit) */ + return NIL; /* Pedantic (lint does not know about erts_exit) */ error: BIF_ERROR(BIF_P, BADARG); } @@ -4089,7 +4091,7 @@ term2list_dsprintf(Process *p, Eterm term) erts_dsprintf_buf_t *dsbufp = erts_create_tmp_dsbuf(64); pres = erts_dsprintf(dsbufp, "%T", term); if (pres < 0) - erl_exit(1, "Failed to convert term to list: %d (%s)\n", + erts_exit(ERTS_ERROR_EXIT, "Failed to convert term to list: %d (%s)\n", -pres, erl_errno_id(-pres)); hp = HAlloc(p, 2*dsbufp->str_len); /* we need length * 2 heap words */ res = buf_to_intlist(&hp, dsbufp->str, dsbufp->str_len, NIL); diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 4f0656d174..3177d5dae7 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -174,6 +174,8 @@ bif erts_internal:time_unit/0 bif erts_internal:is_system_process/1 +bif erts_internal:system_check/1 + # inet_db support bif erlang:port_set_data/2 bif erlang:port_get_data/1 diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index 15bcd44fb9..87d3be2b0f 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -2028,6 +2028,32 @@ term_to_Uint(Eterm term, Uint *up) } } +/* same as term_to_Uint() + but also accept larger bignums by masking + */ +int +term_to_Uint_mask(Eterm term, Uint *up) +{ + if (is_small(term)) { + Sint i = signed_val(term); + if (i < 0) { + *up = BADARG; + return 0; + } + *up = (Uint) i; + return 1; + } else if (is_big(term) && !big_sign(term)) { + ErtsDigit* xr = big_v(term); + + ERTS_CT_ASSERT(sizeof(ErtsDigit) == sizeof(Uint)); + *up = (Uint)*xr; /* just pick first word */ + return 1; + } else { + *up = BADARG; + return 0; + } +} + int term_to_UWord(Eterm term, UWord *up) { diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index 4aa9724ae3..3c1f1e6b23 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -161,6 +161,7 @@ Eterm bytes_to_big(byte*, dsize_t, int, Eterm*); byte* big_to_bytes(Eterm, byte*); int term_to_Uint(Eterm, Uint*); +int term_to_Uint_mask(Eterm, Uint*); int term_to_UWord(Eterm, UWord*); int term_to_Sint(Eterm, Sint*); #if HAVE_INT64 diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index e670fbf31c..247c8f1122 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -47,7 +47,7 @@ erts_init_binary(void) if ((((UWord) &((Binary *) 0)->orig_bytes[0]) % ((UWord) 8)) != 0) { /* I assume that any compiler should be able to optimize this away. If not, this test is not very expensive... */ - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Internal error: Address of orig_bytes[0] of a Binary" " is *not* 8-byte aligned\n"); } diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 4ce9d24479..0ddf7f4e6d 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -104,7 +104,7 @@ process_killer(void) erts_printf("(k)ill (n)ext (r)eturn:\n"); while(1) { if ((j = sys_get_key(0)) <= 0) - erl_exit(0, ""); + erts_exit(0, ""); switch(j) { case 'k': { ErtsProcLocks rp_locks = ERTS_PROC_LOCKS_XSIG_SEND; @@ -493,7 +493,7 @@ do_break(void) halt immediately if break is called */ mode = erts_read_env("ERL_CONSOLE_MODE"); if (mode && strcmp(mode, "window") != 0) - erl_exit(0, ""); + erts_exit(0, ""); erts_free_read_env(mode); #endif /* __WIN32__ */ @@ -503,7 +503,7 @@ do_break(void) while (1) { if ((i = sys_get_key(0)) <= 0) - erl_exit(0, ""); + erts_exit(0, ""); switch (i) { case 'q': case 'a': @@ -513,9 +513,9 @@ do_break(void) * The usual reason for a read error is Ctrl-C. Treat this as * 'a' to avoid infinite loop. */ - erl_exit(0, ""); + erts_exit(0, ""); case 'A': /* Halt generating crash dump */ - erl_exit(1, "Crash dump requested by user"); + erts_exit(ERTS_ERROR_EXIT, "Crash dump requested by user"); case 'c': return; case 'p': @@ -785,7 +785,7 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) erts_fdprintf(fd, "Atoms: %d\n", atom_table_size()); #ifdef USE_THREADS - /* We want to note which thread it was that called erl_exit */ + /* We want to note which thread it was that called erts_exit */ if (erts_get_scheduler_data()) { erts_fdprintf(fd, "Calling Thread: scheduler:%d\n", erts_get_scheduler_data()->no); diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index 8849dadd00..64be43edb4 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -59,7 +59,7 @@ copy_object(Eterm obj, Process* to) res = copy_struct(obj, size, &hp, &to->off_heap); #ifdef DEBUG if (eq(obj, res) == 0) { - erl_exit(ERTS_ABORT_EXIT, "copy not equal to source\n"); + erts_exit(ERTS_ABORT_EXIT, "copy not equal to source\n"); } #endif return res; @@ -171,7 +171,7 @@ Uint size_object(Eterm obj) } break; default: - erl_exit(ERTS_ABORT_EXIT, "size_object: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); + erts_exit(ERTS_ABORT_EXIT, "size_object: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); } break; case SUB_BINARY_SUBTAG: @@ -202,7 +202,7 @@ Uint size_object(Eterm obj) } break; case BIN_MATCHSTATE_SUBTAG: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "size_object: matchstate term not allowed"); default: sum += thing_arityval(hdr) + 1; @@ -219,7 +219,7 @@ Uint size_object(Eterm obj) obj = ESTACK_POP(s); break; default: - erl_exit(ERTS_ABORT_EXIT, "size_object: bad tag for %#x\n", obj); + erts_exit(ERTS_ABORT_EXIT, "size_object: bad tag for %#x\n", obj); } } } @@ -272,7 +272,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) goto L_copy_list; case TAG_PRIMARY_BOXED: argp = &res; goto L_copy_boxed; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s, line %d: Internal error in copy_struct: 0x%08x\n", __FILE__, __LINE__,obj); } @@ -331,7 +331,7 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) case TAG_PRIMARY_IMMED1: *tailp = obj; goto L_copy; case TAG_PRIMARY_BOXED: argp = tailp; goto L_copy_boxed; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s, line %d: Internal error in copy_struct: 0x%08x\n", __FILE__, __LINE__,obj); } @@ -512,11 +512,11 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) *argp = make_hashmap_rel(tp, dst_base); break; default: - erl_exit(ERTS_ABORT_EXIT, "copy_struct: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); + erts_exit(ERTS_ABORT_EXIT, "copy_struct: bad hashmap type %d\n", MAP_HEADER_TYPE(hdr)); } break; case BIN_MATCHSTATE_SUBTAG: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "copy_struct: matchstate term not allowed"); default: i = thing_arityval(hdr)+1; @@ -540,13 +540,13 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) #ifdef DEBUG if (htop != hbot) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Internal error in copy_struct() when copying %T:" " htop=%p != hbot=%p (sz=%beu)\n", org_obj, htop, hbot, org_sz); #else if (htop > hbot) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Internal error in copy_struct(): htop, hbot overrun\n"); } #endif diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 7be2b77a3b..787241b960 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -1959,7 +1959,7 @@ erts_dsig_send(ErtsDSigData *dsdp, struct erts_dsig_send_context* ctx) goto done; } default: - erl_exit(ERTS_ABORT_EXIT, "dsig_send invalid phase (%d)\n", (int)ctx->phase); + erts_exit(ERTS_ABORT_EXIT, "dsig_send invalid phase (%d)\n", (int)ctx->phase); } } @@ -1980,7 +1980,7 @@ dist_port_command(Port *prt, ErtsDistOutputBuf *obuf) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); if (size > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Absurdly large distribution output data buffer " "(%beu bytes) passed.\n", size); @@ -2020,7 +2020,7 @@ dist_port_commandv(Port *prt, ErtsDistOutputBuf *obuf) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); if (size > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Absurdly large distribution output data buffer " "(%beu bytes) passed.\n", size); @@ -3382,7 +3382,7 @@ send_nodes_mon_msgs(Process *c_p, Eterm what, Eterm node, Eterm type, Eterm reas continue; break; default: - erl_exit(ERTS_ABORT_EXIT, "Bad node type found\n"); + erts_exit(ERTS_ABORT_EXIT, "Bad node type found\n"); } } @@ -3691,7 +3691,7 @@ erts_processes_monitoring_nodes(Process *c_p) case ERTS_NODES_MON_OPT_TYPES: type = am_all; break; case ERTS_NODES_MON_OPT_TYPE_VISIBLE: type = am_visible; break; case ERTS_NODES_MON_OPT_TYPE_HIDDEN: type = am_hidden; break; - default: erl_exit(ERTS_ABORT_EXIT, "Bad node type found\n"); + default: erts_exit(ERTS_ABORT_EXIT, "Bad node type found\n"); } olist = erts_bld_cons(hpp, szp, erts_bld_tuple(hpp, szp, 2, diff --git a/erts/emulator/beam/erl_afit_alloc.c b/erts/emulator/beam/erl_afit_alloc.c index 47dafa53c0..4b0541c10e 100644 --- a/erts/emulator/beam/erl_afit_alloc.c +++ b/erts/emulator/beam/erl_afit_alloc.c @@ -241,7 +241,7 @@ info_options(Allctr_t *allctr, if (hpp || szp) { if (!atoms_initialized) - erl_exit(1, "%s:%d: Internal error: Atoms not initialized", + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; res = NIL; diff --git a/erts/emulator/beam/erl_alloc.c b/erts/emulator/beam/erl_alloc.c index 2a97069ac2..0877c24404 100644 --- a/erts/emulator/beam/erl_alloc.c +++ b/erts/emulator/beam/erl_alloc.c @@ -653,11 +653,11 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; - erl_exit(-1, "Failed to lock physical memory: %s (%d)\n", + erts_exit(1, "Failed to lock physical memory: %s (%d)\n", errstr, err); } #else - erl_exit(-1, "Failed to lock physical memory: Not supported\n"); + erts_exit(1, "Failed to lock physical memory: Not supported\n"); #endif } @@ -806,13 +806,13 @@ erts_alloc_init(int *argc, char **argv, ErtsAllocInitOpts *eaiop) for (i = ERTS_ALC_A_MIN; i <= ERTS_ALC_A_MAX; i++) { if (!erts_allctrs[i].alloc) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Missing alloc function for %s\n", ERTS_ALC_A2AD(i)); if (!erts_allctrs[i].realloc) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Missing realloc function for %s\n", ERTS_ALC_A2AD(i)); if (!erts_allctrs[i].free) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Missing free function for %s\n", ERTS_ALC_A2AD(i)); } @@ -890,7 +890,7 @@ erts_alloc_late_init(void) static void * erts_realloc_fixed_size(ErtsAlcType_t type, void *extra, void *p, Uint size) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Attempt to reallocate a block of the fixed size type %s\n", ERTS_ALC_T2TD(type)); } @@ -1012,7 +1012,7 @@ start_au_allocator(ErtsAlcType_t alctr_n, * tspec->size) + ERTS_CACHE_LINE_SIZE - 1)); if (!states) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to allocate allocator states for %salloc\n", init->init.util.name_prefix); tspec->allctr = (Allctr_t **) states; @@ -1040,7 +1040,7 @@ start_au_allocator(ErtsAlcType_t alctr_n, (tot_fix_list_size + ERTS_CACHE_LINE_SIZE - 1)); if (!fix_lists) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to allocate fix lists for %salloc\n", init->init.util.name_prefix); @@ -1114,7 +1114,7 @@ start_au_allocator(ErtsAlcType_t alctr_n, } if (!as) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to start %salloc\n", init->init.util.name_prefix); ASSERT(as == (void *) as0); @@ -1909,7 +1909,7 @@ erts_alc_fatal_error(int error, int func, ErtsAlcType_t n, ...) case ERTS_ALC_O_FREE: op_str = "free"; break; default: op_str = "UNKNOWN"; break; } - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s: %s operation not supported (memory type: \"%s\")\n", allctr_str, op_str, t_str); break; @@ -1923,18 +1923,18 @@ erts_alc_fatal_error(int error, int func, ErtsAlcType_t n, ...) va_start(argp, n); size = va_arg(argp, Uint); va_end(argp); - erl_exit(-1, + erts_exit(1, "%s: Cannot %s %lu bytes of memory (of type \"%s\").\n", allctr_str, op, size, t_str); break; } case ERTS_ALC_E_NOALLCTR: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown allocator type: %d\n", ERTS_ALC_T2A(ERTS_ALC_N2T(n))); break; default: - erl_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown error: %d\n", error); + erts_exit(ERTS_ABORT_EXIT, "erts_alloc: Unknown error: %d\n", error); break; } } @@ -3189,7 +3189,7 @@ reply_alloc_info(void *vair) make_small(0), ainfo); } else { - erl_exit(ERTS_ABORT_EXIT, "%s:%d: internal error\n", + erts_exit(ERTS_ABORT_EXIT, "%s:%d: internal error\n", __FILE__, __LINE__); } } @@ -3426,7 +3426,7 @@ void *safe_realloc(void *ptr, Uint sz) * Keep alloc_SUITE_data/allocator_test.h updated if changes are made * * to erts_alc_test() * \* */ -#define ERTS_ALC_TEST_ABORT erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n") +#define ERTS_ALC_TEST_ABORT erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n") UWord erts_alc_test(UWord op, UWord a1, UWord a2, UWord a3) { @@ -3888,7 +3888,7 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) found_type = GET_TYPE_OF_PATTERN(pre_pattern); if (pre_pattern != MK_PATTERN(n)) { if ((FIXED_FENCE_PATTERN_MASK & pre_pattern) != FIXED_FENCE_PATTERN) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "ERROR: Fence at beginning of memory block (p=0x%u) " "clobbered.\n", (UWord) ptr); @@ -3905,12 +3905,12 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) char *op_str; if ((FIXED_FENCE_PATTERN_MASK & post_pattern) != FIXED_FENCE_PATTERN) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "ERROR: Fence at end of memory block (p=0x%u, sz=%u) " "clobbered.\n", (UWord) ptr, (UWord) sz); if (found_type != GET_TYPE_OF_PATTERN(post_pattern)) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "ERROR: Fence around memory block (p=0x%u, sz=%u) " "clobbered.\n", (UWord) ptr, (UWord) sz); @@ -3933,7 +3933,7 @@ check_memory_fence(void *ptr, Uint *size, ErtsAlcType_t n, int func) default: op_str = "???"; break; } - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "ERROR: Memory block (p=0x%u, sz=%u) allocated as type \"%s\"," " but %s as type \"%s\".\n", (UWord) ptr, (UWord) sz, ftype, op_str, otype); diff --git a/erts/emulator/beam/erl_alloc.types b/erts/emulator/beam/erl_alloc.types index 1ecebdeb07..7738531142 100644 --- a/erts/emulator/beam/erl_alloc.types +++ b/erts/emulator/beam/erl_alloc.types @@ -369,6 +369,7 @@ type AINFO_REQ STANDARD_LOW SYSTEM alloc_info_request type SCHED_WTIME_REQ STANDARD_LOW SYSTEM sched_wall_time_request type GC_INFO_REQ STANDARD_LOW SYSTEM gc_info_request type PORT_DATA_HEAP STANDARD_LOW SYSTEM port_data_heap +type SYS_CHECK_REQ STANDARD_LOW SYSTEM system_check_request +else # "fullword" @@ -389,6 +390,7 @@ type AINFO_REQ SHORT_LIVED SYSTEM alloc_info_request type SCHED_WTIME_REQ SHORT_LIVED SYSTEM sched_wall_time_request type GC_INFO_REQ SHORT_LIVED SYSTEM gc_info_request type PORT_DATA_HEAP STANDARD SYSTEM port_data_heap +type SYS_CHECK_REQ SHORT_LIVED SYSTEM system_check_request +endif diff --git a/erts/emulator/beam/erl_alloc_util.c b/erts/emulator/beam/erl_alloc_util.c index 8229a15824..18312eacde 100644 --- a/erts/emulator/beam/erl_alloc_util.c +++ b/erts/emulator/beam/erl_alloc_util.c @@ -4518,7 +4518,7 @@ make_name_atoms(Allctr_t *allctr) size_t prefix_len = strlen(allctr->name_prefix); if (prefix_len > MAX_ATOM_CHARACTERS + sizeof(realloc) - 1) - erl_exit(1,"Too long allocator name: %salloc\n",allctr->name_prefix); + erts_exit(ERTS_ERROR_EXIT,"Too long allocator name: %salloc\n",allctr->name_prefix); memcpy((void *) buf, (void *) allctr->name_prefix, prefix_len); @@ -5720,7 +5720,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) /* erts_alcu_start assumes that allctr has been zeroed */ if (((UWord)allctr & ERTS_CRR_ALCTR_FLG_MASK) != 0) { - erl_exit(ERTS_ABORT_EXIT, "%s:%d:erts_alcu_start: Alignment error\n", + erts_exit(ERTS_ABORT_EXIT, "%s:%d:erts_alcu_start: Alignment error\n", __FILE__, __LINE__); } @@ -5904,7 +5904,7 @@ erts_alcu_start(Allctr_t *allctr, AllctrInit_t *init) if (allctr->thread_safe) erts_mtx_destroy(&allctr->mutex); #endif - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to create main carrier for %salloc\n", init->name_prefix); } @@ -6120,7 +6120,7 @@ erts_alcu_verify_unused(Allctr_t *allctr) if (no) { UWord sz = allctr->sbcs.blocks.curr.size; sz += allctr->mbcs.blocks.curr.size; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%salloc() used when expected to be unused!\n" "Total amount of blocks allocated: %bpu\n" "Total amount of bytes allocated: %bpu\n", diff --git a/erts/emulator/beam/erl_ao_firstfit_alloc.c b/erts/emulator/beam/erl_ao_firstfit_alloc.c index 19420af8ab..5cd067ff54 100644 --- a/erts/emulator/beam/erl_ao_firstfit_alloc.c +++ b/erts/emulator/beam/erl_ao_firstfit_alloc.c @@ -1035,7 +1035,7 @@ info_options(Allctr_t *allctr, if (hpp || szp) { if (!atoms_initialized) - erl_exit(1, "%s:%d: Internal error: Atoms not initialized", + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; res = NIL; diff --git a/erts/emulator/beam/erl_bestfit_alloc.c b/erts/emulator/beam/erl_bestfit_alloc.c index fb853b65ab..f39a18ac88 100644 --- a/erts/emulator/beam/erl_bestfit_alloc.c +++ b/erts/emulator/beam/erl_bestfit_alloc.c @@ -940,7 +940,7 @@ info_options(Allctr_t *allctr, if (hpp || szp) { if (!atoms_initialized) - erl_exit(1, "%s:%d: Internal error: Atoms not initialized", + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", __FILE__, __LINE__);; res = NIL; diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index 28bec6325c..f4ef59993a 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -1309,7 +1309,7 @@ static Eterm notify_when_loaded(Process *p, Eterm name_term, char *name, ErtsPro case ERL_DE_FORCE_RELOAD: break; default: - erl_exit(1,"Internal error, unknown state %u in dynamic driver.", drv->handle->status); + erts_exit(ERTS_ERROR_EXIT,"Internal error, unknown state %u in dynamic driver.", drv->handle->status); } p->flags |= F_USING_DDLL; r = add_monitor(p, drv->handle, ERL_DE_PROC_AWAIT_LOAD); diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c index 414ff6711a..2c232c6c03 100644 --- a/erts/emulator/beam/erl_bif_info.c +++ b/erts/emulator/beam/erl_bif_info.c @@ -65,6 +65,7 @@ static Export* gather_io_bytes_trap = NULL; static Export *gather_sched_wall_time_res_trap; static Export *gather_gc_info_res_trap; +static Export *gather_system_check_res_trap; #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1) @@ -914,7 +915,7 @@ BIF_RETTYPE process_info_1(BIF_ALIST_1) case ERTS_PI_FAIL_TYPE_AWAIT_EXIT: ERTS_BIF_AWAIT_X_DATA_TRAP(BIF_P, BIF_ARG_1, am_undefined); default: - erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", __FILE__, __LINE__); + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", __FILE__, __LINE__); } } @@ -954,7 +955,7 @@ BIF_RETTYPE process_info_2(BIF_ALIST_2) case ERTS_PI_FAIL_TYPE_AWAIT_EXIT: ERTS_BIF_AWAIT_X_DATA_TRAP(BIF_P, BIF_ARG_1, am_undefined); default: - erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error", __FILE__, __LINE__); } } @@ -1759,7 +1760,7 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */ return res; buf = (char *) erts_alloc(ERTS_ALC_T_TMP, len+1); if (intlist_to_buf(*tp, buf, len) != len) - erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); buf[len] = '\0'; res = erts_instr_dump_memory_map(buf) ? am_true : am_false; erts_free(ERTS_ALC_T_TMP, (void *) buf); @@ -1778,7 +1779,7 @@ info_1_tuple(Process* BIF_P, /* Pointer to current process. */ return res; buf = (char *) erts_alloc(ERTS_ALC_T_TMP, len+1); if (intlist_to_buf(tp[1], buf, len) != len) - erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); buf[len] = '\0'; res = erts_instr_dump_stat(buf, 1) ? am_true : am_false; erts_free(ERTS_ALC_T_TMP, (void *) buf); @@ -3784,6 +3785,18 @@ BIF_RETTYPE erts_internal_is_system_process_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } +BIF_RETTYPE erts_internal_system_check_1(BIF_ALIST_1) +{ + Eterm res; + if (ERTS_IS_ATOM_STR("schedulers", BIF_ARG_1)) { + res = erts_system_check_request(BIF_P); + if (is_non_value(res)) + BIF_RET(am_undefined); + BIF_TRAP1(gather_system_check_res_trap, BIF_P, res); + } + + BIF_ERROR(BIF_P, BADARG); +} static erts_smp_atomic_t hipe_test_reschedule_flag; @@ -3798,7 +3811,7 @@ static void broken_halt_test(Eterm bif_arg_2) #if defined(ERTS_HAVE_TRY_CATCH) erts_get_scheduler_data()->run_queue = NULL; #endif - erl_exit(ERTS_DUMP_EXIT, "%T", bif_arg_2); + erts_exit(ERTS_DUMP_EXIT, "%T", bif_arg_2); } @@ -4045,7 +4058,7 @@ BIF_RETTYPE erts_debug_set_internal_state_2(BIF_ALIST_2) BIF_RET(am_true); } else if (ERTS_IS_ATOM_STR("abort", BIF_ARG_1)) { - erl_exit(ERTS_ABORT_EXIT, "%T\n", BIF_ARG_2); + erts_exit(ERTS_ABORT_EXIT, "%T\n", BIF_ARG_2); } else if (ERTS_IS_ATOM_STR("kill_dist_connection", BIF_ARG_1)) { DistEntry *dep = erts_sysname_to_connected_dist_entry(BIF_ARG_2); @@ -4391,6 +4404,8 @@ erts_bif_info_init(void) = erts_export_put(am_erlang, am_gather_gc_info_result, 1); gather_io_bytes_trap = erts_export_put(am_erts_internal, am_gather_io_bytes, 2); + gather_system_check_res_trap + = erts_export_put(am_erts_internal, am_gather_system_check_result, 1); process_info_init(); os_info_init(); } diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c index e47d7bcbbb..27c24197ea 100644 --- a/erts/emulator/beam/erl_bif_port.c +++ b/erts/emulator/beam/erl_bif_port.c @@ -791,7 +791,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump) } else { name_buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1); if (intlist_to_buf(name, name_buf, i) != i) - erl_exit(1, "%s:%d: Internal error\n", __FILE__, __LINE__); + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); name_buf[i] = '\0'; } driver = &vanilla_driver; @@ -1169,7 +1169,7 @@ static Eterm http_bld_uri(struct packet_callback_args* pca, return erts_bld_tuple(hpp, szp, 3, am_scheme, s1, s2); default: - erl_exit(1, "%s, line %d: type=%u\n", __FILE__, __LINE__, uri->type); + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: type=%u\n", __FILE__, __LINE__, uri->type); } } diff --git a/erts/emulator/beam/erl_cpu_topology.c b/erts/emulator/beam/erl_cpu_topology.c index 8395f6ecc6..c263eebfcc 100644 --- a/erts/emulator/beam/erl_cpu_topology.c +++ b/erts/emulator/beam/erl_cpu_topology.c @@ -402,7 +402,7 @@ cpu_bind_order_sort(erts_cpu_topology_t *cpudata, break; default: cmp_func = NULL; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Bad cpu bind type: %d\n", (int) cpu_bind_order); break; @@ -1590,7 +1590,7 @@ get_cpu_topology_term(Process *c_p, int type) } break; default: - erl_exit(ERTS_ABORT_EXIT, "Bad cpu topology type: %d\n", type); + erts_exit(ERTS_ABORT_EXIT, "Bad cpu topology type: %d\n", type); break; } @@ -1967,7 +1967,7 @@ cpu_group_insert(erts_cpu_groups_map_t *map, ix = 0; } while (ix != start); - erl_exit(ERTS_ABORT_EXIT, "Reader groups map full\n"); + erts_exit(ERTS_ABORT_EXIT, "Reader groups map full\n"); } @@ -2290,7 +2290,7 @@ remove_cpu_groups(erts_cpu_groups_callback_t callback, void *arg) prev_cgm = cgm; } - erl_exit(ERTS_ABORT_EXIT, "Cpu groups not found\n"); + erts_exit(ERTS_ABORT_EXIT, "Cpu groups not found\n"); } static int @@ -2320,7 +2320,7 @@ cpu_groups_lookup(erts_cpu_groups_map_t *map, ix = 0; } while (ix != start); - erl_exit(ERTS_ABORT_EXIT, "Logical cpu id %d not found\n", logical); + erts_exit(ERTS_ABORT_EXIT, "Logical cpu id %d not found\n", logical); } static void diff --git a/erts/emulator/beam/erl_db.c b/erts/emulator/beam/erl_db.c index 645f9e3c28..870b556851 100644 --- a/erts/emulator/beam/erl_db.c +++ b/erts/emulator/beam/erl_db.c @@ -1295,7 +1295,7 @@ BIF_RETTYPE ets_rename_2(BIF_ALIST_2) goto badarg; if (!remove_named_tab(tb, 1)) - erl_exit(1,"Could not find named tab %s", tb->common.id); + erts_exit(ERTS_ERROR_EXIT,"Could not find named tab %s", tb->common.id); tb->common.id = tb->common.the_name = BIF_ARG_2; @@ -1580,7 +1580,7 @@ BIF_RETTYPE ets_new_2(BIF_ALIST_2) BIF_P->common.id, make_small(slot)), 0) != DB_ERROR_NONE) { - erl_exit(1,"Could not update ets metadata."); + erts_exit(ERTS_ERROR_EXIT,"Could not update ets metadata."); } db_meta_unlock(meta_pid_to_tab, LCK_WRITE_REC); @@ -2939,7 +2939,7 @@ void init_db(ErtsDbSpinCount db_spin_count) bits = erts_fit_in_bits_int32(db_max_tabs-1); if (bits > SMALL_BITS) { - erl_exit(1,"Max limit for ets tabled too high %u (max %u).", + erts_exit(ERTS_ERROR_EXIT,"Max limit for ets tabled too high %u (max %u).", db_max_tabs, ((Uint)1)<<SMALL_BITS); } meta_main_tab_slot_mask = (((Uint)1)<<bits) - 1; @@ -3000,7 +3000,7 @@ void init_db(ErtsDbSpinCount db_spin_count) db_init_lock(meta_pid_to_tab, "meta_pid_to_tab", "meta_pid_to_tab_FIX");*/ if (db_create_hash(NULL, meta_pid_to_tab) != DB_ERROR_NONE) { - erl_exit(1,"Unable to create ets metadata tables."); + erts_exit(ERTS_ERROR_EXIT,"Unable to create ets metadata tables."); } erts_smp_atomic_set_nob(&init_tb.common.memory_size, 0); @@ -3031,7 +3031,7 @@ void init_db(ErtsDbSpinCount db_spin_count) db_init_lock(meta_pid_to_fixed_tab, "meta_pid_to_fixed_tab", "meta_pid_to_fixed_tab_FIX");*/ if (db_create_hash(NULL, meta_pid_to_fixed_tab) != DB_ERROR_NONE) { - erl_exit(1,"Unable to create ets metadata tables."); + erts_exit(ERTS_ERROR_EXIT,"Unable to create ets metadata tables."); } /* Non visual BIF to trap to. */ @@ -3228,7 +3228,7 @@ retry: * yielding. */ #define ERTS_DB_INTERNAL_ERROR(LSTR) \ - erl_exit(ERTS_ABORT_EXIT, "%s:%d:erts_db_process_exiting(): " LSTR "\n", \ + erts_exit(ERTS_ABORT_EXIT, "%s:%d:erts_db_process_exiting(): " LSTR "\n", \ __FILE__, __LINE__) int @@ -3500,7 +3500,7 @@ static void fix_table_locked(Process* p, DbTable* tb) make_small(tb->common.slot)), 0) != DB_ERROR_NONE) { UnUseTmpHeap(3,p); - erl_exit(1,"Could not insert ets metadata in safe_fixtable."); + erts_exit(ERTS_ERROR_EXIT,"Could not insert ets metadata in safe_fixtable."); } UnUseTmpHeap(3,p); db_meta_unlock(meta_pid_to_fixed_tab, LCK_WRITE_REC); diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c index 98a2e2842a..fa925c94a5 100644 --- a/erts/emulator/beam/erl_db_hash.c +++ b/erts/emulator/beam/erl_db_hash.c @@ -3028,7 +3028,7 @@ void db_check_table_hash(DbTable *tbl) if ((list = BUCKET(tb,j)) != 0) { while (list != 0) { if (!is_tuple(make_tuple(list->dbterm.tpl))) { - erl_exit(1, "Bad term in slot %d of ets table", j); + erts_exit(ERTS_ERROR_EXIT, "Bad term in slot %d of ets table", j); } list = list->next; } diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c index 465aa566ad..61293fbf9a 100644 --- a/erts/emulator/beam/erl_db_tree.c +++ b/erts/emulator/beam/erl_db_tree.c @@ -1213,7 +1213,7 @@ static int db_select_count_continue_tree(Process *p, tptr = tuple_val(continuation); if (arityval(*tptr) != 5) - erl_exit(1,"Internal error in ets:select_count/1"); + erts_exit(ERTS_ERROR_EXIT,"Internal error in ets:select_count/1"); lastkey = tptr[2]; end_condition = tptr[3]; diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index dab357a079..af5b611afd 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -1946,11 +1946,11 @@ restart: #ifdef DMC_DEBUG if (*heap_fence != FENCE_PATTERN) { - erl_exit(1, "Heap fence overwritten in db_prog_match after op " + erts_exit(ERTS_ERROR_EXIT, "Heap fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *heap_fence); } if (*stack_fence != FENCE_PATTERN) { - erl_exit(1, "Stack fence overwritten in db_prog_match after op " + erts_exit(ERTS_ERROR_EXIT, "Stack fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *stack_fence); } @@ -2615,7 +2615,7 @@ restart: case matchHalt: goto success; default: - erl_exit(1, "Internal error: unexpected opcode in match program."); + erts_exit(ERTS_ERROR_EXIT, "Internal error: unexpected opcode in match program."); } } fail: @@ -2639,11 +2639,11 @@ success: #ifdef DMC_DEBUG if (*heap_fence != FENCE_PATTERN) { - erl_exit(1, "Heap fence overwritten in db_prog_match after op " + erts_exit(ERTS_ERROR_EXIT, "Heap fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *heap_fence); } if (*stack_fence != FENCE_PATTERN) { - erl_exit(1, "Stack fence overwritten in db_prog_match after op " + erts_exit(ERTS_ERROR_EXIT, "Stack fence overwritten in db_prog_match after op " "0x%08x, overwritten with 0x%08x.", save_op, *stack_fence); } @@ -3683,7 +3683,7 @@ static DMCRet dmc_one_term(DMCContext *context, break; } default: - erl_exit(1, "db_match_compile: " + erts_exit(ERTS_ERROR_EXIT, "db_match_compile: " "Bad object on heap: 0x%bex\n", c); } return retOk; @@ -4930,7 +4930,7 @@ static DMCRet dmc_fun(DMCContext *context, DMC_PUSH(*text, matchCall3); break; default: - erl_exit(1,"ets:match() internal error, " + erts_exit(ERTS_ERROR_EXIT,"ets:match() internal error, " "guard with more than 3 arguments."); } DMC_PUSH(*text, (UWord) b->biff); @@ -5210,7 +5210,7 @@ static Uint my_size_object(Eterm t) tmp == am_const) { sum += size_object(tuple_val(t)[2]); } else { - erl_exit(1,"Internal error, sizing unrecognized object in " + erts_exit(ERTS_ERROR_EXIT,"Internal error, sizing unrecognized object in " "(d)ets:match compilation."); } break; @@ -5255,7 +5255,7 @@ static Eterm my_copy_struct(Eterm t, Eterm **hp, ErlOffHeap* off_heap) sz = size_object(b); ret = copy_struct(b,sz,hp,off_heap); } else { - erl_exit(1, "Trying to constant-copy non constant expression " + erts_exit(ERTS_ERROR_EXIT, "Trying to constant-copy non constant expression " "0x%bex in (d)ets:match compilation.", t); } } else { diff --git a/erts/emulator/beam/erl_debug.c b/erts/emulator/beam/erl_debug.c index 2dcfb79f00..4928aae9c2 100644 --- a/erts/emulator/beam/erl_debug.c +++ b/erts/emulator/beam/erl_debug.c @@ -255,14 +255,14 @@ void erts_check_stack(Process *p) Eterm *stack_end = p->htop; if (p->stop > stack_start) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "<%lu.%lu.%lu>: Stack underflow\n", internal_pid_channel_no(p->common.id), internal_pid_number(p->common.id), internal_pid_serial(p->common.id)); if (p->stop < stack_end) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "<%lu.%lu.%lu>: Stack overflow\n", internal_pid_channel_no(p->common.id), internal_pid_number(p->common.id), @@ -287,7 +287,7 @@ void erts_check_stack(Process *p) if (in_mbuf) continue; - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "<%lu.%lu.%lu>: Wild stack pointer\n", internal_pid_channel_no(p->common.id), internal_pid_number(p->common.id), @@ -372,7 +372,7 @@ void erts_check_memory(Process *p, Eterm *start, Eterm *end) #ifdef DEBUG if (hval == DEBUG_BAD_WORD) { print_untagged_memory(start, end); - erl_exit(1, "Uninitialized HAlloc'ed memory found @ 0x%0*lx!\n", + erts_exit(ERTS_ERROR_EXIT, "Uninitialized HAlloc'ed memory found @ 0x%0*lx!\n", PTR_SIZE,(unsigned long)(pos - 1)); } #endif @@ -385,7 +385,7 @@ void erts_check_memory(Process *p, Eterm *start, Eterm *end) if (verify_eterm(p,hval)) continue; - erl_exit(1, "Wild pointer found @ 0x%0*lx!\n", + erts_exit(ERTS_ERROR_EXIT, "Wild pointer found @ 0x%0*lx!\n", PTR_SIZE,(unsigned long)(pos - 1)); } } @@ -395,11 +395,11 @@ void verify_process(Process *p) #define VERIFY_AREA(name,ptr,sz) { \ int n = (sz); \ while (n--) if(!verify_eterm(p,*(ptr+n))) \ - erl_exit(1,"Wild pointer found in " name " of %T!\n",p->common.id); } + erts_exit(ERTS_ERROR_EXIT,"Wild pointer found in " name " of %T!\n",p->common.id); } #define VERIFY_ETERM(name,eterm) { \ if(!verify_eterm(p,eterm)) \ - erl_exit(1,"Wild pointer found in " name " of %T!\n",p->common.id); } + erts_exit(ERTS_ERROR_EXIT,"Wild pointer found in " name " of %T!\n",p->common.id); } ErlMessage* mp = p->msg.first; diff --git a/erts/emulator/beam/erl_drv_thread.c b/erts/emulator/beam/erl_drv_thread.c index e0404eb5c9..184f8e8931 100644 --- a/erts/emulator/beam/erl_drv_thread.c +++ b/erts/emulator/beam/erl_drv_thread.c @@ -43,7 +43,7 @@ fatal_error(int err, char *func) else estr = "Unknown error"; } - erl_exit(ERTS_ABORT_EXIT, "Fatal error in %s: %s [%d]\n", func, estr, err); + erts_exit(ERTS_ABORT_EXIT, "Fatal error in %s: %s [%d]\n", func, estr, err); } #define ERL_DRV_TSD_KEYS_INC 10 diff --git a/erts/emulator/beam/erl_fun.c b/erts/emulator/beam/erl_fun.c index 4268e2d40a..2f13aa364f 100644 --- a/erts/emulator/beam/erl_fun.c +++ b/erts/emulator/beam/erl_fun.c @@ -185,7 +185,7 @@ erts_erase_fun_entry(ErlFunEntry* fe) #endif { if (fe->address != unloaded_fun) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "Internal error: " "Invalid reference count found on #Fun<%T.%d.%d>: " " About to erase fun still referred by code.\n", diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index 2f21111a2e..f48c46ca33 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -59,7 +59,7 @@ erts_fprintf(stderr, "stop=%p\n", (p)->stop); \ erts_fprintf(stderr, "htop=%p\n", (p)->htop); \ erts_fprintf(stderr, "heap=%p\n", (p)->heap); \ - erl_exit(ERTS_ABORT_EXIT, "%s, line %d: %T: Overrun stack and heap\n", \ + erts_exit(ERTS_ABORT_EXIT, "%s, line %d: %T: Overrun stack and heap\n", \ __FILE__,__LINE__,(P)->common.id); \ } @@ -268,7 +268,7 @@ erts_next_heap_size(Uint size, Uint offset) low = mid + 1; } } - erl_exit(1, "no next heap size found: %beu, offset %beu\n", size, offset); + erts_exit(ERTS_ERROR_EXIT, "no next heap size found: %beu, offset %beu\n", size, offset); } return 0; } @@ -2788,7 +2788,7 @@ within(Eterm *ptr, Process *p) #define ERTS_CHK_OFFHEAP_ASSERT(EXP) \ do { \ if (!(EXP)) \ - erl_exit(ERTS_ABORT_EXIT, \ + erts_exit(ERTS_ABORT_EXIT, \ "%s:%d: Assertion failed: %s\n", \ __FILE__, __LINE__, #EXP); \ } while (0) diff --git a/erts/emulator/beam/erl_goodfit_alloc.c b/erts/emulator/beam/erl_goodfit_alloc.c index f89f8723d9..9b4aad9d91 100644 --- a/erts/emulator/beam/erl_goodfit_alloc.c +++ b/erts/emulator/beam/erl_goodfit_alloc.c @@ -571,8 +571,8 @@ info_options(Allctr_t *allctr, if (hpp || szp) { if (!atoms_initialized) - erl_exit(1, "%s:%d: Internal error: Atoms not initialized", - __FILE__, __LINE__);; + erts_exit(ERTS_ERROR_EXIT, "%s:%d: Internal error: Atoms not initialized", + __FILE__, __LINE__); res = NIL; add_2tup(hpp, szp, &res, am.as, am.gf); diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index d9c3b0dcf4..e729574ec7 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -269,7 +269,7 @@ this_rel_num(void) i++; this_rel = atoi(&this_rel_str[i]); if (this_rel < 1) - erl_exit(-1, "Unexpected ERLANG_OTP_RELEASE format\n"); + erts_exit(1, "Unexpected ERLANG_OTP_RELEASE format\n"); } return this_rel; } @@ -415,7 +415,7 @@ erl_first_process_otp(char* modname, void* code, unsigned size, int argc, char** start_mod = erts_atom_put((byte *) modname, sys_strlen(modname), ERTS_ATOM_ENC_LATIN1, 1); if (erts_find_function(start_mod, am_start, 2, erts_active_code_ix()) == NULL) { - erl_exit(5, "No function %s:start/2\n", modname); + erts_exit(ERTS_ERROR_EXIT, "No function %s:start/2\n", modname); } /* @@ -512,12 +512,12 @@ load_preloaded(void) length = preload_p[i].size; module_name = erts_atom_put((byte *) name, sys_strlen(name), ERTS_ATOM_ENC_LATIN1, 1); if ((code = sys_preload_begin(&preload_p[i])) == 0) - erl_exit(1, "Failed to find preloaded code for module %s\n", + erts_exit(ERTS_ERROR_EXIT, "Failed to find preloaded code for module %s\n", name); res = erts_preload_module(NULL, 0, NIL, &module_name, code, length); sys_preload_end(&preload_p[i]); if (res != NIL) - erl_exit(1,"Failed loading preloaded module %s (%T)\n", + erts_exit(ERTS_ERROR_EXIT,"Failed loading preloaded module %s (%T)\n", name, res); i++; } @@ -648,7 +648,7 @@ void erts_usage(void) erts_fprintf(stderr, "Note that if the emulator is started with erlexec (typically\n"); erts_fprintf(stderr, "from the erl script), these flags should be specified with +.\n"); erts_fprintf(stderr, "\n\n"); - erl_exit(-1, ""); + erts_exit(1, ""); } #ifdef USE_THREADS @@ -1445,7 +1445,7 @@ erl_start(int argc, char **argv) } erts_fprintf(stderr, "(" EMULATOR ") emulator version " ERLANG_VERSION "\n"); - erl_exit(0, ""); + erts_exit(0, ""); } break; @@ -2247,23 +2247,17 @@ system_cleanup(int flush_async) } static __decl_noreturn void __noreturn -erl_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2) +erts_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2) { - unsigned int an; - system_cleanup(flush_async); save_statistics(); - if (n < 0) - an = -(unsigned int)n; - else - an = n; if (erts_mtrace_enabled) - erts_mtrace_exit((Uint32) an); + erts_mtrace_exit((Uint32) n); /* Produce an Erlang core dump if error */ - if (((n > 0 && erts_no_crash_dump == 0) || n == ERTS_DUMP_EXIT) + if (((n == ERTS_ERROR_EXIT && erts_no_crash_dump == 0) || n == ERTS_DUMP_EXIT) && erts_initialized) { erl_crash_dump_v((char*) NULL, 0, fmt, args1); } @@ -2276,29 +2270,29 @@ erl_exit_vv(int n, int flush_async, char *fmt, va_list args1, va_list args2) exit(0); else if (n == ERTS_DUMP_EXIT) ERTS_EXIT_AFTER_DUMP(1); - else if (n > 0 || n == ERTS_ABORT_EXIT) + else if (n == ERTS_ERROR_EXIT || n == ERTS_ABORT_EXIT) abort(); - exit(an); + exit(n); } /* Exit without flushing async threads */ -__decl_noreturn void __noreturn erl_exit(int n, char *fmt, ...) +__decl_noreturn void __noreturn erts_exit(int n, char *fmt, ...) { va_list args1, args2; va_start(args1, fmt); va_start(args2, fmt); - erl_exit_vv(n, 0, fmt, args1, args2); + erts_exit_vv(n, 0, fmt, args1, args2); va_end(args2); va_end(args1); } /* Exit after flushing async threads */ -__decl_noreturn void __noreturn erl_exit_flush_async(int n, char *fmt, ...) +__decl_noreturn void __noreturn erts_flush_async_exit(int n, char *fmt, ...) { va_list args1, args2; va_start(args1, fmt); va_start(args2, fmt); - erl_exit_vv(n, 1, fmt, args1, args2); + erts_exit_vv(n, 1, fmt, args1, args2); va_end(args2); va_end(args1); } diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index ff2a355309..3c066cea7b 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -1274,7 +1274,7 @@ recurse: break; } default: - erl_exit(ERTS_ABORT_EXIT, "bad header %ld\r\n", hdrA); + erts_exit(ERTS_ABORT_EXIT, "bad header %ld\r\n", hdrA); } } @@ -1301,7 +1301,7 @@ recurse: break; } default: - erl_exit(ERTS_ABORT_EXIT, "bad header %ld\r\n", hdrB); + erts_exit(ERTS_ABORT_EXIT, "bad header %ld\r\n", hdrB); } } } @@ -1391,7 +1391,7 @@ resume_from_trap: res = make_boxed(nhp); break; default: - erl_exit(ERTS_ABORT_EXIT, "strange mix %d\r\n", sp->mix); + erts_exit(ERTS_ABORT_EXIT, "strange mix %d\r\n", sp->mix); } } @@ -1886,7 +1886,7 @@ void hashmap_iterator_init(ErtsWStack* s, Eterm node, int reverse) { sz = hashmap_bitcount(MAP_HEADER_VAL(hdr)); break; default: - erl_exit(ERTS_ABORT_EXIT, "bad header"); + erts_exit(ERTS_ABORT_EXIT, "bad header"); } WSTACK_PUSH3((*s), (UWord)THE_NON_VALUE, /* end marker */ @@ -1923,7 +1923,7 @@ Eterm* hashmap_iterator_next(ErtsWStack* s) { ASSERT(sz < 17); break; default: - erl_exit(ERTS_ABORT_EXIT, "bad header"); + erts_exit(ERTS_ABORT_EXIT, "bad header"); } idx++; @@ -1973,7 +1973,7 @@ Eterm* hashmap_iterator_prev(ErtsWStack* s) { ASSERT(sz < 17); break; default: - erl_exit(1, "bad header"); + erts_exit(ERTS_ERROR_EXIT, "bad header"); } if (idx > sz) @@ -2161,12 +2161,12 @@ int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz, size += HAMT_HEAD_BITMAP_SZ(n+1); goto unroll; default: - erl_exit(1, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); + erts_exit(ERTS_ERROR_EXIT, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); break; } break; default: - erl_exit(1, "bad primary tag %p\r\n", node); + erts_exit(ERTS_ERROR_EXIT, "bad primary tag %p\r\n", node); break; } } @@ -2281,12 +2281,12 @@ Eterm erts_hashmap_insert_up(Eterm *hp, Eterm key, Eterm value, res = make_hashmap(nhp); break; default: - erl_exit(1, "bad header tag %x\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); + erts_exit(ERTS_ERROR_EXIT, "bad header tag %x\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); break; } break; default: - erl_exit(1, "bad primary tag %x\r\n", primary_tag(node)); + erts_exit(ERTS_ERROR_EXIT, "bad primary tag %x\r\n", primary_tag(node)); break; } @@ -2404,12 +2404,12 @@ static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm map) { /* not occupied */ goto not_found; default: - erl_exit(1, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); + erts_exit(ERTS_ERROR_EXIT, "bad header tag %ld\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); break; } break; default: - erl_exit(1, "bad primary tag %p\r\n", node); + erts_exit(ERTS_ERROR_EXIT, "bad primary tag %p\r\n", node); break; } } @@ -2586,7 +2586,7 @@ unroll: res = make_hashmap(nhp); break; default: - erl_exit(1, "bad header tag %x\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); + erts_exit(ERTS_ERROR_EXIT, "bad header tag %x\r\n", hdr & _HEADER_MAP_SUBTAG_MASK); break; } } while(!ESTACK_ISEMPTY(stack)); @@ -2727,7 +2727,7 @@ BIF_RETTYPE erts_internal_map_type_1(BIF_ALIST_1) { case HAMT_SUBTAG_NODE_BITMAP: BIF_RET(AM_hashmap_node); default: - erl_exit(1, "bad header"); + erts_exit(ERTS_ERROR_EXIT, "bad header"); } } BIF_P->fvalue = BIF_ARG_1; @@ -2763,7 +2763,7 @@ BIF_RETTYPE erts_internal_map_hashmap_children_1(BIF_ALIST_1) { ptr += 2; break; default: - erl_exit(1, "bad header\r\n"); + erts_exit(ERTS_ERROR_EXIT, "bad header\r\n"); break; } ASSERT(sz < 17); @@ -2841,7 +2841,7 @@ static Eterm hashmap_info(Process *p, Eterm node) { } break; default: - erl_exit(1, "bad header\r\n"); + erts_exit(ERTS_ERROR_EXIT, "bad header\r\n"); break; } } diff --git a/erts/emulator/beam/erl_monitors.c b/erts/emulator/beam/erl_monitors.c index 7dfa01c8ac..bd899fa2f9 100644 --- a/erts/emulator/beam/erl_monitors.c +++ b/erts/emulator/beam/erl_monitors.c @@ -356,7 +356,7 @@ void erts_add_monitor(ErtsMonitor **root, Uint type, Eterm ref, Eterm pid, tstack[tpos++] = this; this = &((*this)->right); } else { /* Equal key is an error for monitors */ - erl_exit(1,"Insertion of already present monitor!"); + erts_exit(ERTS_ERROR_EXIT,"Insertion of already present monitor!"); break; } } diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 3141b05e2b..1097916c97 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -330,7 +330,7 @@ int enif_send(ErlNifEnv* env, const ErlNifPid* to_pid, #ifdef ERTS_SMP c_p = NULL; #else - erl_exit(ERTS_ABORT_EXIT,"enif_send: env==NULL on non-SMP VM"); + erts_exit(ERTS_ABORT_EXIT,"enif_send: env==NULL on non-SMP VM"); #endif } diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c index 707de39556..e69bd49c42 100644 --- a/erts/emulator/beam/erl_node_tables.c +++ b/erts/emulator/beam/erl_node_tables.c @@ -1050,7 +1050,7 @@ insert_dist_entry(DistEntry *dist, int type, Eterm id, Uint creation) } if(!rdp) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "Reference to non-existing distribution table entry found!\n"); insert_dist_referrer(rdp, type, id, creation); @@ -1111,7 +1111,7 @@ insert_node(ErlNode *node, int type, Eterm id) } if (!rnp) - erl_exit(1, "Reference to non-existing node table entry found!\n"); + erts_exit(ERTS_ERROR_EXIT, "Reference to non-existing node table entry found!\n"); insert_node_referrer(rnp, type, id); } diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index 5c38db1cbc..ddcca06b0a 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -1784,7 +1784,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) reds = erts_dist_command(pp, CONTEXT_REDS - pp->reds); break; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Invalid port task type: %d\n", (int) ptp->type); break; @@ -2048,7 +2048,7 @@ begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p) break; } default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Invalid port task type: %d\n", (int) ptp->type); } diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index b24f26138c..c2afcc9c4f 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -516,7 +516,7 @@ dbg_chk_aux_work_val(erts_aint32_t value) valid |= ERTS_SSI_AUX_WORK_DEBUG_WAIT_COMPLETED; if (~valid & value) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Invalid aux_work value found: 0x%x\n", ~valid & value); } @@ -967,11 +967,25 @@ typedef struct { erts_smp_atomic32_t refc; } ErtsSchedWallTimeReq; +typedef struct { + Process *proc; + Eterm ref; + Eterm ref_heap[REF_THING_SIZE]; + Uint req_sched; + erts_smp_atomic32_t refc; +} ErtsSystemCheckReq; + + #if !HALFWORD_HEAP ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(swtreq, ErtsSchedWallTimeReq, 5, ERTS_ALC_T_SCHED_WTIME_REQ) + +ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(screq, + ErtsSystemCheckReq, + 5, + ERTS_ALC_T_SYS_CHECK_REQ) #else static ERTS_INLINE ErtsSchedWallTimeReq * swtreq_alloc(void) @@ -985,6 +999,19 @@ swtreq_free(ErtsSchedWallTimeReq *ptr) { erts_free(ERTS_ALC_T_SCHED_WTIME_REQ, ptr); } + +static ERTS_INLINE ErtsSystemCheckReq * +screq_alloc(void) +{ + return erts_alloc(ERTS_ALC_T_SYS_CHECK_REQ, + sizeof(ErtsSystemCheckReq)); +} + +static ERTS_INLINE void +screq_free(ErtsSystemCheckReq *ptr) +{ + erts_free(ERTS_ALC_T_SYS_CHECK_REQ, ptr); +} #endif static void @@ -1118,6 +1145,75 @@ erts_sched_wall_time_request(Process *c_p, int set, int enable) return ref; } +static void +reply_system_check(void *vscrp) +{ + ErtsSchedulerData *esdp = erts_get_scheduler_data(); + ErtsSystemCheckReq *scrp = (ErtsSystemCheckReq *) vscrp; + ErtsProcLocks rp_locks = (scrp->req_sched == esdp->no ? ERTS_PROC_LOCK_MAIN : 0); + Process *rp = scrp->proc; + Eterm msg; + Eterm *hp = NULL; + Eterm **hpp; + Uint sz; + ErlOffHeap *ohp = NULL; + ErlHeapFragment *bp = NULL; + + ASSERT(esdp); +#ifdef ERTS_DIRTY_SCHEDULERS + ASSERT(!ERTS_SCHEDULER_IS_DIRTY(esdp)); +#endif + + sz = REF_THING_SIZE; + hp = erts_alloc_message_heap(sz, &bp, &ohp, rp, &rp_locks); + hpp = &hp; + msg = STORE_NC(hpp, ohp, scrp->ref); + + erts_queue_message(rp, &rp_locks, bp, msg, NIL); + + if (scrp->req_sched == esdp->no) + rp_locks &= ~ERTS_PROC_LOCK_MAIN; + + if (rp_locks) + erts_smp_proc_unlock(rp, rp_locks); + + erts_proc_dec_refc(rp); + + if (erts_smp_atomic32_dec_read_nob(&scrp->refc) == 0) + screq_free(vscrp); +} + + +Eterm erts_system_check_request(Process *c_p) { + ErtsSchedulerData *esdp = ERTS_PROC_GET_SCHDATA(c_p); + Eterm ref; + ErtsSystemCheckReq *scrp; + Eterm *hp; + + scrp = screq_alloc(); + ref = erts_make_ref(c_p); + hp = &scrp->ref_heap[0]; + + scrp->proc = c_p; + scrp->ref = STORE_NC(&hp, NULL, ref); + scrp->req_sched = esdp->no; + erts_smp_atomic32_init_nob(&scrp->refc, (erts_aint32_t) erts_no_schedulers); + + erts_proc_add_refc(c_p, (Sint) erts_no_schedulers); + +#ifdef ERTS_SMP + if (erts_no_schedulers > 1) + erts_schedule_multi_misc_aux_work(1, + erts_no_schedulers, + reply_system_check, + (void *) scrp); +#endif + + reply_system_check((void *) scrp); + + return ref; +} + static ERTS_INLINE ErtsProcList * proclist_create(Process *p) { @@ -1212,7 +1308,7 @@ erts_sched_finish_poke(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flags) case 0: break; default: - erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n", + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n", __FILE__, __LINE__); break; } @@ -2196,7 +2292,7 @@ handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) erts_port_release(prt); } if (erts_smp_atomic32_dec_read_nob(&erts_halt_progress) == 0) { - erl_exit_flush_async(erts_halt_code, ""); + erts_flush_async_exit(erts_halt_code, ""); } } return aux_work & ~ERTS_SSI_AUX_WORK_REAP_PORTS; @@ -3715,7 +3811,7 @@ immigrate(ErtsRunQueue *c_rq, ErtsMigrationPath *mp) prio = ERTS_PORT_PRIO_LEVEL; break; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Invalid immigrate queue mask", __FILE__, __LINE__, __func__); prio = 0; @@ -3739,7 +3835,7 @@ immigrate(ErtsRunQueue *c_rq, ErtsMigrationPath *mp) rq = erts_port_runq(prt); if (rq) { if (rq != c_rq) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Internal error", __FILE__, __LINE__, __func__); erts_enqueue_port(c_rq, prt); @@ -3930,7 +4026,7 @@ evacuate_run_queue(ErtsRunQueue *rq, prt_rq = erts_port_runq(prt); if (prt_rq) { if (prt_rq != to_rq) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s() internal error\n", __FILE__, __LINE__, __func__); erts_enqueue_port(to_rq, prt); @@ -4131,7 +4227,7 @@ no_procs: return 0; else { if (prt_rq != rq) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s() internal error\n", __FILE__, __LINE__, __func__); *rq_lockedp = 1; @@ -5792,6 +5888,7 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online init_misc_aux_work(); #if !HALFWORD_HEAP init_swtreq_alloc(); + init_screq_alloc(); #endif erts_atomic32_init_nob(&debug_wait_completed_count, 0); /* debug only */ @@ -6462,9 +6559,6 @@ suspend_process(Process *c_p, Process *p) if (suspended) { - ASSERT(!(ERTS_PSFLG_RUNNING & state) - || p == erts_get_current_process()); - if (suspended > 0 && erts_system_profile_flags.runnable_procs) { /* 'state' is before our change... */ @@ -8023,7 +8117,7 @@ sched_thread_func(void *vesdp) process_main(); /* No schedulers should *ever* terminate */ - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Scheduler thread number %beu terminated\n", no); return NULL; @@ -8088,7 +8182,7 @@ sched_dirty_cpu_thread_func(void *vesdp) process_main(); /* No schedulers should *ever* terminate */ - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Dirty CPU scheduler thread number %beu terminated\n", no); return NULL; @@ -8151,7 +8245,7 @@ sched_dirty_io_thread_func(void *vesdp) process_main(); /* No schedulers should *ever* terminate */ - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Dirty I/O scheduler thread number %beu terminated\n", no); return NULL; @@ -8181,12 +8275,12 @@ erts_start_schedulers(void) erts_snprintf(opts.name, 16, "runq_supervisor"); erts_atomic_init_nob(&runq_supervisor_sleeping, 0); if (0 != ethr_event_init(&runq_supervision_event)) - erl_exit(1, "Failed to create run-queue supervision event\n"); + erts_exit(ERTS_ERROR_EXIT, "Failed to create run-queue supervision event\n"); if (0 != ethr_thr_create(&runq_supervisor_tid, runq_supervisor, NULL, &opts)) - erl_exit(1, "Failed to create run-queue supervision thread\n"); + erts_exit(ERTS_ERROR_EXIT, "Failed to create run-queue supervision thread\n"); } #endif @@ -8230,14 +8324,14 @@ erts_start_schedulers(void) erts_snprintf(opts.name, 16, "%d_dirty_cpu_scheduler", ix + 1); res = ethr_thr_create(&esdp->tid,sched_dirty_cpu_thread_func,(void*)esdp,&opts); if (res != 0) - erl_exit(1, "Failed to create dirty cpu scheduler thread %d\n", ix); + erts_exit(ERTS_ERROR_EXIT, "Failed to create dirty cpu scheduler thread %d\n", ix); } for (ix = 0; ix < erts_no_dirty_io_schedulers; ix++) { ErtsSchedulerData *esdp = ERTS_DIRTY_IO_SCHEDULER_IX(ix); erts_snprintf(opts.name, 16, "%d_dirty_io_scheduler", ix + 1); res = ethr_thr_create(&esdp->tid,sched_dirty_io_thread_func,(void*)esdp,&opts); if (res != 0) - erl_exit(1, "Failed to create dirty io scheduler thread %d\n", ix); + erts_exit(ERTS_ERROR_EXIT, "Failed to create dirty io scheduler thread %d\n", ix); } } #endif @@ -8253,10 +8347,10 @@ erts_start_schedulers(void) res = ethr_thr_create(&aux_tid, aux_thread, NULL, &opts); if (res != 0) - erl_exit(1, "Failed to create aux thread\n"); + erts_exit(ERTS_ERROR_EXIT, "Failed to create aux thread\n"); if (actual < 1) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "Failed to create any scheduler-threads: %s (%d)\n", erl_errno_id(res), res); @@ -8411,9 +8505,8 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks, resume_process(rp, rp_locks); } else { - rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS, - pid, pid_locks|ERTS_PROC_LOCK_STATUS); + pid, ERTS_PROC_LOCK_STATUS); if (!rp) { c_p->flags &= ~F_P2PNR_RESCHED; @@ -8422,40 +8515,84 @@ pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks, ASSERT(!(c_p->flags & F_P2PNR_RESCHED)); - if (suspend) { - if (suspend_process(c_p, rp)) - goto done; - } - else { - if (!((ERTS_PSFLG_RUNNING|ERTS_PSFLG_RUNNING_SYS) - & erts_smp_atomic32_read_acqb(&rp->state))) - goto done; + /* + * Suspend the other process in order to prevent + * it from being selected for normal execution. + * This will however not prevent it from being + * selected for execution of a system task. If + * it is selected for execution of a system task + * we might be blocked for quite a while if the + * try-lock below fails. That is, there is room + * for improvement here... + */ - } + if (!suspend_process(c_p, rp)) { + /* Other process running */ - /* Other process running */ + ASSERT(ERTS_PSFLG_RUNNING + & erts_smp_atomic32_read_nob(&rp->state)); - /* - * If we got pending suspenders and suspend ourselves waiting - * to suspend another process we might deadlock. - * In this case we have to yield, be suspended by - * someone else and then do it all over again. - */ - if (!c_p->pending_suspenders) { - /* Mark rp pending for suspend by c_p */ - add_pend_suspend(rp, c_p->common.id, handle_pend_sync_suspend); - ASSERT(is_nil(c_p->suspendee)); + running: - /* Suspend c_p; when rp is suspended c_p will be resumed. */ - suspend_process(c_p, c_p); - c_p->flags |= F_P2PNR_RESCHED; + /* + * If we got pending suspenders and suspend ourselves waiting + * to suspend another process we might deadlock. + * In this case we have to yield, be suspended by + * someone else and then do it all over again. + */ + if (!c_p->pending_suspenders) { + /* Mark rp pending for suspend by c_p */ + add_pend_suspend(rp, c_p->common.id, handle_pend_sync_suspend); + ASSERT(is_nil(c_p->suspendee)); + + /* Suspend c_p; when rp is suspended c_p will be resumed. */ + suspend_process(c_p, c_p); + c_p->flags |= F_P2PNR_RESCHED; + } + /* Yield (caller is assumed to yield immediately in bif). */ + erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); + rp = ERTS_PROC_LOCK_BUSY; + } + else { + ErtsProcLocks need_locks = pid_locks & ~ERTS_PROC_LOCK_STATUS; + if (need_locks && erts_smp_proc_trylock(rp, need_locks) == EBUSY) { + if (ERTS_PSFLG_RUNNING_SYS + & erts_smp_atomic32_read_nob(&rp->state)) { + /* Executing system task... */ + resume_process(rp, ERTS_PROC_LOCK_STATUS); + goto running; + } + erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); + /* + * If we are unlucky, the process just got selected for + * execution of a system task. In this case we may be + * blocked here for quite a while... Execution of system + * tasks are fortunately quite rare events. We try to + * avoid this by checking if it is in a state executing + * system tasks (above), but it will not prevent all + * scenarios for a long block here... + */ + rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS, + pid, pid_locks|ERTS_PROC_LOCK_STATUS); + if (!rp) + goto done; + } + + /* + * The previous suspend has prevented the process + * from being selected for normal execution regardless + * of locks held or not held on it... + */ + ASSERT(!(ERTS_PSFLG_RUNNING + & erts_smp_atomic32_read_nob(&rp->state))); + + if (!suspend) + resume_process(rp, pid_locks|ERTS_PROC_LOCK_STATUS); } - /* Yield (caller is assumed to yield immediately in bif). */ - erts_smp_proc_unlock(rp, pid_locks|ERTS_PROC_LOCK_STATUS); - rp = ERTS_PROC_LOCK_BUSY; } done: + if (rp && rp != ERTS_PROC_LOCK_BUSY && !(pid_locks & ERTS_PROC_LOCK_STATUS)) erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS); if (unlock_c_p_status) @@ -12115,7 +12252,7 @@ static void doit_exit_link(ErtsLink *lnk, void *vpcontext) break; default: - erl_exit(1, "bad type in link list\n"); + erts_exit(ERTS_ERROR_EXIT, "bad type in link list\n"); break; } erts_destroy_link(lnk); @@ -12156,7 +12293,7 @@ erts_do_exit_process(Process* p, Eterm reason) #endif if (p->static_flags & ERTS_STC_FLG_SYSTEM_PROC) - erl_exit(ERTS_DUMP_EXIT, "System process %T terminated: %T\n", + erts_exit(ERTS_DUMP_EXIT, "System process %T terminated: %T\n", p->common.id, reason); #ifdef ERTS_SMP @@ -12274,7 +12411,7 @@ erts_continue_exit_process(Process *p) break; case ERTS_SCHDLR_SSPND_EINVAL: default: - erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: %d\n", + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: %d\n", __FILE__, __LINE__, (int) ssr); } } @@ -12771,10 +12908,10 @@ erts_print_scheduler_info(int to, void *to_arg, ErtsSchedulerData *esdp) { * The same global atomic is used as refcount. * * A BIF that calls this should make sure to schedule out to never come back: - * erl_halt((int)(- code)); + * erts_halt(code); * ERTS_BIF_YIELD1(bif_export[BIF_erlang_halt_1], BIF_P, NIL); */ -void erl_halt(int code) +void erts_halt(int code) { if (-1 == erts_smp_atomic32_cmpxchg_acqb(&erts_halt_progress, erts_no_schedulers, diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index cbc2696eab..b536426b0f 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1483,6 +1483,7 @@ void erts_init_scheduling(int, int int erts_set_gc_state(Process *c_p, int enable); Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable); +Eterm erts_system_check_request(Process *c_p); Eterm erts_gc_info_request(Process *c_p); Uint64 erts_get_proc_interval(void); Uint64 erts_ensure_later_proc_interval(Uint64); @@ -2350,6 +2351,6 @@ erts_sched_poke(ErtsSchedulerSleepInfo *ssi) #endif -void erl_halt(int code); +void erts_halt(int code); extern erts_smp_atomic32_t erts_halt_progress; extern int erts_halt_code; diff --git a/erts/emulator/beam/erl_process_dict.c b/erts/emulator/beam/erl_process_dict.c index 8606371bdf..3253ee6b70 100644 --- a/erts/emulator/beam/erl_process_dict.c +++ b/erts/emulator/beam/erl_process_dict.c @@ -374,7 +374,7 @@ static void pd_hash_erase(Process *p, Eterm id, Eterm *ret) "display term found in line %d:\n" "%T\n", p->common.id, __LINE__, old); #endif - erl_exit(1, "Damaged process dictionary found during erase/1."); + erts_exit(ERTS_ERROR_EXIT, "Damaged process dictionary found during erase/1."); } if ((range = HASH_RANGE(p->dictionary)) > INITIAL_SIZE && range / 2 > (p->dictionary->numElements)) { @@ -419,7 +419,7 @@ Eterm erts_pd_hash_get(Process *p, Eterm id) "display term found in line %d:\n" "%T\n", p->common.id, __LINE__, tmp); #endif - erl_exit(1, "Damaged process dictionary found during get/1."); + erts_exit(ERTS_ERROR_EXIT, "Damaged process dictionary found during get/1."); } return am_undefined; } @@ -670,7 +670,7 @@ static Eterm pd_hash_put(Process *p, Eterm id, Eterm value) "%T\n", p->common.id, __LINE__, old); #endif - erl_exit(1, "Damaged process dictionary found during put/2."); + erts_exit(ERTS_ERROR_EXIT, "Damaged process dictionary found during put/2."); } if (HASH_RANGE(p->dictionary) <= p->dictionary->numElements) { grow(p); @@ -1024,7 +1024,7 @@ static void pd_check(ProcDict *pd) } continue; } else { - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "Found tag 0x%08x in process dictionary at position %d", (unsigned long) t, (int) i); } diff --git a/erts/emulator/beam/erl_ptab.c b/erts/emulator/beam/erl_ptab.c index f7997df051..9ed175fe01 100644 --- a/erts/emulator/beam/erl_ptab.c +++ b/erts/emulator/beam/erl_ptab.c @@ -1255,7 +1255,7 @@ ptab_list_bif_engine(Process *c_p, Eterm *res_accp, Binary *mbp) return 1; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:ptab_list_bif_engine(): Invalid state: %d\n", __FILE__, __LINE__, (int) ptlbdp->state); } diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c index e5050bfaa5..bae3385d3f 100644 --- a/erts/emulator/beam/erl_term.c +++ b/erts/emulator/beam/erl_term.c @@ -41,7 +41,7 @@ et_abort(const char *expr, const char *file, unsigned line) * Prevent infinite loop. */ have_been_called = 1; - erl_exit(1, "TYPE ASSERTION FAILED, file %s, line %u: %s\n", file, line, expr); + erts_exit(ERTS_ERROR_EXIT, "TYPE ASSERTION FAILED, file %s, line %u: %s\n", file, line, expr); } #else erts_fprintf(stderr, "TYPE ASSERTION FAILED, file %s, line %u: %s\n", file, line, expr); diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c index 7148b756e7..7b06fd840f 100644 --- a/erts/emulator/beam/erl_thr_progress.c +++ b/erts/emulator/beam/erl_thr_progress.c @@ -502,7 +502,7 @@ erts_thr_progress_register_unmanaged_thread(ErtsThrPrgrCallbacks *callbacks) if (tpd) { if (!tpd->is_temporary) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Double register of thread\n", __FILE__, __LINE__, __func__); is_blocking = tpd->is_blocking; @@ -524,7 +524,7 @@ erts_thr_progress_register_unmanaged_thread(ErtsThrPrgrCallbacks *callbacks) #endif ASSERT(tpd->id >= 0); if (tpd->id >= intrnl->unmanaged.no) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Too many unmanaged registered threads\n", __FILE__, __LINE__, __func__); @@ -547,7 +547,7 @@ erts_thr_progress_register_managed_thread(ErtsSchedulerData *esdp, if (tpd) { if (!tpd->is_temporary) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Double register of thread\n", __FILE__, __LINE__, __func__); is_blocking = tpd->is_blocking; @@ -568,7 +568,7 @@ erts_thr_progress_register_managed_thread(ErtsSchedulerData *esdp, tpd->id = erts_atomic32_inc_read_nob(&intrnl->misc.data.managed_id); ASSERT(tpd->id >= 0); if (tpd->id >= intrnl->managed.no) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Too many managed registered threads\n", __FILE__, __LINE__, __func__); @@ -1033,7 +1033,7 @@ has_reached_wakeup(ErtsThrPrgrVal wakeup) limit += 1; if (!erts_thr_progress_has_passed__(limit, wakeup)) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Invalid wakeup request value found:" " current=%b64u, wakeup=%b64u, limit=%b64u", current, wakeup, limit); @@ -1102,7 +1102,7 @@ request_wakeup_managed(ErtsThrPrgrData *tpd, ErtsThrPrgrVal value) ix = erts_atomic32_inc_read_nob(&mwd->len) - 1; #if ERTS_THR_PRGR_DBG_CHK_WAKEUP_REQUEST_VALUE if (ix >= intrnl->managed.no) - erl_exit(ERTS_ABORT_EXIT, "Internal error: Too many wakeup requests\n"); + erts_exit(ERTS_ABORT_EXIT, "Internal error: Too many wakeup requests\n"); #endif mwd->id[ix] = tpd->id; diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c index 3a91ca9dbe..7ff456b915 100644 --- a/erts/emulator/beam/erl_thr_queue.c +++ b/erts/emulator/beam/erl_thr_queue.c @@ -224,7 +224,7 @@ ErtsThrQCleanState_t erts_thr_q_destroy(ErtsThrQ_t *q) { if (!q->q.blk) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Trying to destroy not created thread queue\n"); return erts_thr_q_finalize(q); } @@ -589,7 +589,7 @@ enqueue(ErtsThrQ_t *q, void *data, ErtsThrQElement_t *this) #if ERTS_THR_Q_DBG_CHK_DATA if (!data) - erl_exit(ERTS_ABORT_EXIT, "Missing data in enqueue\n"); + erts_exit(ERTS_ABORT_EXIT, "Missing data in enqueue\n"); #endif ASSERT(!q->q.finalizing); @@ -771,7 +771,7 @@ erts_thr_q_dequeue(ErtsThrQ_t *q) #if ERTS_THR_Q_DBG_CHK_DATA head->data.ptr = NULL; if (!res) - erl_exit(ERTS_ABORT_EXIT, "Missing data in dequeue\n"); + erts_exit(ERTS_ABORT_EXIT, "Missing data in dequeue\n"); #endif clean(q, (q->head.deq_fini.automatic diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index 5f12c7809a..99005356ed 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -289,7 +289,7 @@ read_corrected_time(int os_drift_corrected) ci = time_sup.inf.c.parmon.cdata.insts.curr; else { if (os_mtime < time_sup.inf.c.parmon.cdata.insts.prev.os_mtime) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "OS monotonic time stepped backwards\n"); ci = time_sup.inf.c.parmon.cdata.insts.prev; } @@ -381,7 +381,7 @@ check_time_correction(void *vesdp) erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx); if (os_mtime < ci.os_mtime) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "OS monotonic time stepped backwards\n"); erl_mtime = calc_corrected_erl_mtime(os_mtime, &ci, &mdiff, @@ -798,7 +798,7 @@ finalize_corrected_time_offset(ErtsSystemTime *stimep) erts_smp_rwmtx_runlock(&time_sup.inf.c.parmon.rwmtx); if (os_mtime < ci.os_mtime) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "OS monotonic time stepped backwards\n"); return calc_corrected_erl_mtime(os_mtime, &ci, NULL, diff --git a/erts/emulator/beam/erl_trace.c b/erts/emulator/beam/erl_trace.c index 8a4c0ab1f2..114853cac4 100644 --- a/erts/emulator/beam/erl_trace.c +++ b/erts/emulator/beam/erl_trace.c @@ -662,7 +662,7 @@ WRITE_SYS_MSG_TO_PORT(Eterm unused_to, erts_encode_ext(message, &ptr); if (!(ptr <= buffer+size)) { - erl_exit(1, "Internal error in do_send_to_port: %d\n", ptr-buffer); + erts_exit(ERTS_ERROR_EXIT, "Internal error in do_send_to_port: %d\n", ptr-buffer); } #ifndef ERTS_SMP @@ -1289,7 +1289,7 @@ seq_trace_output_generic(Eterm token, Eterm msg, Uint type, case SEQ_TRACE_PRINT: type_atom = am_print; break; case SEQ_TRACE_RECEIVE: type_atom = am_receive; break; default: - erl_exit(1, "invalid type in seq_trace_output_generic: %d:\n", type); + erts_exit(ERTS_ERROR_EXIT, "invalid type in seq_trace_output_generic: %d:\n", type); return; /* To avoid warning */ } diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index 551717139d..36d85b0a22 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -2507,7 +2507,7 @@ void erts_copy_utf8_to_utf16_little(byte *target, byte *bytes, int num_chars) ((Uint) (bytes[3] & ((byte) 0x3F))); bytes += 4; } else { - erl_exit(1,"Internal unicode error in prim_file:internal_name2native/1"); + erts_exit(ERTS_ERROR_EXIT,"Internal unicode error in prim_file:internal_name2native/1"); } *target++ = (byte) (unipoint & 0xFF); *target++ = (byte) ((unipoint >> 8) & 0xFF); diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index a85aa15403..ffe3303796 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -570,7 +570,7 @@ void erts_encode_ext(Eterm term, byte **ext) *ep++ = VERSION_MAGIC; ep = enc_term(NULL, term, ep, TERM_TO_BINARY_DFLAGS, NULL); if (!ep) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d:erts_encode_ext(): Internal data structure error\n", __FILE__, __LINE__); *ext = ep; @@ -1559,7 +1559,7 @@ static BIF_RETTYPE binary_to_term_int(Process* p, Uint32 flags, Eterm bin, Binar b2t_destroy_context(ctx); if (ctx->u.dc.factory.hp > ctx->u.dc.factory.hp_end) { - erl_exit(1, ":%s, line %d: heap overrun by %d words(s)\n", + erts_exit(ERTS_ERROR_EXIT, ":%s, line %d: heap overrun by %d words(s)\n", __FILE__, __LINE__, ctx->u.dc.factory.hp - ctx->u.dc.factory.hp_end); } erts_factory_close(&ctx->u.dc.factory); @@ -1708,12 +1708,12 @@ erts_term_to_binary_simple(Process* p, Eterm Term, Uint size, int level, Uint fl if ((endp = enc_term(NULL, Term, bytes, flags, NULL)) == NULL) { - erl_exit(1, "%s, line %d: bad term: %x\n", + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: bad term: %x\n", __FILE__, __LINE__, Term); } real_size = endp - bytes; if (real_size > size) { - erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n", + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: buffer overflow: %d word(s)\n", __FILE__, __LINE__, real_size - size); } @@ -1753,12 +1753,12 @@ erts_term_to_binary_simple(Process* p, Eterm Term, Uint size, int level, Uint fl bytes[0] = VERSION_MAGIC; if ((endp = enc_term(NULL, Term, bytes+1, flags, NULL)) == NULL) { - erl_exit(1, "%s, line %d: bad term: %x\n", + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: bad term: %x\n", __FILE__, __LINE__, Term); } real_size = endp - bytes; if (real_size > size) { - erl_exit(1, "%s, line %d: buffer overflow: %d word(s)\n", + erts_exit(ERTS_ERROR_EXIT, "%s, line %d: buffer overflow: %d word(s)\n", __FILE__, __LINE__, endp - (bytes + size)); } return erts_realloc_binary(bin, real_size); @@ -2650,7 +2650,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, ASSERT(node_sz < 17); break; default: - erl_exit(1, "bad header\r\n"); + erts_exit(ERTS_ERROR_EXIT, "bad header\r\n"); } ptr++; @@ -4110,7 +4110,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, ASSERT(node_sz < 17); break; default: - erl_exit(1, "bad header\r\n"); + erts_exit(ERTS_ERROR_EXIT, "bad header\r\n"); } ptr++; @@ -4202,7 +4202,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, break; default: - erl_exit(1,"Internal data structure error (in encode_size_struct2)%x\n", + erts_exit(ERTS_ERROR_EXIT,"Internal data structure error (in encode_size_struct2)%x\n", obj); } diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index ec9296d034..1b8595fe57 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -428,7 +428,7 @@ void erl_grow_estack(ErtsEStack*, Uint need); #define ESTACK_CHANGE_ALLOCATOR(s,t) \ do { \ if ((s).start != ESTK_DEF_STACK(s)) { \ - erl_exit(1, "Internal error - trying to change allocator " \ + erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \ "type of active estack\n"); \ } \ (s).alloc_type = (t); \ @@ -589,7 +589,7 @@ do { \ #define WSTACK_CHANGE_ALLOCATOR(s,t) \ do { \ if (s.wstart != WSTK_DEF_STACK(s)) { \ - erl_exit(1, "Internal error - trying to change allocator " \ + erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \ "type of active wstack\n"); \ } \ s.alloc_type = (t); \ @@ -781,7 +781,7 @@ ErtsPStack s = { (byte*)PSTK_DEF_STACK(s), /* pstart */ \ #define PSTACK_CHANGE_ALLOCATOR(s,t) \ do { \ if (s.pstart != (byte*)PSTK_DEF_STACK(s)) { \ - erl_exit(1, "Internal error - trying to change allocator " \ + erts_exit(ERTS_ERROR_EXIT, "Internal error - trying to change allocator " \ "type of active pstack\n"); \ } \ s.alloc_type = (t); \ @@ -952,8 +952,8 @@ double erts_get_positive_zero_float(void); /* config.c */ -__decl_noreturn void __noreturn erl_exit(int n, char*, ...); -__decl_noreturn void __noreturn erl_exit_flush_async(int n, char*, ...); +__decl_noreturn void __noreturn erts_exit(int n, char*, ...); +__decl_noreturn void __noreturn erts_flush_async_exit(int n, char*, ...); void erl_error(char*, va_list); /* copy.c */ @@ -1398,7 +1398,7 @@ erts_alloc_message_heap_state(Uint size, #endif if (size > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, "HUGE size (%beu)\n", size); + erts_exit(ERTS_ABORT_EXIT, "HUGE size (%beu)\n", size); if ( #if defined(ERTS_SMP) diff --git a/erts/emulator/beam/hash.c b/erts/emulator/beam/hash.c index e0fde337f2..895fe657d1 100644 --- a/erts/emulator/beam/hash.c +++ b/erts/emulator/beam/hash.c @@ -133,7 +133,7 @@ Hash* hash_init(ErtsAlcType_t type, Hash* h, char* name, int size, HashFunctions while (h_size_table[ix] != -1 && h_size_table[ix] < size) ix++; if (h_size_table[ix] == -1) - erl_exit(1, "panic: too large hash table size (%d)\n", size); + erts_exit(ERTS_ERROR_EXIT, "panic: too large hash table size (%d)\n", size); size = h_size_table[ix]; sz = size*sizeof(HashBucket*); diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c index 06d0b5123d..5f6ea14732 100644 --- a/erts/emulator/beam/index.c +++ b/erts/emulator/beam/index.c @@ -84,7 +84,7 @@ index_put_entry(IndexTable* t, void* tmpl) Uint sz; if (ix >= t->limit) { /* A core dump is unnecessary */ - erl_exit(ERTS_DUMP_EXIT, "no more index entries in %s (max=%d)\n", + erts_exit(ERTS_DUMP_EXIT, "no more index entries in %s (max=%d)\n", t->htable.name, t->limit); } sz = INDEX_PAGE_SIZE*sizeof(IndexSlot*); @@ -123,7 +123,7 @@ void erts_index_merge(Hash* src, IndexTable* dst) ix = dst->entries++; if (ix >= dst->size) { if (ix >= dst->limit) { - erl_exit(1, "no more index entries in %s (max=%d)\n", + erts_exit(ERTS_ERROR_EXIT, "no more index entries in %s (max=%d)\n", dst->htable.name, dst->limit); } sz = INDEX_PAGE_SIZE*sizeof(IndexSlot*); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 2bd31ee97e..81a05a6b87 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -3467,7 +3467,7 @@ terminate_port(Port *prt) if ((state & ERTS_PORT_SFLG_HALT) && (erts_smp_atomic32_dec_read_nob(&erts_halt_progress) == 0)) { erts_port_release(prt); /* We will exit and never return */ - erl_exit_flush_async(erts_halt_code, ""); + erts_flush_async_exit(erts_halt_code, ""); } if (is_internal_port(send_closed_port_id)) deliver_result(send_closed_port_id, connected_id, am_closed); @@ -4882,7 +4882,7 @@ void erts_raw_port_command(Port* p, byte* buf, Uint len) ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p)); if (len > (Uint) INT_MAX) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Absurdly large data buffer (%beu bytes) passed to" "output callback of %s driver.\n", len, @@ -7312,7 +7312,7 @@ driver_system_info(ErlDrvSysInfo *sip, size_t si_size) * of ErlDrvSysInfo (introduced in driver version 1.0). */ if (!sip || si_size < ERL_DRV_SYS_INFO_SIZE(smp_support)) - erl_exit(1, + erts_exit(ERTS_ERROR_EXIT, "driver_system_info(%p, %ld) called with invalid arguments\n", sip, si_size); diff --git a/erts/emulator/beam/register.c b/erts/emulator/beam/register.c index 7ade8bca0f..020e61d136 100644 --- a/erts/emulator/beam/register.c +++ b/erts/emulator/beam/register.c @@ -125,7 +125,7 @@ static RegProc* reg_alloc(RegProc *tmpl) { RegProc* obj = (RegProc*) erts_alloc(ERTS_ALC_T_REG_PROC, sizeof(RegProc)); if (!obj) { - erl_exit(1, "Can't allocate %d bytes of memory\n", sizeof(RegProc)); + erts_exit(ERTS_ERROR_EXIT, "Can't allocate %d bytes of memory\n", sizeof(RegProc)); } obj->name = tmpl->name; obj->p = tmpl->p; diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 03e30573de..6497a1e648 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -611,15 +611,16 @@ static unsigned long zero_value = 0, one_value = 1; # endif /* !__WIN32__ */ #endif /* WANT_NONBLOCKING */ -__decl_noreturn void __noreturn erl_exit(int n, char*, ...); +__decl_noreturn void __noreturn erts_exit(int n, char*, ...); -/* Some special erl_exit() codes: */ -#define ERTS_INTR_EXIT INT_MIN /* called from signal handler */ -#define ERTS_ABORT_EXIT (INT_MIN + 1) /* no crash dump; only abort() */ -#define ERTS_DUMP_EXIT (INT_MIN + 2) /* crash dump; then exit() */ +/* Some special erts_exit() codes: */ +#define ERTS_INTR_EXIT -1 /* called from signal handler */ +#define ERTS_ABORT_EXIT -2 /* no crash dump; only abort() */ +#define ERTS_DUMP_EXIT -3 /* crash dump; then exit() */ +#define ERTS_ERROR_EXIT -4 /* crash dump; then abort() */ #define ERTS_INTERNAL_ERROR(What) \ - erl_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Internal error: %s\n", \ + erts_exit(ERTS_ABORT_EXIT, "%s:%d:%s(): Internal error: %s\n", \ __FILE__, __LINE__, __func__, What) Eterm erts_check_io_info(void *p); @@ -933,7 +934,7 @@ erts_refc_inc(erts_refc_t *refcp, erts_aint_t min_val) #ifdef ERTS_REFC_DEBUG erts_aint_t val = erts_smp_atomic_inc_read_nob((erts_smp_atomic_t *) refcp); if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_inc(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #else @@ -947,7 +948,7 @@ erts_refc_inctest(erts_refc_t *refcp, erts_aint_t min_val) erts_aint_t val = erts_smp_atomic_inc_read_nob((erts_smp_atomic_t *) refcp); #ifdef ERTS_REFC_DEBUG if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_inctest(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #endif @@ -960,7 +961,7 @@ erts_refc_dec(erts_refc_t *refcp, erts_aint_t min_val) #ifdef ERTS_REFC_DEBUG erts_aint_t val = erts_smp_atomic_dec_read_nob((erts_smp_atomic_t *) refcp); if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_dec(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #else @@ -974,7 +975,7 @@ erts_refc_dectest(erts_refc_t *refcp, erts_aint_t min_val) erts_aint_t val = erts_smp_atomic_dec_read_nob((erts_smp_atomic_t *) refcp); #ifdef ERTS_REFC_DEBUG if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_dectest(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #endif @@ -987,7 +988,7 @@ erts_refc_add(erts_refc_t *refcp, erts_aint_t diff, erts_aint_t min_val) #ifdef ERTS_REFC_DEBUG erts_aint_t val = erts_smp_atomic_add_read_nob((erts_smp_atomic_t *) refcp, diff); if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_add(%ld): Bad refc found (refc=%ld < %ld)!\n", diff, val, min_val); #else @@ -1001,7 +1002,7 @@ erts_refc_read(erts_refc_t *refcp, erts_aint_t min_val) erts_aint_t val = erts_smp_atomic_read_nob((erts_smp_atomic_t *) refcp); #ifdef ERTS_REFC_DEBUG if (val < min_val) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "erts_refc_read(): Bad refc found (refc=%ld < %ld)!\n", val, min_val); #endif diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c index 0ab6661c9f..988338ed81 100644 --- a/erts/emulator/beam/time.c +++ b/erts/emulator/beam/time.c @@ -555,7 +555,7 @@ erts_init_time(int time_correction, ErtsTimeWarpMode time_warp_mode) itime = erts_init_time_sup(time_correction, time_warp_mode); #ifdef TIW_ITIME_IS_CONSTANT if (itime != TIW_ITIME) { - erl_exit(ERTS_ABORT_EXIT, "timer resolution mismatch %d != %d", itime, TIW_ITIME); + erts_exit(ERTS_ABORT_EXIT, "timer resolution mismatch %d != %d", itime, TIW_ITIME); } #else tiw_itime = itime; diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 5286391746..b9ce70e364 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -1055,7 +1055,7 @@ tail_recur: } default: - erl_exit(1, "Invalid tag in make_hash(0x%X,0x%X)\n", term, op); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash(0x%X,0x%X)\n", term, op); return 0; } if (WSTACK_ISEMPTY(stack)) break; @@ -1328,7 +1328,7 @@ make_hash2(Eterm term) i = hashmap_bitcount(MAP_HEADER_VAL(hdr)); break; default: - erl_exit(1, "bad header"); + erts_exit(ERTS_ERROR_EXIT, "bad header"); } while (i) { if (is_list(*ptr)) { @@ -1491,7 +1491,7 @@ make_hash2(Eterm term) break; default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); } } break; @@ -1522,7 +1522,7 @@ make_hash2(Eterm term) UINT32_HASH(NIL_DEF, HCONST_2); goto hash2_common; default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); } case _TAG_IMMED1_SMALL: { @@ -1538,7 +1538,7 @@ make_hash2(Eterm term) } break; default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); hash2_common: /* Uint32 hash always has the hash value of the previous term, @@ -1733,7 +1733,7 @@ make_internal_hash(Eterm term) i = hashmap_bitcount(MAP_HEADER_VAL(hdr)); break; default: - erl_exit(1, "bad header"); + erts_exit(ERTS_ERROR_EXIT, "bad header"); } while (i) { if (is_list(*ptr)) { @@ -1909,7 +1909,7 @@ make_internal_hash(Eterm term) goto pop_next; } default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); } } break; @@ -1922,7 +1922,7 @@ make_internal_hash(Eterm term) goto pop_next; default: - erl_exit(1, "Invalid tag in make_hash2(0x%X)\n", term); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_hash2(0x%X)\n", term); pop_next: if (ESTACK_ISEMPTY(s)) { @@ -2205,7 +2205,7 @@ tail_recur: } default: - erl_exit(1, "Invalid tag in make_broken_hash\n"); + erts_exit(ERTS_ERROR_EXIT, "Invalid tag in make_broken_hash\n"); return 0; } if (WSTACK_ISEMPTY(stack)) break; @@ -2879,7 +2879,7 @@ tailrecur_ne: ASSERT(sz > 0 && sz < 17); break; default: - erl_exit(1, "Unknown hashmap subsubtag\n"); + erts_exit(ERTS_ERROR_EXIT, "Unknown hashmap subsubtag\n"); } goto term_array; } diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index a5a5dfb7f8..5e25747ddf 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -125,8 +125,6 @@ #include "dtrace-wrapper.h" -void erl_exit(int n, char *fmt, ...); - static ErlDrvSysInfo sys_info; /* For explanation of this var, see comment for same var in erl_async.c */ @@ -515,21 +513,10 @@ struct t_data static void *ef_safe_alloc(Uint s) { void *p = EF_ALLOC(s); - if (!p) erl_exit(1, "efile drv: Can't allocate %lu bytes of memory\n", (unsigned long)s); - return p; -} - -#if 0 /* Currently not used */ - -static void *ef_safe_realloc(void *op, Uint s) -{ - void *p = EF_REALLOC(op, s); - if (!p) erl_exit(1, "efile drv: Can't reallocate %lu bytes of memory\n", (unsigned long)s); + if (!p) erts_exit(ERTS_ERROR_EXIT, "efile drv: Can't allocate %lu bytes of memory\n", (unsigned long)s); return p; } -#endif - /********************************************************************* * ErlIOVec manipulation functions. */ diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index 43cb15a25f..2d2bd80783 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1574,7 +1574,7 @@ static const struct in6_addr in6addr_loopback = #endif /* HAVE_IN6 */ /* XXX: is this a driver interface function ??? */ -void erl_exit(int n, char*, ...); +void erts_exit(int n, char*, ...); /* * Malloc wrapper, @@ -1587,7 +1587,7 @@ void erl_exit(int n, char*, ...); static void *alloc_wrapper(ErlDrvSizeT size){ void *ret = driver_alloc(size); if(ret == NULL) - erl_exit(1,"Out of virtual memory in malloc (%s)", __FILE__); + erts_exit(ERTS_ERROR_EXIT,"Out of virtual memory in malloc (%s)", __FILE__); return ret; } #define ALLOC(X) alloc_wrapper(X) @@ -1595,7 +1595,7 @@ static void *alloc_wrapper(ErlDrvSizeT size){ static void *realloc_wrapper(void *current, ErlDrvSizeT size){ void *ret = driver_realloc(current,size); if(ret == NULL) - erl_exit(1,"Out of virtual memory in realloc (%s)", __FILE__); + erts_exit(ERTS_ERROR_EXIT,"Out of virtual memory in realloc (%s)", __FILE__); return ret; } #define REALLOC(X,Y) realloc_wrapper(X,Y) @@ -1856,7 +1856,7 @@ check_double_release(InetDrvBufStk *bs, ErlDrvBinary* buf) int i; for (i = 0; i < bs->buf.pos; ++i) { if (bs->buf.stk[i] == buf) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Multiple buffer release in inet_drv, this " "is a bug, save the core and send it to " "[email protected]!"); @@ -7117,7 +7117,7 @@ static ErlDrvSSizeT inet_fill_opts(inet_descriptor* desc, do { \ ErlDrvSizeT new_need = ((Ptr) - (*dest)) + (Size); \ if (new_need > dest_used) { \ - erl_exit(1,"Internal error in inet_drv, " \ + erts_exit(ERTS_ERROR_EXIT,"Internal error in inet_drv, " \ "miscalculated buffer size"); \ } \ dest_used = new_need; \ @@ -7494,7 +7494,7 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, do { \ int need; \ if ((Index) > spec_allocated) { \ - erl_exit(1,"Internal error in inet_drv, " \ + erts_exit(ERTS_ERROR_EXIT,"Internal error in inet_drv, " \ "miscalculated buffer size"); \ } \ need = (Index) + (N); \ diff --git a/erts/emulator/drivers/win32/win_con.c b/erts/emulator/drivers/win32/win_con.c index 0d63d46698..7fe708dc7b 100644 --- a/erts/emulator/drivers/win32/win_con.c +++ b/erts/emulator/drivers/win32/win_con.c @@ -279,7 +279,7 @@ ConInit(void) } /* - ConNormalExit() is called from erl_exit() when the emulator + ConNormalExit() is called from erts_exit() when the emulator is stopping. If the exit has not been initiated by this console thread (WM_DESTROY or ID_BREAK), the function must invoke the console thread to save the user preferences. @@ -529,7 +529,7 @@ ConThreadInit(LPVOID param) /* PostQuitMessage() results in WM_QUIT which makes GetMessage() return 0 (which stops the main loop). Before we return from - the console thread, the ctrl_handler is called to do erl_exit. + the console thread, the ctrl_handler is called to do erts_exit. */ (*ctrl_handler)(CTRL_CLOSE_EVENT); return msg.wParam; diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index cc68e1f74d..c838150db8 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -406,7 +406,7 @@ BIF_RETTYPE hipe_bifs_enter_code_2(BIF_ALIST_2) nrcallees = arityval(tuple_val(BIF_ARG_2)[0]); else nrcallees = 0; - erl_exit(1, "%s: failed to allocate %lu bytes and %lu trampolines\r\n", + erts_exit(ERTS_ERROR_EXIT, "%s: failed to allocate %lu bytes and %lu trampolines\r\n", __func__, (unsigned long)nrbytes, (unsigned long)nrcallees); } memcpy(address, bytes, nrbytes); @@ -1311,7 +1311,7 @@ static void *hipe_make_stub(Eterm m, Eterm f, unsigned int arity, int is_remote) export_entry = erts_export_get_or_make_stub(m, f, arity); StubAddress = hipe_make_native_stub(export_entry, arity); if (!StubAddress) - erl_exit(1, "hipe_make_stub: code allocation failed\r\n"); + erts_exit(ERTS_ERROR_EXIT, "hipe_make_stub: code allocation failed\r\n"); return StubAddress; } diff --git a/erts/emulator/hipe/hipe_mode_switch.c b/erts/emulator/hipe/hipe_mode_switch.c index 968452a641..9243e029f6 100644 --- a/erts/emulator/hipe/hipe_mode_switch.c +++ b/erts/emulator/hipe/hipe_mode_switch.c @@ -108,7 +108,7 @@ static const char *code_str(unsigned code) static void __noreturn hipe_abort(const char *expr, const char *file, unsigned line) { - erl_exit(1, "ASSERTION FAILED, file %s, line %u: %s\r\n", file, line, expr); + erts_exit(ERTS_ERROR_EXIT, "ASSERTION FAILED, file %s, line %u: %s\r\n", file, line, expr); } #define HIPE_ASSERT3(expr, file, line) \ @@ -316,7 +316,7 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) break; } default: - erl_exit(1, "hipe_mode_switch: cmd %#x\r\n", cmd); + erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: cmd %#x\r\n", cmd); } do_return_from_native: DPRINTF("result == %#x (%s)", result, code_str(result)); @@ -560,7 +560,7 @@ Process *hipe_mode_switch(Process *p, unsigned cmd, Eterm reg[]) goto do_throw_to_native; } default: - erl_exit(1, "hipe_mode_switch: result %#x\r\n", result); + erts_exit(ERTS_ERROR_EXIT, "hipe_mode_switch: result %#x\r\n", result); } HIPE_CHECK_PCB(p); p->def_arg_reg[3] = result; diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c index 119b0b0895..994f963ece 100644 --- a/erts/emulator/hipe/hipe_native_bif.c +++ b/erts/emulator/hipe/hipe_native_bif.c @@ -171,7 +171,7 @@ void hipe_fclearerror_error(Process *p) #if !defined(NO_FPE_SIGNALS) erts_fp_check_init_error(&p->fp_exception); #else - erl_exit(ERTS_ABORT_EXIT, "Emulated FPE not cleared by HiPE"); + erts_exit(ERTS_ABORT_EXIT, "Emulated FPE not cleared by HiPE"); #endif } diff --git a/erts/emulator/sys/common/erl_mmap.c b/erts/emulator/sys/common/erl_mmap.c index 754047829f..4180e65fdc 100644 --- a/erts/emulator/sys/common/erl_mmap.c +++ b/erts/emulator/sys/common/erl_mmap.c @@ -1334,7 +1334,7 @@ os_unreserve_physical(char *ptr, UWord size) void *res = mmap((void *) ptr, (size_t) size, ERTS_MMAP_UNRESERVE_PROT, ERTS_MMAP_UNRESERVE_FLAGS, ERTS_MMAP_FD, 0); if (res == (void *) MAP_FAILED) - erl_exit(ERTS_ABORT_EXIT, "Failed to unreserve memory"); + erts_exit(ERTS_ABORT_EXIT, "Failed to unreserve memory"); } static void * @@ -2126,7 +2126,7 @@ erts_mmap_init(ErtsMMapInit *init) #endif erts_page_inv_mask = pagesize - 1; if (pagesize & erts_page_inv_mask) - erl_exit(-1, "erts_mmap: Invalid pagesize: %bpu\n", + erts_exit(1, "erts_mmap: Invalid pagesize: %bpu\n", pagesize); ERTS_MMAP_OP_RINGBUF_INIT(); @@ -2140,7 +2140,7 @@ erts_mmap_init(ErtsMMapInit *init) #if HAVE_MMAP && !defined(MAP_ANON) mmap_state.mmap_fd = open("/dev/zero", O_RDWR); if (mmap_state.mmap_fd < 0) - erl_exit(-1, "erts_mmap: Failed to open /dev/zero\n"); + erts_exit(1, "erts_mmap: Failed to open /dev/zero\n"); #endif erts_smp_mtx_init(&mmap_state.mtx, "erts_mmap"); @@ -2155,7 +2155,7 @@ erts_mmap_init(ErtsMMapInit *init) sz = end - ptr; start = os_mmap_virtual(ptr, sz); if (!start || start > ptr || start >= end) - erl_exit(-1, + erts_exit(1, "erts_mmap: Failed to create virtual range for super carrier\n"); sz = start - ptr; if (sz) @@ -2193,7 +2193,7 @@ erts_mmap_init(ErtsMMapInit *init) start = os_mmap(NULL, sz, 1); } if (!start) - erl_exit(-1, + erts_exit(1, "erts_mmap: Failed to create super carrier of size %bpu MB\n", init->scs/1024/1024); end = start + sz; @@ -2242,7 +2242,7 @@ erts_mmap_init(ErtsMMapInit *init) if ((desc_size + ERTS_SUPERALIGNED_SIZE + ERTS_PAGEALIGNED_SIZE) > end - start) - erl_exit(-1, "erts_mmap: No space for segments in super carrier\n"); + erts_exit(1, "erts_mmap: No space for segments in super carrier\n"); mmap_state.sa.bot = start; mmap_state.sa.bot += desc_size; @@ -2280,7 +2280,7 @@ erts_mmap_init(ErtsMMapInit *init) */ #ifdef ERTS_HAVE_OS_PHYSICAL_MEMORY_RESERVATION if (virtual_map && !os_reserve_physical(start, mmap_state.sa.bot - start)) - erl_exit(-1, "erts_mmap: Failed to reserve physical memory for descriptors\n"); + erts_exit(1, "erts_mmap: Failed to reserve physical memory for descriptors\n"); #endif mmap_state.desc.unused_start = start; mmap_state.desc.unused_end = mmap_state.sa.bot; diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c index 0d51aad863..3398be2b07 100644 --- a/erts/emulator/sys/common/erl_mseg.c +++ b/erts/emulator/sys/common/erl_mseg.c @@ -1490,7 +1490,7 @@ erts_mseg_init(ErtsMsegInit_t *init) #if HALFWORD_HEAP if (sizeof(void *) != 8) - erl_exit(-1,"Halfword emulator cannot be run in 32bit mode"); + erts_exit(1,"Halfword emulator cannot be run in 32bit mode"); init->mmap.virtual_range.start = (char *) sbrk(0); init->mmap.virtual_range.end = (char *) 0x100000000UL; @@ -1500,7 +1500,7 @@ erts_mseg_init(ErtsMsegInit_t *init) erts_mmap_init(&init->mmap); if (!IS_2POW(GET_PAGE_SIZE)) - erl_exit(ERTS_ABORT_EXIT, "erts_mseg: Unexpected page_size %beu\n", GET_PAGE_SIZE); + erts_exit(ERTS_ABORT_EXIT, "erts_mseg: Unexpected page_size %beu\n", GET_PAGE_SIZE); ASSERT((MSEG_ALIGNED_SIZE % GET_PAGE_SIZE) == 0); diff --git a/erts/emulator/sys/common/erl_os_monotonic_time_extender.c b/erts/emulator/sys/common/erl_os_monotonic_time_extender.c index b79485241f..367b22d989 100644 --- a/erts/emulator/sys/common/erl_os_monotonic_time_extender.c +++ b/erts/emulator/sys/common/erl_os_monotonic_time_extender.c @@ -44,7 +44,7 @@ static void *os_monotonic_time_extender(void *vstatep) erts_milli_sleep(sleep_time); } - erl_exit(ERTS_ABORT_EXIT, "os_monotonic_time_extender thread terminating"); + erts_exit(ERTS_ABORT_EXIT, "os_monotonic_time_extender thread terminating"); return NULL; } diff --git a/erts/emulator/sys/ose/erl_poll.c b/erts/emulator/sys/ose/erl_poll.c index 5cee582a00..c690f08dea 100644 --- a/erts/emulator/sys/ose/erl_poll.c +++ b/erts/emulator/sys/ose/erl_poll.c @@ -658,7 +658,7 @@ int erts_poll_wait(ErtsPollSet ps, break; default: res = 0; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: Invalid wakeup_state=%d\n", __FILE__, __LINE__, (int) wakeup_state); } diff --git a/erts/emulator/sys/ose/sys.c b/erts/emulator/sys/ose/sys.c index bcd0ffa0b6..e354faf02c 100644 --- a/erts/emulator/sys/ose/sys.c +++ b/erts/emulator/sys/ose/sys.c @@ -570,7 +570,7 @@ break_requested(void) fprintf(stderr,"break!\n"); #endif if (ERTS_BREAK_REQUESTED) - erl_exit(ERTS_INTR_EXIT, ""); + erts_exit(ERTS_INTR_EXIT, ""); ERTS_SET_BREAK_REQUESTED; ERTS_CHK_IO_AS_INTR(); /* Make sure we don't sleep in poll */ diff --git a/erts/emulator/sys/ose/sys_float.c b/erts/emulator/sys/ose/sys_float.c index 3d9abc6bd1..51875792ae 100644 --- a/erts/emulator/sys/ose/sys_float.c +++ b/erts/emulator/sys/ose/sys_float.c @@ -90,7 +90,7 @@ void erts_fp_check_init_error(volatile unsigned long *fpexnp) snprintf(buf, sizeof buf, "ERTS_FP_CHECK_INIT at %p: detected unhandled FPE at %p\r\n", __builtin_return_address(0), (void*)*fpexnp); if (write(2, buf, strlen(buf)) <= 0) - erl_exit(ERTS_ABORT_EXIT, "%s", buf); + erts_exit(ERTS_ABORT_EXIT, "%s", buf); *fpexnp = 0; #if defined(__i386__) || defined(__x86_64__) erts_restore_fpu(); diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index 8d7da3e47e..d94b37430e 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -638,14 +638,14 @@ erl_sys_init(void) res = erts_sys_getenv_raw("BINDIR", bindir, &bindirsz); if (res != 0) { if (res < 0) - erl_exit(-1, + erts_exit(1, "Environment variable BINDIR is not set\n"); if (res > 0) - erl_exit(-1, + erts_exit(1, "Value of environment variable BINDIR is too large\n"); } if (bindir[0] != DIR_SEPARATOR_CHAR) - erl_exit(-1, + erts_exit(1, "Environment variable BINDIR does not contain an" " absolute path\n"); csp_path_sz = (strlen(bindir) @@ -825,7 +825,7 @@ break_requested(void) fprintf(stderr,"break!\n"); #endif if (ERTS_BREAK_REQUESTED) - erl_exit(ERTS_INTR_EXIT, ""); + erts_exit(ERTS_INTR_EXIT, ""); ERTS_SET_BREAK_REQUESTED; ERTS_CHK_IO_AS_INTR(); /* Make sure we don't sleep in poll */ @@ -864,7 +864,7 @@ sigusr1_exit(void) } prepare_crash_dump(secs); - erl_exit(1, "Received SIGUSR1\n"); + erts_exit(ERTS_ERROR_EXIT, "Received SIGUSR1\n"); } #ifdef ETHR_UNUSABLE_SIGUSRX @@ -920,7 +920,7 @@ static RETSIGTYPE suspend_signal(int signum) static void quit_requested(void) { - erl_exit(ERTS_INTR_EXIT, ""); + erts_exit(ERTS_INTR_EXIT, ""); } #if (defined(SIG_SIGSET) || defined(SIG_SIGNAL)) @@ -3165,7 +3165,7 @@ signal_dispatcher_thread_func(void *unused) if (res < 0) { if (errno == EINTR) continue; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "signal-dispatcher thread got unexpected error: %s (%d)\n", erl_errno_id(errno), errno); @@ -3214,7 +3214,7 @@ signal_dispatcher_thread_func(void *unused) sigusr1_exit(); break; default: - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "signal-dispatcher thread received unknown " "signal notification: '%c'\n", buf[i]); @@ -3233,7 +3233,7 @@ init_smp_sig_notify(void) thr_opts.name = "sys_sig_dispatcher"; if (pipe(sig_notify_fds) < 0) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to create signal-dispatcher pipe: %s (%d)\n", erl_errno_id(errno), errno); @@ -3249,7 +3249,7 @@ init_smp_sig_notify(void) static void init_smp_sig_suspend(void) { if (pipe(sig_suspend_fds) < 0) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to create sig_suspend pipe: %s (%d)\n", erl_errno_id(errno), errno); @@ -3265,7 +3265,7 @@ static void initialize_darwin_main_thread_pipes(void) { if (pipe(erts_darwin_main_thread_pipe) < 0 || pipe(erts_darwin_main_thread_result_pipe) < 0) { - erl_exit(1,"Fatal error initializing Darwin main thread stealing"); + erts_exit(ERTS_ERROR_EXIT,"Fatal error initializing Darwin main thread stealing"); } } diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c index 1ef9e5eef7..8fe7e599e5 100644 --- a/erts/emulator/sys/unix/sys_float.c +++ b/erts/emulator/sys/unix/sys_float.c @@ -90,7 +90,7 @@ void erts_fp_check_init_error(volatile unsigned long *fpexnp) snprintf(buf, sizeof buf, "ERTS_FP_CHECK_INIT at %p: detected unhandled FPE at %p\r\n", __builtin_return_address(0), (void*)*fpexnp); if (write(2, buf, strlen(buf)) <= 0) - erl_exit(ERTS_ABORT_EXIT, "%s", buf); + erts_exit(ERTS_ABORT_EXIT, "%s", buf); *fpexnp = 0; #if defined(__i386__) || defined(__x86_64__) erts_restore_fpu(); diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c index 2e1914f564..95b3daa4ed 100644 --- a/erts/emulator/sys/unix/sys_time.c +++ b/erts/emulator/sys/unix/sys_time.c @@ -342,7 +342,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) * times() (CLK_TCK), the resolution is always one millisecond.. */ if ((erts_sys_time_data__.r.o.ticks_per_sec = TICKS_PER_SEC()) < 0) - erl_exit(ERTS_ABORT_EXIT, "Can't get clock ticks/sec\n"); + erts_exit(ERTS_ABORT_EXIT, "Can't get clock ticks/sec\n"); #if defined(OS_MONOTONIC_TIME_USING_TIMES) #if ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT @@ -450,7 +450,7 @@ posix_clock_gettime(clockid_t id, char *name) if (clock_gettime(id, &ts) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_gettime(%s, _) failed: %s (%d)\n", name, errstr, err); } @@ -495,13 +495,13 @@ posix_clock_gettime_times(clockid_t mid, char *mname, if (mres != 0) { char *errstr = merr ? strerror(merr) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_gettime(%s, _) failed: %s (%d)\n", mname, errstr, merr); } if (sres != 0) { char *errstr = serr ? strerror(serr) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_gettime(%s, _) failed: %s (%d)\n", sname, errstr, serr); } @@ -674,7 +674,7 @@ mach_clocks_init(void) clck_srv_p = &internal_state.r.o.mach.clock.monotonic.srv; kret = host_get_clock_service(host, id, clck_srv_p); if (kret != KERN_SUCCESS) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "host_get_clock_service(_, %s, _) failed\n", name); } @@ -686,7 +686,7 @@ mach_clocks_init(void) clck_srv_p = &internal_state.r.o.mach.clock.wall.srv; kret = host_get_clock_service(host, id, clck_srv_p); if (kret != KERN_SUCCESS) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "host_get_clock_service(_, %s, _) failed\n", name); } @@ -695,7 +695,7 @@ mach_clocks_init(void) if (atexit(mach_clocks_fini) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "Failed to register mach_clocks_fini() " "for call at exit: %s (%d)\n", errstr, err); @@ -717,7 +717,7 @@ mach_clock_getres(ErtsMachClock *clk) (clock_attr_t) attr, &cnt); if (kret != KERN_SUCCESS || cnt != 1) { - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_get_attributes(%s, _) failed\n", clk->name); } @@ -735,7 +735,7 @@ mach_clock_get_time(ErtsMachClock *clk) kret = clock_get_time(clk->srv, &time_spec); if (kret != KERN_SUCCESS) - erl_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", clk->name); + erts_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", clk->name); return ERTS_TimeSpec2Sint64(&time_spec); } @@ -781,11 +781,11 @@ erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) &sys_time_spec); if (mkret != KERN_SUCCESS) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", internal_state.r.o.mach.clock.monotonic.name); if (skret != KERN_SUCCESS) - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "clock_get_time(%s, _) failed\n", internal_state.r.o.mach.clock.wall.name); @@ -850,7 +850,7 @@ erts_os_system_time(void) if (gettimeofday(&tv, NULL) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "gettimeofday(_, NULL) failed: %s (%d)\n", errstr, err); } diff --git a/erts/emulator/sys/win32/erl_poll.c b/erts/emulator/sys/win32/erl_poll.c index 466f4a3b48..547d4b1d21 100644 --- a/erts/emulator/sys/win32/erl_poll.c +++ b/erts/emulator/sys/win32/erl_poll.c @@ -436,7 +436,7 @@ wakeup_cause(ErtsPollSet ps) break; default: res = 0; - erl_exit(ERTS_ABORT_EXIT, + erts_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: Invalid wakeup_state=%d\n", __FILE__, __LINE__, (int) wakeup_state); } @@ -576,7 +576,7 @@ static void signal_standby(ErtsPollSet ps) --(ps->standby_wait_counter); if (ps->standby_wait_counter < 0) { LeaveCriticalSection(&(ps->standby_crit)); - erl_exit(1,"Standby signalled by more threads than expected"); + erts_exit(ERTS_ERROR_EXIT,"Standby signalled by more threads than expected"); } if (!(ps->standby_wait_counter)) { SetEvent(ps->standby_wait_event); @@ -738,7 +738,7 @@ static void *break_waiter(void *param) erts_mtx_unlock(&break_waiter_lock); break; default: - erl_exit(1,"Unexpected event in break_waiter"); + erts_exit(ERTS_ERROR_EXIT,"Unexpected event in break_waiter"); } } } @@ -1157,7 +1157,7 @@ int erts_poll_wait(ErtsPollSet ps, HARDDEBUGF(("Oups!")); /* Oups, got signalled before we took the lock, can't reset */ if(!is_io_ready(ps)) { - erl_exit(1,"Internal error: " + erts_exit(ERTS_ERROR_EXIT,"Internal error: " "Inconsistent io structures in erl_poll.\n"); } START_WAITER(ps,w); @@ -1215,7 +1215,7 @@ int erts_poll_wait(ErtsPollSet ps, ERTS_SET_BREAK_REQUESTED; break; case BREAK_WAITER_GOT_HALT: - erl_exit(0,""); + erts_exit(0,""); break; default: break; diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index fce76db28f..37d3e16256 100644 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -38,7 +38,7 @@ void erts_sys_init_float(void); void erl_start(int, char**); -void erl_exit(int n, char*, ...); +void erts_exit(int n, char*, ...); void erl_error(char*, va_list); void erl_crash_dump(char*, int, char*, ...); @@ -200,7 +200,7 @@ erts_sys_misc_mem_sz(void) */ void sys_tty_reset(int exit_code) { - if (exit_code > 0) + if (exit_code == ERTS_ERROR_EXIT) ConWaitForExit(); else ConNormalExit(); @@ -3110,13 +3110,13 @@ check_supported_os_version(void) || int_os_version.dwMajorVersion < major || (int_os_version.dwMajorVersion == major && int_os_version.dwMinorVersion < minor)) - erl_exit(-1, + erts_exit(1, "Windows version not supported " "(min required: winnt %d.%d)\n", major, minor); } #else - erl_exit(-1, + erts_exit(1, "Windows version not supported " "(min required: win %d.%d)\n", nt_major, nt_minor); diff --git a/erts/emulator/sys/win32/sys_interrupt.c b/erts/emulator/sys/win32/sys_interrupt.c index d6178de03c..a89211fa8e 100644 --- a/erts/emulator/sys/win32/sys_interrupt.c +++ b/erts/emulator/sys/win32/sys_interrupt.c @@ -81,7 +81,7 @@ BOOL WINAPI ctrl_handler_ignore_break(DWORD dwCtrlType) return TRUE; /* else pour through... */ case CTRL_CLOSE_EVENT: - erl_exit(0, ""); + erts_exit(0, ""); break; } return TRUE; @@ -106,7 +106,7 @@ BOOL WINAPI ctrl_handler_replace_intr(DWORD dwCtrlType) /* else pour through... */ case CTRL_CLOSE_EVENT: case CTRL_SHUTDOWN_EVENT: - erl_exit(0, ""); + erts_exit(0, ""); break; } return TRUE; @@ -133,7 +133,7 @@ BOOL WINAPI ctrl_handler(DWORD dwCtrlType) return TRUE; /* else pour through... */ case CTRL_CLOSE_EVENT: - erl_exit(0, ""); + erts_exit(0, ""); break; } return TRUE; diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index 9e5f78703a..3cf7f7cf07 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -147,7 +147,7 @@ os_monotonic_time_qpc(void) LARGE_INTEGER pc; if (!(*internal_state.r.o.pQueryPerformanceCounter)(&pc)) - erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); + erts_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); return (ErtsMonotonicTime) pc.QuadPart; } @@ -164,7 +164,7 @@ os_times_qpc(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) GetSystemTime(&st); if (!qpcr) - erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); + erts_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); *mtimep = (ErtsMonotonicTime) pc.QuadPart; @@ -251,7 +251,7 @@ sys_hrtime_qpc(void) LARGE_INTEGER pc; if (!(*internal_state.r.o.pQueryPerformanceCounter)(&pc)) - erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); + erts_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); ASSERT(pc.QuadPart > 0); diff --git a/erts/emulator/test/distribution_SUITE.erl b/erts/emulator/test/distribution_SUITE.erl index d71cedbdc5..151fab0a0e 100644 --- a/erts/emulator/test/distribution_SUITE.erl +++ b/erts/emulator/test/distribution_SUITE.erl @@ -164,7 +164,7 @@ bulk_send(Terms, BinSize) -> ?line stop_node(Node), ?line test_server:timetrap_cancel(Dog), - {comment, integer_to_list(trunc(Size/1024/Elapsed+0.5)) ++ " K/s"}. + {comment, integer_to_list(trunc(Size/1024/max(1,Elapsed)+0.5)) ++ " K/s"}. bulk_sendsend(Terms, BinSize) -> {Rate1, MonitorCount1} = bulk_sendsend2(Terms, BinSize, 5), diff --git a/erts/emulator/test/estone_SUITE.erl b/erts/emulator/test/estone_SUITE.erl index dc8f0aaee9..d49ab3de4d 100644 --- a/erts/emulator/test/estone_SUITE.erl +++ b/erts/emulator/test/estone_SUITE.erl @@ -382,11 +382,11 @@ apply_micro(M) -> {weight_percentage, M#micro.weight}, {loops, M#micro.loops}, {microsecs,MicroSecs}, - {estones, (M#micro.weight * M#micro.weight * ?STONEFACTOR) div MicroSecs}, + {estones, (M#micro.weight * M#micro.weight * ?STONEFACTOR) div max(1,MicroSecs)}, {gcs, GC1 - GC0}, {kilo_word_reclaimed, (Words1 - Words0) div 1000}, {kilo_reductions, Reds div 1000}, - {gc_intensity, gci(Elapsed, GC1 - GC0, Words1 - Words0)}]. + {gc_intensity, gci(max(1,Elapsed), GC1 - GC0, Words1 - Words0)}]. monotonic_time() -> try erlang:monotonic_time() catch error:undef -> erlang:now() end. diff --git a/erts/emulator/valgrind/suppress.patched.3.6.0 b/erts/emulator/valgrind/suppress.patched.3.6.0 index 16cecf2dba..fcde4a0123 100644 --- a/erts/emulator/valgrind/suppress.patched.3.6.0 +++ b/erts/emulator/valgrind/suppress.patched.3.6.0 @@ -368,7 +368,7 @@ Memcheck:Addr4 ... fun:erts_print_scheduler_info ... -fun:erl_exit +fun:erts_exit fun:broken_halt_test fun:erts_debug_set_internal_state_2 fun:process_main diff --git a/erts/emulator/valgrind/suppress.standard b/erts/emulator/valgrind/suppress.standard index a1f3f82364..bb07c92fc1 100644 --- a/erts/emulator/valgrind/suppress.standard +++ b/erts/emulator/valgrind/suppress.standard @@ -336,7 +336,7 @@ Memcheck:Addr4 ... fun:erts_print_scheduler_info ... -fun:erl_exit +fun:erts_exit fun:broken_halt_test fun:erts_debug_set_internal_state_2 fun:process_main diff --git a/erts/epmd/src/epmd.c b/erts/epmd/src/epmd.c index 63ec18d939..5513cb2d7e 100644 --- a/erts/epmd/src/epmd.c +++ b/erts/epmd/src/epmd.c @@ -343,7 +343,7 @@ static void run_daemon(EpmdVars *g) for (fd = 0; fd < g->max_conn ; fd++) /* close all files ... */ close(fd); /* Syslog on linux will try to write to whatever if we dont - inform it of that the log is closed. */ + inform it that the log is closed. */ closelog(); /* These shouldn't be needed but for safety... */ diff --git a/erts/epmd/src/epmd_cli.c b/erts/epmd/src/epmd_cli.c index a8fe865d9a..6fc05e153e 100644 --- a/erts/epmd/src/epmd_cli.c +++ b/erts/epmd/src/epmd_cli.c @@ -136,19 +136,33 @@ void epmd_call(EpmdVars *g,int what) static int conn_to_epmd(EpmdVars *g) { struct EPMD_SOCKADDR_IN address; + size_t salen = 0; int connect_sock; - - connect_sock = socket(FAMILY, SOCK_STREAM, 0); - if (connect_sock<0) - goto error; + unsigned short sport = g->port; + +#if defined(EPMD6) + SET_ADDR6(address, in6addr_loopback, sport); + salen = sizeof(struct sockaddr_in6); + + connect_sock = socket(AF_INET6, SOCK_STREAM, 0); + if (connect_sock>=0) { + + if (connect(connect_sock, (struct sockaddr*)&address, salen) == 0) + return connect_sock; - { /* store port number in unsigned short */ - unsigned short sport = g->port; - SET_ADDR(address, EPMD_ADDR_LOOPBACK, sport); + close(connect_sock); } +#endif + SET_ADDR(address, htonl(INADDR_LOOPBACK), sport); + salen = sizeof(struct sockaddr_in); - if (connect(connect_sock, (struct sockaddr*)&address, sizeof address) < 0) + connect_sock = socket(AF_INET, SOCK_STREAM, 0); + if (connect_sock<0) goto error; + + if (connect(connect_sock, (struct sockaddr*)&address, salen) < 0) + goto error; + return connect_sock; error: diff --git a/erts/epmd/src/epmd_int.h b/erts/epmd/src/epmd_int.h index 26100afc93..09317094c7 100644 --- a/erts/epmd/src/epmd_int.h +++ b/erts/epmd/src/epmd_int.h @@ -55,6 +55,7 @@ # ifndef WINDOWS_H_INCLUDES_WINSOCK2_H # include <winsock2.h> # endif +# include <ws2tcpip.h> # include <windows.h> # include <process.h> #endif @@ -130,6 +131,10 @@ # include <systemd/sd-daemon.h> #endif /* HAVE_SYSTEMD_DAEMON */ +#if defined(HAVE_IN6) && defined(AF_INET6) && defined(HAVE_INET_PTON) +# define EPMD6 +#endif + /* ************************************************************************ */ /* Replace some functions by others by making the function name a macro */ @@ -183,33 +188,53 @@ /* ************************************************************************ */ /* Macros that let us use IPv6 */ -#if defined(HAVE_IN6) && defined(AF_INET6) && defined(EPMD6) +#if HAVE_IN6 +# if ! defined(HAVE_IN6ADDR_ANY) || ! HAVE_IN6ADDR_ANY +# if HAVE_DECL_IN6ADDR_ANY_INIT +static const struct in6_addr in6addr_any = { { IN6ADDR_ANY_INIT } }; +# else +static const struct in6_addr in6addr_any = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 } } }; +# endif /* HAVE_IN6ADDR_ANY_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_ANY */ + +# if ! defined(HAVE_IN6ADDR_LOOPBACK) || ! HAVE_IN6ADDR_LOOPBACK +# if HAVE_DECL_IN6ADDR_LOOPBACK_INIT +static const struct in6_addr in6addr_loopback = + { { IN6ADDR_LOOPBACK_INIT } }; +# else +static const struct in6_addr in6addr_loopback = + { { { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } }; +# endif /* HAVE_IN6ADDR_LOOPBACK_INIT */ +# endif /* ! HAVE_DECL_IN6ADDR_LOOPBACK */ +#endif /* HAVE_IN6 */ + +#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK)) + +#if defined(EPMD6) -#define EPMD_SOCKADDR_IN sockaddr_in6 -#define EPMD_IN_ADDR in6_addr -#define EPMD_S_ADDR s6_addr -#define EPMD_ADDR_LOOPBACK in6addr_loopback.s6_addr -#define EPMD_ADDR_ANY in6addr_any.s6_addr +#define EPMD_SOCKADDR_IN sockaddr_storage #define FAMILY AF_INET6 -#define SET_ADDR(dst, addr, port) do { \ - memset((char*)&(dst), 0, sizeof(dst)); \ - memcpy((char*)&(dst).sin6_addr.s6_addr, (char*)&(addr), 16); \ - (dst).sin6_family = AF_INET6; \ - (dst).sin6_flowinfo = 0; \ - (dst).sin6_port = htons(port); \ +#define SET_ADDR6(dst, addr, port) do { \ + struct sockaddr_in6 *sa = (struct sockaddr_in6 *)&(dst); \ + memset(sa, 0, sizeof(dst)); \ + sa->sin6_family = AF_INET6; \ + sa->sin6_addr = (addr); \ + sa->sin6_port = htons(port); \ } while(0) -#define IS_ADDR_LOOPBACK(addr) \ - (memcmp((addr).s6_addr, in6addr_loopback.s6_addr, 16) == 0) +#define SET_ADDR(dst, addr, port) do { \ + struct sockaddr_in *sa = (struct sockaddr_in *)&(dst); \ + memset(sa, 0, sizeof(dst)); \ + sa->sin_family = AF_INET; \ + sa->sin_addr.s_addr = (addr); \ + sa->sin_port = htons(port); \ + } while(0) #else /* Not IP v6 */ #define EPMD_SOCKADDR_IN sockaddr_in -#define EPMD_IN_ADDR in_addr -#define EPMD_S_ADDR s_addr -#define EPMD_ADDR_LOOPBACK htonl(INADDR_LOOPBACK) -#define EPMD_ADDR_ANY htonl(INADDR_ANY) #define FAMILY AF_INET #define SET_ADDR(dst, addr, port) do { \ @@ -219,8 +244,6 @@ (dst).sin_port = htons(port); \ } while(0) -#define IS_ADDR_LOOPBACK(addr) ((addr).s_addr == htonl(INADDR_LOOPBACK)) - #endif /* Not IP v6 */ /* ************************************************************************ */ diff --git a/erts/epmd/src/epmd_srv.c b/erts/epmd/src/epmd_srv.c index 7100855407..e1bac99ef9 100644 --- a/erts/epmd/src/epmd_srv.c +++ b/erts/epmd/src/epmd_srv.c @@ -76,6 +76,7 @@ static time_t current_time(EpmdVars*); static Connection *conn_init(EpmdVars*); static int conn_open(EpmdVars*,int); +static int conn_local_peer_check(EpmdVars*, int); static int conn_close_fd(EpmdVars*,int); static void node_init(EpmdVars*); @@ -206,10 +207,11 @@ void run(EpmdVars *g) { struct EPMD_SOCKADDR_IN iserv_addr[MAX_LISTEN_SOCKETS]; int listensock[MAX_LISTEN_SOCKETS]; - int num_sockets; + int num_sockets = 0; int i; int opt; unsigned short sport = g->port; + int bound = 0; node_init(g); g->conn = conn_init(g); @@ -252,64 +254,82 @@ void run(EpmdVars *g) if (g->addresses != NULL && /* String contains non-separator characters if: */ g->addresses[strspn(g->addresses," ,")] != '\000') { - char *tmp; - char *token; - int loopback_ok = 0; + char *tmp = NULL; + char *token = NULL; + + /* Always listen on the loopback. */ + SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_LOOPBACK),sport); + num_sockets++; +#if defined(EPMD6) + SET_ADDR6(iserv_addr[num_sockets],in6addr_loopback,sport); + num_sockets++; +#endif - if ((tmp = (char *)malloc(strlen(g->addresses) + 1)) == NULL) + if ((tmp = strdup(g->addresses)) == NULL) { dbg_perror(g,"cannot allocate memory"); epmd_cleanup_exit(g,1); } - strcpy(tmp,g->addresses); - for(token = strtok(tmp,", "), num_sockets = 0; + for(token = strtok(tmp,", "); token != NULL; - token = strtok(NULL,", "), num_sockets++) + token = strtok(NULL,", ")) { - struct EPMD_IN_ADDR addr; -#ifdef HAVE_INET_PTON - int ret; + struct in_addr addr; +#if defined(EPMD6) + struct in6_addr addr6; + struct sockaddr_storage *sa = &iserv_addr[num_sockets]; - if ((ret = inet_pton(FAMILY,token,&addr)) == -1) + if (inet_pton(AF_INET6,token,&addr6) == 1) { - dbg_perror(g,"cannot convert IP address to network format"); - epmd_cleanup_exit(g,1); + SET_ADDR6(iserv_addr[num_sockets],addr6,sport); + } + else if (inet_pton(AF_INET,token,&addr) == 1) + { + SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport); + } + else +#else + if ((addr.s_addr = inet_addr(token)) != INADDR_NONE) + { + SET_ADDR(iserv_addr[num_sockets],addr.s_addr,sport); } - else if (ret == 0) -#elif !defined(EPMD6) - if ((addr.EPMD_S_ADDR = inet_addr(token)) == INADDR_NONE) + else #endif { dbg_tty_printf(g,0,"cannot parse IP address \"%s\"",token); epmd_cleanup_exit(g,1); } +#if defined(EPMD6) + if (sa->ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&addr6)) + continue; + + if (sa->ss_family == AF_INET) +#endif if (IS_ADDR_LOOPBACK(addr)) - loopback_ok = 1; + continue; - if (num_sockets - loopback_ok == MAX_LISTEN_SOCKETS - 1) + num_sockets++; + + if (num_sockets >= MAX_LISTEN_SOCKETS) { dbg_tty_printf(g,0,"cannot listen on more than %d IP addresses", MAX_LISTEN_SOCKETS); epmd_cleanup_exit(g,1); } - - SET_ADDR(iserv_addr[num_sockets],addr.EPMD_S_ADDR,sport); } free(tmp); - - if (!loopback_ok) - { - SET_ADDR(iserv_addr[num_sockets],EPMD_ADDR_LOOPBACK,sport); - num_sockets++; - } } else { - SET_ADDR(iserv_addr[0],EPMD_ADDR_ANY,sport); - num_sockets = 1; + SET_ADDR(iserv_addr[num_sockets],htonl(INADDR_ANY),sport); + num_sockets++; +#if defined(EPMD6) + SET_ADDR6(iserv_addr[num_sockets],in6addr_any,sport); + num_sockets++; +#endif } #ifdef HAVE_SYSTEMD_DAEMON } @@ -340,13 +360,39 @@ void run(EpmdVars *g) #endif /* HAVE_SYSTEMD_DAEMON */ for (i = 0; i < num_sockets; i++) { - if ((listensock[i] = socket(FAMILY,SOCK_STREAM,0)) < 0) + struct sockaddr *sa = (struct sockaddr *)&iserv_addr[i]; +#if defined(EPMD6) + size_t salen = (sa->sa_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : + sizeof(struct sockaddr_in)); +#else + size_t salen = sizeof(struct sockaddr_in); +#endif + + if ((listensock[i] = socket(sa->sa_family,SOCK_STREAM,0)) < 0) { - dbg_perror(g,"error opening stream socket"); + switch (errno) { + case EAFNOSUPPORT: + case EPROTONOSUPPORT: + continue; + default: + dbg_perror(g,"error opening stream socket"); + epmd_cleanup_exit(g,1); + } + } + g->listenfd[bound++] = listensock[i]; + +#if HAVE_DECL_IPV6_V6ONLY + opt = 1; + if (sa->sa_family == AF_INET6 && + setsockopt(listensock[i],IPPROTO_IPV6,IPV6_V6ONLY,&opt, + sizeof(opt)) <0) + { + dbg_perror(g,"can't set IPv6 only socket option"); epmd_cleanup_exit(g,1); } - g->listenfd[i] = listensock[i]; - +#endif + /* * Note that we must not enable the SO_REUSEADDR on Windows, * because addresses will be reused even if they are still in use. @@ -378,8 +424,7 @@ void run(EpmdVars *g) dbg_perror(g,"failed to set non-blocking mode of listening socket %d", listensock[i]); - if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], - sizeof(iserv_addr[i])) < 0) + if (bind(listensock[i], (struct sockaddr*) &iserv_addr[i], salen) < 0) { if (errno == EADDRINUSE) { @@ -400,6 +445,11 @@ void run(EpmdVars *g) } select_fd_set(g, listensock[i]); } + if (bound == 0) { + dbg_perror(g,"unable to bind any address"); + epmd_cleanup_exit(g,1); + } + num_sockets = bound; #ifdef HAVE_SYSTEMD_DAEMON } sd_notifyf(0, "READY=1\n" @@ -444,8 +494,8 @@ void run(EpmdVars *g) } for (i = 0; i < num_sockets; i++) - if (FD_ISSET(listensock[i],&read_mask)) { - if (do_accept(g, listensock[i]) && g->active_conn < g->max_conn) { + if (FD_ISSET(g->listenfd[i],&read_mask)) { + if (do_accept(g, g->listenfd[i]) && g->active_conn < g->max_conn) { /* * The accept() succeeded, and we have at least one file * descriptor still free, which means that another accept() @@ -1005,15 +1055,6 @@ static int conn_open(EpmdVars *g,int fd) for (i = 0; i < g->max_conn; i++) { if (g->conn[i].open == EPMD_FALSE) { - struct sockaddr_in si; - struct sockaddr_in di; -#ifdef HAVE_SOCKLEN_T - socklen_t st; -#else - int st; -#endif - st = sizeof(si); - g->active_conn++; s = &g->conn[i]; @@ -1024,20 +1065,7 @@ static int conn_open(EpmdVars *g,int fd) s->open = EPMD_TRUE; s->keep = EPMD_FALSE; - /* Determine if connection is from localhost */ - if (getpeername(s->fd,(struct sockaddr*) &si,&st) || - st < sizeof(si)) { - /* Failure to get peername is regarded as non local host */ - s->local_peer = EPMD_FALSE; - } else { - /* Only 127.x.x.x and connections from the host's IP address - allowed, no false positives */ - s->local_peer = - (((((unsigned) ntohl(si.sin_addr.s_addr)) & 0xFF000000U) == - 0x7F000000U) || - (getsockname(s->fd,(struct sockaddr*) &di,&st) ? - EPMD_FALSE : si.sin_addr.s_addr == di.sin_addr.s_addr)); - } + s->local_peer = conn_local_peer_check(g, s->fd); dbg_tty_printf(g,2,(s->local_peer) ? "Local peer connected" : "Non-local peer connected"); @@ -1045,7 +1073,7 @@ static int conn_open(EpmdVars *g,int fd) s->got = 0; s->mod_time = current_time(g); /* Note activity */ - s->buf = (char *)malloc(INBUF_SIZE); + s->buf = malloc(INBUF_SIZE); if (s->buf == NULL) { dbg_printf(g,0,"epmd: Insufficient memory"); @@ -1063,6 +1091,60 @@ static int conn_open(EpmdVars *g,int fd) return EPMD_FALSE; } +static int conn_local_peer_check(EpmdVars *g, int fd) +{ + struct EPMD_SOCKADDR_IN si; + struct EPMD_SOCKADDR_IN di; + + struct sockaddr_in *si4 = (struct sockaddr_in *)&si; + struct sockaddr_in *di4 = (struct sockaddr_in *)&di; + +#if defined(EPMD6) + struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&si; + struct sockaddr_in6 *di6 = (struct sockaddr_in6 *)&di; +#endif + +#ifdef HAVE_SOCKLEN_T + socklen_t st; +#else + int st; +#endif + + st = sizeof(si); + + /* Determine if connection is from localhost */ + if (getpeername(fd,(struct sockaddr*) &si,&st) || + st > sizeof(si)) { + /* Failure to get peername is regarded as non local host */ + return EPMD_FALSE; + } + + /* Only 127.x.x.x and connections from the host's IP address + allowed, no false positives */ +#if defined(EPMD6) + if (si.ss_family == AF_INET6 && IN6_IS_ADDR_LOOPBACK(&(si6->sin6_addr))) + return EPMD_TRUE; + + if (si.ss_family == AF_INET) +#endif + if ((((unsigned) ntohl(si4->sin_addr.s_addr)) & 0xFF000000U) == + 0x7F000000U) + return EPMD_TRUE; + + if (getsockname(fd,(struct sockaddr*) &di,&st)) + return EPMD_FALSE; + +#if defined(EPMD6) + if (si.ss_family == AF_INET6) + return IN6_ARE_ADDR_EQUAL( &(si6->sin6_addr), &(di6->sin6_addr)); + if (si.ss_family == AF_INET) +#endif + return si4->sin_addr.s_addr == di4->sin_addr.s_addr; +#if defined(EPMD6) + return EPMD_FALSE; +#endif +} + static int conn_close_fd(EpmdVars *g,int fd) { int i; diff --git a/erts/epmd/test/epmd_SUITE.erl b/erts/epmd/test/epmd_SUITE.erl index 4de65500e9..d5837e5b8c 100644 --- a/erts/epmd/test/epmd_SUITE.erl +++ b/erts/epmd/test/epmd_SUITE.erl @@ -43,6 +43,7 @@ -export( [ register_name/1, + register_name_ipv6/1, register_names_1/1, register_names_2/1, register_duplicate_name/1, @@ -113,7 +114,8 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [register_name, register_names_1, register_names_2, + [register_name, register_name_ipv6, + register_names_1, register_names_2, register_duplicate_name, unicode_name, long_unicode_name, get_port_nr, slow_get_port_nr, unregister_others_name_1, unregister_others_name_2, @@ -172,6 +174,24 @@ register_name(Config) when is_list(Config) -> ?line ok = close(Sock), % Unregister ok. +register_name_ipv6(doc) -> + ["Register a name over IPv6"]; +register_name_ipv6(suite) -> + []; +register_name_ipv6(Config) when is_list(Config) -> + % Test if the host has an IPv6 loopback address + Res = gen_tcp:listen(0, [inet6, {ip, {0,0,0,0,0,0,0,1}}]), + case Res of + {ok,LSock} -> + gen_tcp:close(LSock), + ?line ok = epmdrun(), + ?line {ok,Sock} = register_node6("foobar6"), + ?line ok = close(Sock), % Unregister + ok; + _Error -> + {skip, "Host does not have an IPv6 loopback address"} + end. + register_names_1(doc) -> ["Register and unregister two nodes"]; register_names_1(suite) -> @@ -245,9 +265,14 @@ register_node(Name) -> register_node(Name,Port) -> register_node_v2(Port,$M,0,5,5,Name,""). +register_node6(Name) -> + register_node_v2({0,0,0,0,0,0,0,1},?DUMMY_PORT,$M,0,5,5,Name,""). + register_node_v2(Port, NodeType, Prot, HVsn, LVsn, Name, Extra) -> + register_node_v2("localhost", Port, NodeType, Prot, HVsn, LVsn, Name, Extra). +register_node_v2(Addr, Port, NodeType, Prot, HVsn, LVsn, Name, Extra) -> Req = alive2_req(Port, NodeType, Prot, HVsn, LVsn, Name, Extra), - case send_req(Req) of + case send_req(Req, Addr) of {ok,Sock} -> case recv(Sock,4) of {ok, [?EPMD_ALIVE2_RESP,_Res=0,_C0,_C1]} -> @@ -1186,7 +1211,9 @@ send_direct(Sock, Bytes) -> end. send_req(Req) -> - case connect() of + send_req(Req, "localhost"). +send_req(Req, Addr) -> + case connect(Addr) of {ok,Sock} -> case send(Sock, [size16(Req), Req]) of ok -> diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index 9571b83ffd..1a826221fb 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -472,10 +472,6 @@ message_loop(erlin_fd, erlout_fd) switch (mp->op) { case HEART_BEAT: timestamp(&last_received); -#ifdef USE_WATCHDOG - /* reset the hardware watchdog timer */ - wd_reset(); -#endif break; case SHUT_DOWN: return R_SHUT_DOWN; diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam Binary files differindex 32d5d70122..21dde7f257 100644 --- a/erts/preloaded/ebin/erts_internal.beam +++ b/erts/preloaded/ebin/erts_internal.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 97170551bf..9256e35553 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index 7ed4efea4b..6db77a8482 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -35,6 +35,9 @@ -export([port_command/3, port_connect/2, port_close/1, port_control/3, port_call/3, port_info/1, port_info/2]). +-export([system_check/1, + gather_system_check_result/1]). + -export([request_system_task/3]). -export([check_process_code/2]). @@ -197,6 +200,23 @@ request_system_task(_Pid, _Prio, _Request) -> check_process_code(_Module, _OptionList) -> erlang:nif_error(undefined). +-spec system_check(Type) -> 'ok' when + Type :: 'schedulers'. + +system_check(_Type) -> + erlang:nif_error(undefined). + +gather_system_check_result(Ref) when is_reference(Ref) -> + gather_system_check_result(Ref, erlang:system_info(schedulers)). + +gather_system_check_result(_Ref, 0) -> + ok; +gather_system_check_result(Ref, N) -> + receive + Ref -> + gather_system_check_result(Ref, N - 1) + end. + %% term compare where integer() < float() = true -spec cmp_term(A,B) -> Result when diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index ce87fd3180..6dea1787a8 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -628,12 +628,22 @@ ber_other(Config, Rule, Opts) -> der(Config) -> asn1_test_lib:compile_all(ber_modules(), Config, [der]). -module_test(M, Config, Rule, Opts) -> - asn1_test_lib:compile(M, Config, [Rule|Opts]), - case asn1ct:test(list_to_atom(M), [{i, ?config(case_dir, Config)}]) of - ok -> ok; - Error -> - erlang:error({test_failed, M, Opts, Error}) +module_test(M0, Config, Rule, Opts) -> + asn1_test_lib:compile(M0, Config, [Rule|Opts]), + case list_to_atom(M0) of + 'LDAP' -> + %% Because of the recursive definition of 'Filter' in + %% the LDAP module, the construction of a sample + %% value for 'Filter' is not guaranteed to terminate. + ok; + M -> + TestOpts = [{i, ?config(case_dir, Config)}], + case asn1ct:test(M, TestOpts) of + ok -> + ok; + Error -> + erlang:error({test_failed, M, Opts, Error}) + end end. diff --git a/lib/common_test/src/ct_conn_log_h.erl b/lib/common_test/src/ct_conn_log_h.erl index f7615fdc14..93f358462d 100644 --- a/lib/common_test/src/ct_conn_log_h.erl +++ b/lib/common_test/src/ct_conn_log_h.erl @@ -117,7 +117,7 @@ write_report(Time,#conn_log{module=ConnMod}=Info,Data,GL,State) -> ok; {LogType,Fd} -> case format_data(ConnMod,LogType,Data) of - [] -> + [] when Info#conn_log.action==send; Info#conn_log.action==recv -> ok; FormattedData -> io:format(Fd,"~n~ts~ts~ts",[format_head(ConnMod,LogType,Time), diff --git a/lib/common_test/src/ct_framework.erl b/lib/common_test/src/ct_framework.erl index f792269c41..8fb7a03bb0 100644 --- a/lib/common_test/src/ct_framework.erl +++ b/lib/common_test/src/ct_framework.erl @@ -28,7 +28,7 @@ -export([init_tc/3, end_tc/3, end_tc/4, get_suite/2, get_all_cases/1]). -export([report/2, warn/1, error_notification/4]). --export([get_logopts/0, format_comment/1, get_html_wrapper/4]). +-export([get_log_dir/0, get_logopts/0, format_comment/1, get_html_wrapper/4]). -export([error_in_suite/1, init_per_suite/1, end_per_suite/1, init_per_group/2, end_per_group/2]). @@ -1480,3 +1480,8 @@ get_html_wrapper(TestName, PrintLabel, Cwd, TableCols) -> get_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding) -> ct_logs:get_ts_html_wrapper(TestName, PrintLabel, Cwd, TableCols, Encoding). + +%%%----------------------------------------------------------------- +%%% @spec get_log_dir() -> {ok,LogDir} +get_log_dir() -> + ct_logs:get_log_dir(true). diff --git a/lib/common_test/src/ct_netconfc.erl b/lib/common_test/src/ct_netconfc.erl index 3da1115c76..8812514ad9 100644 --- a/lib/common_test/src/ct_netconfc.erl +++ b/lib/common_test/src/ct_netconfc.erl @@ -234,7 +234,6 @@ %% Internal defines %%---------------------------------------------------------------------- -define(APPLICATION,?MODULE). --define(VALID_SSH_OPTS,[user, password, user_dir]). -define(DEFAULT_STREAM,"NETCONF"). -define(error(ConnName,Report), @@ -1257,13 +1256,11 @@ check_options([{port,Port}|T], Host, _, #options{} = Options) -> check_options([{timeout, Timeout}|T], Host, Port, Options) when is_integer(Timeout); Timeout==infinity -> check_options(T, Host, Port, Options#options{timeout = Timeout}); -check_options([{X,_}=Opt|T], Host, Port, #options{ssh=SshOpts}=Options) -> - case lists:member(X,?VALID_SSH_OPTS) of - true -> - check_options(T, Host, Port, Options#options{ssh=[Opt|SshOpts]}); - false -> - {error, {invalid_option, Opt}} - end. +check_options([{timeout, _} = Opt|_T], _Host, _Port, _Options) -> + {error, {invalid_option, Opt}}; +check_options([Opt|T], Host, Port, #options{ssh=SshOpts}=Options) -> + %% Option verified by ssh + check_options(T, Host, Port, Options#options{ssh=[Opt|SshOpts]}). %%%----------------------------------------------------------------- set_request_timer(infinity) -> diff --git a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl index 49b02d2bba..9d4c798795 100644 --- a/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE_data/netconfc1_SUITE.erl @@ -332,7 +332,8 @@ invalid_opt(Config) -> Opts1 = ?DEFAULT_SSH_OPTS(DataDir) ++ [{timeout,invalidvalue}], {error,{invalid_option,{timeout,invalidvalue}}} = ct_netconfc:open(Opts1), Opts2 = ?DEFAULT_SSH_OPTS(DataDir) ++ [{some_other_opt,true}], - {error,{invalid_option,{some_other_opt,true}}} = ct_netconfc:open(Opts2), + {error,{ssh,could_not_connect_to_server,{options,_}}} = + ct_netconfc:open(Opts2), ok. timeout_close_session(Config) -> diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index d49176ec3e..66c4a7582f 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2015. All Rights Reserved. +%% Copyright Ericsson AB 2010-2016. 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. @@ -83,16 +83,8 @@ -define(DEFAULT_TC, 30000). %% RFC 3588 ch 2.1 -define(RESTART_TC, 1000). %% if restart was this recent -%% Used to be able to swap this with anything else dict-like but now -%% rely on the fact that a service's #state{} record does not change -%% in storing in it ?STATE table and not always going through the -%% service process. In particular, rely on the fact that operations on -%% a ?Dict don't change the handle to it. --define(Dict, diameter_dict). - -%% Maintains state in a table. In contrast to previously, a service's -%% stat is not constant and is accessed outside of the service -%% process. +%% Maintain state in a table since a service's state is accessed +%% outside of the service process. -define(STATE_TABLE, ?MODULE). %% The default sequence mask. @@ -117,12 +109,11 @@ service :: #diameter_service{}, watchdogT = ets_new(watchdogs) %% #watchdog{} at start :: ets:tid(), - peerT = ets_new(peers) %% #peer{pid = TPid} at okay/reopen - :: ets:tid(), - shared_peers = ?Dict:new() %% Alias -> [{TPid, Caps}, ...] - :: ets:tid(), - local_peers = ?Dict:new() %% Alias -> [{TPid, Caps}, ...] - :: ets:tid(), + peerT, %% undefined in new code, but remain for upgrade + shared_peers, %% reasons. Replaced by local/remote. + local_peers, %% + local :: {ets:tid(), ets:tid(), ets:tid()}, + remote :: {ets:tid(), ets:tid(), ets:tid()}, monitor = false :: false | pid(), %% process to die with options :: [{sequence, diameter:sequence()} %% sequence mask @@ -150,10 +141,12 @@ %% diameter_peer_fsm. -record(peer, {pid :: pid(), - apps :: [{0..16#FFFFFFFF, diameter:app_alias()}], %% {Id, Alias} + apps :: [{0..16#FFFFFFFF, diameter:app_alias()}] %% {Id, Alias} + | [diameter:app_alias()], %% remote caps :: #diameter_caps{}, - started = diameter_lib:now(), %% at process start - watchdog :: pid()}). %% key into watchdogT + started = diameter_lib:now(), %% at process start or sharing + watchdog :: pid() %% key into watchdogT + | undefined}). %% undefined if remote %% --------------------------------------------------------------------------- %% # start/1 @@ -181,7 +174,7 @@ stop(SvcName) -> end. stop(ok, Pid) -> - MRef = erlang:monitor(process, Pid), + MRef = monitor(process, Pid), receive {'DOWN', MRef, process, _, _} -> ok end; stop(No, _) -> No. @@ -495,6 +488,9 @@ transition({service, Pid}, S) -> transition({peer, TPid, Aliases, Caps}, S) -> remote_peer_up(TPid, Aliases, Caps, S), ok; +transition({peer, TPid}, S) -> + remote_peer_down(TPid, S), + ok; %% Remote peer process has died. transition({'DOWN', _, process, TPid, _}, S) -> @@ -514,7 +510,7 @@ transition(Req, S) -> %% # terminate/2 %% --------------------------------------------------------------------------- -terminate(Reason, #state{service_name = Name, peerT = PeerT} = S) -> +terminate(Reason, #state{service_name = Name, local = {PeerT, _, _}} = S) -> send_event(Name, stop), ets:delete(?STATE_TABLE, Name), @@ -536,23 +532,81 @@ terminate(Reason, #state{service_name = Name, peerT = PeerT} = S) -> %% # code_change/3 %% --------------------------------------------------------------------------- -code_change(FromVsn, - #state{service_name = SvcName, - service = #diameter_service{applications = Apps}} - = S, - Extra) -> - lists:foreach(fun(A) -> - code_change(FromVsn, SvcName, Extra, A) - end, - Apps), +code_change(_FromVsn, #state{} = S, _Extra) -> + {ok, S}; + +%% Don't support downgrade since we won't in appup. +code_change({down = T, _}, _, _Extra) -> + {error, T}; + +%% Upgrade local/shared peers dicts populated in old code. Don't +code_change(_FromVsn, S0, _Extra) -> + {state, Id, SvcName, Svc, WT, PeerT, SDict, LDict, Monitor, Opts} + = S0, + + init_peers(LT = setelement(1, {PT, _, _} = init_peers(), PeerT), + fun({_,A}) -> A end), + init_peers(init_peers(RT = init_peers(), SDict), + fun(A) -> A end), + + S = #state{id = Id, + service_name = SvcName, + service = Svc, + watchdogT = WT, + peerT = PT, %% empty + shared_peers = SDict, + local_peers = LDict, + local = LT, + remote = RT, + monitor = Monitor, + options = Opts}, + + %% Replacing the table entry and deleting the old shared tables + %% can make outgoing requests return {error, no_connection} until + %% everyone is running new code. Don't delete the tables to avoid + %% crashing request processes. + ets:delete_all_objects(SDict), + ets:delete_all_objects(LDict), + ets:insert(?STATE_TABLE, S), {ok, S}. -code_change(FromVsn, SvcName, Extra, #diameter_app{alias = Alias} = A) -> - {ok, S} = cb(A, code_change, [FromVsn, - mod_state(Alias), - Extra, - SvcName]), - mod_state(Alias, S). +%% init_peers/2 + +%% Populate app and identity bags from a new-style #peer{} sets. +init_peers({PeerT, _, _} = T, F) + when is_function(F) -> + ets:foldl(fun(#peer{pid = P, apps = As, caps = C}, N) -> + insert_peer(P, lists:map(F, As), C, T), + N+1 + end, + 0, + PeerT); + +%% Populate #peer{} table given a shared peers dict. +init_peers({PeerT, _, _}, SDict) + when is_integer(SDict) -> + dict:fold(fun(P, As, N) -> + ets:update_element(PeerT, P, {#peer.apps, As}), + N+1 + end, + 0, + diameter_dict:fold(fun(A, Ps, D) -> + init_peers(A, Ps, PeerT, D) + end, + dict:new(), + SDict)). + +%% init_peers/4 + +init_peers(App, TCs, PeerT, Dict) -> + lists:foldl(fun({P,C}, D) -> + ets:insert(PeerT, #peer{pid = P, + apps = [], + caps = C}), + dict:append(P, App, D) + end, + Dict, + TCs). %% =========================================================================== %% =========================================================================== @@ -560,9 +614,6 @@ code_change(FromVsn, SvcName, Extra, #diameter_app{alias = Alias} = A) -> unexpected(F, A, #state{service_name = Name}) -> ?UNEXPECTED(F, A ++ [Name]). -cb(#diameter_app{module = [_|_] = M}, F, A) -> - eval(M, F, A). - eval([M|X], F, A) -> apply(M, F, A ++ X). @@ -582,10 +633,6 @@ choose(false, _, X) -> X. ets_new(Tbl) -> ets:new(Tbl, [{keypos, 2}]). -insert(Tbl, Rec) -> - ets:insert(Tbl, Rec), - Rec. - %% Using the process dictionary for the callback state was initially %% just a way to make what was horrendous trace (big state record and %% much else everywhere) somewhat more readable. There's not as much @@ -686,6 +733,8 @@ cfg_acc({SvcName, #diameter_service{applications = Apps} = Rec, Opts}, lists:foreach(fun init_mod/1, Apps), S = #state{service_name = SvcName, service = Rec#diameter_service{pid = self()}, + local = init_peers(), + remote = init_peers(), monitor = mref(get_value(monitor, Opts)), options = service_options(Opts)}, {S, Acc}; @@ -695,6 +744,13 @@ cfg_acc({_Ref, Type, _Opts} = T, {S, Acc}) Type == listen -> {S, [T | Acc]}. +init_peers() -> + {ets_new(caps), %% #peer{} + ets:new(apps, [bag]), %% {Alias, TPid} + ets:new(idents, [bag])}. %% {{host, OH} | {realm, OR} | {OR, OH}, + %% Alias, + %% TPid} + service_options(Opts) -> [{sequence, proplists:get_value(sequence, Opts, ?NOMASK)}, {share_peers, get_value(share_peers, Opts)}, @@ -711,7 +767,7 @@ service_options(Opts) -> mref(false = No) -> No; mref(P) -> - erlang:monitor(process, P). + monitor(process, P). init_shared(#state{options = [_, _, {_,T} | _], service_name = Svc}) -> @@ -810,7 +866,7 @@ start(Ref, Type, Opts, State) -> %% start/5 start(Ref, Type, Opts, N, #state{watchdogT = WatchdogT, - peerT = PeerT, + local = {PeerT, _, _}, options = SvcOpts, service_name = SvcName, service = Svc0}) @@ -841,7 +897,7 @@ binary_caps(#diameter_service{capabilities = Caps} = Svc, false) -> wd(Type, Ref, T, WatchdogT, Rec) -> Pid = start_watchdog(Type, Ref, T), - insert(WatchdogT, Rec#watchdog{pid = Pid}), + ets:insert(WatchdogT, Rec#watchdog{pid = Pid}), Pid. %% Note that the service record passed into the watchdog is the merged @@ -898,8 +954,8 @@ accepted(Pid, _TPid, #state{watchdogT = WatchdogT} = S) -> #watchdog{ref = Ref, type = accept = T, peer = false, options = Opts} = Wd = fetch(WatchdogT, Pid), - insert(WatchdogT, Wd#watchdog{peer = true}),%% mark replacement as started - start(Ref, T, Opts, S). %% start new watchdog + ets:insert(WatchdogT, Wd#watchdog{peer = true}),%% mark replacement started + start(Ref, T, Opts, S). %% start new watchdog fetch(Tid, Key) -> [T] = ets:lookup(Tid, Key), @@ -925,13 +981,14 @@ watchdog(TPid, [], ?WD_SUSPECT, ?WD_OKAY, Wd, State) -> #watchdog{peer = TPid} = Wd, %% assert connection_up(Wd, State); -%% Watchdog has an unresponsive connection. +%% Watchdog has an unresponsive connection. Note that the peer table +%% entry isn't removed until DOWN. watchdog(TPid, [], ?WD_OKAY, ?WD_SUSPECT = To, Wd, State) -> #watchdog{peer = TPid} = Wd, %% assert watchdog_down(Wd, To, State); %% Watchdog has lost its connection. -watchdog(TPid, [], _, ?WD_DOWN = To, Wd, #state{peerT = PeerT} = S) -> +watchdog(TPid, [], _, ?WD_DOWN = To, Wd, #state{local = {PeerT, _, _}} = S) -> close(Wd), watchdog_down(Wd, To, S), ets:delete(PeerT, TPid); @@ -940,7 +997,7 @@ watchdog(_, [], _, _, _, _) -> ok. watchdog_down(Wd, To, #state{watchdogT = WatchdogT} = S) -> - insert(WatchdogT, Wd#watchdog{state = To}), + ets:insert(WatchdogT, Wd#watchdog{state = To}), connection_down(Wd, To, S). %% --------------------------------------------------------------------------- @@ -952,14 +1009,14 @@ watchdog_down(Wd, To, #state{watchdogT = WatchdogT} = S) -> connection_up({TPid, {Caps, SupportedApps, Pkt}}, #watchdog{pid = Pid} = Wd, - #state{peerT = PeerT} + #state{local = {PeerT, _, _}} = S) -> - Pr = #peer{pid = TPid, - apps = SupportedApps, - caps = Caps, - watchdog = Pid}, - insert(PeerT, Pr), - connection_up([Pkt], Wd#watchdog{peer = TPid}, Pr, S). + Rec = #peer{pid = TPid, + apps = SupportedApps, + caps = Caps, + watchdog = Pid}, + ets:insert(PeerT, Rec), + connection_up([Pkt], Wd#watchdog{peer = TPid}, Rec, S). %% --------------------------------------------------------------------------- %% # reopen/3 @@ -969,22 +1026,23 @@ reopen({TPid, {Caps, SupportedApps, _Pkt}}, #watchdog{pid = Pid} = Wd, #state{watchdogT = WatchdogT, - peerT = PeerT}) -> - insert(PeerT, #peer{pid = TPid, - apps = SupportedApps, - caps = Caps, - watchdog = Pid}), - insert(WatchdogT, Wd#watchdog{state = ?WD_REOPEN, - peer = TPid}). + local = {PeerT, _, _}}) -> + ets:insert(PeerT, #peer{pid = TPid, + apps = SupportedApps, + caps = Caps, + watchdog = Pid}), + ets:insert(WatchdogT, Wd#watchdog{state = ?WD_REOPEN, + peer = TPid}). %% --------------------------------------------------------------------------- %% # connection_up/2 %% --------------------------------------------------------------------------- -%% Watchdog has recovered as suspect connection. Note that there has +%% Watchdog has recovered a suspect connection. Note that there has %% been no new capabilties exchange in this case. -connection_up(#watchdog{peer = TPid} = Wd, #state{peerT = PeerT} = S) -> +connection_up(#watchdog{peer = TPid} = Wd, #state{local = {PeerT, _, _}} + = S) -> connection_up([], Wd, fetch(PeerT, TPid), S). %% connection_up/4 @@ -995,23 +1053,23 @@ connection_up(Extra, #peer{apps = SApps, caps = Caps} = Pr, #state{watchdogT = WatchdogT, - local_peers = LDict, + local = LT, service_name = SvcName, service = #diameter_service{applications = Apps}} = S) -> - insert(WatchdogT, Wd#watchdog{state = ?WD_OKAY}), + ets:insert(WatchdogT, Wd#watchdog{state = ?WD_OKAY}), diameter_traffic:peer_up(TPid), - insert_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict), + local_peer_up(SApps, {TPid, Caps}, {SvcName, Apps}, LT), report_status(up, Wd, Pr, S, Extra). -insert_local_peer(SApps, T, LDict) -> - lists:foldl(fun(A,D) -> ilp(A, T, D) end, LDict, SApps). +local_peer_up(SApps, {TPid, Caps} = TC, SA, LT) -> + insert_peer(TPid, [A || {_,A} <- SApps], Caps, LT), + lists:foreach(fun(A) -> peer_up(A, TC, SA) end, SApps). -ilp({Id, Alias}, {TC, SA}, LDict) -> - init_conn(Id, Alias, TC, SA), - ?Dict:append(Alias, TC, LDict). +peer_up({Id, Alias}, TC, SA) -> + peer_up(Id, Alias, TC, SA). -init_conn(Id, Alias, {TPid, _} = TC, {SvcName, Apps}) -> +peer_up(Id, Alias, {TPid, _} = TC, {SvcName, Apps}) -> #diameter_app{id = Id} %% assert = App = find_app(Alias, Apps), @@ -1109,17 +1167,17 @@ connection_down(#watchdog{state = ?WD_OKAY, = Pr, #state{service_name = SvcName, service = #diameter_service{applications = Apps}, - local_peers = LDict} + local = LT} = S) -> report_status(down, Wd, Pr, S, []), - remove_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict), + local_peer_down(SApps, {TPid, Caps}, {SvcName, Apps}, LT), diameter_traffic:peer_down(TPid); connection_down(#watchdog{state = ?WD_OKAY, peer = TPid} = Wd, To, - #state{peerT = PeerT} + #state{local = {PeerT, _, _}} = S) when is_atom(To) -> connection_down(Wd, #peer{} = fetch(PeerT, TPid), S); @@ -1127,15 +1185,14 @@ connection_down(#watchdog{state = ?WD_OKAY, connection_down(#watchdog{}, _, _) -> ok. -remove_local_peer(SApps, T, LDict) -> - lists:foldl(fun(A,D) -> rlp(A, T, D) end, LDict, SApps). +local_peer_down(SApps, {TPid, _Caps} = TC, SA, LT) -> + delete_peer(TPid, LT), + lists:foreach(fun(A) -> peer_down(A, TC, SA) end, SApps). -rlp({Id, Alias}, {TC, SA}, LDict) -> - L = ?Dict:fetch(Alias, LDict), - down_conn(Id, Alias, TC, SA), - ?Dict:store(Alias, lists:delete(TC, L), LDict). +peer_down({Id, Alias}, TC, SA) -> + peer_down(Id, Alias, TC, SA). -down_conn(Id, Alias, TC, {SvcName, Apps}) -> +peer_down(Id, Alias, TC, {SvcName, Apps}) -> #diameter_app{id = Id} %% assert = App = find_app(Alias, Apps), @@ -1160,7 +1217,7 @@ wd_down(#watchdog{peer = B}, _) ok; %% ... or maybe it has. -wd_down(#watchdog{peer = TPid} = Wd, #state{peerT = PeerT} = S) -> +wd_down(#watchdog{peer = TPid} = Wd, #state{local = {PeerT, _, _}} = S) -> connection_down(Wd, ?WD_DOWN, S), ets:delete(PeerT, TPid). @@ -1368,19 +1425,37 @@ share_peer(up, Caps, Apps, TPid, #state{options = [_, {_,T} | _], service_name = Svc}) -> notify(T, Svc, {peer, TPid, [A || {_,A} <- Apps], Caps}); -share_peer(_, _, _, _, _) -> - ok. +share_peer(down, _Caps, _Apps, TPid, #state{options = [_, {_,T} | _], + service_name = Svc}) -> + notify(T, Svc, {peer, TPid}). %% --------------------------------------------------------------------------- %% # share_peers/2 %% --------------------------------------------------------------------------- -share_peers(Pid, #state{options = [_, {_,T} | _], local_peers = PDict}) -> - is_remote(Pid, T) - andalso ?Dict:fold(fun(A,Ps,ok) -> sp(Pid, A, Ps), ok end, ok, PDict). - -sp(Pid, Alias, Peers) -> - lists:foreach(fun({P,C}) -> Pid ! {peer, P, [Alias], C} end, Peers). +share_peers(Pid, #state{options = [_, {_,SP} | _], + local = {PeerT, AppT, _}}) -> + is_remote(Pid, SP) + andalso ets:foldl(fun(T, N) -> N + sp(Pid, AppT, T) end, + 0, + PeerT). + +%% An entry in the peer table doesn't mean the watchdog state is OKAY, +%% an entry in the app table does. + +sp(Pid, AppT, #peer{pid = TPid, + apps = [{_, Alias} | _] = Apps, + caps = Caps}) -> + Spec = [{{'$1', TPid}, + [{'==', '$1', {const, Alias}}], + ['$_']}], + case ets:select(AppT, Spec, 1) of + '$end_of_table' -> + 0; + _ -> + Pid ! {peer, TPid, [A || {_,A} <- Apps], Caps}, + 1 + end. is_remote(Pid, T) -> Node = node(Pid), @@ -1390,32 +1465,49 @@ is_remote(Pid, T) -> %% # remote_peer_up/4 %% --------------------------------------------------------------------------- -remote_peer_up(Pid, Aliases, Caps, #state{options = [_, _, {_,T} | _]} = S) -> - is_remote(Pid, T) - andalso rpu(Pid, Aliases, Caps, S). +remote_peer_up(TPid, Aliases, Caps, #state{options = [_, _, {_,T} | _]} = S) -> + is_remote(TPid, T) andalso rpu(TPid, Aliases, Caps, S). -rpu(Pid, Aliases, Caps, #state{service = Svc, shared_peers = PDict}) -> +rpu(TPid, Aliases, Caps, #state{service = Svc, remote = RT}) -> #diameter_service{applications = Apps} = Svc, Key = #diameter_app.alias, F = fun(A) -> lists:keymember(A, Key, Apps) end, - rpu(Pid, lists:filter(F, Aliases), Caps, PDict); + rpu(TPid, lists:filter(F, Aliases), Caps, RT); rpu(_, [] = No, _, _) -> No; -rpu(Pid, Aliases, Caps, PDict) -> - erlang:monitor(process, Pid), - T = {Pid, Caps}, - lists:foreach(fun(A) -> ?Dict:append(A, T, PDict) end, Aliases). +rpu(TPid, Aliases, Caps, {PeerT, _, _} = RT) -> + monitor(process, TPid), + ets:insert(PeerT, #peer{pid = TPid, + apps = Aliases, + caps = Caps}), + insert_peer(TPid, Aliases, Caps, RT). + +%% insert_peer/4 + +insert_peer(TPid, Aliases, Caps, {_PeerT, AppT, IdentT}) -> + #diameter_caps{origin_host = {_, OH}, + origin_realm = {_, OR}} + = Caps, + ets:insert(AppT, [{A, TPid} || A <- Aliases]), + H = iolist_to_binary(OH), + R = iolist_to_binary(OR), + ets:insert(IdentT, [{T, A, TPid} || T <- [{host, H}, {realm, R}, {R, H}], + A <- Aliases]). %% --------------------------------------------------------------------------- %% # remote_peer_down/2 %% --------------------------------------------------------------------------- -remote_peer_down(Pid, #state{shared_peers = PDict}) -> - lists:foreach(fun(A) -> rpd(Pid, A, PDict) end, ?Dict:fetch_keys(PDict)). +remote_peer_down(TPid, #state{remote = {PeerT, _, _} = RT}) -> + ets:delete(PeerT, TPid), + delete_peer(TPid, RT). + +%% delete_peer/2 -rpd(Pid, Alias, PDict) -> - ?Dict:update(Alias, fun(Ps) -> lists:keydelete(Pid, 1, Ps) end, PDict). +delete_peer(TPid, {_PeerT, AppT, IdentT}) -> + ets:select_delete(AppT, [{{'_', TPid}, [], [true]}]), + ets:select_delete(IdentT, [{{'_', '_', TPid}, [], [true]}]). %% --------------------------------------------------------------------------- %% pick_peer/4 @@ -1425,12 +1517,12 @@ pick_peer(#diameter_app{alias = Alias} = App, RealmAndHost, Filter, - #state{local_peers = L, - shared_peers = S, + #state{local = LT, + remote = RT, service_name = SvcName, service = #diameter_service{pid = Pid}}) -> - pick_peer(peers(Alias, RealmAndHost, Filter, L), - peers(Alias, RealmAndHost, Filter, S), + pick_peer(peers(Alias, RealmAndHost, Filter, LT), + peers(Alias, RealmAndHost, Filter, RT), Pid, SvcName, App). @@ -1495,54 +1587,196 @@ pick_peer(Local, %% peers/4 -peers(Alias, RH, Filter, Peers) -> - case ?Dict:find(Alias, Peers) of - {ok, L} -> - filter(L, RH, Filter); - error -> +peers(Alias, RH, Filter, T) -> + filter(Alias, RH, Filter, T, true). + +%% filter/5 +%% +%% Try to limit the peers list by starting with a host/realm lookup. + +filter(Alias, RH, {neg, F}, T, B) -> + filter(Alias, RH, F, T, not B); + +filter(_, _, none, _, false) -> + []; + +filter(Alias, _, none, T, true) -> + all_peers(Alias, T); + +filter(Alias, [DR,DH] = RH, K, T, B) + when K == realm, DR == undefined; + K == host, DH == undefined -> + filter(Alias, RH, none, T, B); + +filter(Alias, [DR,_] = RH, realm = K, T, B) -> + filter(Alias, RH, {K, DR}, T, B); + +filter(Alias, [_,DH] = RH, host = K, T, B) -> + filter(Alias, RH, {K, DH}, T, B); + +filter(Alias, _, {K, D}, {PeerT, _AppT, IdentT}, true) + when K == host; + K == realm -> + try iolist_to_binary(D) of + B -> + caps(PeerT, ets:select(IdentT, [{{{K, B}, '$1', '$2'}, + [{'==', '$1', {const, Alias}}], + ['$2']}])) + catch + error:_ -> [] - end. + end; -%% filter/3 +filter(Alias, RH, {all, Filters}, T, B) + when is_list(Filters) -> + fltr_all(Alias, RH, Filters, T, B); + +filter(Alias, RH, {first, Filters}, T, B) + when is_list(Filters) -> + fltr_first(Alias, RH, Filters, T, B); + +filter(Alias, RH, Filter, T, B) -> + {Ts, Fs} = filter(all_peers(Alias, T), RH, Filter), + choose(B, Ts, Fs). + +%% fltr_all/5 + +fltr_all(Alias, RH, [{K, any} | Filters], T, B) + when K == host; + K == realm -> + fltr_all(Alias, RH, Filters, T, B); + +fltr_all(Alias, RH, [{host, _} = H, {realm, _} = R | Filters], T, B) -> + fltr_all(Alias, RH, [R, H | Filters], T, B); + +fltr_all(Alias, RH, [{realm, _} = R, {host, any} | Filters], T, B) -> + fltr_all(Alias, RH, [R | Filters], T, B); + +fltr_all(Alias, RH, [{realm, OR}, {host, OH} | Filters], T, true) -> + {PeerT, _AppT, IdentT} = T, + try {iolist_to_binary(OR), iolist_to_binary(OH)} of + BT -> + Peers = caps(PeerT, + ets:select(IdentT, [{{BT, '$1', '$2'}, + [{'==', '$1', {const, Alias}}], + ['$2']}])), + {Ts, _} = filter(Peers, RH, {all, Filters}), + Ts + catch + error:_ -> + [] + end; + +fltr_all(Alias, [undefined,_] = RH, [realm | Filters], T, B) -> + fltr_all(Alias, RH, Filters, T, B); + +fltr_all(Alias, [DR,_] = RH, [realm | Filters], T, B) -> + fltr_all(Alias, RH, [{realm, DR} | Filters], T, B); + +fltr_all(Alias, [_,undefined] = RH, [host | Filters], T, B) -> + fltr_all(Alias, RH, Filters, T, B); + +fltr_all(Alias, [_,DH] = RH, [host | Filters], T, B) -> + fltr_all(Alias, RH, [{host, DH} | Filters], T, B); + +fltr_all(Alias, RH, [{K, _} = KT, KA | Filters], T, B) + when K == host, KA == realm; + K == realm, KA == host -> + fltr_all(Alias, RH, [KA, KT | Filters], T, B); + +fltr_all(Alias, RH, [F | Filters], T, B) -> + {Ts, Fs} = filter(filter(Alias, RH, F, T, B), RH, {all, Filters}), + choose(B, Ts, Fs); + +fltr_all(Alias, RH, [], T, B) -> + filter(Alias, RH, none, T, B). + +%% fltr_first/5 %% -%% Return peers in match order. +%% Like any, but stop at the first filter with any matches. + +fltr_first(Alias, RH, [F | Filters], T, B) -> + case filter(Alias, RH, F, T, B) of + [] -> + fltr_first(Alias, RH, Filters, T, B); + [_|_] = Ts -> + Ts + end; -filter(Peers, RH, Filter) -> - {Ts, _} = fltr(Peers, RH, Filter), - Ts. +fltr_first(Alias, RH, [], T, B) -> + filter(Alias, RH, none, T, not B). -%% fltr/4 +%% all_peers/2 + +all_peers(Alias, {PeerT, AppT, _}) -> + ets:select(PeerT, [{#peer{pid = P, caps = '$1', _ = '_'}, + [], + [{{P, '$1'}}]} + || {_,P} <- ets:lookup(AppT, Alias)]). -fltr(Peers, _, none) -> +%% caps/2 + +caps(PeerT, Pids) -> + ets:select(PeerT, [{#peer{pid = P, caps = '$1', _ = '_'}, + [], + [{{P, '$1'}}]} + || P <- Pids]). + +%% filter/3 +%% +%% Return peers in match order. + +filter(Peers, _, none) -> {Peers, []}; -fltr(Peers, RH, {neg, F}) -> - {Ts, Fs} = fltr(Peers, RH, F), +filter(Peers, RH, {neg, F}) -> + {Ts, Fs} = filter(Peers, RH, F), {Fs, Ts}; -fltr(Peers, RH, {all, L}) +filter(Peers, RH, {all, L}) when is_list(L) -> lists:foldl(fun(F,A) -> fltr_all(F, A, RH) end, {Peers, []}, L); -fltr(Peers, RH, {any, L}) +filter(Peers, RH, {any, L}) when is_list(L) -> lists:foldl(fun(F,A) -> fltr_any(F, A, RH) end, {[], Peers}, L); -fltr(Peers, RH, F) -> +filter(Peers, RH, {first, L}) + when is_list(L) -> + fltr_first(Peers, RH, L); + +filter(Peers, RH, F) -> lists:partition(fun({_,C}) -> caps_filter(C, RH, F) end, Peers). +%% fltr_all/3 + fltr_all(F, {Ts0, Fs0}, RH) -> - {Ts1, Fs1} = fltr(Ts0, RH, F), + {Ts1, Fs1} = filter(Ts0, RH, F), {Ts1, Fs0 ++ Fs1}. +%% fltr_any/3 + fltr_any(F, {Ts0, Fs0}, RH) -> - {Ts1, Fs1} = fltr(Fs0, RH, F), + {Ts1, Fs1} = filter(Fs0, RH, F), {Ts0 ++ Ts1, Fs1}. +%% fltr_first/3 + +fltr_first(Peers, _, []) -> + {[], Peers}; + +fltr_first(Peers, RH, [F | Filters]) -> + case filter(Peers, RH, F) of + {[], _} -> + fltr_first(Peers, RH, Filters); + {_, _} = T -> + T + end. + %% caps_filter/3 caps_filter(#diameter_caps{origin_host = {_,OH}}, [_,DH], host) -> @@ -1586,8 +1820,8 @@ eq(Any, Id, PeerId) -> transports(#state{watchdogT = WatchdogT}) -> ets:select(WatchdogT, [{#watchdog{peer = '$1', _ = '_'}, - [{'is_pid', '$1'}], - ['$1']}]). + [{'is_pid', '$1'}], + ['$1']}]). %% --------------------------------------------------------------------------- %% # service_info/2 @@ -1640,7 +1874,7 @@ tagged_info(Item, S) undefined end; -tagged_info(TPid, #state{watchdogT = WatchdogT, peerT = PeerT}) +tagged_info(TPid, #state{watchdogT = WatchdogT, local = {PeerT, _, _}}) when is_pid(TPid) -> try [#peer{watchdog = Pid}] = ets:lookup(PeerT, TPid), @@ -1790,7 +2024,7 @@ keys(connect = T, Opts) -> keys(_, _) -> [{listen, accept}]. -peer_dict(#state{watchdogT = WatchdogT, peerT = PeerT}, Dict0) -> +peer_dict(#state{watchdogT = WatchdogT, local = {PeerT, _, _}}, Dict0) -> try ets:tab2list(WatchdogT) of L -> lists:foldl(fun(T,A) -> peer_acc(PeerT, A, T) end, Dict0, L) catch diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl index 07f39c562f..516353219a 100644 --- a/lib/diameter/src/base/diameter_traffic.erl +++ b/lib/diameter/src/base/diameter_traffic.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2013-2015. All Rights Reserved. +%% Copyright Ericsson AB 2013-2016. 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. @@ -41,7 +41,6 @@ -export([make_recvdata/1, peer_up/1, peer_down/1, - failover/1, pending/1]). %% towards ?MODULE @@ -1814,7 +1813,7 @@ store_request(T, TPid) -> ets:member(?REQUEST_TABLE, TPid) orelse begin {_Seqs, _Req, TRef} = T, - (self() ! {failover, TRef}) %% failover/1 may have missed + self() ! {failover, TRef} %% failover/1 may have missed end. %% lookup_request/2 @@ -1864,7 +1863,7 @@ failover(TPid) %% notifications are sent here: store_request/2 sends the notification %% in that case. -%% Failover as a consequence of request_peer_down/1: inform the +%% Failover as a consequence of peer_down/1: inform the %% request process. failover({_, Req, TRef}) -> #request{handler = Pid, diff --git a/lib/eldap/doc/src/eldap.xml b/lib/eldap/doc/src/eldap.xml index 8f4479a730..43873e44e2 100644 --- a/lib/eldap/doc/src/eldap.xml +++ b/lib/eldap/doc/src/eldap.xml @@ -4,7 +4,7 @@ <erlref> <header> <copyright> - <year>2012</year><year>2013</year> + <year>2012</year><year>2016</year> <holder>Ericsson AB. All Rights Reserved.</holder> </copyright> <legalnotice> @@ -29,7 +29,7 @@ <rev>B</rev> </header> <module>eldap</module> - <modulesummary>Eldap Functions</modulesummary> + <modulesummary>LDAP Client</modulesummary> <description> <p>This module provides a client api to the Lightweight Directory Access Protocol (LDAP). </p> @@ -40,20 +40,67 @@ </list> <p>The above publications can be found at <url href="http://www.ietf.org">IETF</url>. </p> - <p><em>Types</em></p> - <pre> -handle() Connection handle -attribute() {Type = string(), Values=[string()]} -modify_op() See mod_add/2, mod_delete/2, mod_replace/2 -scope() See baseObject/0, singleLevel/0, wholeSubtree/0 -dereference() See neverDerefAliases/0, derefInSearching/0, derefFindingBaseObj/0, derefAlways/0 -filter() See present/1, substrings/2, - equalityMatch/2, greaterOrEqual/2, lessOrEqual/2, - approxMatch/2, extensibleMatch/2, - 'and'/1, 'or'/1, 'not'/1. - </pre> - <p></p> </description> + + <section> + <title>DATA TYPES</title> + <p>Type definitions that are used more than once in this module: + </p> + <taglist> + <tag><c>handle()</c></tag> + <item><p>Connection handle</p></item> + + <tag><c>attribute() =</c></tag> + <item><p><c>{Type = string(), Values=[string()]}</c></p></item> + + <tag><c>modify_op()</c></tag> + <item><p>See + <seealso marker="#mod_add/2">mod_add/2</seealso>, + <seealso marker="#mod_delete/2">mod_delete/2</seealso>, + <seealso marker="#mod_replace/2">mod_replace/2</seealso> + </p></item> + + <tag><c>scope()</c></tag> + <item><p>See + <seealso marker="#baseObject/0">baseObject/0</seealso>, + <seealso marker="#singleLevel/0">singleLevel/0</seealso>, + <seealso marker="#wholeSubtree/0">wholeSubtree/0</seealso> + </p></item> + + <tag><c>dereference()</c></tag> + <item><p>See + <seealso marker="#neverDerefAliases/0">neverDerefAliases/0</seealso>, + <seealso marker="#derefInSearching/0">derefInSearching/0</seealso>, + <seealso marker="#derefFindingBaseObj/0">derefFindingBaseObj/0</seealso>, + <seealso marker="#derefAlways/0">derefAlways/0</seealso> + </p></item> + + <tag><c>filter()</c></tag> + <item><p>See + <seealso marker="#present/1">present/1</seealso>, + <seealso marker="#substrings/2">substrings/2</seealso>, + <seealso marker="#equalityMatch/2">equalityMatch/2</seealso>, + <seealso marker="#greaterOrEqual/2">greaterOrEqual/2</seealso>, + <seealso marker="#lessOrEqual/2">lessOrEqual/2</seealso>, + <seealso marker="#approxMatch/2">approxMatch/2</seealso>, + <seealso marker="#extensibleMatch/2">extensibleMatch/2</seealso>, + <seealso marker="#'and'/1">'and'/1</seealso>, + <seealso marker="#'or'/1">'or'/1</seealso>, + <seealso marker="#'not'/1">'not'/1</seealso> + </p></item> + + <tag><c>return_value() = </c></tag> + <item><p><c>ok | {ok, {referral,referrals()}} | {error,Error}</c> + </p></item> + + <tag><c>referrals() =</c></tag> + <item><p><c>[Address = string()]</c> The contents of <c>Address</c> is server dependent. + </p></item> + + </taglist> + </section> + + <funcs> <func> <name>open([Host]) -> {ok, Handle} | {error, Reason}</name> @@ -88,18 +135,19 @@ filter() See present/1, substrings/2, <v>Handle = handle()</v> </type> <desc> - <p>Shutdown the connection.</p> + <p>Shutdown the connection after sending an unbindRequest to the server. If the connection is tls the connection + will be closed with <c>ssl:close/1</c>, otherwise with <c>gen_tcp:close/1</c>.</p> </desc> </func> <func> - <name>start_tls(Handle, Options) -> ok | {error,Error}</name> + <name>start_tls(Handle, Options) -> return_value()</name> <fsummary>Upgrade a connection to TLS.</fsummary> <desc> <p>Same as start_tls(Handle, Options, infinity)</p> </desc> </func> <func> - <name>start_tls(Handle, Options, Timeout) -> ok | {error,Error}</name> + <name>start_tls(Handle, Options, Timeout) -> return_value()</name> <fsummary>Upgrade a connection to TLS.</fsummary> <type> <v>Handle = handle()</v> @@ -128,7 +176,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>simple_bind(Handle, Dn, Password) -> ok | {error, Reason}</name> + <name>simple_bind(Handle, Dn, Password) -> return_value()</name> <fsummary>Authenticate the connection.</fsummary> <type> <v>Handle = handle()</v> @@ -140,7 +188,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>add(Handle, Dn, [Attribute]) -> ok | {error, Reason}</name> + <name>add(Handle, Dn, [Attribute]) -> return_value()</name> <fsummary>Add an entry.</fsummary> <type> <v>Handle = handle()</v> @@ -161,7 +209,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>delete(Handle, Dn) -> ok | {error, Reason}</name> + <name>delete(Handle, Dn) -> return_value()</name> <fsummary>Delete an entry.</fsummary> <type> <v>Dn = string()</v> @@ -203,7 +251,7 @@ filter() See present/1, substrings/2, </func> <func> - <name>modify(Handle, Dn, [ModifyOp]) -> ok | {error, Reason}</name> + <name>modify(Handle, Dn, [ModifyOp]) -> return_value()</name> <fsummary>Modify an entry.</fsummary> <type> <v>Dn = string()</v> @@ -219,7 +267,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>modify_password(Handle, Dn, NewPasswd) -> ok | {ok, GenPasswd} | {error, Reason}</name> + <name>modify_password(Handle, Dn, NewPasswd) -> return_value() | {ok, GenPasswd}</name> <fsummary>Modify the password of a user.</fsummary> <type> <v>Dn = string()</v> @@ -230,7 +278,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>modify_password(Handle, Dn, NewPasswd, OldPasswd) -> ok | {ok, GenPasswd} | {error, Reason}</name> + <name>modify_password(Handle, Dn, NewPasswd, OldPasswd) -> return_value() | {ok, GenPasswd}</name> <fsummary>Modify the password of a user.</fsummary> <type> <v>Dn = string()</v> @@ -259,7 +307,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> ok | {error, Reason}</name> + <name>modify_dn(Handle, Dn, NewRDN, DeleteOldRDN, NewSupDN) -> return_value()</name> <fsummary>Modify the DN of an entry.</fsummary> <type> <v>Dn = string()</v> @@ -279,7 +327,7 @@ filter() See present/1, substrings/2, </desc> </func> <func> - <name>search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {error, Reason}</name> + <name>search(Handle, SearchOptions) -> {ok, #eldap_search_result{}} | {ok, {referral,referrals()}} | {error, Reason}</name> <fsummary>Search the Directory</fsummary> <type> <v>SearchOptions = #eldap_search{} | [SearchOption]</v> diff --git a/lib/eldap/src/eldap.erl b/lib/eldap/src/eldap.erl index ae47c815c9..0c03021bd0 100644 --- a/lib/eldap/src/eldap.erl +++ b/lib/eldap/src/eldap.erl @@ -10,16 +10,23 @@ %%% See MIT-LICENSE at the top dir for licensing information. %%% -------------------------------------------------------------------- -vc('$Id$ '). --export([open/1,open/2,simple_bind/3,controlling_process/2, - start_tls/2, start_tls/3, - modify_password/3, modify_password/4, +-export([open/1, open/2, + simple_bind/3, simple_bind/4, + controlling_process/2, + start_tls/2, start_tls/3, start_tls/4, + modify_password/3, modify_password/4, modify_password/5, getopts/2, baseObject/0,singleLevel/0,wholeSubtree/0,close/1, equalityMatch/2,greaterOrEqual/2,lessOrEqual/2, extensibleMatch/2, - approxMatch/2,search/2,substrings/2,present/1, - 'and'/1,'or'/1,'not'/1,modify/3, mod_add/2, mod_delete/2, - mod_replace/2, add/3, delete/2, modify_dn/5,parse_dn/1, + search/2, search/3, + approxMatch/2,substrings/2,present/1, + 'and'/1,'or'/1,'not'/1,mod_add/2, mod_delete/2, + mod_replace/2, + modify/3, modify/4, + add/3, add/4, + delete/2, delete/3, + modify_dn/5,parse_dn/1, parse_ldap_url/1]). -export([neverDerefAliases/0, derefInSearching/0, @@ -91,7 +98,10 @@ start_tls(Handle, TlsOptions) -> start_tls(Handle, TlsOptions, infinity). start_tls(Handle, TlsOptions, Timeout) -> - send(Handle, {start_tls,TlsOptions,Timeout}), + start_tls(Handle, TlsOptions, Timeout, asn1_NOVALUE). + +start_tls(Handle, TlsOptions, Timeout, Controls) -> + send(Handle, {start_tls,TlsOptions,Timeout,Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -108,7 +118,11 @@ modify_password(Handle, Dn, NewPasswd) -> modify_password(Handle, Dn, NewPasswd, OldPasswd) when is_pid(Handle), is_list(Dn), is_list(NewPasswd), is_list(OldPasswd) -> - send(Handle, {passwd_modify,optional(Dn),optional(NewPasswd),optional(OldPasswd)}), + modify_password(Handle, Dn, NewPasswd, OldPasswd, asn1_NOVALUE). + +modify_password(Handle, Dn, NewPasswd, OldPasswd, Controls) + when is_pid(Handle), is_list(Dn), is_list(NewPasswd), is_list(OldPasswd) -> + send(Handle, {passwd_modify,optional(Dn),optional(NewPasswd),optional(OldPasswd),Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -147,7 +161,10 @@ controlling_process(Handle, Pid) when is_pid(Handle), is_pid(Pid) -> %%% Returns: ok | {error, Error} %%% -------------------------------------------------------------------- simple_bind(Handle, Dn, Passwd) when is_pid(Handle) -> - send(Handle, {simple_bind, Dn, Passwd}), + simple_bind(Handle, Dn, Passwd, asn1_NOVALUE). + +simple_bind(Handle, Dn, Passwd, Controls) when is_pid(Handle) -> + send(Handle, {simple_bind, Dn, Passwd, Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -164,7 +181,10 @@ simple_bind(Handle, Dn, Passwd) when is_pid(Handle) -> %%% ) %%% -------------------------------------------------------------------- add(Handle, Entry, Attributes) when is_pid(Handle),is_list(Entry),is_list(Attributes) -> - send(Handle, {add, Entry, add_attrs(Attributes)}), + add(Handle, Entry, Attributes, asn1_NOVALUE). + +add(Handle, Entry, Attributes, Controls) when is_pid(Handle),is_list(Entry),is_list(Attributes) -> + send(Handle, {add, Entry, add_attrs(Attributes), Controls}), recv(Handle). %%% Do sanity check ! @@ -188,7 +208,10 @@ add_attrs(Attrs) -> %%% ) %%% -------------------------------------------------------------------- delete(Handle, Entry) when is_pid(Handle), is_list(Entry) -> - send(Handle, {delete, Entry}), + delete(Handle, Entry, asn1_NOVALUE). + +delete(Handle, Entry, Controls) when is_pid(Handle), is_list(Entry) -> + send(Handle, {delete, Entry, Controls}), recv(Handle). %%% -------------------------------------------------------------------- @@ -203,7 +226,10 @@ delete(Handle, Entry) when is_pid(Handle), is_list(Entry) -> %%% ) %%% -------------------------------------------------------------------- modify(Handle, Object, Mods) when is_pid(Handle), is_list(Object), is_list(Mods) -> - send(Handle, {modify, Object, Mods}), + modify(Handle, Object, Mods, asn1_NOVALUE). + +modify(Handle, Object, Mods, Controls) when is_pid(Handle), is_list(Object), is_list(Mods) -> + send(Handle, {modify, Object, Mods, Controls}), recv(Handle). %%% @@ -236,8 +262,12 @@ m(Operation, Type, Values) -> %%% -------------------------------------------------------------------- modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup) when is_pid(Handle),is_list(Entry),is_list(NewRDN),is_atom(DelOldRDN),is_list(NewSup) -> + modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup, asn1_NOVALUE). + +modify_dn(Handle, Entry, NewRDN, DelOldRDN, NewSup, Controls) + when is_pid(Handle),is_list(Entry),is_list(NewRDN),is_atom(DelOldRDN),is_list(NewSup) -> send(Handle, {modify_dn, Entry, NewRDN, - bool_p(DelOldRDN), optional(NewSup)}), + bool_p(DelOldRDN), optional(NewSup), Controls}), recv(Handle). %%% Sanity checks ! @@ -272,16 +302,19 @@ optional(Value) -> Value. %%% []}} %%% %%% -------------------------------------------------------------------- -search(Handle, A) when is_pid(Handle), is_record(A, eldap_search) -> - call_search(Handle, A); -search(Handle, L) when is_pid(Handle), is_list(L) -> +search(Handle, X) when is_pid(Handle), is_record(X,eldap_search) ; is_list(X) -> + search(Handle, X, asn1_NOVALUE). + +search(Handle, A, Controls) when is_pid(Handle), is_record(A, eldap_search) -> + call_search(Handle, A, Controls); +search(Handle, L, Controls) when is_pid(Handle), is_list(L) -> case catch parse_search_args(L) of {error, Emsg} -> {error, Emsg}; - A when is_record(A, eldap_search) -> call_search(Handle, A) + A when is_record(A, eldap_search) -> call_search(Handle, A, Controls) end. -call_search(Handle, A) -> - send(Handle, {search, A}), +call_search(Handle, A, Controls) -> + send(Handle, {search, A, Controls}), recv(Handle). parse_search_args(Args) -> @@ -484,33 +517,33 @@ do_connect(Host, Data, Opts) when Data#eldap.ldaps == true -> loop(Cpid, Data) -> receive - {From, {search, A}} -> - {Res,NewData} = do_search(Data, A), + {From, {search, A, Controls}} -> + {Res,NewData} = do_search(Data, A, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {modify, Obj, Mod}} -> - {Res,NewData} = do_modify(Data, Obj, Mod), + {From, {modify, Obj, Mod, Controls}} -> + {Res,NewData} = do_modify(Data, Obj, Mod, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {modify_dn, Obj, NewRDN, DelOldRDN, NewSup}} -> - {Res,NewData} = do_modify_dn(Data, Obj, NewRDN, DelOldRDN, NewSup), + {From, {modify_dn, Obj, NewRDN, DelOldRDN, NewSup, Controls}} -> + {Res,NewData} = do_modify_dn(Data, Obj, NewRDN, DelOldRDN, NewSup, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {add, Entry, Attrs}} -> - {Res,NewData} = do_add(Data, Entry, Attrs), + {From, {add, Entry, Attrs, Controls}} -> + {Res,NewData} = do_add(Data, Entry, Attrs, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {delete, Entry}} -> - {Res,NewData} = do_delete(Data, Entry), + {From, {delete, Entry, Controls}} -> + {Res,NewData} = do_delete(Data, Entry, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {simple_bind, Dn, Passwd}} -> - {Res,NewData} = do_simple_bind(Data, Dn, Passwd), + {From, {simple_bind, Dn, Passwd, Controls}} -> + {Res,NewData} = do_simple_bind(Data, Dn, Passwd, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); @@ -520,17 +553,18 @@ loop(Cpid, Data) -> ?PRINT("New Cpid is: ~p~n",[NewCpid]), ?MODULE:loop(NewCpid, Data); - {From, {start_tls,TlsOptions,Timeout}} -> - {Res,NewData} = do_start_tls(Data, TlsOptions, Timeout), + {From, {start_tls,TlsOptions,Timeout,Controls}} -> + {Res,NewData} = do_start_tls(Data, TlsOptions, Timeout, Controls), send(From,Res), ?MODULE:loop(Cpid, NewData); - {From, {passwd_modify,Dn,NewPasswd,OldPasswd}} -> - {Res,NewData} = do_passwd_modify(Data, Dn, NewPasswd, OldPasswd), + {From, {passwd_modify,Dn,NewPasswd,OldPasswd,Controls}} -> + {Res,NewData} = do_passwd_modify(Data, Dn, NewPasswd, OldPasswd, Controls), send(From, Res), ?MODULE:loop(Cpid, NewData); {_From, close} -> + {no_reply,_NewData} = do_unbind(Data), unlink(Cpid), exit(closed); @@ -578,11 +612,10 @@ loop(Cpid, Data) -> %%% -------------------------------------------------------------------- %%% startTLS Request %%% -------------------------------------------------------------------- - -do_start_tls(Data=#eldap{using_tls=true}, _, _) -> +do_start_tls(Data=#eldap{using_tls=true}, _, _, _) -> {{error,tls_already_started}, Data}; -do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) -> - case catch exec_start_tls(Data) of +do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout, Controls) -> + case catch exec_start_tls(Data, Controls) of {ok,NewData} -> case ssl:connect(FD,TlsOptions,Timeout) of {ok, SslSocket} -> @@ -593,15 +626,16 @@ do_start_tls(Data=#eldap{fd=FD} , TlsOptions, Timeout) -> {error,Error} -> {{error,Error}, Data} end; - {error,Error} -> {{error,Error},Data}; - Else -> {{error,Else},Data} + {{ok,Val},NewData} -> {{ok,Val},NewData}; + {error,Error} -> {{error,Error},Data}; + Else -> {{error,Else},Data} end. -define(START_TLS_OID, "1.3.6.1.4.1.1466.20037"). -exec_start_tls(Data) -> +exec_start_tls(Data, Controls) -> Req = #'ExtendedRequest'{requestName = ?START_TLS_OID}, - Reply = request(Data#eldap.fd, Data, Data#eldap.id, {extendedReq, Req}), + Reply = request(Data#eldap.fd, Data, Data#eldap.id, {extendedReq, Req, Controls}), exec_extended_req_reply(Data, Reply). exec_extended_req_reply(Data, {ok,Msg}) when @@ -611,6 +645,8 @@ exec_extended_req_reply(Data, {ok,Msg}) when case Result#'ExtendedResponse'.resultCode of success -> {ok,Data}; + referral -> + {{ok, {referral,Result#'ExtendedResponse'.referral}}, Data}; Error -> {error, {response,Error}} end; @@ -626,30 +662,32 @@ exec_extended_req_reply(_, Error) -> %%% Authenticate ourselves to the directory using %%% simple authentication. -do_simple_bind(Data, anon, anon) -> %% For testing - do_the_simple_bind(Data, "", ""); -do_simple_bind(Data, Dn, _Passwd) when Dn=="",Data#eldap.anon_auth==false -> +do_simple_bind(Data, anon, anon, Controls) -> %% For testing + do_the_simple_bind(Data, "", "", Controls); +do_simple_bind(Data, Dn, _Passwd,_) when Dn=="",Data#eldap.anon_auth==false -> {{error,anonymous_auth},Data}; -do_simple_bind(Data, _Dn, Passwd) when Passwd=="",Data#eldap.anon_auth==false -> +do_simple_bind(Data, _Dn, Passwd,_) when Passwd=="",Data#eldap.anon_auth==false -> {{error,anonymous_auth},Data}; -do_simple_bind(Data, Dn, Passwd) -> - do_the_simple_bind(Data, Dn, Passwd). +do_simple_bind(Data, Dn, Passwd, Controls) -> + do_the_simple_bind(Data, Dn, Passwd, Controls). -do_the_simple_bind(Data, Dn, Passwd) -> +do_the_simple_bind(Data, Dn, Passwd, Controls) -> case catch exec_simple_bind(Data#eldap{binddn = Dn, passwd = Passwd, - id = bump_id(Data)}) of - {ok,NewData} -> {ok,NewData}; - {error,Emsg} -> {{error,Emsg},Data}; - Else -> {{error,Else},Data} + id = bump_id(Data)}, + Controls) of + {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; + {error,Emsg} -> {{error,Emsg},Data}; + Else -> {{error,Else},Data} end. -exec_simple_bind(Data) -> +exec_simple_bind(Data, Controls) -> Req = #'BindRequest'{version = Data#eldap.version, name = Data#eldap.binddn, authentication = {simple, Data#eldap.passwd}}, log2(Data, "bind request = ~p~n", [Req]), - Reply = request(Data#eldap.fd, Data, Data#eldap.id, {bindRequest, Req}), + Reply = request(Data#eldap.fd, Data, Data#eldap.id, {bindRequest, Req, Controls}), log2(Data, "bind reply = ~p~n", [Reply]), exec_simple_bind_reply(Data, Reply). @@ -659,6 +697,7 @@ exec_simple_bind_reply(Data, {ok,Msg}) when {bindResponse, Result} -> case Result#'BindResponse'.resultCode of success -> {ok,Data}; + referral -> {{ok, {referral,Result#'BindResponse'.referral}}, Data}; Error -> {error, Error} end; Other -> {error, Other} @@ -671,10 +710,11 @@ exec_simple_bind_reply(_, Error) -> %%% searchRequest %%% -------------------------------------------------------------------- -do_search(Data, A) -> - case catch do_search_0(Data, A) of +do_search(Data, A, Controls) -> + case catch do_search_0(Data, A, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; {ok,Res,Ref,NewData} -> {{ok,polish(Res, Ref)},NewData}; {{error,Reason},NewData} -> {{error,Reason},NewData}; Else -> {ldap_closed_p(Data, Else),Data} @@ -700,7 +740,7 @@ polish_result([H|T]) when is_record(H, 'SearchResultEntry') -> polish_result([]) -> []. -do_search_0(Data, A) -> +do_search_0(Data, A, Controls) -> Req = #'SearchRequest'{baseObject = A#eldap_search.base, scope = v_scope(A#eldap_search.scope), derefAliases = v_deref(A#eldap_search.deref), @@ -711,15 +751,15 @@ do_search_0(Data, A) -> attributes = v_attributes(A#eldap_search.attributes) }, Id = bump_id(Data), - collect_search_responses(Data#eldap{id=Id}, Req, Id). + collect_search_responses(Data#eldap{id=Id}, Req, Id, Controls). %%% The returned answers cames in one packet per entry %%% mixed with possible referals -collect_search_responses(Data, Req, ID) -> +collect_search_responses(Data, Req, ID, Controls) -> S = Data#eldap.fd, log2(Data, "search request = ~p~n", [Req]), - send_request(S, Data, ID, {searchRequest, Req}), + send_request(S, Data, ID, {searchRequest, Req, Controls}), Resp = recv_response(S, Data), log2(Data, "search reply = ~p~n", [Resp]), collect_search_responses(Data, S, ID, Resp, [], []). @@ -732,6 +772,8 @@ collect_search_responses(Data, S, ID, {ok,Msg}, Acc, Ref) success -> log2(Data, "search reply = searchResDone ~n", []), {ok,Acc,Ref,Data}; + referral -> + {{ok, {referral,R#'LDAPResult'.referral}}, Data}; Reason -> {{error,Reason},Data} end; @@ -756,21 +798,22 @@ collect_search_responses(_, _, _, Else, _, _) -> %%% addRequest %%% -------------------------------------------------------------------- -do_add(Data, Entry, Attrs) -> - case catch do_add_0(Data, Entry, Attrs) of +do_add(Data, Entry, Attrs, Controls) -> + case catch do_add_0(Data, Entry, Attrs, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_add_0(Data, Entry, Attrs) -> +do_add_0(Data, Entry, Attrs, Controls) -> Req = #'AddRequest'{entry = Entry, attributes = Attrs}, S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "add request = ~p~n", [Req]), - Resp = request(S, Data, Id, {addRequest, Req}), + Resp = request(S, Data, Id, {addRequest, Req, Controls}), log2(Data, "add reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, addResponse). @@ -779,19 +822,20 @@ do_add_0(Data, Entry, Attrs) -> %%% deleteRequest %%% -------------------------------------------------------------------- -do_delete(Data, Entry) -> - case catch do_delete_0(Data, Entry) of +do_delete(Data, Entry, Controls) -> + case catch do_delete_0(Data, Entry, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_delete_0(Data, Entry) -> +do_delete_0(Data, Entry, Controls) -> S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "del request = ~p~n", [Entry]), - Resp = request(S, Data, Id, {delRequest, Entry}), + Resp = request(S, Data, Id, {delRequest, Entry, Controls}), log2(Data, "del reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, delResponse). @@ -800,22 +844,23 @@ do_delete_0(Data, Entry) -> %%% modifyRequest %%% -------------------------------------------------------------------- -do_modify(Data, Obj, Mod) -> - case catch do_modify_0(Data, Obj, Mod) of +do_modify(Data, Obj, Mod, Controls) -> + case catch do_modify_0(Data, Obj, Mod, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_modify_0(Data, Obj, Mod) -> +do_modify_0(Data, Obj, Mod, Controls) -> v_modifications(Mod), Req = #'ModifyRequest'{object = Obj, changes = Mod}, S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "modify request = ~p~n", [Req]), - Resp = request(S, Data, Id, {modifyRequest, Req}), + Resp = request(S, Data, Id, {modifyRequest, Req, Controls}), log2(Data, "modify reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, modifyResponse). @@ -825,16 +870,17 @@ do_modify_0(Data, Obj, Mod) -> -define(PASSWD_MODIFY_OID, "1.3.6.1.4.1.4203.1.11.1"). -do_passwd_modify(Data, Dn, NewPasswd, OldPasswd) -> - case catch do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) of +do_passwd_modify(Data, Dn, NewPasswd, OldPasswd, Controls) -> + case catch do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; {ok,Passwd,NewData} -> {{ok, Passwd},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) -> +do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd, Controls) -> Req = #'PasswdModifyRequestValue'{userIdentity = Dn, oldPasswd = OldPasswd, newPasswd = NewPasswd}, @@ -844,7 +890,7 @@ do_passwd_modify_0(Data, Dn, NewPasswd, OldPasswd) -> requestValue = Bytes}, Id = bump_id(Data), log2(Data, "extended request = ~p~n", [ExtReq]), - Reply = request(Data#eldap.fd, Data, Id, {extendedReq, ExtReq}), + Reply = request(Data#eldap.fd, Data, Id, {extendedReq, ExtReq, Controls}), log2(Data, "modify password reply = ~p~n", [Reply]), exec_passwd_modify_reply(Data#eldap{id = Id}, Reply). @@ -865,6 +911,8 @@ exec_passwd_modify_reply(Data, {ok,Msg}) when throw(Error) end end; + referral -> + {{ok, {referral,Result#'ExtendedResponse'.referral}}, Data}; Error -> {error, {response,Error}} end; @@ -877,15 +925,16 @@ exec_passwd_modify_reply(_, Error) -> %%% modifyDNRequest %%% -------------------------------------------------------------------- -do_modify_dn(Data, Entry, NewRDN, DelOldRDN, NewSup) -> - case catch do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) of +do_modify_dn(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) -> + case catch do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) of {error,Emsg} -> {ldap_closed_p(Data, Emsg),Data}; {'EXIT',Error} -> {ldap_closed_p(Data, Error),Data}; {ok,NewData} -> {ok,NewData}; + {{ok,Val},NewData} -> {{ok,Val},NewData}; Else -> {ldap_closed_p(Data, Else),Data} end. -do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) -> +do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup, Controls) -> Req = #'ModifyDNRequest'{entry = Entry, newrdn = NewRDN, deleteoldrdn = DelOldRDN, @@ -893,22 +942,51 @@ do_modify_dn_0(Data, Entry, NewRDN, DelOldRDN, NewSup) -> S = Data#eldap.fd, Id = bump_id(Data), log2(Data, "modify DN request = ~p~n", [Req]), - Resp = request(S, Data, Id, {modDNRequest, Req}), + Resp = request(S, Data, Id, {modDNRequest, Req, Controls}), log2(Data, "modify DN reply = ~p~n", [Resp]), check_reply(Data#eldap{id = Id}, Resp, modDNResponse). +%%%-------------------------------------------------------------------- +%%% unbindRequest +%%%-------------------------------------------------------------------- +do_unbind(Data) -> + Req = "", + log2(Data, "unbind request = ~p (has no reply)~n", [Req]), + send_request(Data#eldap.fd, Data, Data#eldap.id, {unbindRequest, Req}), + case Data#eldap.using_tls of + true -> ssl:close(Data#eldap.fd); + false -> gen_tcp:close(Data#eldap.fd) + end, + {no_reply, Data#eldap{binddn = (#eldap{})#eldap.binddn, + passwd = (#eldap{})#eldap.passwd, + fd = (#eldap{})#eldap.fd, + using_tls = false + }}. + + %%% -------------------------------------------------------------------- %%% Send an LDAP request and receive the answer %%% -------------------------------------------------------------------- - request(S, Data, ID, Request) -> send_request(S, Data, ID, Request), recv_response(S, Data). -send_request(S, Data, ID, Request) -> - Message = #'LDAPMessage'{messageID = ID, - protocolOp = Request}, - {ok,Bytes} = 'ELDAPv3':encode('LDAPMessage', Message), +send_request(S, Data, Id, {T,P}) -> + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}}); +send_request(S, Data, Id, {T,P,asn1_NOVALUE}) -> + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}}); +send_request(S, Data, Id, {T,P,Controls0}) -> + Controls = [#'Control'{controlType=F1, + criticality=F2, + controlValue=F3} || {control,F1,F2,F3} <- Controls0], + send_the_LDAPMessage(S, Data, #'LDAPMessage'{messageID = Id, + protocolOp = {T,P}, + controls = Controls}). + +send_the_LDAPMessage(S, Data, LDAPMessage) -> + {ok,Bytes} = 'ELDAPv3':encode('LDAPMessage', LDAPMessage), case do_send(S, Data, Bytes) of {error,Reason} -> throw({gen_tcp_error,Reason}); Else -> Else @@ -942,6 +1020,7 @@ check_reply(Data, {ok,Msg}, Op) when {Op, Result} -> case Result#'LDAPResult'.resultCode of success -> {ok,Data}; + referral -> {{ok, {referral,Result#'LDAPResult'.referral}}, Data}; Error -> {error, Error} end; Other -> {error, Other} diff --git a/lib/eldap/test/eldap_basic_SUITE.erl b/lib/eldap/test/eldap_basic_SUITE.erl index 638a609346..8414ca6e46 100644 --- a/lib/eldap/test/eldap_basic_SUITE.erl +++ b/lib/eldap/test/eldap_basic_SUITE.erl @@ -30,6 +30,11 @@ -define(TIMEOUT, 120000). % 2 min + +%% Control to delete a referral object: +-define(manageDsaIT, {control,"2.16.840.1.113730.3.4.2",false,asn1_NOVALUE}). + + all() -> [app, appup, @@ -59,6 +64,7 @@ groups() -> {api_bound, [], [add_when_bound, add_already_exists, more_add, + add_referral, search_filter_equalityMatch, search_filter_substring_any, search_filter_initial, @@ -67,8 +73,11 @@ groups() -> search_filter_or, search_filter_and_not, search_two_hits, + search_referral, modify, + modify_referral, delete, + delete_referral, modify_dn_delete_old, modify_dn_keep_old]}, {v4_connections, [], connection_tests()}, @@ -92,11 +101,16 @@ connection_tests() -> init_per_suite(Config) -> SSL_available = init_ssl_certs_et_al(Config), - LDAP_server = find_first_server(false, [{config,eldap_server}, {config,ldap_server}, {"localhost",9876}]), + LDAP_server = find_first_server(false, [{config,eldap_server}, + {config,ldap_server}, + {"localhost",9876}, + {"aramis.otp.ericsson.se",9876}]), LDAPS_server = case SSL_available of true -> - find_first_server(true, [{config,ldaps_server}, {"localhost",9877}]); + find_first_server(true, [{config,ldaps_server}, + {"localhost",9877}, + {"aramis.otp.ericsson.se",9877}]); false -> undefined end, @@ -454,6 +468,16 @@ more_add(Config) -> [{"objectclass", ["organizationalUnit"]}, {"ou", ["Team"]}]). +%%%---------------------------------------------------------------- +add_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:add(H, "cn=Foo Bar,dc=notHere," ++ BasePath, + [{"objectclass", ["person"]}, + {"cn", ["Foo Bar"]}, + {"sn", ["Bar"]}, + {"telephoneNumber", ["555-1232", "555-5432"]}]). %%%---------------------------------------------------------------- search_filter_equalityMatch(Config) -> @@ -569,6 +593,16 @@ search_two_hits(Config) -> [ok=eldap:delete(H,DN) || DN <- ExpectedDNs]. %%%---------------------------------------------------------------- +search_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + DN = "cn=Santa Claus,dc=notHere," ++ BasePath, + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:search(H, #eldap_search{base = DN, + filter = eldap:present("description"), + scope=eldap:singleLevel()}). + +%%%---------------------------------------------------------------- modify(Config) -> H = ?config(handle, Config), BasePath = ?config(eldap_path, Config), @@ -602,6 +636,19 @@ modify(Config) -> restore_original_object(H, DN, OriginalAttrs). %%%---------------------------------------------------------------- +modify_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + %% The object to modify + DN = "cn=Foo Bar,dc=notHere," ++ BasePath, + + %% Do a change + Mod = [eldap:mod_replace("telephoneNumber", ["555-12345"]), + eldap:mod_add("description", ["Nice guy"])], + {ok,{referral,["ldap://nowhere.example.com"++_]}} = + eldap:modify(H, DN, Mod). + +%%%---------------------------------------------------------------- delete(Config) -> H = ?config(handle, Config), BasePath = ?config(eldap_path, Config), @@ -620,6 +667,14 @@ delete(Config) -> restore_original_object(H, DN, OriginalAttrs). %%%---------------------------------------------------------------- +delete_referral(Config) -> + H = ?config(handle, Config), + BasePath = ?config(eldap_path, Config), + %% The element to play with: + DN = "cn=Jonas Jonsson,dc=notHere," ++ BasePath, + {ok,{referral,["ldap://nowhere.example.com"++_]}} = eldap:delete(H, DN). + +%%%---------------------------------------------------------------- modify_dn_delete_old(Config) -> H = ?config(handle, Config), BasePath = ?config(eldap_path, Config), @@ -817,25 +872,44 @@ delete_old_contents(H, Path) -> {filter, eldap:present("objectclass")}, {scope, eldap:wholeSubtree()}]) of - {ok, #eldap_search_result{entries=Entries}} -> + {ok, _R=#eldap_search_result{entries=Entries}} -> + case eldap:delete(H, "dc=notHere,"++Path, [?manageDsaIT]) of + ok -> ok; + {error,noSuchObject} -> ok; + Other -> ct:fail("eldap:delete notHere ret ~p",[Other]) + end, [ok = eldap:delete(H,DN) || #eldap_entry{object_name=DN} <- Entries]; _Res -> ignore end. + +-define(ok(X), ok(?MODULE,?LINE,X)). + add_new_contents(H, Path, MyHost) -> - ok(eldap:add(H,"dc=ericsson,dc=se", + ?ok(eldap:add(H,"dc=ericsson,dc=se", [{"objectclass", ["dcObject", "organization"]}, {"dc", ["ericsson"]}, {"o", ["Testing"]}])), - ok(eldap:add(H,Path, + ?ok(eldap:add(H,Path, [{"objectclass", ["dcObject", "organization"]}, {"dc", [MyHost]}, - {"o", ["Test machine"]}])). - - -ok({error,entryAlreadyExists}) -> ok; -ok(X) -> ok=X. + {"o", ["Test machine"]}])), + ?ok(eldap:add(H, "dc=notHere,"++Path, + [{"objectclass", ["referral", + "dcObject" + ]}, + {"ref", ["ldap://nowhere.example.com/notHere,"++Path]}, + {"dc", ["notHere"]} + ])). + + + +ok(_, _, {error,entryAlreadyExists}) -> ok; +ok(_, _, ok) -> ok; +ok(MODULE, LINE, X) -> + ct:pal("~p:~p add_new_contents: ret from eldap:add = ~p",[MODULE,LINE,X]), + X. diff --git a/lib/eldap/vsn.mk b/lib/eldap/vsn.mk index 105a2bcdbb..99c474d588 100644 --- a/lib/eldap/vsn.mk +++ b/lib/eldap/vsn.mk @@ -1 +1 @@ -ELDAP_VSN = 1.2 +ELDAP_VSN = 1.2.1 diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in index 3ac9212085..7a3b5ce378 100644 --- a/lib/erl_interface/configure.in +++ b/lib/erl_interface/configure.in @@ -251,7 +251,7 @@ case "$threads_disabled" in ;; win32_threads) EI_THREADS="true" - THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0500 -DWINVER=0x0500" + THR_DEFS="$THR_DEFS -D_WIN32_WINNT=0x0600 -DWINVER=0x0600" ;; pthread) EI_THREADS="true" diff --git a/lib/erl_interface/doc/src/ei.xml b/lib/erl_interface/doc/src/ei.xml index 6044ac8ef7..8ef433d10f 100644 --- a/lib/erl_interface/doc/src/ei.xml +++ b/lib/erl_interface/doc/src/ei.xml @@ -264,9 +264,9 @@ typedef enum { <fsummary>Encode an atom</fsummary> <desc> <p>Encodes an atom in the binary format with character encoding - <c><seealso marker="#erlang_char_encoding">to_enc</seealso></c> (latin1 or utf8). + <seealso marker="#erlang_char_encoding"><c>to_enc</c></seealso> (latin1 or utf8). The <c>p</c> parameter is the name of the atom with character encoding - <c><seealso marker="#erlang_char_encoding">from_enc</seealso></c> (ascii, latin1 or utf8). + <seealso marker="#erlang_char_encoding"><c>from_enc</c></seealso> (ascii, latin1 or utf8). The name must either be zero-terminated or a function variant with a <c>len</c> parameter must be used. If <c>to_enc</c> is set to the bitwise-or'd combination <c>(ERLANG_LATIN1|ERLANG_UTF8)</c>, utf8 encoding is only used if the atom string @@ -569,8 +569,8 @@ ei_x_encode_string(&x, "Banana"); <p>This function decodes an atom from the binary format. The null terminated name of the atom is placed in buffer at <c>p</c> of length <c>plen</c> bytes.</p> - <p>The wanted string encoding is specified by <c><seealso marker="#erlang_char_encoding"> - want</seealso></c>. The original encoding used in the + <p>The wanted string encoding is specified by <seealso marker="#erlang_char_encoding"> + <c>want</c></seealso>. The original encoding used in the binary format (latin1 or utf8) can be obtained from <c>*was</c>. The actual encoding of the resulting string (7-bit ascii, latin1 or utf8) can be obtained from <c>*result</c>. Both <c>was</c> and <c>result</c> can be <c>NULL</c>. diff --git a/lib/erl_interface/doc/src/erl_call.xml b/lib/erl_interface/doc/src/erl_call.xml index aed1ba0ac9..e982bf89e1 100644 --- a/lib/erl_interface/doc/src/erl_call.xml +++ b/lib/erl_interface/doc/src/erl_call.xml @@ -178,7 +178,7 @@ erl_call -s -a 'erlang halt' -n madonna <code type="none"><![CDATA[ erl_call -s -a 'lists map [{math,sqrt},[1,4,9,16,25]]' -n madonna ]]></code> - <p>Evaluates a couple of expressions. <b>The input ends with EOF (Control-D)</b>.</p> + <p>Evaluates a couple of expressions. <em>The input ends with EOF (Control-D)</em>.</p> <code type="none"><![CDATA[ erl_call -s -e -n madonna statistics(runtime), @@ -189,7 +189,7 @@ Y=2, ^D {ok,{3,0}} ]]></code> - <p>Compiles a module and runs it. <b>Again, the input ends with EOF (Control-D)</b>. (In the example shown, the output has been formatted afterwards).</p> + <p>Compiles a module and runs it. <em>Again, the input ends with EOF (Control-D)</em>. (In the example shown, the output has been formatted afterwards).</p> <code type="none"><![CDATA[ erl_call -s -m -a lolita -n madonna -module(lolita). diff --git a/lib/erl_interface/doc/src/erl_eterm.xml b/lib/erl_interface/doc/src/erl_eterm.xml index 9a53a137c2..713a90a390 100644 --- a/lib/erl_interface/doc/src/erl_eterm.xml +++ b/lib/erl_interface/doc/src/erl_eterm.xml @@ -78,10 +78,12 @@ </p> <taglist> <tag><c><![CDATA[char *ERL_ATOM_PTR(t)]]></c></tag> + <item/> <tag><c><![CDATA[char *ERL_ATOM_PTR_UTF8(t)]]></c></tag> <item>A string representing atom <c><![CDATA[t]]></c>. </item> <tag><c><![CDATA[int ERL_ATOM_SIZE(t)]]></c></tag> + <item/> <tag><c><![CDATA[int ERL_ATOM_SIZE_UTF8(t)]]></c></tag> <item>The length (in bytes) of atom t.</item> <tag><c><![CDATA[void *ERL_BIN_PTR(t)]]></c></tag> @@ -95,6 +97,7 @@ <tag><c><![CDATA[double ERL_FLOAT_VALUE(t)]]></c></tag> <item>The floating point value of <c><![CDATA[t]]></c>.</item> <tag><c><![CDATA[ETERM *ERL_PID_NODE(t)]]></c></tag> + <item/> <tag><c><![CDATA[ETERM *ERL_PID_NODE_UTF8(t)]]></c></tag> <item>The Node in pid <c><![CDATA[t]]></c>.</item> <tag><c><![CDATA[int ERL_PID_NUMBER(t)]]></c></tag> @@ -108,6 +111,7 @@ <tag><c><![CDATA[int ERL_PORT_CREATION(t)]]></c></tag> <item>The creation number in port <c><![CDATA[t]]></c>.</item> <tag><c><![CDATA[ETERM *ERL_PORT_NODE(t)]]></c></tag> + <item/> <tag><c><![CDATA[ETERM *ERL_PORT_NODE_UTF8(t)]]></c></tag> <item>The node in port <c><![CDATA[t]]></c>.</item> <tag><c><![CDATA[int ERL_REF_NUMBER(t)]]></c></tag> diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl index 84aae30291..a0deb31c42 100644 --- a/lib/hipe/icode/hipe_icode_primops.erl +++ b/lib/hipe/icode/hipe_icode_primops.erl @@ -504,16 +504,16 @@ type(Primop, Args) -> NewBinType = match_bin(erl_types:t_bitstr(0, Size), BinType), NewMatchState = erl_types:t_matchstate_update_present(NewBinType, MatchState), - if Signed =:= 0 -> - UpperBound = inf_add(safe_bsl(1, Size), -1), - erl_types:t_product([erl_types:t_from_range(0, UpperBound), - NewMatchState]); - Signed =:= 4 -> - erl_types:t_product([erl_types:t_from_range( - inf_inv(safe_bsl(1, Size-1)), - inf_add(safe_bsl(1, Size-1), -1)), - NewMatchState]) - end; + Range = + case Signed of + 0 -> + UpperBound = inf_add(safe_bsl_1(Size), -1), + erl_types:t_from_range(0, UpperBound); + 4 -> + Bound = safe_bsl_1(Size - 1), + erl_types:t_from_range(inf_inv(Bound), inf_add(Bound, -1)) + end, + erl_types:t_product([Range, NewMatchState]); [_Arg] -> NewBinType = match_bin(erl_types:t_bitstr(Size, 0), BinType), NewMatchState = @@ -969,18 +969,19 @@ check_fun_args(_, _) -> match_bin(Pattern, Match) -> erl_types:t_bitstr_match(Pattern, Match). -safe_bsl(0, _) -> 0; -safe_bsl(Base, Shift) when Shift =< 128 -> Base bsl Shift; -safe_bsl(Base, _Shift) when Base > 0 -> pos_inf; -safe_bsl(Base, _Shift) when Base < 0 -> neg_inf. +-spec safe_bsl_1(non_neg_integer()) -> non_neg_integer() | 'pos_inf'. + +safe_bsl_1(Shift) when Shift =< 128 -> 1 bsl Shift; +safe_bsl_1(_Shift) -> pos_inf. + +%% +%% The following two functions are stripped-down versions of more +%% general functions that exist in hipe_icode_range.erl +%% inf_inv(pos_inf) -> neg_inf; -inf_inv(neg_inf) -> pos_inf; -inf_inv(Number) -> -Number. +inf_inv(Number) when is_integer(Number) -> -Number. inf_add(pos_inf, _Number) -> pos_inf; -inf_add(neg_inf, _Number) -> neg_inf; -inf_add(_Number, pos_inf) -> pos_inf; -inf_add(_Number, neg_inf) -> neg_inf; inf_add(Number1, Number2) when is_integer(Number1), is_integer(Number2) -> Number1 + Number2. diff --git a/lib/inets/src/http_server/httpd_request_handler.erl b/lib/inets/src/http_server/httpd_request_handler.erl index 134576059d..8fae9ac46e 100644 --- a/lib/inets/src/http_server/httpd_request_handler.erl +++ b/lib/inets/src/http_server/httpd_request_handler.erl @@ -102,8 +102,8 @@ init([Manager, ConfigDB, AcceptTimeout]) -> KeepAliveTimeOut = 1000 * httpd_util:lookup(ConfigDB, keep_alive_timeout, 150), case http_transport:negotiate(SocketType, Socket, ?HANDSHAKE_TIMEOUT) of - {error, _Error} -> - exit(shutdown); %% Can be 'normal'. + {error, Error} -> + exit({shutdown, Error}); %% Can be 'normal'. ok -> continue_init(Manager, ConfigDB, SocketType, Socket, KeepAliveTimeOut) end. @@ -294,7 +294,10 @@ handle_info(Info, #state{mod = ModData} = State) -> %% cleaning up. When it returns, the gen_server terminates with Reason. %% The return value is ignored. %%-------------------------------------------------------------------- -terminate(normal, State) -> +terminate(Reason, State) when Reason == normal; + Reason == shutdown -> + do_terminate(State); +terminate({shutdown,_}, State) -> do_terminate(State); terminate(Reason, #state{response_sent = false, mod = ModData} = State) -> httpd_response:send_status(ModData, 500, none), diff --git a/lib/inets/src/tftp/tftp_engine.erl b/lib/inets/src/tftp/tftp_engine.erl index 8d282a1e9d..493a29a68f 100644 --- a/lib/inets/src/tftp/tftp_engine.erl +++ b/lib/inets/src/tftp/tftp_engine.erl @@ -656,22 +656,11 @@ common_read(Config, Callback, Req, _LocalAccess, ExpectedBlockNo, ActualBlockNo, do_common_read(Config, Callback, Req, LocalAccess, BlockNo, Data, Prepared) when is_binary(Data), is_record(Prepared, prepared) -> - NextBlockNo = BlockNo + 1, - case NextBlockNo =< 65535 of - true -> - Reply = #tftp_msg_data{block_no = NextBlockNo, data = Data}, - {Config2, Callback2, TransferRes} = - transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared), - ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo); - false -> - Code = badblk, - Text = "Too big transfer ID = " ++ - integer_to_list(NextBlockNo) ++ " > 65535", - {undefined, Error} = - callback({abort, {Code, Text}}, Config, Callback, Req), - send_msg(Config, Req, Error), - terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename)) - end. + NextBlockNo = (BlockNo + 1) rem 65536, + Reply = #tftp_msg_data{block_no = NextBlockNo, data = Data}, + {Config2, Callback2, TransferRes} = + transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared), + ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo). -spec common_write(#config{}, #callback{}, _, 'write', integer(), integer(), _, #prepared{}) -> no_return(). @@ -715,21 +704,10 @@ common_write(Config, Callback, Req, _, ExpectedBlockNo, ActualBlockNo, Data, Pre common_ack(Config, Callback, Req, LocalAccess, BlockNo, Prepared) when is_record(Prepared, prepared) -> Reply = #tftp_msg_ack{block_no = BlockNo}, - NextBlockNo = BlockNo + 1, + NextBlockNo = (BlockNo + 1) rem 65536, {Config2, Callback2, TransferRes} = transfer(Config, Callback, Req, Reply, LocalAccess, NextBlockNo, Prepared), - case NextBlockNo =< 65535 of - true -> - ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo); - false -> - Code = badblk, - Text = "Too big transfer ID = " ++ - integer_to_list(NextBlockNo) ++ " > 65535", - {undefined, Error} = - callback({abort, {Code, Text}}, Config, Callback2, Req), - send_msg(Config, Req, Error), - terminate(Config, Req, ?ERROR(read, Code, Text, Req#tftp_msg_req.filename)) - end. + ?MODULE:common_loop(Config2, Callback2, Req, TransferRes, LocalAccess, NextBlockNo). pre_terminate(Config, Req, Result) -> if diff --git a/lib/inets/test/tftp_SUITE.erl b/lib/inets/test/tftp_SUITE.erl index d29d210d7d..497a50e654 100644 --- a/lib/inets/test/tftp_SUITE.erl +++ b/lib/inets/test/tftp_SUITE.erl @@ -76,7 +76,7 @@ suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [simple, extra, reuse_connection, resend_client, - resend_server]. + resend_server, large_file]. groups() -> []. @@ -902,6 +902,41 @@ reuse_connection(Config) when is_list(Config) -> ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% Large file: transfer > 65535 blocks +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +large_file(doc) -> + ["Start the daemon and test transfer of files greater than 32M."]; +large_file(suite) -> + []; +large_file(Config) when is_list(Config) -> + ?VERIFY(ok, application:start(inets)), + + {Port, DaemonPid} = ?IGNORE(?START_DAEMON(0, [{debug, brief}])), + + %% Read fail + RemoteFilename = "tftp_temporary_large_file_remote_test_file.txt", + LocalFilename = "tftp_temporary_large_file_local_test_file.txt", + + {ok, FH} = file:open(LocalFilename, [write,exclusive]), + {ok, Size} = file:position(FH, {eof, 2*512*65535}), + ok = file:truncate(FH), + ?IGNORE(file:close(FH)), + + %% Write and read + ?VERIFY({ok, Size}, tftp:write_file(RemoteFilename, LocalFilename, [{port, Port}])), + ?IGNORE(file:delete(LocalFilename)), + ?VERIFY({ok, Size}, tftp:read_file(RemoteFilename, LocalFilename, [{port, Port}])), + + %% Cleanup + unlink(DaemonPid), + exit(DaemonPid, kill), + ?VERIFY(ok, file:delete(LocalFilename)), + ?VERIFY(ok, file:delete(RemoteFilename)), + ?VERIFY(ok, application:stop(inets)), + ok. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Goodies %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index b9fad17ce1..9da4773f2d 100644 --- a/lib/kernel/doc/src/heart.xml +++ b/lib/kernel/doc/src/heart.xml @@ -118,6 +118,13 @@ <p>In the following descriptions, all function fails with reason <c>badarg</c> if <c>heart</c> is not started.</p> </description> + + <datatypes> + <datatype> + <name name="heart_option"/> + </datatype> + </datatypes> + <funcs> <func> <name name="set_cmd" arity="1"/> @@ -154,6 +161,62 @@ the empty string will be returned.</p> </desc> </func> + + <func> + <name name="set_callback" arity="2"/> + <fsummary>Set a validation callback</fsummary> + <desc> + <p> This validation callback will be executed before any heartbeat sent + to the port program. For the validation to succeed it needs to return + with the value <c>ok</c>. + </p> + <p> An exception within the callback will be treated as a validation failure. </p> + <p> The callback will be removed if the system reboots. </p> + </desc> + </func> + <func> + <name name="clear_callback" arity="0"/> + <fsummary>Clear the validation callback</fsummary> + <desc> + <p>Removes the validation callback call before heartbeats.</p> + </desc> + </func> + <func> + <name name="get_callback" arity="0"/> + <fsummary>Get the validation callback</fsummary> + <desc> + <p>Get the validation callback. If the callback is cleared, <c>none</c> will be returned.</p> + </desc> + </func> + + <func> + <name name="set_options" arity="1"/> + <fsummary>Set a list of options</fsummary> + <desc> + <p> Valid options <c>set_options</c> are: </p> + <taglist> + <tag><c>check_schedulers</c></tag> + <item> + <p>If enabled, a signal will be sent to each scheduler to check its + responsiveness. The system check occurs before any heartbeat sent + to the port program. If any scheduler is not responsive enough the + heart program will not receive its heartbeat and thus eventually terminate the node. + </p> + </item> + </taglist> + <p> Returns with the value <c>ok</c> if the options are valid.</p> + </desc> + </func> + <func> + <name name="get_options" arity="0"/> + <fsummary>Get the temporary reboot command</fsummary> + <desc> + <p>Returns <c>{ok, Options}</c> where <c>Options</c> is a list of current options enabled for heart. + If the callback is cleared, <c>none</c> will be returned.</p> + </desc> + </func> + + </funcs> </erlref> diff --git a/lib/kernel/examples/uds_dist/c_src/uds_drv.c b/lib/kernel/examples/uds_dist/c_src/uds_drv.c index e32ad69adf..8c028ba910 100644 --- a/lib/kernel/examples/uds_dist/c_src/uds_drv.c +++ b/lib/kernel/examples/uds_dist/c_src/uds_drv.c @@ -957,28 +957,24 @@ static void put_packet_length(char *b, int len) /* ** Malloc wrappers -** Note! -** The function erl_exit is actually not a pert of the -** driver interface, but it is very nice to use if one wants to halt -** with a core and an erlang crash dump. */ static void *my_malloc(size_t size) { - void erl_exit(int, char *, ...); void *ptr; if ((ptr = driver_alloc(size)) == NULL) { - erl_exit(1,"Could not allocate %lu bytes of memory",(unsigned long) size); + fprintf(stderr, "Could not allocate %lu bytes of memory",(unsigned long) size); + abort(); } return ptr; } static void *my_realloc(void *ptr, size_t size) { - void erl_exit(int, char *, ...); void *nptr; if ((nptr = driver_realloc(ptr, size)) == NULL) { - erl_exit(1,"Could not reallocate %lu bytes of memory",(unsigned long) size); + fprintf(stderr, "Could not reallocate %lu bytes of memory",(unsigned long) size); + abort(); } return nptr; } diff --git a/lib/kernel/src/erl_epmd.erl b/lib/kernel/src/erl_epmd.erl index 55ce9a7e64..c6202dd796 100644 --- a/lib/kernel/src/erl_epmd.erl +++ b/lib/kernel/src/erl_epmd.erl @@ -32,7 +32,7 @@ %% External exports -export([start/0, start_link/0, stop/0, port_please/2, port_please/3, names/0, names/1, - register_node/2, open/0, open/1, open/2]). + register_node/2, register_node/3, open/0, open/1, open/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2, handle_info/2, @@ -102,7 +102,9 @@ names(EpmdAddr) -> register_node(Name, PortNo) -> - gen_server:call(erl_epmd, {register, Name, PortNo}, infinity). + register_node(Name, PortNo, inet). +register_node(Name, PortNo, Family) -> + gen_server:call(erl_epmd, {register, Name, PortNo, Family}, infinity). %%%---------------------------------------------------------------------- %%% Callback functions from gen_server @@ -120,10 +122,10 @@ init(_) -> -spec handle_call(calls(), term(), state()) -> {'reply', term(), state()} | {'stop', 'shutdown', 'ok', state()}. -handle_call({register, Name, PortNo}, _From, State) -> +handle_call({register, Name, PortNo, Family}, _From, State) -> case State#state.socket of P when P < 0 -> - case do_register_node(Name, PortNo) of + case do_register_node(Name, PortNo, Family) of {alive, Socket, Creation} -> S = State#state{socket = Socket, port_no = PortNo, @@ -206,8 +208,12 @@ open({A,B,C,D,E,F,G,H}=EpmdAddr, Timeout) when ?ip6(A,B,C,D,E,F,G,H) -> close(Socket) -> gen_tcp:close(Socket). -do_register_node(NodeName, TcpPort) -> - case open() of +do_register_node(NodeName, TcpPort, Family) -> + Localhost = case Family of + inet -> open({127,0,0,1}); + inet6 -> open({0,0,0,0,0,0,0,1}) + end, + case Localhost of {ok, Socket} -> Name = to_string(NodeName), Extra = "", diff --git a/lib/kernel/src/gen_tcp.erl b/lib/kernel/src/gen_tcp.erl index d7dba4ac80..8cb2a725e8 100644 --- a/lib/kernel/src/gen_tcp.erl +++ b/lib/kernel/src/gen_tcp.erl @@ -114,7 +114,8 @@ option(). -type socket() :: port(). --export_type([option/0, option_name/0, connect_option/0, listen_option/0]). +-export_type([option/0, option_name/0, connect_option/0, listen_option/0, + socket/0]). %% %% Connect a socket diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl index 137fad706f..eea78aabdf 100644 --- a/lib/kernel/src/heart.erl +++ b/lib/kernel/src/heart.erl @@ -34,7 +34,11 @@ %%% %%% It recognizes the flag '-heart' %%%-------------------------------------------------------------------- --export([start/0, init/2, set_cmd/1, clear_cmd/0, get_cmd/0, cycle/0]). +-export([start/0, init/2, + set_cmd/1, clear_cmd/0, get_cmd/0, + set_callback/2, clear_callback/0, get_callback/0, + set_options/1, get_options/0, + cycle/0]). -define(START_ACK, 1). -define(HEART_BEAT, 2). @@ -49,6 +53,16 @@ -define(CYCLE_TIMEOUT, 10000). -define(HEART_PORT_NAME, heart_port). +%% valid heart options +-define(SCHEDULER_CHECK_OPT, check_schedulers). + +-type heart_option() :: ?SCHEDULER_CHECK_OPT. + +-record(state,{port :: port(), + cmd :: [] | binary(), + options :: [heart_option()], + callback :: 'undefined' | {atom(), atom()}}). + %%--------------------------------------------------------------------- -spec start() -> 'ignore' | {'error', term()} | {'ok', pid()}. @@ -81,11 +95,11 @@ wait_for_init_ack(From) -> init(Starter, Parent) -> process_flag(trap_exit, true), process_flag(priority, max), - register(heart, self()), + register(?MODULE, self()), case catch start_portprogram() of {ok, Port} -> Starter ! {ok, self()}, - loop(Parent, Port, ""); + loop(Parent, #state{port=Port, cmd=[], options=[]}); no_heart -> Starter ! {no_heart, self()}; error -> @@ -96,33 +110,68 @@ init(Starter, Parent) -> Cmd :: string(). set_cmd(Cmd) -> - heart ! {self(), set_cmd, Cmd}, + ?MODULE ! {self(), set_cmd, Cmd}, wait(). -spec get_cmd() -> {ok, Cmd} when Cmd :: string(). get_cmd() -> - heart ! {self(), get_cmd}, + ?MODULE ! {self(), get_cmd}, wait(). -spec clear_cmd() -> ok. clear_cmd() -> - heart ! {self(), clear_cmd}, + ?MODULE ! {self(), clear_cmd}, + wait(). + +-spec set_callback(Module,Function) -> 'ok' | {'error', {'bad_callback', {Module, Function}}} when + Module :: atom(), + Function :: atom(). + +set_callback(Module, Function) -> + ?MODULE ! {self(), set_callback, {Module,Function}}, + wait(). + +-spec get_callback() -> {'ok', {Module, Function}} | 'none' when + Module :: atom(), + Function :: atom(). + +get_callback() -> + ?MODULE ! {self(), get_callback}, + wait(). + +-spec clear_callback() -> ok. + +clear_callback() -> + ?MODULE ! {self(), clear_callback}, + wait(). + +-spec set_options(Options) -> 'ok' | {'error', {'bad_options', Options}} when + Options :: [heart_option()]. + +set_options(Options) -> + ?MODULE ! {self(), set_options, Options}, wait(). +-spec get_options() -> {'ok', Options} | 'none' when + Options :: [atom()]. + +get_options() -> + ?MODULE ! {self(), get_options}, + wait(). %%% Should be used solely by the release handler!!!!!!! -spec cycle() -> 'ok' | {'error', term()}. cycle() -> - heart ! {self(), cycle}, + ?MODULE ! {self(), cycle}, wait(). wait() -> receive - {heart, Res} -> + {?MODULE, Res} -> Res end. @@ -182,8 +231,8 @@ wait_ack(Port) -> {error, Reason} end. -loop(Parent, Port, Cmd) -> - _ = send_heart_beat(Port), +loop(Parent, #state{port=Port}=S) -> + _ = send_heart_beat(S), receive {From, set_cmd, NewCmd0} -> Enc = file:native_name_encoding(), @@ -191,37 +240,72 @@ loop(Parent, Port, Cmd) -> NewCmd when is_binary(NewCmd), byte_size(NewCmd) < 2047 -> _ = send_heart_cmd(Port, NewCmd), _ = wait_ack(Port), - From ! {heart, ok}, - loop(Parent, Port, NewCmd); + From ! {?MODULE, ok}, + loop(Parent, S#state{cmd=NewCmd}); _ -> - From ! {heart, {error, {bad_cmd, NewCmd0}}}, - loop(Parent, Port, Cmd) + From ! {?MODULE, {error, {bad_cmd, NewCmd0}}}, + loop(Parent, S) end; {From, clear_cmd} -> - From ! {heart, ok}, - _ = send_heart_cmd(Port, ""), + From ! {?MODULE, ok}, + _ = send_heart_cmd(Port, []), _ = wait_ack(Port), - loop(Parent, Port, ""); + loop(Parent, S#state{cmd = []}); {From, get_cmd} -> - From ! {heart, get_heart_cmd(Port)}, - loop(Parent, Port, Cmd); + From ! {?MODULE, get_heart_cmd(Port)}, + loop(Parent, S); + {From, set_callback, Callback} -> + case Callback of + {M,F} when is_atom(M), is_atom(F) -> + From ! {?MODULE, ok}, + loop(Parent, S#state{callback=Callback}); + _ -> + From ! {?MODULE, {error, {bad_callback, Callback}}}, + loop(Parent, S) + end; + {From, get_callback} -> + Res = case S#state.callback of + undefined -> none; + Cb -> {ok, Cb} + end, + From ! {?MODULE, Res}, + loop(Parent, S); + {From, clear_callback} -> + From ! {?MODULE, ok}, + loop(Parent, S#state{callback=undefined}); + {From, set_options, Options} -> + case validate_options(Options) of + Validated when is_list(Validated) -> + From ! {?MODULE, ok}, + loop(Parent, S#state{options=Validated}); + _ -> + From ! {?MODULE, {error, {bad_options, Options}}}, + loop(Parent, S) + end; + {From, get_options} -> + Res = case S#state.options of + [] -> none; + Cb -> {ok, Cb} + end, + From ! {?MODULE, Res}, + loop(Parent, S); {From, cycle} -> %% Calls back to loop - do_cycle_port_program(From, Parent, Port, Cmd); + do_cycle_port_program(From, Parent, S); {'EXIT', Parent, shutdown} -> no_reboot_shutdown(Port); {'EXIT', Parent, Reason} -> exit(Port, Reason), exit(Reason); {'EXIT', Port, badsig} -> % we can ignore badsig-messages! - loop(Parent, Port, Cmd); + loop(Parent, S); {'EXIT', Port, _Reason} -> - exit({port_terminated, {heart, loop, [Parent, Port, Cmd]}}); + exit({port_terminated, {?MODULE, loop, [Parent, S]}}); _ -> - loop(Parent, Port, Cmd) + loop(Parent, S) after ?TIMEOUT -> - loop(Parent, Port, Cmd) + loop(Parent, S) end. -spec no_reboot_shutdown(port()) -> no_return(). @@ -233,36 +317,44 @@ no_reboot_shutdown(Port) -> exit(normal) end. -do_cycle_port_program(Caller, Parent, Port, Cmd) -> +validate_options(Opts) -> validate_options(Opts,[]). +validate_options([],Res) -> Res; +validate_options([?SCHEDULER_CHECK_OPT=Opt|Opts],Res) -> validate_options(Opts,[Opt|Res]); +validate_options(_,_) -> error. + +do_cycle_port_program(Caller, Parent, #state{port=Port} = S) -> unregister(?HEART_PORT_NAME), case catch start_portprogram() of {ok, NewPort} -> _ = send_shutdown(Port), receive {'EXIT', Port, _Reason} -> - _ = send_heart_cmd(NewPort, Cmd), - Caller ! {heart, ok}, - loop(Parent, NewPort, Cmd) + _ = send_heart_cmd(NewPort, S#state.cmd), + Caller ! {?MODULE, ok}, + loop(Parent, S#state{port=NewPort}) after ?CYCLE_TIMEOUT -> %% Huh! Two heart port programs running... %% well, the old one has to be sick not to respond %% so we'll settle for the new one... - _ = send_heart_cmd(NewPort, Cmd), - Caller ! {heart, {error, stop_error}}, - loop(Parent, NewPort, Cmd) + _ = send_heart_cmd(NewPort, S#state.cmd), + Caller ! {?MODULE, {error, stop_error}}, + loop(Parent, S#state{port=NewPort}) end; no_heart -> - Caller ! {heart, {error, no_heart}}, - loop(Parent, Port, Cmd); + Caller ! {?MODULE, {error, no_heart}}, + loop(Parent, S); error -> - Caller ! {heart, {error, start_error}}, - loop(Parent, Port, Cmd) + Caller ! {?MODULE, {error, start_error}}, + loop(Parent, S) end. %% "Beates" the heart once. -send_heart_beat(Port) -> Port ! {self(), {command, [?HEART_BEAT]}}. +send_heart_beat(#state{port=Port, callback=Cb, options=Opts}) -> + ok = check_system(Opts), + ok = check_callback(Cb), + Port ! {self(), {command, [?HEART_BEAT]}}. %% Set a new HEART_COMMAND. -dialyzer({no_improper_lists, send_heart_cmd/2}). @@ -278,6 +370,24 @@ get_heart_cmd(Port) -> {ok, Cmd} end. +check_system([]) -> ok; +check_system([?SCHEDULER_CHECK_OPT|Opts]) -> + ok = erts_internal:system_check(schedulers), + check_system(Opts). + +%% validate system by performing a check before the heartbeat +%% return 'ok' if everything is alright. +%% Terminate if with reason if something is a miss. +%% It is fine to timeout in the callback, in fact that is the intention +%% if something goes wront -> no heartbeat. + +check_callback(Callback) -> + case Callback of + undefined -> ok; + {M,F} -> + erlang:apply(M,F,[]) + end. + %% Sends shutdown command to the port. send_shutdown(Port) -> Port ! {self(), {command, [?SHUT_DOWN]}}. diff --git a/lib/kernel/src/kernel.appup.src b/lib/kernel/src/kernel.appup.src index 860d3640d0..cc9e6f771a 100644 --- a/lib/kernel/src/kernel.appup.src +++ b/lib/kernel/src/kernel.appup.src @@ -18,9 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"4\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + [{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 %% Down to - max one major revision back - [{<<"4\\.[0-1](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + [{<<"4\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* {<<"3\\.[0-2](\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 }. diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl index 83efbb4c35..39cd29cea0 100644 --- a/lib/kernel/test/heart_SUITE.erl +++ b/lib/kernel/test/heart_SUITE.erl @@ -27,6 +27,8 @@ node_start_immediately_after_crash/1, node_start_soon_after_crash/1, set_cmd/1, clear_cmd/1, get_cmd/1, + callback_api/1, + options_api/1, dont_drop/1, kill_pid/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -66,6 +68,8 @@ all() -> [ node_start_immediately_after_crash, node_start_soon_after_crash, set_cmd, clear_cmd, get_cmd, + callback_api, + options_api, kill_pid ]. @@ -358,6 +362,69 @@ get_cmd(Config) when is_list(Config) -> stop_node(Node), ok. +callback_api(Config) when is_list(Config) -> + {ok, Node} = start_check(slave, heart_test), + none = rpc:call(Node, heart, get_callback, []), + M0 = self(), + F0 = ok, + {error, {bad_callback, {M0,F0}}} = rpc:call(Node, heart, set_callback, [M0,F0]), + none = rpc:call(Node, heart, get_callback, []), + M1 = lists:duplicate(28, $a), + F1 = lists:duplicate(28, $b), + {error, {bad_callback, {M1,F1}}} = rpc:call(Node, heart, set_callback, [M1,F1]), + none = rpc:call(Node, heart, get_callback, []), + + M2 = heart_check_module, + F2 = cb_ok, + F3 = cb_error, + Code0 = generate(M2, [], [ + atom_to_list(F2) ++ "() -> ok.", + atom_to_list(F3) ++ "() -> exit(\"callback_error (as intended)\")." + ]), + {module, M2} = rpc:call(Node, erlang, load_module, [M2, Code0]), + ok = rpc:call(Node, M2, F2, []), + ok = rpc:call(Node, heart, set_callback, [M2,F2]), + {ok, {M2,F2}} = rpc:call(Node, heart, get_callback, []), + ok = rpc:call(Node, heart, clear_callback, []), + none = rpc:call(Node, heart, get_callback, []), + ok = rpc:call(Node, heart, set_callback, [M2,F2]), + {ok, {M2,F2}} = rpc:call(Node, heart, get_callback, []), + ok = rpc:call(Node, heart, set_callback, [M2,F3]), + receive {nodedown, Node} -> ok + after 5000 -> test_server:fail(node_not_killed) + end, + stop_node(Node), + ok. + +options_api(Config) when is_list(Config) -> + {ok, Node} = start_check(slave, heart_test), + none = rpc:call(Node, heart, get_options, []), + M0 = self(), + F0 = ok, + {error, {bad_options, {M0,F0}}} = rpc:call(Node, heart, set_options, [{M0,F0}]), + none = rpc:call(Node, heart, get_options, []), + Ls = lists:duplicate(28, $b), + {error, {bad_options, Ls}} = rpc:call(Node, heart, set_options, [Ls]), + none = rpc:call(Node, heart, get_options, []), + + ok = rpc:call(Node, heart, set_options, [[check_schedulers]]), + {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []), + ok = rpc:call(Node, heart, set_options, [[]]), + none = rpc:call(Node, heart, get_options, []), + + ok = rpc:call(Node, heart, set_options, [[check_schedulers]]), + {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []), + {error, {bad_options, Ls}} = rpc:call(Node, heart, set_options, [Ls]), + {ok, [check_schedulers]} = rpc:call(Node, heart, get_options, []), + + receive after 3000 -> ok end, %% wait 3 secs + + ok = rpc:call(Node, heart, set_options, [[]]), + none = rpc:call(Node, heart, get_options, []), + stop_node(Node), + ok. + + dont_drop(suite) -> %%% Removed as it may crash epmd/distribution in colourful %%% ways. While we ARE finding out WHY, it would diff --git a/lib/observer/test/crashdump_viewer_SUITE.erl b/lib/observer/test/crashdump_viewer_SUITE.erl index 84af440245..eae4ee01b9 100644 --- a/lib/observer/test/crashdump_viewer_SUITE.erl +++ b/lib/observer/test/crashdump_viewer_SUITE.erl @@ -564,22 +564,11 @@ dump_with_strange_module_name(DataDir,Rel,DumpName) -> CD. dump(Node,DataDir,Rel,DumpName) -> + Crashdump = filename:join(DataDir, dump_prefix(Rel)++DumpName), + rpc:call(Node,os,putenv,["ERL_CRASH_DUMP",Crashdump]), rpc:call(Node,erlang,halt,[DumpName]), - Crashdump0 = filename:join(filename:dirname(code:which(?t)), - "erl_crash_dump.n1"), - Crashdump1 = filename:join(DataDir, dump_prefix(Rel)++DumpName), - ok = rename(Crashdump0,Crashdump1), - Crashdump1. - -rename(From,To) -> - ok = check_complete(From), - case file:rename(From,To) of - {error,exdev} -> - {ok,_} = file:copy(From,To), - ok = file:delete(From); - ok -> - ok - end. + ok = check_complete(Crashdump), + Crashdump. check_complete(File) -> check_complete1(File,10). diff --git a/lib/public_key/src/pubkey_pem.erl b/lib/public_key/src/pubkey_pem.erl index 6a722b0525..d163004c7c 100644 --- a/lib/public_key/src/pubkey_pem.erl +++ b/lib/public_key/src/pubkey_pem.erl @@ -103,7 +103,7 @@ encode_pem_entry({'PrivateKeyInfo', Der, EncParams}) -> [StartStr, "\n", b64encode_and_split(EncDer), "\n", pem_end(StartStr) ,"\n\n"]; encode_pem_entry({Type, Der, {Cipher, Salt}}) -> StartStr = pem_start(Type), - [StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n", + [StartStr,"\n", pem_decrypt(),"\n", pem_decrypt_info(Cipher, Salt),"\n\n", b64encode_and_split(Der), "\n", pem_end(StartStr) ,"\n\n"]. decode_pem_entries([], Entries) -> diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl index 5e677f31d6..ea5e036a7e 100644 --- a/lib/public_key/test/public_key_SUITE.erl +++ b/lib/public_key/test/public_key_SUITE.erl @@ -189,6 +189,8 @@ encrypted_pem(Config) when is_list(Config) -> erl_make_certs:der_to_pem(DesKeyFile, [Entry1]), [{'RSAPrivateKey', _, {"DES-CBC", Salt1}} =Entry2] = erl_make_certs:pem_to_der(DesKeyFile), + {ok, Pem} = file:read_file(DesKeyFile), + check_encapsulated_header(Pem), true = check_entry_type(public_key:pem_entry_decode(Entry2, "4567efgh"), 'RSAPrivateKey'). @@ -826,6 +828,15 @@ check_entry_type(#'Certificate'{}, 'Certificate') -> check_entry_type(_,_) -> false. +check_encapsulated_header(Pem) when is_binary(Pem)-> + check_encapsulated_header( binary:split(Pem, <<"\n">>, [global])); +check_encapsulated_header([<<"DEK-Info: DES-CBC,FB7577791A9056A1">>, <<>> | _]) -> + true; +check_encapsulated_header([ _ | Rest]) -> + check_encapsulated_header(Rest); +check_encapsulated_header([]) -> + false. + strip_ending_newlines(Bin) -> string:strip(binary_to_list(Bin), right, 10). diff --git a/lib/runtime_tools/c_src/trace_file_drv.c b/lib/runtime_tools/c_src/trace_file_drv.c index a63a7d3ad9..8863b0d6ac 100644 --- a/lib/runtime_tools/c_src/trace_file_drv.c +++ b/lib/runtime_tools/c_src/trace_file_drv.c @@ -75,12 +75,8 @@ #ifdef DEBUG -#ifndef __WIN32__ -#define ASSERT(X) do {if (!(X)) {erl_exit(1,"%s",#X);} } while(0) -#else #include <assert.h> #define ASSERT(X) assert(X) -#endif #else #define ASSERT(X) #endif diff --git a/lib/runtime_tools/c_src/trace_ip_drv.c b/lib/runtime_tools/c_src/trace_ip_drv.c index f7b5ea65cb..5b43f8179e 100644 --- a/lib/runtime_tools/c_src/trace_ip_drv.c +++ b/lib/runtime_tools/c_src/trace_ip_drv.c @@ -44,19 +44,8 @@ #endif #ifdef DEBUG -# ifndef __WIN32__ - /* erl_exit is not available to dll_drivers on windows. */ - void erl_exit(int, char *, ...); -# define ASSERT(X) \ - do { \ - if (!(X)) { \ - erl_exit(1,"%s",#X); \ - } \ - } while(0) -# else -# include <assert.h> -# define ASSERT(X) assert(X) -# endif +# include <assert.h> +# define ASSERT(X) assert(X) #else # define ASSERT(X) #endif diff --git a/lib/sasl/src/sasl.appup.src b/lib/sasl/src/sasl.appup.src index 8faa0afbd4..e08ae369b8 100644 --- a/lib/sasl/src/sasl.appup.src +++ b/lib/sasl/src/sasl.appup.src @@ -18,9 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"2\\.[5-6](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* {<<"2\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}], % OTP-17 %% Down to - max one major revision back - [{<<"2\\.[5-6](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* {<<"2\\.4(\\.[0-9]+)*">>,[restart_new_emulator]}] % OTP-17 }. diff --git a/lib/ssh/doc/src/ssh_sftp.xml b/lib/ssh/doc/src/ssh_sftp.xml index c6ca0f161a..f4b41b74f3 100644 --- a/lib/ssh/doc/src/ssh_sftp.xml +++ b/lib/ssh/doc/src/ssh_sftp.xml @@ -333,7 +333,7 @@ <func> <name>position(ChannelPid, Handle, Location) -></name> - <name>position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition | {error, Error}</name> + <name>position(ChannelPid, Handle, Location, Timeout) -> {ok, NewPosition} | {error, Reason}</name> <fsummary>Sets the file position of a file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -399,7 +399,7 @@ <func> <name>pwrite(ChannelPid, Handle, Position, Data) -> ok</name> - <name>pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, Error}</name> + <name>pwrite(ChannelPid, Handle, Position, Data, Timeout) -> ok | {error, Reason}</name> <fsummary>Writes to an open file.</fsummary> <type> <v>ChannelPid = pid()</v> @@ -592,7 +592,7 @@ <func> <name>write(ChannelPid, Handle, Data) -></name> - <name>write(ChannelPid, Handle, Data, Timeout) -> ok | {error, Error}</name> + <name>write(ChannelPid, Handle, Data, Timeout) -> ok | {error, Reason}</name> <fsummary>Writes to an open file.</fsummary> <type> <v>ChannelPid = pid()</v> diff --git a/lib/ssh/test/ssh_algorithms_SUITE.erl b/lib/ssh/test/ssh_algorithms_SUITE.erl index f0ac92fef6..49ed15698c 100644 --- a/lib/ssh/test/ssh_algorithms_SUITE.erl +++ b/lib/ssh/test/ssh_algorithms_SUITE.erl @@ -35,7 +35,8 @@ %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,10}}]. all() -> %% [{group,kex},{group,cipher}... etc @@ -90,18 +91,12 @@ init_per_suite(Config) -> ?MAX_NUM_ALGORITHMS ]), ct:log("all() ->~n ~p.~n~ngroups()->~n ~p.~n",[all(),groups()]), - catch crypto:stop(), - case catch crypto:start() of - ok -> - ssh:start(), - [{std_simple_sftp_size,25000} % Sftp transferred data size - | setup_pubkey(Config)]; - _Else -> - {skip, "Crypto could not be started!"} - end. + ssh:start(), + [{std_simple_sftp_size,25000} % Sftp transferred data size + | setup_pubkey(Config)]. + end_per_suite(_Config) -> - ssh:stop(), - crypto:stop(). + ssh:stop(). init_per_group(Group, Config) -> @@ -231,8 +226,11 @@ sshc_simple_exec(Config) -> " ",Host," 1+1."]), ct:log("~p",[Cmd]), SshPort = open_port({spawn, Cmd}, [binary]), + Expect = <<"2\n">>, receive - {SshPort,{data, <<"2\n">>}} -> + {SshPort, {data,Expect}} -> + ct:log("Got expected ~p from ~p",[Expect,SshPort]), + catch port_close(SshPort), ok after ?TIMEOUT -> ct:fail("Did not receive answer") @@ -273,7 +271,9 @@ sshd_simple_exec(_Config) -> ConnectionRef, ChannelId1); Other1 -> ct:fail(Other1) - end. + end, + ssh:close(ConnectionRef). + %%%================================================================ %%% diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 4b53f6ec57..094d28e879 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -78,7 +78,8 @@ %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,10}}]. all() -> [app_test, @@ -129,16 +130,11 @@ basic_tests() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - Config; - _Else -> - {skip, "Crypto could not be started!"} - end. + Config. + end_per_suite(_Config) -> - ssh:stop(), - crypto:stop(). + ssh:stop(). + %%-------------------------------------------------------------------- init_per_group(dsa_key, Config) -> DataDir = ?config(data_dir, Config), @@ -441,6 +437,7 @@ exec(Config) when is_list(Config) -> ct:fail(Other1) end, ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId1), + ssh:close(ConnectionRef), ssh:stop_daemon(Pid). %%-------------------------------------------------------------------- @@ -474,6 +471,7 @@ exec_compressed(Config) when is_list(Config) -> ct:fail(Other) end, ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), + ssh:close(ConnectionRef), ssh:stop_daemon(Pid) end. @@ -979,7 +977,10 @@ shell_no_unicode(Config) -> new_do_shell(?config(io,Config), [new_prompt, {type,"io:format(\"hej ~p~n\",[42])."}, - {expect,"hej 42"} + {expect,"hej 42"}, + {expect,"ok"}, + new_prompt, + {type,"exit()."} ]). %%-------------------------------------------------------------------- @@ -988,7 +989,9 @@ shell_unicode_string(Config) -> [new_prompt, {type,"io:format(\"こにちわ~ts~n\",[\"四二\"])."}, {expect,"こにちわ四二"}, - {expect,"ok"} + {expect,"ok"}, + new_prompt, + {type,"exit()."} ]). %%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_benchmark_SUITE.erl b/lib/ssh/test/ssh_benchmark_SUITE.erl index e90bfa3d16..fe90da3028 100644 --- a/lib/ssh/test/ssh_benchmark_SUITE.erl +++ b/lib/ssh/test/ssh_benchmark_SUITE.erl @@ -44,9 +44,7 @@ groups() -> init_per_suite(Config) -> catch ssh:stop(), - catch crypto:stop(), try - ok = crypto:start(), report_client_algorithms(), ok = ssh:start(), {ok,TracerPid} = erlang_trace(), @@ -58,7 +56,6 @@ init_per_suite(Config) -> end_per_suite(_Config) -> catch ssh:stop(), - catch crypto:stop(), ok. @@ -406,7 +403,7 @@ function_algs_times_sizes(EncDecs, L) -> end || EncDec <- EncDecs, C = #call{mfa = ED, - args = Args, %%[S,Data], + % args = Args, %%[S,Data], t_call = T0, t_return = T1} <- L, ED == EncDec diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl index 1b93cc9c32..6e90faf0e8 100644 --- a/lib/ssh/test/ssh_connection_SUITE.erl +++ b/lib/ssh/test/ssh_connection_SUITE.erl @@ -36,6 +36,9 @@ %% suite() -> %% [{ct_hooks,[ts_install_cth]}]. +suite() -> + [{timetrap,{minutes,2}}]. + all() -> [ {group, openssh}, @@ -67,16 +70,10 @@ ptty() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - Config; - _Else -> - {skip, "Crypto could not be started!"} - end. + Config. -end_per_suite(_Config) -> - crypto:stop(). +end_per_suite(Config) -> + Config. %%-------------------------------------------------------------------- init_per_group(openssh, Config) -> diff --git a/lib/ssh/test/ssh_options_SUITE.erl b/lib/ssh/test/ssh_options_SUITE.erl index 6a201d401f..ba0107efd6 100644 --- a/lib/ssh/test/ssh_options_SUITE.erl +++ b/lib/ssh/test/ssh_options_SUITE.erl @@ -79,7 +79,8 @@ %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,6}}]. all() -> [connectfun_disconnectfun_server, @@ -125,16 +126,11 @@ groups() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - Config; - _Else -> - {skip, "Crypto could not be started!"} - end. + Config. + end_per_suite(_Config) -> - ssh:stop(), - crypto:stop(). + ssh:stop(). + %%-------------------------------------------------------------------- init_per_group(hardening_tests, Config) -> DataDir = ?config(data_dir, Config), diff --git a/lib/ssh/test/ssh_protocol_SUITE.erl b/lib/ssh/test/ssh_protocol_SUITE.erl index fe197f8672..44da0f4d6f 100644 --- a/lib/ssh/test/ssh_protocol_SUITE.erl +++ b/lib/ssh/test/ssh_protocol_SUITE.erl @@ -42,7 +42,8 @@ %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,2}}]. all() -> [{group,tool_tests}, @@ -579,23 +580,11 @@ client_handles_keyboard_interactive_0_pwds(Config) -> %%%---- init_suite and end_suite --------------------------------------- start_apps(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - catch ssh:stop(), - ok = ssh:start(), - [{stop_apps, - fun() -> - ssh:stop(), - crypto:stop() - end} | Config]; - _Else -> - {skip, "Crypto could not be started!"} - end. - + catch ssh:stop(), + ok = ssh:start(), + Config. -stop_apps(Config) -> - (?v(stop_apps, Config, fun()-> ok end))(), +stop_apps(_Config) -> ssh:stop(). diff --git a/lib/ssh/test/ssh_renegotiate_SUITE.erl b/lib/ssh/test/ssh_renegotiate_SUITE.erl index e5cfa58bad..6d2c97aa68 100644 --- a/lib/ssh/test/ssh_renegotiate_SUITE.erl +++ b/lib/ssh/test/ssh_renegotiate_SUITE.erl @@ -30,7 +30,9 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- -suite() -> [{ct_hooks,[ts_install_cth]}]. +suite() -> [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,12}}]. + all() -> [{group,default_algs}, {group,aes_gcm} @@ -44,16 +46,10 @@ tests() -> [rekey, rekey_limit, renegotiate1, renegotiate2]. %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - Config; - _Else -> - {skip, "Crypto could not be started!"} - end. + Config. + end_per_suite(_Config) -> - ssh:stop(), - crypto:stop(). + ssh:stop(). %%-------------------------------------------------------------------- init_per_group(aes_gcm, Config) -> diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl index 698af259c8..c2b04d7a05 100644 --- a/lib/ssh/test/ssh_sftp_SUITE.erl +++ b/lib/ssh/test/ssh_sftp_SUITE.erl @@ -35,7 +35,9 @@ %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,2}}]. + all() -> [{group, not_unicode}, @@ -44,22 +46,14 @@ all() -> init_per_suite(Config) -> - catch crypto:stop(), - case (catch crypto:start()) of - ok -> - ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p", - [file:native_name_encoding(),io:getopts()]), - ssh:start(), - Config; - _ -> - {skip,"Could not start crypto!"} - end. - -end_per_suite(Config) -> - ssh:stop(), - crypto:stop(), + ct:log("file:native_name_encoding() = ~p,~nio:getopts() = ~p", + [file:native_name_encoding(),io:getopts()]), + ssh:start(), Config. +end_per_suite(_onfig) -> + ssh:stop(). + %%-------------------------------------------------------------------- groups() -> [{not_unicode, [], [{group,erlang_server}, diff --git a/lib/ssh/test/ssh_sftpd_SUITE.erl b/lib/ssh/test/ssh_sftpd_SUITE.erl index 6b03a2b763..45439ce0fa 100644 --- a/lib/ssh/test/ssh_sftpd_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_SUITE.erl @@ -44,6 +44,9 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- +suite() -> + [{timetrap,{minutes,3}}]. + all() -> [open_close_file, open_close_dir, @@ -69,28 +72,21 @@ groups() -> %%-------------------------------------------------------------------- init_per_suite(Config) -> - catch crypto:stop(), - case (catch crypto:start()) of - ok -> - DataDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - ssh_test_lib:setup_dsa(DataDir, PrivDir), - %% to make sure we don't use public-key-auth - %% this should be tested by other test suites - UserDir = filename:join(?config(priv_dir, Config), nopubkey), - file:make_dir(UserDir), - Config; - _ -> - {skip,"Could not start crypto!"} - end. + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + %% to make sure we don't use public-key-auth + %% this should be tested by other test suites + UserDir = filename:join(?config(priv_dir, Config), nopubkey), + file:make_dir(UserDir), + Config. end_per_suite(Config) -> SysDir = ?config(priv_dir, Config), ssh_test_lib:clean_dsa(SysDir), UserDir = filename:join(?config(priv_dir, Config), nopubkey), file:del_dir(UserDir), - ssh:stop(), - crypto:stop(). + ssh:stop(). %%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl index 7a025a6518..02a2ac4cf9 100644 --- a/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl +++ b/lib/ssh/test/ssh_sftpd_erlclient_SUITE.erl @@ -36,7 +36,9 @@ %%-------------------------------------------------------------------- suite() -> - [{ct_hooks,[ts_install_cth]}]. + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,2}}]. + all() -> [close_file, @@ -53,29 +55,22 @@ groups() -> init_per_suite(Config) -> catch ssh:stop(), - catch crypto:stop(), - case catch crypto:start() of - ok -> - DataDir = ?config(data_dir, Config), - PrivDir = ?config(priv_dir, Config), - FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), - c:c(FileAlt), - FileName = filename:join(DataDir, "test.txt"), - {ok, FileInfo} = file:read_file_info(FileName), - ok = file:write_file_info(FileName, - FileInfo#file_info{mode = 8#400}), - ssh_test_lib:setup_dsa(DataDir, PrivDir), - Config; - _Else -> - {skip,"Could not start ssh!"} - end. + DataDir = ?config(data_dir, Config), + PrivDir = ?config(priv_dir, Config), + FileAlt = filename:join(DataDir, "ssh_sftpd_file_alt.erl"), + c:c(FileAlt), + FileName = filename:join(DataDir, "test.txt"), + {ok, FileInfo} = file:read_file_info(FileName), + ok = file:write_file_info(FileName, + FileInfo#file_info{mode = 8#400}), + ssh_test_lib:setup_dsa(DataDir, PrivDir), + Config. end_per_suite(Config) -> UserDir = filename:join(?config(priv_dir, Config), nopubkey), file:del_dir(UserDir), SysDir = ?config(priv_dir, Config), ssh_test_lib:clean_dsa(SysDir), - crypto:stop(), ok. %%-------------------------------------------------------------------- diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl index 5c77fcf1ef..18e91a9af3 100644 --- a/lib/ssh/test/ssh_sup_SUITE.erl +++ b/lib/ssh/test/ssh_sup_SUITE.erl @@ -34,6 +34,10 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- +suite() -> + [{ct_hooks,[ts_install_cth]}, + {timetrap,{minutes,1}}]. + all() -> [default_tree, sshc_subtree, sshd_subtree, sshd_subtree_profile]. diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl index 2db55b97b4..5f91fb627a 100644 --- a/lib/ssh/test/ssh_test_lib.erl +++ b/lib/ssh/test/ssh_test_lib.erl @@ -120,7 +120,8 @@ std_simple_exec(Host, Port, Config, Opts) -> Other -> ct:fail(Other) end, - ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId). + ssh_test_lib:receive_exec_end(ConnectionRef, ChannelId), + ssh:close(ConnectionRef). start_shell(Port, IOServer, UserDir) -> @@ -154,14 +155,12 @@ loop_io_server(TestCase, Buff0) -> {input, TestCase, Line} -> loop_io_server(TestCase, Buff0 ++ [Line]); {io_request, From, ReplyAs, Request} -> -%%ct:log("~p",[{io_request, From, ReplyAs, Request}]), {ok, Reply, Buff} = io_request(Request, TestCase, From, ReplyAs, Buff0), -%%ct:log("io_request(~p)-->~p",[Request,{ok, Reply, Buff}]), io_reply(From, ReplyAs, Reply), loop_io_server(TestCase, Buff); - {'EXIT',_, _} -> - erlang:display('ssh_test_lib:loop_io_server/2 EXIT'), + {'EXIT',_, _} = _Exit -> +%% ct:log("ssh_test_lib:loop_io_server/2 got ~p",[_Exit]), ok after 30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE]) diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl index 67a61d3c11..2788bc6b58 100644 --- a/lib/ssh/test/ssh_to_openssh_SUITE.erl +++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl @@ -33,6 +33,9 @@ %% Common Test interface functions ----------------------------------- %%-------------------------------------------------------------------- +suite() -> + [{timetrap,{minutes,1}}]. + all() -> case os:find_executable("ssh") of false -> @@ -57,21 +60,14 @@ groups() -> ]. init_per_suite(Config) -> - catch crypto:stop(), - case catch crypto:start() of - ok -> - case gen_tcp:connect("localhost", 22, []) of - {error,econnrefused} -> - {skip,"No openssh deamon"}; - _ -> - ssh_test_lib:openssh_sanity_check(Config) - end; - _Else -> - {skip,"Could not start crypto!"} + case gen_tcp:connect("localhost", 22, []) of + {error,econnrefused} -> + {skip,"No openssh deamon"}; + _ -> + ssh_test_lib:openssh_sanity_check(Config) end. end_per_suite(_Config) -> - crypto:stop(), ok. init_per_group(erlang_server, Config) -> diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl index 85f4d36258..bf8874b118 100644 --- a/lib/ssh/test/ssh_upgrade_SUITE.erl +++ b/lib/ssh/test/ssh_upgrade_SUITE.erl @@ -38,6 +38,9 @@ %%% %%% CommonTest callbacks %%% +suite() -> + [{timetrap,{minutes,2}}]. + all() -> [ minor_upgrade, @@ -45,27 +48,17 @@ all() -> ]. init_per_suite(Config0) -> - catch crypto:stop(), - try {crypto:start(), erlang:system_info({wordsize, internal}) == - erlang:system_info({wordsize, external})} of - {ok, true} -> - case ct_release_test:init(Config0) of - {skip, Reason} -> - {skip, Reason}; - Config -> - ssh:start(), - Config - end; - {ok, false} -> - {skip, "Test server will not handle halfwordemulator correctly. Skip as halfwordemulator is deprecated"} - catch _:_ -> - {skip, "Crypto did not start"} + case ct_release_test:init(Config0) of + {skip, Reason} -> + {skip, Reason}; + Config -> + ssh:start(), + Config end. end_per_suite(Config) -> ct_release_test:cleanup(Config), ssh:stop(), - crypto:stop(), UserDir = ?config(priv_dir, Config), ssh_test_lib:clean_rsa(UserDir). diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index 55d12abffe..41b42d454b 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 4.2.1 +SSH_VSN = 4.2.2 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml index d3881ad117..a76d46ee9b 100644 --- a/lib/ssl/doc/src/ssl.xml +++ b/lib/ssl/doc/src/ssl.xml @@ -271,7 +271,11 @@ atom()}} | terminate regarding verification failures and the connection is established.</p></item> <item><p>If called with an extension unknown to the user application, - return value <c>{unknown, UserState}</c> is to be used.</p></item> + return value <c>{unknown, UserState}</c> is to be used.</p> + + <p>Note that if the fun returns <c>unknown</c> for an extension marked + as critical, validation will fail.</p> + </item> </list> <p>Default option <c>verify_fun</c> in <c>verify_peer mode</c>:</p> @@ -293,6 +297,8 @@ atom()}} | <code> {fun(_,{bad_cert, _}, UserState) -> {valid, UserState}; + (_,{extension, #'Extension'{critical = true}}, UserState) -> + {valid, UserState}; (_,{extension, _}, UserState) -> {unknown, UserState}; (_, valid, UserState) -> diff --git a/lib/ssl/doc/src/ssl_distribution.xml b/lib/ssl/doc/src/ssl_distribution.xml index a347ce5ae6..dc04d446b0 100644 --- a/lib/ssl/doc/src/ssl_distribution.xml +++ b/lib/ssl/doc/src/ssl_distribution.xml @@ -271,4 +271,27 @@ Eshell V5.0 (abort with ^G) <p>The <c>init:get_arguments()</c> call verifies that the correct arguments are supplied to the emulator.</p> </section> + + <section> + <title>Using SSL distribution over IPv6</title> + <p>It is possible to use SSL distribution over IPv6 instead of + IPv4. To do this, pass the option <c>-proto_dist inet6_tls</c> + instead of <c>-proto_dist inet_tls</c> when starting Erlang, + either on the command line or in the <c>ERL_FLAGS</c> environment + variable.</p> + + <p>An example command line with this option would look like this:</p> + <code type="none"> +$ erl -boot /home/me/ssl/start_ssl -proto_dist inet6_tls + -ssl_dist_opt server_certfile "/home/me/ssl/erlserver.pem" + -ssl_dist_opt server_secure_renegotiate true client_secure_renegotiate true + -sname ssl_test +Erlang (BEAM) emulator version 5.0 [source] + +Eshell V5.0 (abort with ^G) +(ssl_test@myhost)1> </code> + + <p>A node started in this way will only be able to communicate with + other nodes using SSL distribution over IPv6.</p> + </section> </chapter> diff --git a/lib/ssl/examples/src/client_server.erl b/lib/ssl/examples/src/client_server.erl index 799027123f..019b5130d2 100644 --- a/lib/ssl/examples/src/client_server.erl +++ b/lib/ssl/examples/src/client_server.erl @@ -26,9 +26,7 @@ start() -> %% Start ssl application - application:start(crypto), - application:start(public_key), - application:start(ssl), + {ok, StartedApps} = application:ensure_all_started(ssl), %% Let the current process be the server that listens and accepts %% Listen @@ -52,7 +50,8 @@ start() -> ssl:close(ASock), io:fwrite("Listen: closing and terminating.~n"), ssl:close(LSock), - application:stop(ssl). + + lists:foreach(fun application:stop/1, lists:reverse(StartedApps)). %% Client connect diff --git a/lib/ssl/src/Makefile b/lib/ssl/src/Makefile index 790328dc45..7a7a373487 100644 --- a/lib/ssl/src/Makefile +++ b/lib/ssl/src/Makefile @@ -51,6 +51,7 @@ MODULES= \ ssl_dist_sup\ ssl_sup \ inet_tls_dist \ + inet6_tls_dist \ ssl_certificate\ ssl_pkix_db\ ssl_cipher \ diff --git a/lib/ssl/src/inet6_tls_dist.erl b/lib/ssl/src/inet6_tls_dist.erl new file mode 100644 index 0000000000..ffd7296f93 --- /dev/null +++ b/lib/ssl/src/inet6_tls_dist.erl @@ -0,0 +1,46 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015. All Rights Reserved. +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +%% +%% %CopyrightEnd% +%% + +%% +-module(inet6_tls_dist). + +-export([childspecs/0, listen/1, accept/1, accept_connection/5, + setup/5, close/1, select/1]). + +childspecs() -> + inet_tls_dist:childspecs(). + +select(Node) -> + inet_tls_dist:gen_select(inet6_tcp, Node). + +listen(Name) -> + inet_tls_dist:gen_listen(inet6_tcp, Name). + +accept(Listen) -> + inet_tls_dist:gen_accept(inet6_tcp, Listen). + +accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> + inet_tls_dist:gen_accept_connection(inet6_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). + +setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> + inet_tls_dist:gen_setup(inet6_tcp, Node, Type, MyNode, LongOrShortNames,SetupTime). + +close(Socket) -> + inet_tls_dist:close(Socket). diff --git a/lib/ssl/src/inet_tls_dist.erl b/lib/ssl/src/inet_tls_dist.erl index 6fe99a81c5..ec26142a75 100644 --- a/lib/ssl/src/inet_tls_dist.erl +++ b/lib/ssl/src/inet_tls_dist.erl @@ -24,6 +24,10 @@ -export([childspecs/0, listen/1, accept/1, accept_connection/5, setup/5, close/1, select/1, is_node_name/1]). +%% Generalized dist API +-export([gen_listen/2, gen_accept/2, gen_accept_connection/6, + gen_setup/6, gen_select/2]). + -include_lib("kernel/include/net_address.hrl"). -include_lib("kernel/include/dist.hrl"). -include_lib("kernel/include/dist_util.hrl"). @@ -33,9 +37,15 @@ childspecs() -> permanent, infinity, supervisor, [ssl_dist_sup]}]}. select(Node) -> + gen_select(inet_tcp, Node). + +gen_select(Driver, Node) -> case split_node(atom_to_list(Node), $@, []) of - [_,_Host] -> - true; + [_, Host] -> + case inet:getaddr(Host, Driver:family()) of + {ok, _} -> true; + _ -> false + end; _ -> false end. @@ -46,23 +56,35 @@ is_node_name(_) -> false. listen(Name) -> - ssl_tls_dist_proxy:listen(Name). + gen_listen(inet_tcp, Name). + +gen_listen(Driver, Name) -> + ssl_tls_dist_proxy:listen(Driver, Name). accept(Listen) -> - ssl_tls_dist_proxy:accept(Listen). + gen_accept(inet_tcp, Listen). + +gen_accept(Driver, Listen) -> + ssl_tls_dist_proxy:accept(Driver, Listen). accept_connection(AcceptPid, Socket, MyNode, Allowed, SetupTime) -> + gen_accept_connection(inet_tcp, AcceptPid, Socket, MyNode, Allowed, SetupTime). + +gen_accept_connection(Driver, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> Kernel = self(), - spawn_link(fun() -> do_accept(Kernel, AcceptPid, Socket, + spawn_link(fun() -> do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) end). setup(Node, Type, MyNode, LongOrShortNames,SetupTime) -> + gen_setup(inet_tcp, Node, Type, MyNode, LongOrShortNames,SetupTime). + +gen_setup(Driver, Node, Type, MyNode, LongOrShortNames,SetupTime) -> Kernel = self(), - spawn_opt(fun() -> do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end, [link, {priority, max}]). + spawn_opt(fun() -> do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) end, [link, {priority, max}]). -do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> - [Name, Address] = splitnode(Node, LongOrShortNames), - case inet:getaddr(Address, inet) of +do_setup(Driver, Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> + [Name, Address] = splitnode(Driver, Node, LongOrShortNames), + case inet:getaddr(Address, Driver:family()) of {ok, Ip} -> Timer = dist_util:start_timer(SetupTime), case erl_epmd:port_please(Name, Ip) of @@ -70,7 +92,7 @@ do_setup(Kernel, Node, Type, MyNode, LongOrShortNames, SetupTime) -> ?trace("port_please(~p) -> version ~p~n", [Node,Version]), dist_util:reset_timer(Timer), - case ssl_tls_dist_proxy:connect(Ip, TcpPort) of + case ssl_tls_dist_proxy:connect(Driver, Ip, TcpPort) of {ok, Socket} -> HSData = connect_hs_data(Kernel, Node, MyNode, Socket, Timer, Version, Ip, TcpPort, Address, @@ -99,12 +121,12 @@ close(Socket) -> gen_tcp:close(Socket), ok. -do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> +do_accept(Driver, Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> process_flag(priority, max), receive {AcceptPid, controller} -> Timer = dist_util:start_timer(SetupTime), - case check_ip(Socket) of + case check_ip(Driver, Socket) of true -> HSData = accept_hs_data(Kernel, MyNode, Socket, Timer, Allowed), dist_util:handshake_other_started(HSData); @@ -118,12 +140,12 @@ do_accept(Kernel, AcceptPid, Socket, MyNode, Allowed, SetupTime) -> %% Do only accept new connection attempts from nodes at our %% own LAN, if the check_ip environment parameter is true. %% ------------------------------------------------------------ -check_ip(Socket) -> +check_ip(Driver, Socket) -> case application:get_env(check_ip) of {ok, true} -> case get_ifs(Socket) of {ok, IFs, IP} -> - check_ip(IFs, IP); + check_ip(Driver, IFs, IP); _ -> ?shutdown(no_node) end; @@ -142,37 +164,21 @@ get_ifs(Socket) -> Error end. -check_ip([{OwnIP, _, Netmask}|IFs], PeerIP) -> - case {mask(Netmask, PeerIP), mask(Netmask, OwnIP)} of +check_ip(Driver, [{OwnIP, _, Netmask}|IFs], PeerIP) -> + case {Driver:mask(Netmask, PeerIP), Driver:mask(Netmask, OwnIP)} of {M, M} -> true; _ -> check_ip(IFs, PeerIP) end; -check_ip([], PeerIP) -> +check_ip(_Driver, [], PeerIP) -> {false, PeerIP}. -mask({M1,M2,M3,M4}, {IP1,IP2,IP3,IP4}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4}; - -mask({M1,M2,M3,M4, M5, M6, M7, M8}, {IP1,IP2,IP3,IP4, IP5, IP6, IP7, IP8}) -> - {M1 band IP1, - M2 band IP2, - M3 band IP3, - M4 band IP4, - M5 band IP5, - M6 band IP6, - M7 band IP7, - M8 band IP8}. - %% If Node is illegal terminate the connection setup!! -splitnode(Node, LongOrShortNames) -> +splitnode(Driver, Node, LongOrShortNames) -> case split_node(atom_to_list(Node), $@, []) of [Name|Tail] when Tail =/= [] -> Host = lists:append(Tail), - check_node(Name, Node, Host, LongOrShortNames); + check_node(Driver, Name, Node, Host, LongOrShortNames); [_] -> error_logger:error_msg("** Nodename ~p illegal, no '@' character **~n", [Node]), @@ -182,15 +188,20 @@ splitnode(Node, LongOrShortNames) -> ?shutdown(Node) end. -check_node(Name, Node, Host, LongOrShortNames) -> +check_node(Driver, Name, Node, Host, LongOrShortNames) -> case split_node(Host, $., []) of [_] when LongOrShortNames == longnames -> - error_logger:error_msg("** System running to use " - "fully qualified " - "hostnames **~n" - "** Hostname ~s is illegal **~n", - [Host]), - ?shutdown(Node); + case Driver:parse_address(Host) of + {ok, _} -> + [Name, Host]; + _ -> + error_logger:error_msg("** System running to use " + "fully qualified " + "hostnames **~n" + "** Hostname ~s is illegal **~n", + [Host]), + ?shutdown(Node) + end; [_, _ | _] when LongOrShortNames == shortnames -> error_logger:error_msg("** System NOT running to use fully qualified " "hostnames **~n" diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src index 619ab7b610..1a2bf90ccf 100644 --- a/lib/ssl/src/ssl.app.src +++ b/lib/ssl/src/ssl.app.src @@ -31,6 +31,7 @@ ssl_listen_tracker_sup, %% Erlang Distribution over SSL/TLS inet_tls_dist, + inet6_tls_dist, ssl_tls_dist_proxy, ssl_dist_sup, %% SSL/TLS session handling diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl index c1bc90559e..780bef5877 100644 --- a/lib/ssl/src/ssl.erl +++ b/lib/ssl/src/ssl.erl @@ -60,22 +60,19 @@ -spec start() -> ok | {error, reason()}. -spec start(permanent | transient | temporary) -> ok | {error, reason()}. %% -%% Description: Utility function that starts the ssl, -%% crypto and public_key applications. Default type -%% is temporary. see application(3) +%% Description: Utility function that starts the ssl and applications +%% that it depends on. +%% see application(3) %%-------------------------------------------------------------------- start() -> - application:start(crypto), - application:start(asn1), - application:start(public_key), - application:start(ssl). - + start(temporary). start(Type) -> - application:start(crypto, Type), - application:start(asn1), - application:start(public_key, Type), - application:start(ssl, Type). - + case application:ensure_all_started(ssl, Type) of + {ok, _} -> + ok; + Other -> + Other + end. %%-------------------------------------------------------------------- -spec stop() -> ok. %% @@ -1296,6 +1293,12 @@ handle_verify_options(Opts, CaCerts) -> DefaultVerifyNoneFun = {fun(_,{bad_cert, _}, UserState) -> {valid, UserState}; + (_,{extension, #'Extension'{critical = true}}, UserState) -> + %% This extension is marked as critical, so + %% certificate verification should fail if we don't + %% understand the extension. However, this is + %% `verify_none', so let's accept it anyway. + {valid, UserState}; (_,{extension, _}, UserState) -> {unknown, UserState}; (_, valid, UserState) -> diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl index e9e140836b..e98073080a 100644 --- a/lib/ssl/src/ssl_handshake.erl +++ b/lib/ssl/src/ssl_handshake.erl @@ -2072,12 +2072,9 @@ crl_check(OtpCert, Check, CertDbHandle, CertDbRef, {Callback, CRLDbHandle}, _) - ], case dps_and_crls(OtpCert, Callback, CRLDbHandle, ext) of no_dps -> - case dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer) of - [] -> - valid; %% No relevant CRL existed - DpsAndCRls -> - crl_check_same_issuer(OtpCert, Check, DpsAndCRls, Options) - end; + crl_check_same_issuer(OtpCert, Check, + dps_and_crls(OtpCert, Callback, CRLDbHandle, same_issuer), + Options); DpsAndCRLs -> %% This DP list may be empty if relevant CRLs existed %% but could not be retrived, will result in {bad_cert, revocation_status_undetermined} case public_key:pkix_crls_validate(OtpCert, DpsAndCRLs, Options) of diff --git a/lib/ssl/src/ssl_tls_dist_proxy.erl b/lib/ssl/src/ssl_tls_dist_proxy.erl index 211badef56..4c789793ec 100644 --- a/lib/ssl/src/ssl_tls_dist_proxy.erl +++ b/lib/ssl/src/ssl_tls_dist_proxy.erl @@ -20,7 +20,7 @@ -module(ssl_tls_dist_proxy). --export([listen/1, accept/1, connect/2, get_tcp_address/1]). +-export([listen/2, accept/2, connect/3, get_tcp_address/1]). -export([init/1, start_link/0, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3, ssl_options/2]). @@ -39,14 +39,14 @@ %% Internal application API %%==================================================================== -listen(Name) -> - gen_server:call(?MODULE, {listen, Name}, infinity). +listen(Driver, Name) -> + gen_server:call(?MODULE, {listen, Driver, Name}, infinity). -accept(Listen) -> - gen_server:call(?MODULE, {accept, Listen}, infinity). +accept(Driver, Listen) -> + gen_server:call(?MODULE, {accept, Driver, Listen}, infinity). -connect(Ip, Port) -> - gen_server:call(?MODULE, {connect, Ip, Port}, infinity). +connect(Driver, Ip, Port) -> + gen_server:call(?MODULE, {connect, Driver, Ip, Port}, infinity). do_listen(Options) -> @@ -108,10 +108,11 @@ init([]) -> process_flag(priority, max), {ok, #state{}}. -handle_call({listen, Name}, _From, State) -> +handle_call({listen, Driver, Name}, _From, State) -> case gen_tcp:listen(0, [{active, false}, {packet,?PPRE}, {ip, loopback}]) of {ok, Socket} -> - {ok, World} = do_listen([{active, false}, binary, {packet,?PPRE}, {reuseaddr, true}]), + {ok, World} = do_listen([{active, false}, binary, {packet,?PPRE}, {reuseaddr, true}, + Driver:family()]), {ok, TcpAddress} = get_tcp_address(Socket), {ok, WorldTcpAddress} = get_tcp_address(World), {_,Port} = WorldTcpAddress#net_address.address, @@ -126,15 +127,15 @@ handle_call({listen, Name}, _From, State) -> {reply, Error, State} end; -handle_call({accept, Listen}, {From, _}, State = #state{listen={_, World}}) -> +handle_call({accept, _Driver, Listen}, {From, _}, State = #state{listen={_, World}}) -> Self = self(), ErtsPid = spawn_link(fun() -> accept_loop(Self, erts, Listen, From) end), WorldPid = spawn_link(fun() -> accept_loop(Self, world, World, Listen) end), {reply, ErtsPid, State#state{accept_loop={ErtsPid, WorldPid}}}; -handle_call({connect, Ip, Port}, {From, _}, State) -> +handle_call({connect, Driver, Ip, Port}, {From, _}, State) -> Me = self(), - Pid = spawn_link(fun() -> setup_proxy(Ip, Port, Me) end), + Pid = spawn_link(fun() -> setup_proxy(Driver, Ip, Port, Me) end), receive {Pid, go_ahead, LPort} -> Res = {ok, Socket} = try_connect(LPort), @@ -263,10 +264,11 @@ try_connect(Port) -> try_connect(Port) end. -setup_proxy(Ip, Port, Parent) -> +setup_proxy(Driver, Ip, Port, Parent) -> process_flag(trap_exit, true), Opts = connect_options(get_ssl_options(client)), - case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}, nodelay()] ++ Opts) of + case ssl:connect(Ip, Port, [{active, true}, binary, {packet,?PPRE}, nodelay(), + Driver:family()] ++ Opts) of {ok, World} -> {ok, ErtsL} = gen_tcp:listen(0, [{active, true}, {ip, loopback}, binary, {packet,?PPRE}]), {ok, #net_address{address={_,LPort}}} = get_tcp_address(ErtsL), diff --git a/lib/ssl/test/ssl_certificate_verify_SUITE.erl b/lib/ssl/test/ssl_certificate_verify_SUITE.erl index 968ef30791..d10506cb69 100644 --- a/lib/ssl/test/ssl_certificate_verify_SUITE.erl +++ b/lib/ssl/test/ssl_certificate_verify_SUITE.erl @@ -66,7 +66,9 @@ tests() -> invalid_signature_client, invalid_signature_server, extended_key_usage_verify_peer, - extended_key_usage_verify_none]. + extended_key_usage_verify_none, + critical_extension_verify_peer, + critical_extension_verify_none]. error_handling_tests()-> [client_with_cert_cipher_suites_handshake, @@ -795,6 +797,121 @@ extended_key_usage_verify_none(Config) when is_list(Config) -> ssl_test_lib:close(Client). %%-------------------------------------------------------------------- +critical_extension_verify_peer() -> + [{doc,"Test cert that has a critical unknown extension in verify_peer mode"}]. + +critical_extension_verify_peer(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + NewCertName = integer_to_list(erlang:unique_integer()) ++ ".pem", + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join([PrivDir, "server", NewCertName]), + add_critical_netscape_cert_type(ServerCertFile, NewServerCertFile, KeyFile), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join([PrivDir, "client", NewCertName]), + add_critical_netscape_cert_type(ClientCertFile, NewClientCertFile, KeyFile), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server_error( + [{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_peer}, {active, Active} | NewServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client_error( + [{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_peer}, {active, Active} | NewClientOpts]}]), + + %% This certificate has a critical extension that we don't + %% understand. Therefore, verification should fail. + tcp_delivery_workaround(Server, {error, {tls_alert, "unsupported certificate"}}, + Client, {error, {tls_alert, "unsupported certificate"}}), + + ssl_test_lib:close(Server), + ok. + +%%-------------------------------------------------------------------- +critical_extension_verify_none() -> + [{doc,"Test cert that has a critical unknown extension in verify_none mode"}]. + +critical_extension_verify_none(Config) when is_list(Config) -> + ClientOpts = ?config(client_verification_opts, Config), + ServerOpts = ?config(server_verification_opts, Config), + PrivDir = ?config(priv_dir, Config), + Active = ?config(active, Config), + ReceiveFunction = ?config(receive_function, Config), + + KeyFile = filename:join(PrivDir, "otpCA/private/key.pem"), + NewCertName = integer_to_list(erlang:unique_integer()) ++ ".pem", + + ServerCertFile = proplists:get_value(certfile, ServerOpts), + NewServerCertFile = filename:join([PrivDir, "server", NewCertName]), + add_critical_netscape_cert_type(ServerCertFile, NewServerCertFile, KeyFile), + NewServerOpts = [{certfile, NewServerCertFile} | proplists:delete(certfile, ServerOpts)], + + ClientCertFile = proplists:get_value(certfile, ClientOpts), + NewClientCertFile = filename:join([PrivDir, "client", NewCertName]), + add_critical_netscape_cert_type(ClientCertFile, NewClientCertFile, KeyFile), + NewClientOpts = [{certfile, NewClientCertFile} | proplists:delete(certfile, ClientOpts)], + + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + Server = ssl_test_lib:start_server( + [{node, ServerNode}, {port, 0}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_none}, {active, Active} | NewServerOpts]}]), + Port = ssl_test_lib:inet_port(Server), + Client = ssl_test_lib:start_client( + [{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {mfa, {ssl_test_lib, ReceiveFunction, []}}, + {options, [{verify, verify_none}, {active, Active} | NewClientOpts]}]), + + %% This certificate has a critical extension that we don't + %% understand. But we're using `verify_none', so verification + %% shouldn't fail. + ssl_test_lib:check_result(Server, ok, Client, ok), + + ssl_test_lib:close(Server), + ssl_test_lib:close(Client), + ok. + +add_critical_netscape_cert_type(CertFile, NewCertFile, KeyFile) -> + [KeyEntry] = ssl_test_lib:pem_to_der(KeyFile), + Key = ssl_test_lib:public_key(public_key:pem_entry_decode(KeyEntry)), + + [{'Certificate', DerCert, _}] = ssl_test_lib:pem_to_der(CertFile), + OTPCert = public_key:pkix_decode_cert(DerCert, otp), + %% This is the "Netscape Cert Type" extension, telling us that the + %% certificate can be used for SSL clients and SSL servers. + NetscapeCertTypeExt = #'Extension'{ + extnID = {2,16,840,1,113730,1,1}, + critical = true, + extnValue = <<3,2,6,192>>}, + OTPTbsCert = OTPCert#'OTPCertificate'.tbsCertificate, + Extensions = OTPTbsCert#'OTPTBSCertificate'.extensions, + NewOTPTbsCert = OTPTbsCert#'OTPTBSCertificate'{ + extensions = [NetscapeCertTypeExt] ++ Extensions}, + NewDerCert = public_key:pkix_sign(NewOTPTbsCert, Key), + ssl_test_lib:der_to_pem(NewCertFile, [{'Certificate', NewDerCert, not_encrypted}]), + ok. + +%%-------------------------------------------------------------------- no_authority_key_identifier() -> [{doc, "Test cert that does not have authorityKeyIdentifier extension" " but are present in trusted certs db."}]. diff --git a/lib/ssl/test/ssl_crl_SUITE.erl b/lib/ssl/test/ssl_crl_SUITE.erl index 44580be1ff..5b86027210 100644 --- a/lib/ssl/test/ssl_crl_SUITE.erl +++ b/lib/ssl/test/ssl_crl_SUITE.erl @@ -53,7 +53,7 @@ groups() -> {idp_crl, [], basic_tests()}]. basic_tests() -> - [crl_verify_valid, crl_verify_revoked]. + [crl_verify_valid, crl_verify_revoked, crl_verify_no_crl]. init_per_suite(Config) -> @@ -186,11 +186,6 @@ crl_verify_revoked(Config) when is_list(Config) -> {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), - Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, - {from, self()}, - {options, ServerOpts}]), - Port = ssl_test_lib:inet_port(Server), - ssl_crl_cache:insert({file, filename:join([PrivDir, "erlangCA", "crl.pem"])}), ssl_crl_cache:insert({file, filename:join([PrivDir, "otpCA", "crl.pem"])}), @@ -206,16 +201,55 @@ crl_verify_revoked(Config) when is_list(Config) -> {verify, verify_peer}] end, - Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, - {host, Hostname}, - {from, self()}, - {options, ClientOpts}]), - receive - {Server, AlertOrColse} -> - ct:pal("Server Alert or Close ~p", [AlertOrColse]) - end, - ssl_test_lib:check_result(Client, {error, {tls_alert, "certificate revoked"}}). + crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, + "certificate revoked"). +crl_verify_no_crl() -> + [{doc,"Verify a simple CRL chain when the CRL is missing"}]. +crl_verify_no_crl(Config) when is_list(Config) -> + PrivDir = ?config(cert_dir, Config), + Check = ?config(crl_check, Config), + ServerOpts = [{keyfile, filename:join([PrivDir, "server", "key.pem"])}, + {certfile, filename:join([PrivDir, "server", "cert.pem"])}, + {cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}], + ClientOpts = case ?config(idp_crl, Config) of + true -> + [{cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}, + {crl_check, Check}, + {crl_cache, {ssl_crl_cache, {internal, [{http, 5000}]}}}, + {verify, verify_peer}]; + false -> + [{cacertfile, filename:join([PrivDir, "server", "cacerts.pem"])}, + {crl_check, Check}, + {verify, verify_peer}] + end, + {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config), + + %% In case we're running an HTTP server that serves CRLs, let's + %% rename those files, so the CRL is absent when we try to verify + %% it. + %% + %% If we're not using an HTTP server, we just need to refrain from + %% adding the CRLs to the cache manually. + rename_crl(filename:join([PrivDir, "erlangCA", "crl.pem"])), + rename_crl(filename:join([PrivDir, "otpCA", "crl.pem"])), + + %% The expected outcome when the CRL is missing depends on the + %% crl_check setting. + case Check of + true -> + %% The error "revocation status undetermined" gets turned + %% into "bad certificate". + crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, + "bad certificate"); + peer -> + crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, + "bad certificate"); + best_effort -> + %% In "best effort" mode, we consider the certificate not + %% to be revoked if we can't find the appropriate CRL. + crl_verify_valid(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts) + end. crl_verify_valid(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts) -> Server = ssl_test_lib:start_server([{node, ServerNode}, {port, 0}, @@ -236,6 +270,22 @@ crl_verify_valid(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts) -> ssl_test_lib:close(Server), ssl_test_lib:close(Client). +crl_verify_error(Hostname, ServerNode, ServerOpts, ClientNode, ClientOpts, ExpectedAlert) -> + Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0}, + {from, self()}, + {options, ServerOpts}]), + Port = ssl_test_lib:inet_port(Server), + + Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port}, + {host, Hostname}, + {from, self()}, + {options, ClientOpts}]), + receive + {Server, AlertOrClose} -> + ct:pal("Server Alert or Close ~p", [AlertOrClose]) + end, + ssl_test_lib:check_result(Client, {error, {tls_alert, ExpectedAlert}}). + %%-------------------------------------------------------------------- %% Internal functions ------------------------------------------------ %%-------------------------------------------------------------------- @@ -259,3 +309,5 @@ make_dir_path(PathComponents) -> "", PathComponents). +rename_crl(Filename) -> + file:rename(Filename, Filename ++ ".notfound"). diff --git a/lib/stdlib/src/maps.erl b/lib/stdlib/src/maps.erl index 3c798b7a04..43d10f4800 100644 --- a/lib/stdlib/src/maps.erl +++ b/lib/stdlib/src/maps.erl @@ -205,7 +205,7 @@ size(Val) -> K :: term(). without(Ks,M) when is_list(Ks), is_map(M) -> - maps:from_list([{K,V}||{K,V} <- maps:to_list(M), not lists:member(K, Ks)]); + lists:foldl(fun(K, M1) -> ?MODULE:remove(K, M1) end, M, Ks); without(Ks,M) -> erlang:error(error_type(M),[Ks,M]). @@ -216,8 +216,16 @@ without(Ks,M) -> Map2 :: map(), K :: term(). -with(Ks,M) when is_list(Ks), is_map(M) -> - maps:from_list([{K,V}||{K,V} <- maps:to_list(M), lists:member(K, Ks)]); +with(Ks,Map1) when is_list(Ks), is_map(Map1) -> + Fun = fun(K, List) -> + case ?MODULE:find(K, Map1) of + {ok, V} -> + [{K, V} | List]; + error -> + List + end + end, + ?MODULE:from_list(lists:foldl(Fun, [], Ks)); with(Ks,M) -> erlang:error(error_type(M),[Ks,M]). diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src index 04cdf31ada..8a313591a7 100644 --- a/lib/stdlib/src/stdlib.appup.src +++ b/lib/stdlib/src/stdlib.appup.src @@ -18,9 +18,9 @@ %% %CopyrightEnd% {"%VSN%", %% Up from - max one major revision back - [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + [{<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}], % 17.0-17.5 %% Down to - max one major revision back - [{<<"2\\.[5-7](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* + [{<<"2\\.[5-8](\\.[0-9]+)*">>,[restart_new_emulator]}, % OTP-18.* {<<"2\\.[0-4](\\.[0-9]+)*">>,[restart_new_emulator]}] % 17.0-17.5 }. diff --git a/lib/stdlib/test/win32reg_SUITE.erl b/lib/stdlib/test/win32reg_SUITE.erl index 82baa43318..6d27ac6387 100644 --- a/lib/stdlib/test/win32reg_SUITE.erl +++ b/lib/stdlib/test/win32reg_SUITE.erl @@ -49,48 +49,53 @@ init_per_suite(Config) when is_list(Config) -> end_per_suite(Config) when is_list(Config) -> Config. + long(doc) -> "Test long keys and entries (OTP-3446)."; long(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), + Dog = test_server:timetrap(test_server:seconds(10)), - ?line LongKey = "software\\" ++ + LongKey = "software\\" ++ lists:flatten(lists:duplicate(10, "..\\software\\")) ++ "Ericsson\\Erlang", - ?line {ok,Reg} = win32reg:open([read,write]), - ?line ok = win32reg:change_key(Reg, "\\hklm"), - ?line ok = win32reg:change_key(Reg, LongKey), - ?line {ok,ErlangKey} = win32reg:current_key(Reg), - io:format("Erlang key: ~s", [ErlangKey]), + {ok,Read} = win32reg:open([read]), + ok = win32reg:change_key(Read, "\\hklm"), + + ok = win32reg:change_key(Read, LongKey), + {ok,ErlangKey} = win32reg:current_key(Read), + io:format("Erlang key: ~s~n", [ErlangKey]), + ok = win32reg:close(Read), + {ok,Reg} = win32reg:open([read, write]), %% Write a long value and read it back. - ?line TestKey = "test_key", - ?line LongValue = lists:concat(["This is a long value generated by the test case ",?MODULE,":long/1. "|lists:duplicate(128, "a")]), - ?line ok = win32reg:set_value(Reg, TestKey, LongValue), - ?line {ok,LongValue} = win32reg:value(Reg, TestKey), + TestKey = "test_key", + LongValue = lists:concat(["This is a long value generated by the test case ",?MODULE,":long/1. "|lists:duplicate(128, "a")]), + ok = win32reg:set_value(Reg, TestKey, LongValue), + {ok,LongValue} = win32reg:value(Reg, TestKey), + io:format("Where ~p Key ~s Value ~s ~n", [win32reg:current_key(Reg), TestKey, LongValue]), %% Done. - ?line ok = win32reg:close(Reg), - ?line test_server:timetrap_cancel(Dog), + ok = win32reg:close(Reg), + test_server:timetrap_cancel(Dog), ok. evil_write(Config) when is_list(Config) -> - ?line Dog = test_server:timetrap(test_server:seconds(10)), + Dog = test_server:timetrap(test_server:seconds(10)), - ?line Key = "Software\\Ericsson\\Erlang", - ?line {ok,Reg} = win32reg:open([read,write]), - ?line ok = win32reg:change_key(Reg, "\\hklm"), - ?line ok = win32reg:change_key(Reg, Key), - ?line {ok,ErlangKey} = win32reg:current_key(Reg), + Key = "Software\\Ericsson\\Erlang", + {ok,Reg} = win32reg:open([read,write]), + ok = win32reg:change_key(Reg, "\\hkcu"), + ok = win32reg:change_key_create(Reg, Key), + {ok,ErlangKey} = win32reg:current_key(Reg), io:format("Erlang key: ~s", [ErlangKey]), %% Write keys with different length and read it back. - ?line TestKey = "test_key " ++ lists:duplicate(128, $a), + TestKey = "test_key " ++ lists:duplicate(128, $a), evil_write_1(Reg, TestKey), %% Done. - ?line ok = win32reg:close(Reg), - ?line test_server:timetrap_cancel(Dog), + ok = win32reg:close(Reg), + test_server:timetrap_cancel(Dog), ok. evil_write_1(Reg, [_|[_|_]=Key]=Key0) -> diff --git a/lib/test_server/src/test_server.erl b/lib/test_server/src/test_server.erl index 73803030a3..671674c617 100644 --- a/lib/test_server/src/test_server.erl +++ b/lib/test_server/src/test_server.erl @@ -63,13 +63,11 @@ init_target_info() -> [$.|Emu] = code:objfile_extension(), {_, OTPRel} = init:script_id(), - TestServerDir = filename:absname(filename:dirname(code:which(?MODULE))), #target_info{os_family=test_server_sup:get_os_family(), os_type=os:type(), version=erlang:system_info(version), system_version=erlang:system_info(system_version), root_dir=code:root_dir(), - test_server_dir=TestServerDir, emulator=Emu, otp_release=OTPRel, username=test_server_sup:get_username(), diff --git a/lib/test_server/src/test_server_internal.hrl b/lib/test_server/src/test_server_internal.hrl index 578f359010..1ec2d83417 100644 --- a/lib/test_server/src/test_server_internal.hrl +++ b/lib/test_server/src/test_server_internal.hrl @@ -30,7 +30,6 @@ version, % string() system_version, % string() root_dir, % string() - test_server_dir, % string() emulator, % string() otp_release, % string() username, % string() diff --git a/lib/test_server/src/test_server_node.erl b/lib/test_server/src/test_server_node.erl index 70cc2625d4..37f8941d24 100644 --- a/lib/test_server/src/test_server_node.erl +++ b/lib/test_server/src/test_server_node.erl @@ -307,11 +307,11 @@ start_node_peer(SlaveName, OptList, From, TI) -> HostStr, " ", WaitPort]), % Support for erl_crash_dump files.. - CrashFile = filename:join([TI#target_info.test_server_dir, + CrashDir = test_server_sup:crash_dump_dir(), + CrashFile = filename:join([CrashDir, "erl_crash_dump."++cast_to_list(SlaveName)]), CrashArgs = lists:concat([" -env ERL_CRASH_DUMP \"",CrashFile,"\" "]), FailOnError = start_node_get_option_value(fail_on_error, OptList, true), - Pa = TI#target_info.test_server_dir, Prog0 = start_node_get_option_value(erl, OptList, default), Prog = quote_progname(pick_erl_program(Prog0)), Args = @@ -322,7 +322,6 @@ start_node_peer(SlaveName, OptList, From, TI) -> Cmd = lists:concat([Prog, " -detached ", TI#target_info.naming, " ", SlaveName, - " -pa \"", Pa,"\"", NodeStarted, CrashArgs, " ", Args]), @@ -370,15 +369,15 @@ wait_for_node_started_fun(LSock, Tmo, Cleanup, TI, Self) -> %% Slave nodes are started on a remote host if %% - the option remote is given when calling test_server:start_node/3 %% -start_node_slave(SlaveName, OptList, From, TI) -> +start_node_slave(SlaveName, OptList, From, _TI) -> SuppliedArgs = start_node_get_option_value(args, OptList, []), Cleanup = start_node_get_option_value(cleanup, OptList, true), - CrashFile = filename:join([TI#target_info.test_server_dir, + CrashDir = test_server_sup:crash_dump_dir(), + CrashFile = filename:join([CrashDir, "erl_crash_dump."++cast_to_list(SlaveName)]), CrashArgs = lists:concat([" -env ERL_CRASH_DUMP \"",CrashFile,"\" "]), - Pa = TI#target_info.test_server_dir, - Args = lists:concat([" -pa \"", Pa, "\" ", SuppliedArgs, CrashArgs]), + Args = lists:concat([" ", SuppliedArgs, CrashArgs]), Prog0 = start_node_get_option_value(erl, OptList, default), Prog = pick_erl_program(Prog0), diff --git a/lib/test_server/src/test_server_sup.erl b/lib/test_server/src/test_server_sup.erl index fc2cfd57bd..1c0eb18d70 100644 --- a/lib/test_server/src/test_server_sup.erl +++ b/lib/test_server/src/test_server_sup.erl @@ -594,7 +594,8 @@ cleanup_crash_dumps() -> delete_files(Dumps). crash_dump_dir() -> - filename:dirname(code:which(?MODULE)). + {ok,Dir} = test_server_sup:framework_call(get_log_dir,[]), + Dir. tar_crash_dumps() -> Dir = crash_dump_dir(), diff --git a/lib/wx/configure.in b/lib/wx/configure.in index 48fcca640c..bf27b72aa7 100644 --- a/lib/wx/configure.in +++ b/lib/wx/configure.in @@ -164,14 +164,14 @@ case $host_os in CPPFLAGS="$CPPFLAGS -D_MACOSX $PTHR_CFLAGS" ;; mingw32) - CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0500 -D_WINDOWS -D_UNICODE -DUNICODE" - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500" + CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" AC_MSG_WARN([Reverting to 32-bit time_t]) CPPFLAGS="$CPPFLAGS -D_USE_32BIT_TIME_T" ;; win32) - CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0500 -D_WINDOWS -D_UNICODE -DUNICODE" - CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0500" + CFLAGS="$CFLAGS -DWIN32 -DWINVER=0x0600 -D_WINDOWS -D_UNICODE -DUNICODE" + CPPFLAGS="$CPPFLAGS -D_WIN32_WINNT=0x0600" ;; *) CFLAGS="$CFLAGS -Wno-deprecated-declarations" |