diff options
115 files changed, 3338 insertions, 6859 deletions
diff --git a/erts/configure.in b/erts/configure.in index 8d70a1b74a..6ad1951a4e 100644 --- a/erts/configure.in +++ b/erts/configure.in @@ -3575,6 +3575,11 @@ case $host_os in DED_LDFLAGS="-m32 $DED_LDFLAGS" fi ;; + openbsd*) + DED_LD="$CC" + DED_LD_FLAG_RUNTIME_LIBRARY_PATH="$CFLAG_RUNTIME_LIBRARY_PATH" + DED_LDFLAGS="-shared" + ;; osf*) # NOTE! Whitespace after -rpath is important. DED_LD_FLAG_RUNTIME_LIBRARY_PATH="-rpath " diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml index 2dea477d99..f931445a3e 100644 --- a/erts/doc/src/erl.xml +++ b/erts/doc/src/erl.xml @@ -1040,6 +1040,37 @@ the emulator will be allowed to spend writing a crash dump. When the given number of seconds have elapsed, the emulator will be terminated by a SIGALRM signal.</p> + + <p> If the environment variable is <em>not</em> set or it is set to zero seconds, <c><![CDATA[ERL_CRASH_DUMP_SECONDS=0]]></c>, + the runtime system will not even attempt to write the crash dump file. It will just terminate. + </p> + <p> If the environment variable is set to negative valie, e.g. <c><![CDATA[ERL_CRASH_DUMP_SECONDS=-1]]></c>, + the runtime system will wait indefinitely for the crash dump file to be written. + </p> + <p> This environment variable is used in conjuction with + <seealso marker="kernel:heart"><c>heart</c></seealso> if <c>heart</c> is running: + </p> + <taglist> + <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=0]]></c></tag> + <item><p> + Suppresses the writing a crash dump file entirely, + thus rebooting the runtime system immediately. + This is the same as not setting the environment variable. + </p> + </item> + <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=-1]]></c></tag> + <item><p>Setting the environment variable to a negative value will cause the + termination of the runtime system to wait until the crash dump file + has been completly written. + </p> + </item> + <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=S]]></c></tag> + <item><p> + Will wait for <c>S</c> seconds to complete the crash dump file and + then terminate the runtime system. + </p> + </item> + </taglist> </item> <tag><c><![CDATA[ERL_AFLAGS]]></c></tag> <item> diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names index 106fad030b..afcbd732df 100644 --- a/erts/emulator/beam/atom.names +++ b/erts/emulator/beam/atom.names @@ -252,6 +252,7 @@ atom heap_block_size atom heap_size atom heap_sizes atom heap_type +atom heart_port atom heir atom hidden atom hide diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c index 93aa2fb8d0..cf66f4e6b6 100644 --- a/erts/emulator/beam/break.c +++ b/erts/emulator/beam/break.c @@ -650,10 +650,13 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) ErtsThrPrgrData tpd_buf; /* in case we aren't a managed thread... */ #endif int fd; + size_t envsz; time_t now; + char env[21]; /* enough to hold any 64-bit integer */ size_t dumpnamebufsize = MAXPATHLEN; char dumpnamebuf[MAXPATHLEN]; char* dumpname; + int secs; if (ERTS_SOMEONE_IS_CRASH_DUMPING) return; @@ -676,9 +679,41 @@ erl_crash_dump_v(char *file, int line, char* fmt, va_list args) erts_writing_erl_crash_dump = 1; #endif - erts_sys_prepare_crash_dump(); + envsz = sizeof(env); + /* ERL_CRASH_DUMP_SECONDS not set + * same as ERL_CRASH_DUMP_SECONDS = 0 + * - do not write dump + * - do not set an alarm + * - break immediately + * + * ERL_CRASH_DUMP_SECONDS = 0 + * - do not write dump + * - do not set an alarm + * - break immediately + * + * ERL_CRASH_DUMP_SECONDS < 0 + * - do not set alarm + * - write dump until done + * + * ERL_CRASH_DUMP_SECONDS = S (and S positive) + * - Don't dump file forever + * - set alarm (set in sys) + * - write dump until alarm or file is written completely + */ + + if (erts_sys_getenv__("ERL_CRASH_DUMP_SECONDS", env, &envsz) != 0) { + return; /* break immediately */ + } else { + secs = atoi(env); + } + + if (secs == 0) { + return; + } + + erts_sys_prepare_crash_dump(secs); - if (erts_sys_getenv_raw("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0) + if (erts_sys_getenv__("ERL_CRASH_DUMP",&dumpnamebuf[0],&dumpnamebufsize) != 0) dumpname = "erl_crash.dump"; else dumpname = &dumpnamebuf[0]; diff --git a/erts/emulator/beam/erl_bits.c b/erts/emulator/beam/erl_bits.c index 6bc227eeda..3753b618e1 100644 --- a/erts/emulator/beam/erl_bits.c +++ b/erts/emulator/beam/erl_bits.c @@ -1247,6 +1247,12 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, */ erts_bin_offset = 8*sb->size + sb->bitsize; + if (unit > 1) { + if ((unit == 8 && (erts_bin_offset & 7) != 0) || + (erts_bin_offset % unit) != 0) { + goto badarg; + } + } used_size_in_bits = erts_bin_offset + build_size_in_bits; sb->is_writable = 0; /* Make sure that no one else can write. */ pb->size = NBYTES(used_size_in_bits); @@ -1316,6 +1322,12 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, */ ERTS_GET_BINARY_BYTES(bin, src_bytes, bitoffs, bitsize); erts_bin_offset = 8*binary_size(bin) + bitsize; + if (unit > 1) { + if ((unit == 8 && (erts_bin_offset & 7) != 0) || + (erts_bin_offset % unit) != 0) { + goto badarg; + } + } used_size_in_bits = erts_bin_offset + build_size_in_bits; used_size_in_bytes = NBYTES(used_size_in_bits); bin_size = 2*used_size_in_bytes; @@ -1363,12 +1375,6 @@ erts_bs_append(Process* c_p, Eterm* reg, Uint live, Eterm build_size_term, /* * Now copy the data into the binary. */ - if (unit > 1) { - if ((unit == 8 && (erts_bin_offset & 7) != 0) || - (erts_bin_offset % unit) != 0) { - return THE_NON_VALUE; - } - } copy_binary_to_buffer(erts_current_bin, 0, src_bytes, bitoffs, erts_bin_offset); return make_binary(sb); diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c index b545ec07c0..1f388c1796 100644 --- a/erts/emulator/beam/erl_lock_check.c +++ b/erts/emulator/beam/erl_lock_check.c @@ -443,7 +443,7 @@ print_lock2(char *prefix, Sint16 id, Wterm extra, Uint16 flags, char *suffix) "%s'%s:%p%s'%s%s", prefix, lname, - boxed_val(extra), + _unchecked_boxed_val(extra), lock_type(flags), rw_op_str(flags), suffix); diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index aad2e42a50..3dc7c14faf 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -984,8 +984,9 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) #endif done: - ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); + runq->scheduler->reductions += reds; + ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); ERTS_PORT_REDUCTIONS_EXECUTED(runq, reds); return res; diff --git a/erts/emulator/beam/erl_posix_str.c b/erts/emulator/beam/erl_posix_str.c index 02db10905b..deb7e3e173 100644 --- a/erts/emulator/beam/erl_posix_str.c +++ b/erts/emulator/beam/erl_posix_str.c @@ -619,6 +619,7 @@ erl_errno_id(error) case WSAEINVALIDPROVIDER: return "einvalidprovider"; #endif #ifdef WSAEPROVIDERFAILEDINIT + /* You could get this if SYSTEMROOT env variable is set incorrectly */ case WSAEPROVIDERFAILEDINIT: return "eproviderfailedinit"; #endif #ifdef WSASYSCALLFAILURE diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 0fa2def5af..c5127bc29d 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -43,6 +43,9 @@ #include "erl_async.h" #include "dtrace-wrapper.h" +#define ERTS_DELAYED_WAKEUP_INFINITY (~(Uint64) 0) +#define ERTS_DELAYED_WAKEUP_REDUCTIONS ((Uint64) CONTEXT_REDS/2) + #define ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED (2000*CONTEXT_REDS) #define ERTS_RUNQ_CALL_CHECK_BALANCE_REDS \ (ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED/2) @@ -932,9 +935,15 @@ haw_thr_prgr_current_check_progress(ErtsAuxWorkData *awdp) } static ERTS_INLINE erts_aint32_t -handle_delayed_aux_work_wakeup(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +handle_delayed_aux_work_wakeup(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { int jix, max_jix; + + ASSERT(awdp->delayed_wakeup.next != ERTS_DELAYED_WAKEUP_INFINITY); + + if (!waiting && awdp->delayed_wakeup.next > awdp->esdp->reductions) + return aux_work; + unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP); ERTS_THR_MEMORY_BARRIER; @@ -950,11 +959,14 @@ handle_delayed_aux_work_wakeup(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) set_aux_work_flags_wakeup_nob(ERTS_SCHED_SLEEP_INFO_IX(sched-1), aux_work); } + awdp->delayed_wakeup.next = ERTS_DELAYED_WAKEUP_INFINITY; return aux_work & ~ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP; } static ERTS_INLINE void -schedule_aux_work_wakeup(ErtsAuxWorkData *awdp, int sched, erts_aint32_t aux_work) +schedule_aux_work_wakeup(ErtsAuxWorkData *awdp, + int sched, + erts_aint32_t aux_work) { int jix = awdp->delayed_wakeup.sched2jix[sched]; if (jix >= 0) { @@ -967,7 +979,20 @@ schedule_aux_work_wakeup(ErtsAuxWorkData *awdp, int sched, erts_aint32_t aux_wor awdp->delayed_wakeup.job[jix].sched = sched; awdp->delayed_wakeup.job[jix].aux_work = aux_work; } - set_aux_work_flags_wakeup_nob(awdp->ssi, ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP); + + if (awdp->delayed_wakeup.next != ERTS_DELAYED_WAKEUP_INFINITY) { + ASSERT(erts_atomic32_read_nob(&awdp->ssi->aux_work) + & ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP); + } + else { + awdp->delayed_wakeup.next = (awdp->esdp->reductions + + ERTS_DELAYED_WAKEUP_REDUCTIONS); + + ASSERT(!(erts_atomic32_read_nob(&awdp->ssi->aux_work) + & ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP)); + set_aux_work_flags_wakeup_nob(awdp->ssi, + ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP); + } } #endif @@ -1046,7 +1071,8 @@ misc_aux_work_clean(ErtsThrQ_t *q, static ERTS_INLINE erts_aint32_t handle_misc_aux_work(ErtsAuxWorkData *awdp, - erts_aint32_t aux_work) + erts_aint32_t aux_work, + int waiting) { ErtsThrQ_t *q = &misc_aux_work_queues[awdp->sched_id].q; @@ -1066,7 +1092,8 @@ handle_misc_aux_work(ErtsAuxWorkData *awdp, static ERTS_INLINE erts_aint32_t handle_misc_aux_work_thr_prgr(ErtsAuxWorkData *awdp, - erts_aint32_t aux_work) + erts_aint32_t aux_work, + int waiting) { if (!erts_thr_progress_has_reached_this(haw_thr_prgr_current(awdp), awdp->misc.thr_prgr)) @@ -1145,7 +1172,8 @@ erts_notify_check_async_ready_queue(void *vno) static ERTS_INLINE erts_aint32_t handle_async_ready(ErtsAuxWorkData *awdp, - erts_aint32_t aux_work) + erts_aint32_t aux_work, + int waiting) { ErtsSchedulerSleepInfo *ssi = awdp->ssi; unset_aux_work_flags(ssi, ERTS_SSI_AUX_WORK_ASYNC_READY); @@ -1167,7 +1195,8 @@ handle_async_ready(ErtsAuxWorkData *awdp, static ERTS_INLINE erts_aint32_t handle_async_ready_clean(ErtsAuxWorkData *awdp, - erts_aint32_t aux_work) + erts_aint32_t aux_work, + int waiting) { void *thr_prgr_p; @@ -1203,7 +1232,7 @@ handle_async_ready_clean(ErtsAuxWorkData *awdp, #endif static ERTS_INLINE erts_aint32_t -handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +handle_fix_alloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { ErtsSchedulerSleepInfo *ssi = awdp->ssi; erts_aint32_t res; @@ -1237,7 +1266,7 @@ erts_alloc_notify_delayed_dealloc(int ix) } static ERTS_INLINE erts_aint32_t -handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { ErtsSchedulerSleepInfo *ssi = awdp->ssi; int need_thr_progress = 0; @@ -1275,7 +1304,7 @@ handle_delayed_dealloc(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) } static ERTS_INLINE erts_aint32_t -handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +handle_delayed_dealloc_thr_prgr(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { ErtsSchedulerSleepInfo *ssi; int need_thr_progress; @@ -1403,7 +1432,7 @@ erts_smp_notify_check_children_needed(void) } static ERTS_INLINE erts_aint32_t -handle_check_children(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +handle_check_children(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_CHECK_CHILDREN); erts_check_children(); @@ -1426,7 +1455,7 @@ erts_smp_atomic32_t erts_halt_progress; int erts_halt_code; static ERTS_INLINE erts_aint32_t -handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_REAP_PORTS); awdp->esdp->run_queue->halt_in_progress = 1; @@ -1474,7 +1503,7 @@ handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) #if HAVE_ERTS_MSEG static ERTS_INLINE erts_aint32_t -handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK); erts_mseg_cache_check(); @@ -1484,7 +1513,7 @@ handle_mseg_cache_check(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) #endif static ERTS_INLINE erts_aint32_t -handle_setup_aux_work_timer(ErtsAuxWorkData *awdp, erts_aint32_t aux_work) +handle_setup_aux_work_timer(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) { unset_aux_work_flags(awdp->ssi, ERTS_SSI_AUX_WORK_SET_TMO); setup_aux_work_timer(); @@ -1498,7 +1527,7 @@ handle_aux_work(ErtsAuxWorkData *awdp, erts_aint32_t orig_aux_work, int waiting) #define HANDLE_AUX_WORK(FLG, HNDLR) \ ignore |= FLG; \ if (aux_work & FLG) { \ - aux_work = HNDLR(awdp, aux_work); \ + aux_work = HNDLR(awdp, aux_work, waiting); \ ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); \ if (!(aux_work & ~ignore)) { \ ERTS_DBG_CHK_AUX_WORK_VAL(aux_work); \ @@ -3917,6 +3946,7 @@ init_aux_work_data(ErtsAuxWorkData *awdp, ErtsSchedulerData *esdp, char *dawwp) awdp->async_ready.queue = NULL; #endif #ifdef ERTS_SMP + awdp->delayed_wakeup.next = ERTS_DELAYED_WAKEUP_INFINITY; if (!dawwp) { awdp->delayed_wakeup.job = NULL; awdp->delayed_wakeup.sched2jix = NULL; @@ -4121,6 +4151,9 @@ erts_init_scheduling(int no_schedulers, int no_schedulers_online) #ifdef ERTS_SMP daww_ptr += daww_sz; #endif + + esdp->reductions = 0; + init_sched_wall_time(&esdp->sched_wall_time); } @@ -6664,6 +6697,9 @@ Process *schedule(Process *p, int calls) || p->rcount == 0); } #endif + + esdp->reductions += reds; + erts_smp_runq_lock(rq); ERTS_PROC_REDUCTIONS_EXECUTED(rq, p->prio, reds, actual_reds); diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index 9e7a5a5c74..7c481a91dd 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -439,6 +439,7 @@ typedef struct { #endif #ifdef ERTS_SMP struct { + Uint64 next; int *sched2jix; int jix; ErtsDelayedAuxWorkWakeupJob *job; @@ -481,6 +482,7 @@ struct ErtsSchedulerData_ { ErtsSchedAllocData alloc_data; + Uint64 reductions; ErtsSchedWallTime sched_wall_time; #ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC diff --git a/erts/emulator/beam/erl_process_lock.c b/erts/emulator/beam/erl_process_lock.c index f28ef6a6d7..f7900317cc 100644 --- a/erts/emulator/beam/erl_process_lock.c +++ b/erts/emulator/beam/erl_process_lock.c @@ -1349,7 +1349,7 @@ erts_proc_lc_chk_no_proc_locks(char *file, int line) lc_id.proc_lock_msgq, lc_id.proc_lock_status}; erts_lc_have_lock_ids(resv, ids, 4); - if (resv[0] || resv[1] || resv[2] || resv[3]) { + if (!ERTS_IS_CRASH_DUMPING && (resv[0] || resv[1] || resv[2] || resv[3])) { erts_lc_fail("%s:%d: Thread has process locks locked when expected " "not to have any process locks locked", file, line); diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index dbf95f5bd7..2c20e3da3b 100755 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -983,6 +983,9 @@ Uint erts_port_ioq_size(Port *pp); void erts_stale_drv_select(Eterm, ErlDrvEvent, int, int); void erts_port_cleanup(Port *); void erts_fire_port_monitor(Port *prt, Eterm ref); + +Port *erts_get_heart_port(void); + #ifdef ERTS_SMP void erts_smp_xports_unlock(Port *); #endif diff --git a/erts/emulator/beam/index.c b/erts/emulator/beam/index.c index a4a3007f93..ad4672c3de 100644 --- a/erts/emulator/beam/index.c +++ b/erts/emulator/beam/index.c @@ -82,7 +82,8 @@ index_put(IndexTable* t, void* tmpl) if (ix >= t->size) { Uint sz; if (ix >= t->limit) { - erl_exit(1, "no more index entries in %s (max=%d)\n", + /* A core dump is unnecessary */ + erl_exit(ERTS_DUMP_EXIT, "no more index entries in %s (max=%d)\n", t->htable.name, t->limit); } sz = INDEX_PAGE_SIZE*sizeof(IndexSlot*); diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 35b194f927..609fe9f5fb 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -1132,7 +1132,7 @@ int erts_write_to_port(Eterm caller_id, Port *p, Eterm list) Uint size; int fpe_was_unmasked; - ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p)); + ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p) || ERTS_IS_CRASH_DUMPING); ERTS_SMP_CHK_NO_PROC_LOCKS; p->caller = caller_id; @@ -5235,3 +5235,27 @@ erl_drv_getenv(char *key, char *value, size_t *value_size) { return erts_sys_getenv_raw(key, value, value_size); } + +/* get heart_port + * used by erl_crash_dump + * - uses the fact that heart_port is registered when starting heart + */ + +Port *erts_get_heart_port() { + + Port* port; + Uint ix; + + for(ix = 0; ix < erts_max_ports; ix++) { + port = &erts_port[ix]; + /* only examine undead or alive ports */ + if (port->status & ERTS_PORT_SFLGS_DEAD) + continue; + /* immediate atom compare */ + if (port->reg && port->reg->name == am_heart_port) { + return port; + } + } + + return NULL; +} diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 2406c52f14..9dd8341520 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -652,7 +652,7 @@ void erts_sys_schedule_interrupt_timed(int set, erts_short_time_t msec); void erts_sys_main_thread(void); #endif -extern void erts_sys_prepare_crash_dump(void); +extern void erts_sys_prepare_crash_dump(int secs); extern void erts_sys_pre_init(void); extern void erl_sys_init(void); extern void erl_sys_args(int *argc, char **argv); diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index c1fa00b4ea..c485a4eece 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -58,7 +58,6 @@ #define __DARWIN__ 1 #endif - #ifdef USE_THREADS #include "erl_threads.h" #endif @@ -71,7 +70,6 @@ static erts_smp_rwmtx_t environ_rwmtx; #define MAX_VSIZE 16 /* Max number of entries allowed in an I/O * vector sock_sendv(). */ - /* * Don't need global.h, but bif_table.h (included by bif.h), * won't compile otherwise @@ -123,6 +121,15 @@ struct ErtsSysReportExit_ { #endif }; +/* This data is shared by these drivers - initialized by spawn_init() */ +static struct driver_data { + int port_num, ofd, packet_bytes; + ErtsSysReportExit *report_exit; + int pid; + int alive; + int status; +} *driver_data; /* indexed by fd */ + static ErtsSysReportExit *report_exit_list; #if CHLDWTHR && !defined(ERTS_SMP) static ErtsSysReportExit *report_exit_transit_list; @@ -680,17 +687,40 @@ static RETSIGTYPE break_handler(int sig) #endif /* 0 */ static ERTS_INLINE void -prepare_crash_dump(void) +prepare_crash_dump(int secs) { +#define NUFBUF (3) int i, max; char env[21]; /* enough to hold any 64-bit integer */ size_t envsz; + DeclareTmpHeapNoproc(heap,NUFBUF); + Port *heart_port; + Eterm *hp = heap; + Eterm list = NIL; + int heart_fd[2] = {-1,-1}; + + UseTmpHeapNoproc(NUFBUF); if (ERTS_PREPARED_CRASH_DUMP) return; /* We have already been called */ + heart_port = erts_get_heart_port(); + if (heart_port) { + /* hearts input fd + * We "know" drv_data is the in_fd since the port is started with read|write + */ + heart_fd[0] = (int)heart_port->drv_data; + heart_fd[1] = (int)driver_data[heart_fd[0]].ofd; + + list = CONS(hp, make_small(8), list); hp += 2; + + /* send to heart port, CMD = 8, i.e. prepare crash dump =o */ + erts_write_to_port(ERTS_INVALID_PID, heart_port, list); + } + /* Make sure we unregister at epmd (unknown fd) and get at least one free filedescriptor (for erl_crash.dump) */ + max = max_files; if (max < 1024) max = 1024; @@ -704,11 +734,15 @@ prepare_crash_dump(void) if (i == async_fd[0] || i == async_fd[1]) continue; #endif + /* We don't want to close our heart yet ... */ + if (i == heart_fd[0] || i == heart_fd[1]) + continue; + close(i); } envsz = sizeof(env); - i = erts_sys_getenv_raw("ERL_CRASH_DUMP_NICE", env, &envsz); + i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz); if (i >= 0) { int nice_val; nice_val = i != 0 ? 0 : atoi(env); @@ -717,21 +751,21 @@ prepare_crash_dump(void) } erts_silence_warn_unused_result(nice(nice_val)); } - - envsz = sizeof(env); - i = erts_sys_getenv_raw("ERL_CRASH_DUMP_SECONDS", env, &envsz); - if (i >= 0) { - unsigned sec; - sec = (unsigned) i != 0 ? 0 : atoi(env); - alarm(sec); - } + /* Positive secs means an alarm must be set + * 0 or negative means no alarm + */ + if (secs > 0) { + alarm((unsigned int)secs); + } + UnUseTmpHeapNoproc(NUFBUF); +#undef NUFBUF } void -erts_sys_prepare_crash_dump(void) +erts_sys_prepare_crash_dump(int secs) { - prepare_crash_dump(); + prepare_crash_dump(secs); } static ERTS_INLINE void @@ -773,7 +807,7 @@ sigusr1_exit(void) is hung somewhere, so it won't be able to poll any flag we set here. */ ERTS_SET_GOT_SIGUSR1; - prepare_crash_dump(); + prepare_crash_dump((int)0); erl_exit(1, "Received SIGUSR1\n"); } @@ -1021,15 +1055,6 @@ void fini_getenv_state(GETENV_STATE *state) #define ERTS_SYS_READ_BUF_SZ (64*1024) -/* This data is shared by these drivers - initialized by spawn_init() */ -static struct driver_data { - int port_num, ofd, packet_bytes; - ErtsSysReportExit *report_exit; - int pid; - int alive; - int status; -} *driver_data; /* indexed by fd */ - /* Driver interfaces */ static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*); static ErlDrvData fd_start(ErlDrvPort, char*, SysDriverOpts*); @@ -2417,6 +2442,15 @@ erts_sys_getenv_raw(char *key, char *value, size_t *size) { return erts_sys_getenv(key, value, size); } +/* + * erts_sys_getenv + * returns: + * -1, if environment key is not set with a value + * 0, if environment key is set and value fits into buffer size + * 1, if environment key is set but does not fit into buffer size + * size is set with the needed buffer size value + */ + int erts_sys_getenv(char *key, char *value, size_t *size) { diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index 6894d682e7..50f6219374 100755 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -256,10 +256,25 @@ void erl_sys_args(int* argc, char** argv) } void -erts_sys_prepare_crash_dump(void) +erts_sys_prepare_crash_dump(int secs) { + Port *heart_port; + Eterm heap[3]; + Eterm *hp = heap; + Eterm list = NIL; + + heart_port = erts_get_heart_port(); + + if (heart_port) { + + list = CONS(hp, make_small(8), list); hp += 2; + + /* send to heart port, CMD = 8, i.e. prepare crash dump =o */ + erts_write_to_port(NIL, heart_port, list); + } + /* Windows - free file descriptors are hopefully available */ - return; + /* Alarm not used on windows */ } static void @@ -420,6 +435,8 @@ typedef struct async_io { HANDLE ioAllowed; /* The thread will wait for this event * before starting a new read or write. */ + HANDLE flushEvent; /* Used to signal that a flush should be done. */ + HANDLE flushReplyEvent; /* Used to signal that a flush has been done. */ DWORD pendingError; /* Used to delay presentating an error to Erlang * until the check_io function is entered. */ @@ -878,6 +895,8 @@ init_async_io(AsyncIo* aio, int use_threads) aio->ov.Offset = 0L; aio->ov.OffsetHigh = 0L; aio->ioAllowed = NULL; + aio->flushEvent = NULL; + aio->flushReplyEvent = NULL; aio->pendingError = 0; aio->bytesTransferred = 0; #ifdef ERTS_SMP @@ -890,6 +909,12 @@ init_async_io(AsyncIo* aio, int use_threads) aio->ioAllowed = CreateAutoEvent(FALSE); if (aio->ioAllowed == NULL) return -1; + aio->flushEvent = CreateAutoEvent(FALSE); + if (aio->flushEvent == NULL) + return -1; + aio->flushReplyEvent = CreateAutoEvent(FALSE); + if (aio->flushReplyEvent == NULL) + return -1; } return 0; } @@ -923,6 +948,14 @@ release_async_io(AsyncIo* aio, ErlDrvPort port_num) if (aio->ioAllowed != NULL) CloseHandle(aio->ioAllowed); aio->ioAllowed = NULL; + + if (aio->flushEvent != NULL) + CloseHandle(aio->flushEvent); + aio->flushEvent = NULL; + + if (aio->flushReplyEvent != NULL) + CloseHandle(aio->flushReplyEvent); + aio->flushReplyEvent = NULL; } /* ---------------------------------------------------------------------- @@ -2083,16 +2116,26 @@ threaded_writer(LPVOID param) AsyncIo* aio = (AsyncIo *) param; HANDLE thread = GetCurrentThread(); char* buf; - DWORD numToWrite; + DWORD numToWrite, handle; int ok; + HANDLE handles[2]; + handles[0] = aio->ioAllowed; + handles[1] = aio->flushEvent; for (;;) { - WaitForSingleObject(aio->ioAllowed, INFINITE); + handle = WaitForMultipleObjects(2, handles, FALSE, INFINITE); if (aio->flags & DF_EXIT_THREAD) break; + buf = OV_BUFFER_PTR(aio); numToWrite = OV_NUM_TO_READ(aio); aio->pendingError = 0; + + if (handle == (WAIT_OBJECT_0 + 1) && numToWrite == 0) { + SetEvent(aio->flushReplyEvent); + continue; + } + ok = WriteFile(aio->fd, buf, numToWrite, &aio->bytesTransferred, NULL); if (!ok) { aio->pendingError = GetLastError(); @@ -2127,7 +2170,11 @@ threaded_writer(LPVOID param) } } } - SetEvent(aio->ov.hEvent); + OV_NUM_TO_READ(aio) = 0; + if (handle == (WAIT_OBJECT_0 + 1)) + SetEvent(aio->flushReplyEvent); + else + SetEvent(aio->ov.hEvent); if (aio->pendingError != NO_ERROR || aio->bytesTransferred == 0) break; if (aio->flags & DF_EXIT_THREAD) @@ -2193,6 +2240,43 @@ fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) if ((dp = new_driver_data(port_num, opts->packet_bytes, 2, TRUE)) == NULL) return ERL_DRV_ERROR_GENERAL; + /** + * Here is a brief description about how the fd driver works on windows. + * + * fd_init: + * For each in/out fd pair a threaded_reader and threaded_writer thread is + * created. Within the DriverData struct each of the threads have an AsyncIO + * sctruct associated with it. Within AsyncIO there are two important HANDLEs, + * ioAllowed and ov.hEvent. ioAllowed is used to signal the threaded_* threads + * should read/write some data, and ov.hEvent is driver_select'ed to be used to + * signal that the thread is done reading/writing. + * + * The reason for the driver being threaded like this is because once the FD is open + * on windows, it is not possible to set the it in overlapped mode. So we have to + * simulate this using threads. + * + * output: + * When an output occurs the data to be outputted is copied to AsyncIO.ov. Then + * the ioAllowed HANDLE is set, ov.hEvent is cleared and the port is marked as busy. + * The threaded_writer thread is lying in WaitForMultipleObjects on ioAllowed, and + * when signalled it writes all data in AsyncIO.ov and then sets ov.hEvent so that + * ready_output gets triggered and (potentially) sends the reply to the port and + * marks the port an non-busy. + * + * input: + * The threaded_reader is lying waiting in ReadFile on the in fd and when a new + * line is written it sets ov.hEvent that new data is available and then goes + * and waits for ioAllowed to be set. ready_input is run when ov.hEvent is set and + * delivers the data to the port. Then ioAllowed is signalled again and threaded_reader + * goes back to ReadFile. + * + * shutdown: + * In order to guarantee that all io is outputted before the driver is stopped, + * fd_stop uses flushEvent and flushReplyEvent to make sure that there is no data + * in ov which needs writing before returning from fd_stop. + * + **/ + if (!create_file_thread(&dp->in, DO_READ)) { dp->port_num = PORT_FREE; return ERL_DRV_ERROR_GENERAL; @@ -2241,6 +2325,8 @@ static void fd_stop(ErlDrvData d) (void) driver_select(dp->port_num, (ErlDrvEvent)dp->out.ov.hEvent, ERL_DRV_WRITE, 0); + SetEvent(dp->out.flushEvent); + WaitForSingleObject(dp->out.flushReplyEvent, INFINITE); } } diff --git a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c index 13af7d861a..b214f87e4a 100644 --- a/erts/emulator/test/alloc_SUITE_data/bucket_mask.c +++ b/erts/emulator/test/alloc_SUITE_data/bucket_mask.c @@ -16,11 +16,19 @@ * $Id$ */ +#include "erl_int_sizes_config.h" + #include "testcase_driver.h" #include "allocator_test.h" #include <stdio.h> -#define SBCT (512*1024) +#ifdef __WIN32__ && SIZEOF_VOID_P == 8 +/* Use larger threashold for win64 as block alignment + is 16 bytes and not 8 */ +#define SBCT ((1024*1024)) +#else +#define SBCT ((512*1024)) +#endif char * testcase_name(void) diff --git a/erts/emulator/test/bs_bit_binaries_SUITE.erl b/erts/emulator/test/bs_bit_binaries_SUITE.erl index ff1088118d..1428387a65 100644 --- a/erts/emulator/test/bs_bit_binaries_SUITE.erl +++ b/erts/emulator/test/bs_bit_binaries_SUITE.erl @@ -177,14 +177,55 @@ append(Config) when is_list(Config) -> cs_init(), ?line <<(-1):256/signed-unit:8>> = cs(do_append(id(<<>>), 256*8)), ?line <<(-1):256/signed-unit:8>> = cs(do_append2(id(<<>>), 256*4)), + <<(-1):256/signed-unit:8>> = cs(do_append3(id(<<>>), 256*8)), cs_end(). do_append(Bin, N) when N > 0 -> do_append(<<Bin/bits,1:1>>, N-1); do_append(Bin, 0) -> Bin. -do_append2(Bin, N) when N > 0 -> do_append2(<<Bin/bits,3:2>>, N-1); +do_append2(Bin, N) when N > 0 -> do_append2(<<Bin/binary-unit:2,3:2>>, N-1); do_append2(Bin, 0) -> Bin. +do_append3(Bin, N) when N > 0 -> + Bits = bit_size(Bin), + if + Bits rem 2 =:= 0 -> + do_append3(<<Bin/binary-unit:2,1:1>>, N-1); + Bits rem 3 =:= 0 -> + do_append3(<<Bin/binary-unit:3,1:1>>, N-1); + Bits rem 4 =:= 0 -> + do_append3(<<Bin/binary-unit:4,1:1>>, N-1); + Bits rem 5 =:= 0 -> + do_append3(<<Bin/binary-unit:5,1:1>>, N-1); + Bits rem 6 =:= 0 -> + do_append3(<<Bin/binary-unit:6,1:1>>, N-1); + Bits rem 7 =:= 0 -> + do_append3(<<Bin/binary-unit:7,1:1>>, N-1); + Bits rem 8 =:= 0 -> + do_append3(<<Bin/binary-unit:8,1:1>>, N-1); + Bits rem 9 =:= 0 -> + do_append3(<<Bin/binary-unit:9,1:1>>, N-1); + Bits rem 10 =:= 0 -> + do_append3(<<Bin/binary-unit:10,1:1>>, N-1); + Bits rem 11 =:= 0 -> + do_append3(<<Bin/binary-unit:11,1:1>>, N-1); + Bits rem 12 =:= 0 -> + do_append3(<<Bin/binary-unit:12,1:1>>, N-1); + Bits rem 13 =:= 0 -> + do_append3(<<Bin/binary-unit:13,1:1>>, N-1); + Bits rem 14 =:= 0 -> + do_append3(<<Bin/binary-unit:14,1:1>>, N-1); + Bits rem 15 =:= 0 -> + do_append3(<<Bin/binary-unit:15,1:1>>, N-1); + Bits rem 16 =:= 0 -> + do_append3(<<Bin/binary-unit:16,1:1>>, N-1); + Bits rem 17 =:= 0 -> + do_append3(<<Bin/binary-unit:17,1:1>>, N-1); + true -> + do_append3(<<Bin/binary-unit:1,1:1>>, N-1) + end; +do_append3(Bin, 0) -> Bin. + cs_init() -> erts_debug:set_internal_state(available_internal_state, true), ok. diff --git a/erts/emulator/test/bs_construct_SUITE.erl b/erts/emulator/test/bs_construct_SUITE.erl index 8b5c82d968..9c88803fea 100644 --- a/erts/emulator/test/bs_construct_SUITE.erl +++ b/erts/emulator/test/bs_construct_SUITE.erl @@ -28,7 +28,7 @@ mem_leak/1, coerce_to_float/1, bjorn/1, huge_float_field/1, huge_binary/1, system_limit/1, badarg/1, copy_writable_binary/1, kostis/1, dynamic/1, bs_add/1, - otp_7422/1, zero_width/1]). + otp_7422/1, zero_width/1, bad_append/1]). -include_lib("test_server/include/test_server.hrl"). @@ -38,7 +38,8 @@ all() -> [test1, test2, test3, test4, test5, testf, not_used, in_guard, mem_leak, coerce_to_float, bjorn, huge_float_field, huge_binary, system_limit, badarg, - copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width]. + copy_writable_binary, kostis, dynamic, bs_add, otp_7422, zero_width, + bad_append]. groups() -> []. @@ -827,5 +828,49 @@ zero_width(Config) when is_list(Config) -> ?line {'EXIT',{badarg,_}} = (catch <<(id(not_a_number)):0>>), ok. + +bad_append(_) -> + do_bad_append(<<127:1>>, fun append_unit_3/1), + do_bad_append(<<127:2>>, fun append_unit_3/1), + do_bad_append(<<127:17>>, fun append_unit_3/1), + + do_bad_append(<<127:3>>, fun append_unit_4/1), + do_bad_append(<<127:5>>, fun append_unit_4/1), + do_bad_append(<<127:7>>, fun append_unit_4/1), + do_bad_append(<<127:199>>, fun append_unit_4/1), + + do_bad_append(<<127:7>>, fun append_unit_8/1), + do_bad_append(<<127:9>>, fun append_unit_8/1), + + do_bad_append(<<0:8>>, fun append_unit_16/1), + do_bad_append(<<0:15>>, fun append_unit_16/1), + do_bad_append(<<0:17>>, fun append_unit_16/1), + ok. + +do_bad_append(Bin0, Appender) -> + {'EXIT',{badarg,_}} = (catch Appender(Bin0)), + + Bin1 = id(<<0:3,Bin0/bitstring>>), + <<_:3,Bin2/bitstring>> = Bin1, + {'EXIT',{badarg,_}} = (catch Appender(Bin2)), + + %% Create a writable binary. + Empty = id(<<>>), + Bin3 = <<Empty/bitstring,Bin0/bitstring>>, + {'EXIT',{badarg,_}} = (catch Appender(Bin3)), + ok. + +append_unit_3(Bin) -> + <<Bin/binary-unit:3,0:1>>. + +append_unit_4(Bin) -> + <<Bin/binary-unit:4,0:1>>. + +append_unit_8(Bin) -> + <<Bin/binary,0:1>>. + +append_unit_16(Bin) -> + <<Bin/binary-unit:16,0:1>>. + id(I) -> I. diff --git a/erts/emulator/test/smoke_test_SUITE.erl b/erts/emulator/test/smoke_test_SUITE.erl index 98f1cf1ad5..71186d4942 100644 --- a/erts/emulator/test/smoke_test_SUITE.erl +++ b/erts/emulator/test/smoke_test_SUITE.erl @@ -51,7 +51,17 @@ end_per_group(_GroupName, Config) -> Config. +init_per_testcase(boot_combo = Case, Config) when is_list(Config) -> + case erlang:system_info(build_type) of + opt -> + init_per_tc(Case, Config); + _ -> + {skip,"Cannot test boot_combo in special builds since beam.* may not exist"} + end; init_per_testcase(Case, Config) when is_list(Config) -> + init_per_tc(Case, Config). + +init_per_tc(Case, Config) -> Dog = ?t:timetrap(?DEFAULT_TIMEOUT), [{testcase, Case},{watchdog, Dog}|Config]. @@ -121,18 +131,19 @@ start_node(Config) -> start_node(Config, ""). start_node(Config, Args) when is_list(Config) -> - ?line Pa = filename:dirname(code:which(?MODULE)), - ?line {A, B, C} = now(), - ?line Name = list_to_atom(atom_to_list(?MODULE) - ++ "-" - ++ atom_to_list(?config(testcase, Config)) - ++ "-" - ++ integer_to_list(A) - ++ "-" - ++ integer_to_list(B) - ++ "-" - ++ integer_to_list(C)), - ?line ?t:start_node(Name, slave, [{args, "-pa "++Pa++" "++Args}]). + Pa = filename:dirname(code:which(?MODULE)), + {A, B, C} = now(), + Name = list_to_atom(atom_to_list(?MODULE) + ++ "-" + ++ atom_to_list(?config(testcase, Config)) + ++ "-" + ++ integer_to_list(A) + ++ "-" + ++ integer_to_list(B) + ++ "-" + ++ integer_to_list(C)), + Opts = [{args, "-pa "++Pa++" "++Args}], + ?t:start_node(Name, slave, Opts). stop_node(Node) -> ?t:stop_node(Node). diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index 70c2b3bb23..ed75a8f256 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -137,7 +137,8 @@ # endif #endif -#define HEART_COMMAND_ENV "HEART_COMMAND" +#define HEART_COMMAND_ENV "HEART_COMMAND" +#define ERL_CRASH_DUMP_SECONDS_ENV "ERL_CRASH_DUMP_SECONDS" #define MSG_HDR_SIZE 2 #define MSG_HDR_PLUS_OP_SIZE 3 @@ -153,13 +154,14 @@ struct msg { }; /* operations */ -#define HEART_ACK 1 -#define HEART_BEAT 2 -#define SHUT_DOWN 3 -#define SET_CMD 4 -#define CLEAR_CMD 5 -#define GET_CMD 6 -#define HEART_CMD 7 +#define HEART_ACK (1) +#define HEART_BEAT (2) +#define SHUT_DOWN (3) +#define SET_CMD (4) +#define CLEAR_CMD (5) +#define GET_CMD (6) +#define HEART_CMD (7) +#define PREPARING_CRASH (8) /* Maybe interesting to change */ @@ -187,10 +189,11 @@ unsigned long heart_beat_kill_pid = 0; #define SOL_WD_TIMEOUT (heart_beat_timeout+heart_beat_boot_delay) /* reasons for reboot */ -#define R_TIMEOUT 1 -#define R_CLOSED 2 -#define R_ERROR 3 -#define R_SHUT_DOWN 4 +#define R_TIMEOUT (1) +#define R_CLOSED (2) +#define R_ERROR (3) +#define R_SHUT_DOWN (4) +#define R_CRASHING (5) /* Doing a crash dump and we will wait for it */ /* macros */ @@ -200,8 +203,8 @@ unsigned long heart_beat_kill_pid = 0; /* prototypes */ -static int message_loop(int,int); -static void do_terminate(int); +static int message_loop(int, int); +static void do_terminate(int, int); static int notify_ack(int); static int heart_cmd_reply(int, char *); static int write_message(int, struct msg *); @@ -212,6 +215,7 @@ static void print_error(const char *,...); static void debugf(const char *,...); static void init_timestamp(void); static time_t timestamp(time_t *); +static int wait_until_close_write_or_env_tmo(int); #ifdef __WIN32__ static BOOL enable_privilege(void); @@ -350,12 +354,14 @@ static void get_arguments(int argc, char** argv) { debugf("arguments -ht %d -wt %d -pid %lu\n",h,w,p); } -int -main(int argc, char **argv) -{ +int main(int argc, char **argv) { + + if (is_env_set("HEART_DEBUG")) { + fprintf(stderr, "heart: debug is ON!\r\n"); + debug_on = 1; + } + get_arguments(argc,argv); - if (is_env_set("HEART_DEBUG")) - debug_on=1; #ifdef __WIN32__ if (debug_on) { if(!is_env_set("ERLSRV_SERVICE_NAME")) { @@ -376,7 +382,7 @@ main(int argc, char **argv) program_name[sizeof(program_name)-1] = '\0'; notify_ack(erlout_fd); cmd[0] = '\0'; - do_terminate(message_loop(erlin_fd,erlout_fd)); + do_terminate(erlin_fd,message_loop(erlin_fd,erlout_fd)); return 0; } @@ -410,6 +416,7 @@ message_loop(erlin_fd, erlout_fd) #endif while (1) { + /* REFACTOR: below to select/tmo function */ #ifdef __WIN32__ wresult = WaitForSingleObject(hevent_dataready,SELECT_TIMEOUT*1000+ 2); if (wresult == WAIT_FAILED) { @@ -504,6 +511,10 @@ message_loop(erlin_fd, erlout_fd) free_env_val(env); } break; + case PREPARING_CRASH: + /* Erlang has reached a crushdump point (is crashing for sure) */ + print_error("Erlang is crashing .. (waiting for crash dump file)"); + return R_CRASHING; default: /* ignore all other messages */ break; @@ -635,72 +646,130 @@ void win_system(char *command) * do_terminate */ static void -do_terminate(reason) - int reason; -{ +do_terminate(int erlin_fd, int reason) { /* When we get here, we have HEART_BEAT_BOOT_DELAY secs to finish (plus heart_beat_report_delay if under VxWorks), so we don't need to call wd_reset(). */ - + int ret = 0, tmo=0; + char *tmo_env; + switch (reason) { case R_SHUT_DOWN: break; + case R_CRASHING: + if (is_env_set(ERL_CRASH_DUMP_SECONDS_ENV)) { + tmo_env = get_env(ERL_CRASH_DUMP_SECONDS_ENV); + tmo = atoi(tmo_env); + print_error("Waiting for dump - timeout set to %d seconds.", tmo); + wait_until_close_write_or_env_tmo(tmo); + free_env_val(tmo_env); + } + /* fall through */ case R_TIMEOUT: - case R_ERROR: case R_CLOSED: + case R_ERROR: default: -#if defined(__WIN32__) /* Not VxWorks */ { - if(!cmd[0]) { - char *command = get_env(HEART_COMMAND_ENV); - if(!command) - print_error("Would reboot. Terminating."); - else { - kill_old_erlang(); - /* High prio combined with system() works badly indeed... */ - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); - win_system(command); - print_error("Executed \"%s\". Terminating.",command); +#if defined(__WIN32__) /* Not VxWorks */ + if(!cmd[0]) { + char *command = get_env(HEART_COMMAND_ENV); + if(!command) + print_error("Would reboot. Terminating."); + else { + kill_old_erlang(); + /* High prio combined with system() works badly indeed... */ + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); + win_system(command); + print_error("Executed \"%s\". Terminating.",command); + } + free_env_val(command); + } else { + kill_old_erlang(); + /* High prio combined with system() works badly indeed... */ + SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); + win_system(&cmd[0]); + print_error("Executed \"%s\". Terminating.",cmd); } - free_env_val(command); - } - else { - kill_old_erlang(); - /* High prio combined with system() works badly indeed... */ - SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); - win_system(&cmd[0]); - print_error("Executed \"%s\". Terminating.",cmd); - } - } - #else - { - if(!cmd[0]) { - char *command = get_env(HEART_COMMAND_ENV); - if(!command) - print_error("Would reboot. Terminating."); - else { - kill_old_erlang(); - /* suppress gcc warning with 'if' */ - if(system(command)); - print_error("Executed \"%s\". Terminating.",command); + if(!cmd[0]) { + char *command = get_env(HEART_COMMAND_ENV); + if(!command) + print_error("Would reboot. Terminating."); + else { + kill_old_erlang(); + /* suppress gcc warning with 'if' */ + ret = system(command); + print_error("Executed \"%s\" -> %d. Terminating.",command, ret); + } + free_env_val(command); + } else { + kill_old_erlang(); + /* suppress gcc warning with 'if' */ + ret = system((char*)&cmd[0]); + print_error("Executed \"%s\" -> %d. Terminating.",cmd, ret); } - free_env_val(command); - } - else { - kill_old_erlang(); - /* suppress gcc warning with 'if' */ - if(system((char*)&cmd[0])); - print_error("Executed \"%s\". Terminating.",cmd); - } +#endif } break; -#endif } /* switch(reason) */ } + +/* Waits until something happens on socket or handle + * + * Uses global variables erlin_fd or hevent_dataready + */ +int wait_until_close_write_or_env_tmo(int tmo) { + int i = 0; + +#ifdef __WIN32__ + DWORD wresult; + DWORD wtmo = INFINITE; + + if (tmo >= 0) { + wtmo = tmo*1000 + 2; + } + + wresult = WaitForSingleObject(hevent_dataready, wtmo); + if (wresult == WAIT_FAILED) { + print_last_error(); + return -1; + } + + if (wresult == WAIT_TIMEOUT) { + debugf("wait timed out\n"); + i = 0; + } else { + debugf("wait ok\n"); + i = 1; + } +#else + fd_set read_fds; + int max_fd; + struct timeval timeout; + struct timeval *tptr = NULL; + + max_fd = erlin_fd; /* global */ + + if (tmo >= 0) { + timeout.tv_sec = tmo; /* On Linux timeout is modified by select */ + timeout.tv_usec = 0; + tptr = &timeout; + } + + FD_ZERO(&read_fds); + FD_SET(erlin_fd, &read_fds); + if ((i = select(max_fd + 1, &read_fds, NULLFDS, NULLFDS, tptr)) < 0) { + print_error("error in select."); + return -1; + } +#endif + return i; +} + + /* * notify_ack * @@ -891,12 +960,13 @@ debugf(const char *format,...) { va_list args; - if (!debug_on) return; - va_start(args, format); - fprintf(stderr, "Heart: "); - vfprintf(stderr, format, args); - va_end(args); - fprintf(stderr, "\r\n"); + if (debug_on) { + va_start(args, format); + fprintf(stderr, "Heart: "); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\r\n"); + } } #ifdef __WIN32__ diff --git a/erts/etc/win32/nsis/Makefile b/erts/etc/win32/nsis/Makefile index f377a68c69..a53ac708f8 100644 --- a/erts/etc/win32/nsis/Makefile +++ b/erts/etc/win32/nsis/Makefile @@ -91,7 +91,7 @@ release_spec: fi;\ if [ '!' -z "$(REDIST_FILE)" -a '!' -z "$(REDIST_DLL_VERSION)" ];\ then \ - cp $(REDIST_FILE) "$(RELEASE_PATH)/$(REDIST_TARGET);"\ + cp $(REDIST_FILE) "$(RELEASE_PATH)/$(REDIST_TARGET)";\ echo '!define HAVE_REDIST_FILE 1' >> $(VERSION_HEADER); \ echo '!define REDIST_DLL_VERSION "$(REDIST_DLL_VERSION)"' >> $(VERSION_HEADER);\ echo '!define REDIST_DLL_NAME "$(REDIST_DLL_NAME)"' >> $(VERSION_HEADER);\ diff --git a/erts/include/internal/ethread.h b/erts/include/internal/ethread.h index 142c26c0ca..e1885c627a 100644 --- a/erts/include/internal/ethread.h +++ b/erts/include/internal/ethread.h @@ -355,10 +355,8 @@ extern ethr_runtime_t ethr_runtime__; # include "sparc64/ethread.h" # endif # endif -#if 0 # include "gcc/ethread.h" # include "libatomic_ops/ethread.h" -#endif # endif # elif defined(ETHR_HAVE_LIBATOMIC_OPS) # include "libatomic_ops/ethread.h" diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl index 5f28f22606..7df611e749 100644 --- a/erts/test/otp_SUITE.erl +++ b/erts/test/otp_SUITE.erl @@ -150,8 +150,8 @@ is_hipe_module(Mod) -> end. ssl_crypto_filter(Undef) -> - case {code:lib_dir(crypto),code:lib_dir(ssl)} of - {{error,bad_name},{error,bad_name}} -> + case {app_exists(crypto),app_exists(ssl)} of + {false,false} -> filter(fun({_,{ssl,_,_}}) -> false; ({_,{crypto,_,_}}) -> false; ({_,{ssh,_,_}}) -> false; @@ -175,8 +175,8 @@ eunit_filter(Undef) -> end, Undef). dialyzer_filter(Undef) -> - case code:lib_dir(dialyzer) of - {error,bad_name} -> + case app_exists(dialyzer) of + false -> filter(fun({_,{dialyzer_callgraph,_,_}}) -> false; ({_,{dialyzer_codeserver,_,_}}) -> false; ({_,{dialyzer_contracts,_,_}}) -> false; @@ -191,8 +191,8 @@ dialyzer_filter(Undef) -> end. wx_filter(Undef) -> - case code:lib_dir(wx) of - {error,bad_name} -> + case app_exists(wx) of + false -> filter(fun({_,{MaybeWxModule,_,_}}) -> case atom_to_list(MaybeWxModule) of "wx"++_ -> false; @@ -338,3 +338,16 @@ open_log(Config, Name) -> close_log(Fd) -> ok = file:close(Fd). + +app_exists(AppAtom) -> + case code:lib_dir(AppAtom) of + {error,bad_name} -> + false; + Path -> + case file:read_file_info(filename:join(Path,"ebin")) of + {ok,_} -> + true; + _ -> + false + end + end. diff --git a/erts/vsn.mk b/erts/vsn.mk index da0f03b24f..37ccd8df22 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -17,8 +17,8 @@ # %CopyrightEnd% # -VSN = 5.9.2 -SYSTEM_VSN = R15B02 +VSN = 5.9.3 +SYSTEM_VSN = R15B03 # Port number 4365 in 4.2 # Port number 4366 in 4.3 diff --git a/lib/asn1/test/asn1_SUITE.erl b/lib/asn1/test/asn1_SUITE.erl index b0c37d79e7..9a6201455d 100644 --- a/lib/asn1/test/asn1_SUITE.erl +++ b/lib/asn1/test/asn1_SUITE.erl @@ -51,7 +51,8 @@ %% Suite definition %%------------------------------------------------------------------------------ -suite() -> [{ct_hooks, [ts_install_cth]}]. +suite() -> [{ct_hooks, [ts_install_cth]}, + {timetrap,{minutes,60}}]. all() -> [{group, parallel}, @@ -241,15 +242,10 @@ init_per_testcase(Func, Config) -> ok = filelib:ensure_dir(filename:join([CaseDir, dummy_file])), true = code:add_patha(CaseDir), - Dog = case Func of - testX420 -> test_server:timetrap({minutes, 90}); - _ -> test_server:timetrap({minutes, 60}) - end, - [{case_dir, CaseDir}, {watchdog, Dog}|Config]. + [{case_dir, CaseDir}|Config]. end_per_testcase(_Func, Config) -> - code:del_path(?config(case_dir, Config)), - test_server:timetrap_cancel(?config(watchdog, Config)). + code:del_path(?config(case_dir, Config)). %%------------------------------------------------------------------------------ %% Test runners @@ -1064,6 +1060,9 @@ test_modified_x420(Config) -> asn1_test_lib:compile_all(Files, Config, [der]), test_modified_x420:test_io(Config). + +testX420() -> + [{timetrap,{minutes,90}}]. testX420(Config) -> test(Config, fun testX420/3, [ber, ber_bin, ber_bin_v2]). testX420(Config, Rule, Opts) -> diff --git a/lib/common_test/doc/src/notes.xml b/lib/common_test/doc/src/notes.xml index 64eeb4af92..abe8cb2041 100644 --- a/lib/common_test/doc/src/notes.xml +++ b/lib/common_test/doc/src/notes.xml @@ -32,6 +32,22 @@ <file>notes.xml</file> </header> +<section><title>Common_Test 1.6.2.1</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + The interactive mode (ct_run -shell) would not start + properly. This error has been fixed.</p> + <p> + Own Id: OTP-10414</p> + </item> + </list> + </section> + +</section> + <section><title>Common_Test 1.6.2</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/lib/common_test/src/ct.erl b/lib/common_test/src/ct.erl index 49b51c9207..5014309c0f 100644 --- a/lib/common_test/src/ct.erl +++ b/lib/common_test/src/ct.erl @@ -274,7 +274,8 @@ step(TestDir,Suite,Case,Opts) -> %%% <c>> ct_telnet:cmd(unix_telnet, "ls .").</c><br/> %%% <c>{ok,["ls","file1 ...",...]}</c></p> start_interactive() -> - ct_util:start(interactive). + ct_util:start(interactive), + ok. %%%----------------------------------------------------------------- %%% @spec stop_interactive() -> ok @@ -282,7 +283,8 @@ start_interactive() -> %%% @doc Exit the interactive mode. %%% @see start_interactive/0 stop_interactive() -> - ct_util:stop(normal). + ct_util:stop(normal), + ok. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %%% MISC INTERFACE diff --git a/lib/common_test/src/ct_config.erl b/lib/common_test/src/ct_config.erl index 30bf5925c0..06a8e12f55 100644 --- a/lib/common_test/src/ct_config.erl +++ b/lib/common_test/src/ct_config.erl @@ -532,7 +532,8 @@ do_require(Name,Key) -> case get_key_from_name(Name) of {error,_} -> allocate(Name,Key); - {ok,Key} -> + {ok,NameKey} when NameKey == Key; + is_tuple(Key) andalso element(1,Key) == NameKey -> %% already allocated - check that it has all required subkeys R = make_ref(), case get_config(Key,R,[]) of diff --git a/lib/common_test/src/ct_run.erl b/lib/common_test/src/ct_run.erl index d80d216f9e..3383244bf4 100644 --- a/lib/common_test/src/ct_run.erl +++ b/lib/common_test/src/ct_run.erl @@ -211,6 +211,8 @@ analyze_test_result([Result|Rs], Args) -> end; analyze_test_result([], _) -> ?EXIT_STATUS_TEST_SUCCESSFUL; +analyze_test_result(interactive_mode, _) -> + interactive_mode; analyze_test_result(Unknown, _) -> io:format("\nTest run failed! Reason:\n~p\n\n\n",[Unknown]), ?EXIT_STATUS_TEST_RUN_FAILED. @@ -218,17 +220,22 @@ analyze_test_result(Unknown, _) -> finish(Tracing, ExitStatus, Args) -> stop_trace(Tracing), timer:sleep(1000), - %% it's possible to tell CT to finish execution with a call - %% to a different function than the normal halt/1 BIF - %% (meant to be used mainly for reading the CT exit status) - case get_start_opt(halt_with, - fun([HaltMod,HaltFunc]) -> {list_to_atom(HaltMod), - list_to_atom(HaltFunc)} end, - Args) of - undefined -> - halt(ExitStatus); - {M,F} -> - apply(M, F, [ExitStatus]) + if ExitStatus == interactive_mode -> + interactive_mode; + true -> + %% it's possible to tell CT to finish execution with a call + %% to a different function than the normal halt/1 BIF + %% (meant to be used mainly for reading the CT exit status) + case get_start_opt(halt_with, + fun([HaltMod,HaltFunc]) -> + {list_to_atom(HaltMod), + list_to_atom(HaltFunc)} end, + Args) of + undefined -> + halt(ExitStatus); + {M,F} -> + apply(M, F, [ExitStatus]) + end end. script_start1(Parent, Args) -> @@ -635,6 +642,7 @@ script_start4(#opts{label = Label, profile = Profile, verbosity = Verbosity, enable_builtin_hooks = EnableBuiltinHooks, logdir = LogDir, testspecs = Specs}, _Args) -> + %% label - used by ct_logs application:set_env(common_test, test_label, Label), @@ -655,7 +663,7 @@ script_start4(#opts{label = Label, profile = Profile, ct_util:set_testdata({logopts, LogOpts}), log_ts_names(Specs), io:nl(), - ok; + interactive_mode; Error -> Error end; @@ -2776,6 +2784,8 @@ opts2args(EnvStartOpts) -> [{exit_status,[atom_to_list(ExitStatusOpt)]}]; ({halt_with,{HaltM,HaltF}}) -> [{halt_with,[atom_to_list(HaltM),atom_to_list(HaltF)]}]; + ({interactive_mode,true}) -> + [{shell,[]}]; ({config,CfgFiles}) -> [{ct_config,[CfgFiles]}]; ({userconfig,{CBM,CfgStr=[X|_]}}) when is_integer(X) -> diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile index 7628ada61a..686ee43aa3 100644 --- a/lib/common_test/test/Makefile +++ b/lib/common_test/test/Makefile @@ -50,7 +50,8 @@ MODULES= \ ct_netconfc_SUITE \ ct_basic_html_SUITE \ ct_auto_compile_SUITE \ - ct_verbosity_SUITE + ct_verbosity_SUITE \ + ct_shell_SUITE ERL_FILES= $(MODULES:%=%.erl) diff --git a/lib/common_test/test/ct_config_SUITE.erl b/lib/common_test/test/ct_config_SUITE.erl index 0b1abae757..1e1df908db 100644 --- a/lib/common_test/test/ct_config_SUITE.erl +++ b/lib/common_test/test/ct_config_SUITE.erl @@ -251,6 +251,7 @@ expected_events(config_static_SUITE)-> ?sok(test_alias_tclocal_nested,{14,0,{2,1}}), ?sok(test_alias_tclocal_nested_backward_compat,{15,0,{2,1}}), ?sok(test_alias_tclocal_nested_backward_compat_subvals,{16,0,{2,1}}), + ?sok(test_config_same_name_already_in_use,{17,0,{2,1}}), {?eh,tc_start,{config_static_SUITE,end_per_suite}}, {?eh,tc_done,{config_static_SUITE,end_per_suite,ok}}, {?eh,test_done,{'DEF','STOP_TIME'}}, diff --git a/lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl b/lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl index 2e1ad651e8..19f1dab4af 100644 --- a/lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl +++ b/lib/common_test/test/ct_config_SUITE_data/config/test/config_static_SUITE.erl @@ -64,7 +64,8 @@ all() -> [test_get_config_simple, test_get_config_nested, test_shadow_all,test_element,test_shadow_all_element, test_internal_deep, test_alias_tclocal_nested, test_alias_tclocal_nested_backward_compat, - test_alias_tclocal_nested_backward_compat_subvals + test_alias_tclocal_nested_backward_compat_subvals, + test_config_same_name_already_in_use ]. init_per_testcase(_,Config) -> @@ -124,6 +125,13 @@ test_config_name_already_in_use2(_) -> ct:fail("Test should've been skipped, you shouldn't see this!"), ok. + +test_config_same_name_already_in_use() -> + []. +test_config_same_name_already_in_use(_) -> + ok = ct:require(x2,{gen_cfg,c}), + ok = ct:require(x2,{gen_cfg,c}). + %% test aliases test_alias_tclocal() -> [{require,newalias,gen_cfg}]. diff --git a/lib/common_test/test/ct_netconfc_SUITE.erl b/lib/common_test/test/ct_netconfc_SUITE.erl index e6e8d5b09c..30084a6228 100644 --- a/lib/common_test/test/ct_netconfc_SUITE.erl +++ b/lib/common_test/test/ct_netconfc_SUITE.erl @@ -44,7 +44,12 @@ %%-------------------------------------------------------------------- init_per_suite(Config) -> Config1 = ct_test_support:init_per_suite(Config), - Config1. + case application:load(crypto) of + {error,Reason} -> + {skip, Reason}; + _ -> + Config1 + end. end_per_suite(Config) -> ct_test_support:end_per_suite(Config). diff --git a/lib/common_test/test/ct_shell_SUITE.erl b/lib/common_test/test/ct_shell_SUITE.erl new file mode 100644 index 0000000000..4b8c43d800 --- /dev/null +++ b/lib/common_test/test/ct_shell_SUITE.erl @@ -0,0 +1,133 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%%%------------------------------------------------------------------- +%%% File: ct_shell_SUITE +%%% +%%% Description: +%%% Test that the interactive mode starts properly +%%% +%%% The suites used for the test are located in the data directory. +%%%------------------------------------------------------------------- +-module(ct_shell_SUITE). + +-compile(export_all). + +-include_lib("common_test/include/ct.hrl"). +-include_lib("common_test/include/ct_event.hrl"). + +-define(eh, ct_test_support_eh). + +%%-------------------------------------------------------------------- +%% TEST SERVER CALLBACK FUNCTIONS +%%-------------------------------------------------------------------- + +init_per_suite(Config) -> + Config1 = ct_test_support:init_per_suite(Config), + Config1. + +end_per_suite(Config) -> + ct_test_support:end_per_suite(Config). + +init_per_testcase(TestCase, Config) -> + ct_test_support:init_per_testcase(TestCase, Config). + +end_per_testcase(TestCase, Config) -> + ct_test_support:end_per_testcase(TestCase, Config). + +suite() -> [{ct_hooks,[ts_install_cth]}]. + +all() -> + [start_interactive]. + +%%-------------------------------------------------------------------- +%% TEST CASES +%%-------------------------------------------------------------------- + +%%%----------------------------------------------------------------- +%%% +start_interactive(Config) -> + DataDir = ?config(data_dir, Config), + CfgFile = filename:join(DataDir, "cfgdata"), + + {Opts,ERPid} = setup([{interactive_mode,true},{config,CfgFile}], + Config), + CTNode = proplists:get_value(ct_node, Config), + Level = proplists:get_value(trace_level, Config), + test_server:format(Level, "Saving start opts on ~p: ~p~n", + [CTNode, Opts]), + rpc:call(CTNode, application, set_env, + [common_test, run_test_start_opts, Opts]), + test_server:format(Level, "Calling ct_run:script_start() on ~p~n", + [CTNode]), + + interactive_mode = rpc:call(CTNode, ct_run, script_start, []), + + ok = rpc:call(CTNode, ct, require, [key1]), + value1 = rpc:call(CTNode, ct, get_config, [key1]), + ok = rpc:call(CTNode, ct, require, [x,key2]), + value2 = rpc:call(CTNode, ct, get_config, [x]), + + ok = rpc:call(CTNode, ct, stop_interactive, []), + + case rpc:call(CTNode, erlang, whereis, [ct_util_server]) of + undefined -> + ok; + _ -> + test_server:format(Level, + "ct_util_server not stopped on ~p yet, waiting 5 s...~n", + [CTNode]), + timer:sleep(5000), + undefined = rpc:call(CTNode, erlang, whereis, [ct_util_server]) + end, + Events = ct_test_support:get_events(ERPid, Config), + + ct_test_support:log_events(start_interactive, + reformat(Events, ?eh), + ?config(priv_dir, Config), + Opts), + TestEvents = test_events(start_interactive), + ok = ct_test_support:verify_events(TestEvents, Events, Config). + +%%%----------------------------------------------------------------- +%%% HELP FUNCTIONS +%%%----------------------------------------------------------------- + +setup(Test, Config) -> + Opts0 = ct_test_support:get_opts(Config), + Level = ?config(trace_level, Config), + EvHArgs = [{cbm,ct_test_support},{trace_level,Level}], + Opts = Opts0 ++ [{event_handler,{?eh,EvHArgs}}|Test], + ERPid = ct_test_support:start_event_receiver(Config), + {Opts,ERPid}. + +reformat(Events, EH) -> + ct_test_support:reformat(Events, EH). + +%%%----------------------------------------------------------------- +%%% TEST EVENTS +%%%----------------------------------------------------------------- + +test_events(start_interactive) -> + [ + {?eh,start_logging,{'DEF','RUNDIR'}}, + {?eh,test_start,{'DEF',{'START_TIME','LOGDIR'}}}, + {?eh,test_done,{'DEF','STOP_TIME'}}, + {?eh,stop_logging,[]} + ]. diff --git a/lib/common_test/test/ct_shell_SUITE_data/cfgdata b/lib/common_test/test/ct_shell_SUITE_data/cfgdata new file mode 100644 index 0000000000..23a40ad21a --- /dev/null +++ b/lib/common_test/test/ct_shell_SUITE_data/cfgdata @@ -0,0 +1,2 @@ +{key1,value1}. +{key2,value2}. diff --git a/lib/common_test/vsn.mk b/lib/common_test/vsn.mk index 877aa775fd..5c9fdfc47e 100644 --- a/lib/common_test/vsn.mk +++ b/lib/common_test/vsn.mk @@ -1 +1 @@ -COMMON_TEST_VSN = 1.6.2 +COMMON_TEST_VSN = 1.6.2.1 diff --git a/lib/dialyzer/src/dialyzer.erl b/lib/dialyzer/src/dialyzer.erl index 3e3c12405f..99388438b1 100644 --- a/lib/dialyzer/src/dialyzer.erl +++ b/lib/dialyzer/src/dialyzer.erl @@ -162,14 +162,17 @@ run(Opts) -> {error, Msg} -> throw({dialyzer_error, Msg}); OptsRecord -> - case cl_check_init(OptsRecord) of - {ok, ?RET_NOTHING_SUSPICIOUS} -> - case dialyzer_cl:start(OptsRecord) of - {?RET_DISCREPANCIES, Warnings} -> Warnings; - {?RET_NOTHING_SUSPICIOUS, []} -> [] - end; - {error, ErrorMsg1} -> - throw({dialyzer_error, ErrorMsg1}) + case OptsRecord#options.check_plt of + true -> + case cl_check_init(OptsRecord) of + {ok, ?RET_NOTHING_SUSPICIOUS} -> ok; + {error, ErrorMsg1} -> throw({dialyzer_error, ErrorMsg1}) + end; + false -> ok + end, + case dialyzer_cl:start(OptsRecord) of + {?RET_DISCREPANCIES, Warnings} -> Warnings; + {?RET_NOTHING_SUSPICIOUS, []} -> [] end catch throw:{dialyzer_error, ErrorMsg} -> diff --git a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl index c237d4e0e9..86618a4915 100644 --- a/lib/dialyzer/src/dialyzer_analysis_callgraph.erl +++ b/lib/dialyzer/src/dialyzer_analysis_callgraph.erl @@ -326,13 +326,6 @@ cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent, ModuleDeps = dialyzer_callgraph:module_deps(Callgraph), send_mod_deps(Parent, ModuleDeps), {Callgraph1, ExtCalls} = dialyzer_callgraph:remove_external(Callgraph), - RelevantAPICalls = - dialyzer_behaviours:get_behaviour_apis([gen_server]), - BehaviourAPICalls = [Call || {_From, To} = Call <- ExtCalls, - lists:member(To, RelevantAPICalls)], - Callgraph2 = - dialyzer_callgraph:put_behaviour_api_calls(BehaviourAPICalls, - Callgraph1), ExtCalls1 = [Call || Call = {_From, To} <- ExtCalls, not dialyzer_plt:contains_mfa(InitPlt, To)], {BadCalls1, RealExtCalls} = @@ -355,7 +348,7 @@ cleanup_callgraph(#analysis_state{plt = InitPlt, parent = Parent, true -> send_ext_calls(Parent, lists:usort([To || {_From, To} <- RealExtCalls])) end, - Callgraph2. + Callgraph1. compile_src(File, Includes, Defines, Callgraph, CServer, UseContracts) -> DefaultIncludes = default_includes(filename:dirname(File)), diff --git a/lib/dialyzer/src/dialyzer_behaviours.erl b/lib/dialyzer/src/dialyzer_behaviours.erl index b84071b95c..36aef2a37f 100644 --- a/lib/dialyzer/src/dialyzer_behaviours.erl +++ b/lib/dialyzer/src/dialyzer_behaviours.erl @@ -30,11 +30,9 @@ -module(dialyzer_behaviours). --export([check_callbacks/5, get_behaviour_apis/1, - translate_behaviour_api_call/5, translatable_behaviours/1, - translate_callgraph/3]). +-export([check_callbacks/5]). --export_type([behaviour/0, behaviour_api_dict/0]). +-export_type([behaviour/0]). %%-------------------------------------------------------------------- @@ -224,103 +222,3 @@ get_line([]) -> -1. get_file([{file, File}|_]) -> File; get_file([_|Tail]) -> get_file(Tail). - -%%----------------------------------------------------------------------------- - --spec translatable_behaviours(cerl:c_module()) -> behaviour_api_dict(). - -translatable_behaviours(Tree) -> - Attrs = cerl:module_attrs(Tree), - {Behaviours, _BehLines} = get_behaviours(Attrs), - [{B, Calls} || B <- Behaviours, (Calls = behaviour_api_calls(B)) =/= []]. - --spec get_behaviour_apis([behaviour()]) -> [mfa()]. - -get_behaviour_apis(Behaviours) -> - get_behaviour_apis(Behaviours, []). - --spec translate_behaviour_api_call(dialyzer_callgraph:mfa_or_funlbl(), - [erl_types:erl_type()], - [dialyzer_races:core_vars()], - module(), - behaviour_api_dict()) -> - {dialyzer_callgraph:mfa_or_funlbl(), - [erl_types:erl_type()], - [dialyzer_races:core_vars()]} - | 'plain_call'. - -translate_behaviour_api_call(_Fun, _ArgTypes, _Args, _Module, []) -> - plain_call; -translate_behaviour_api_call({Module, Fun, Arity}, ArgTypes, Args, - CallbackModule, BehApiInfo) -> - case lists:keyfind(Module, 1, BehApiInfo) of - false -> plain_call; - {Module, Calls} -> - case lists:keyfind({Fun, Arity}, 1, Calls) of - false -> plain_call; - {{Fun, Arity}, {CFun, CArity, COrder}} -> - {{CallbackModule, CFun, CArity}, - [nth_or_0(N, ArgTypes, erl_types:t_any()) || N <-COrder], - [nth_or_0(N, Args, bypassed) || N <-COrder]} - end - end; -translate_behaviour_api_call(_Fun, _ArgTypes, _Args, _Module, _BehApiInfo) -> - plain_call. - --spec translate_callgraph(behaviour_api_dict(), atom(), - dialyzer_callgraph:callgraph()) -> - dialyzer_callgraph:callgraph(). - -translate_callgraph([{Behaviour,_}|Behaviours], Module, Callgraph) -> - UsedCalls = [Call || {_From, {M, _F, _A}} = Call <- - dialyzer_callgraph:get_behaviour_api_calls(Callgraph), - M =:= Behaviour], - Calls = [{{Behaviour, API, Arity}, Callback} || - {{API, Arity}, Callback} <- behaviour_api_calls(Behaviour)], - DirectCalls = [{From, {Module, Fun, Arity}} || - {From, To} <- UsedCalls,{API, {Fun, Arity, _Ord}} <- Calls, - To =:= API], - dialyzer_callgraph:add_edges(DirectCalls, Callgraph), - translate_callgraph(Behaviours, Module, Callgraph); -translate_callgraph([], _Module, Callgraph) -> - Callgraph. - -get_behaviour_apis([], Acc) -> - Acc; -get_behaviour_apis([Behaviour | Rest], Acc) -> - MFAs = [{Behaviour, Fun, Arity} || - {{Fun, Arity}, _} <- behaviour_api_calls(Behaviour)], - get_behaviour_apis(Rest, MFAs ++ Acc). - -%------------------------------------------------------------------------------ - -nth_or_0(0, _List, Zero) -> - Zero; -nth_or_0(N, List, _Zero) -> - lists:nth(N, List). - -%------------------------------------------------------------------------------ - --type behaviour_api_dict()::[{behaviour(), behaviour_api_info()}]. --type behaviour_api_info()::[{original_fun(), replacement_fun()}]. --type original_fun()::{atom(), arity()}. --type replacement_fun()::{atom(), arity(), arg_list()}. --type arg_list()::[byte()]. - --spec behaviour_api_calls(behaviour()) -> behaviour_api_info(). - -behaviour_api_calls(gen_server) -> - [{{start_link, 3}, {init, 1, [2]}}, - {{start_link, 4}, {init, 1, [3]}}, - {{start, 3}, {init, 1, [2]}}, - {{start, 4}, {init, 1, [3]}}, - {{call, 2}, {handle_call, 3, [2, 0, 0]}}, - {{call, 3}, {handle_call, 3, [2, 0, 0]}}, - {{multi_call, 2}, {handle_call, 3, [2, 0, 0]}}, - {{multi_call, 3}, {handle_call, 3, [3, 0, 0]}}, - {{multi_call, 4}, {handle_call, 3, [3, 0, 0]}}, - {{cast, 2}, {handle_cast, 2, [2, 0]}}, - {{abcast, 2}, {handle_cast, 2, [2, 0]}}, - {{abcast, 3}, {handle_cast, 2, [3, 0]}}]; -behaviour_api_calls(_Other) -> - []. diff --git a/lib/dialyzer/src/dialyzer_dataflow.erl b/lib/dialyzer/src/dialyzer_dataflow.erl index 7131633da1..0ef008bc58 100644 --- a/lib/dialyzer/src/dialyzer_dataflow.erl +++ b/lib/dialyzer/src/dialyzer_dataflow.erl @@ -91,9 +91,8 @@ warning_mode = false :: boolean(), warnings = [] :: [dial_warning()], work :: {[_], [_], set()}, - module :: module(), - behaviour_api_dict = [] :: - dialyzer_behaviours:behaviour_api_dict()}). + module :: module() + }). -record(map, {dict = dict:new() :: dict(), subst = dict:new() :: dict(), @@ -135,38 +134,15 @@ get_fun_types(Tree, Plt, Callgraph, Records) -> analyze_module(Tree, Plt, Callgraph, Records, GetWarnings) -> debug_pp(Tree, false), Module = cerl:atom_val(cerl:module_name(Tree)), - RaceDetection = dialyzer_callgraph:get_race_detection(Callgraph), - BehaviourTranslations = - case RaceDetection of - true -> dialyzer_behaviours:translatable_behaviours(Tree); - false -> [] - end, TopFun = cerl:ann_c_fun([{label, top}], [], Tree), - State = - state__new(Callgraph, TopFun, Plt, Module, Records, BehaviourTranslations), + State = state__new(Callgraph, TopFun, Plt, Module, Records), State1 = state__race_analysis(not GetWarnings, State), State2 = analyze_loop(State1), case GetWarnings of true -> State3 = state__set_warning_mode(State2), State4 = analyze_loop(State3), - - %% EXPERIMENTAL: Turn all behaviour API calls into calls to the - %% respective callback module's functions. - - case BehaviourTranslations of - [] -> dialyzer_races:race(State4); - Behaviours -> - Digraph = dialyzer_callgraph:get_digraph(State4#state.callgraph), - TranslatedCallgraph = - dialyzer_behaviours:translate_callgraph(Behaviours, Module, - Callgraph), - St = - dialyzer_races:race(State4#state{callgraph = TranslatedCallgraph}), - FinalCallgraph = dialyzer_callgraph:put_digraph(Digraph, - St#state.callgraph), - St#state{callgraph = FinalCallgraph} - end; + dialyzer_races:race(State4); false -> State2 end. @@ -530,21 +506,8 @@ handle_apply_or_call([{TypeOfApply, {Fun, Sig, Contr, LocalRet}}|Left], Ann = cerl:get_ann(Tree), File = get_file(Ann), Line = abs(get_line(Ann)), - - %% EXPERIMENTAL: Turn a behaviour's API call into a call to the - %% respective callback module's function. - - Module = State#state.module, - BehApiDict = State#state.behaviour_api_dict, - {RealFun, RealArgTypes, RealArgs} = - case dialyzer_behaviours:translate_behaviour_api_call(Fun, ArgTypes, - Args, Module, - BehApiDict) of - plain_call -> {Fun, ArgTypes, Args}; - BehaviourAPI -> BehaviourAPI - end, - dialyzer_races:store_race_call(RealFun, RealArgTypes, RealArgs, - {File, Line}, State); + dialyzer_races:store_race_call(Fun, ArgTypes, Args, + {File, Line}, State); false -> State end, FailedConj = any_none([RetWithoutLocal|NewArgTypes]), @@ -2711,7 +2674,7 @@ determine_mode(Type, Opaques) -> %%% %%% =========================================================================== -state__new(Callgraph, Tree, Plt, Module, Records, BehaviourTranslations) -> +state__new(Callgraph, Tree, Plt, Module, Records) -> Opaques = erl_types:module_builtin_opaques(Module) ++ erl_types:t_opaque_from_records(Records), TreeMap = build_tree_map(Tree), @@ -2725,7 +2688,7 @@ state__new(Callgraph, Tree, Plt, Module, Records, BehaviourTranslations) -> #state{callgraph = Callgraph, envs = Env, fun_tab = FunTab, opaques = Opaques, plt = Plt, races = dialyzer_races:new(), records = Records, warning_mode = false, warnings = [], work = Work, tree_map = TreeMap, - module = Module, behaviour_api_dict = BehaviourTranslations}. + module = Module}. state__warning_mode(#state{warning_mode = WM}) -> WM. diff --git a/lib/dialyzer/src/dialyzer_races.erl b/lib/dialyzer/src/dialyzer_races.erl index cdb9f25999..2aa8343bce 100644 --- a/lib/dialyzer/src/dialyzer_races.erl +++ b/lib/dialyzer/src/dialyzer_races.erl @@ -1758,7 +1758,10 @@ compare_var_list(Var, VarList, RaceVarMap) -> ets_list_args(MaybeList) -> case is_list(MaybeList) of - true -> [ets_tuple_args(T) || T <- MaybeList]; + true -> + try [ets_tuple_args(T) || T <- MaybeList] + catch _:_ -> [?no_label] + end; false -> [ets_tuple_args(MaybeList)] end. diff --git a/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10 b/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10 new file mode 100644 index 0000000000..c3c9b12bdd --- /dev/null +++ b/lib/dialyzer/test/race_SUITE_data/results/ets_insert_args10 @@ -0,0 +1,2 @@ + +ets_insert_args10.erl:9: The call ets:insert(T::'foo',[{'counter',number()},...]) might have an unintended effect due to a possible race condition caused by its combination with the ets:lookup(T::'foo','counter') call in ets_insert_args10.erl on line 8 diff --git a/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl b/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl new file mode 100644 index 0000000000..c897a34af0 --- /dev/null +++ b/lib/dialyzer/test/race_SUITE_data/src/ets_insert_args10.erl @@ -0,0 +1,19 @@ +%% This tests the presence of possible races due to an ets:lookup/ets:insert +%% combination. It takes into account the argument types of the calls. + +-module(ets_insert_args10). +-export([start/0]). + +start() -> + F = fun(T) -> [{_, N}] = ets:lookup(T, counter), + ets:insert(T, [{counter, N+1}]) + end, + io:format("Created ~w\n", [ets:new(foo, [named_table, public])]), + A = {counter, 0}, + B = [], + ets:insert(foo, [A|B]), + io:format("Inserted ~w\n", [{counter, 0}]), + F(foo), + io:format("Update complete\n", []), + ObjectList = ets:lookup(foo, counter), + io:format("Counter: ~w\n", [ObjectList]). diff --git a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes index 8dc0361b0d..4850f3ff0c 100644 --- a/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes +++ b/lib/dialyzer/test/small_SUITE_data/results/contracts_with_subtypes @@ -6,7 +6,7 @@ contracts_with_subtypes.erl:109: The call contracts_with_subtypes:rec_arg({'b',{ contracts_with_subtypes.erl:110: The call contracts_with_subtypes:rec_arg({'a',{'b',{'a','b'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A}) contracts_with_subtypes.erl:111: The call contracts_with_subtypes:rec_arg({'b',{'a',{'b','a'}}}) breaks the contract (Arg) -> 'ok' when is_subtype(Arg,{'a',A} | {'b',B}), is_subtype(A,'a' | {'b',B}), is_subtype(B,'b' | {'a',A}) contracts_with_subtypes.erl:142: The pattern 1 can never match the type binary() | string() -contracts_with_subtypes.erl:145: The pattern 'alpha' can never match the type {'ok',X} | {'ok',X,binary() | string()} +contracts_with_subtypes.erl:145: The pattern 'alpha' can never match the type {'ok',_} | {'ok',_,binary() | string()} contracts_with_subtypes.erl:147: The pattern 42 can never match the type {'ok',_} | {'ok',_,binary() | string()} contracts_with_subtypes.erl:163: The pattern 'alpha' can never match the type {'ok',X} contracts_with_subtypes.erl:165: The pattern 42 can never match the type {'ok',X} diff --git a/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl b/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl new file mode 100644 index 0000000000..6c440ed04c --- /dev/null +++ b/lib/dialyzer/test/small_SUITE_data/src/remote_tuple_set.erl @@ -0,0 +1,8 @@ +-module(remote_tuple_set). + +-export([parse_cidr/0]). + +-spec parse_cidr() -> {inet:address_family(),1,2} | {error}. + +parse_cidr() -> + {inet,1,2}. diff --git a/lib/diameter/.gitignore b/lib/diameter/.gitignore index 5afcbedc23..8b13789179 100644 --- a/lib/diameter/.gitignore +++ b/lib/diameter/.gitignore @@ -1,58 +1 @@ -# Match at any level. -*~ -autom4te.cache - -# Compiler derivatives -# -# Do not use too creative wildcards. -# Those might ignore files that should not be ignored. - -i686-pc-linux-gnu -x86_64-unknown-linux-gnu -i386-apple-darwin[0-9]*.[0-9]*.[0-9]* -sparc-sun-solaris[0-9]*.[0-9]* -i386-pc-solaris[0-9]*.[0-9]* -i386-unknown-freebsd[0-9]*.[0-9]* -tile-tilera-linux-gnu -powerpc-unknown-linux-gnu - -# Mac OS X -a.out.dSYM/ - -# Anchored from $DIAMETER_TOP -/config.log -/config.status - -/Makefile -/configure - - -# General patterns for applications in lib. -# -# Assume that all test/Emakefiles are generated. -# -# Any application with a checked-in test/Emakefile should -# use a negative pattern in its own .gitignore. - -# -# Files generated by configure. -# - -/configure -/config.log -/config.status - - -# -# Generated documentation. (ie. not doc/src) -# - -/doc/[^s]* - - -# -# Files generated when building/running tests -# - -/test/*.log diff --git a/lib/diameter/Makefile b/lib/diameter/Makefile new file mode 100644 index 0000000000..9961d627cf --- /dev/null +++ b/lib/diameter/Makefile @@ -0,0 +1,32 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2010-2012. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% + +include $(ERL_TOP)/make/target.mk +include $(ERL_TOP)/make/$(TARGET)/otp.mk +include vsn.mk +include subdirs.mk + +SUB_DIRECTORIES = $(SUB_DIRS) doc/src +SPECIAL_TARGETS = + +include $(ERL_TOP)/make/otp_subdir.mk + +info: + @echo "APP_VSN = $(APP_VSN)" + +.PHONY: info diff --git a/lib/diameter/Makefile.in b/lib/diameter/Makefile.in deleted file mode 100644 index cf38c26045..0000000000 --- a/lib/diameter/Makefile.in +++ /dev/null @@ -1,88 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2010-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% - -ifneq ($(ERL_TOP),) -include $(ERL_TOP)/make/target.mk -include $(ERL_TOP)/make/$(TARGET)/otp.mk -else -include $(DIAMETER_TOP)/make/target.mk -include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk -endif - -# ---------------------------------------------------- -# Application version -# ---------------------------------------------------- -include vsn.mk -VSN=$(DIAMETER_VSN) - -DIAMETER_TOP = @DIAMETER_TOP@ - - -# ---------------------------------------------------- -# Common Macros -# ---------------------------------------------------- - -include subdirs.mk - -SUB_DIRECTORIES = $(SUB_DIRS) doc/src - -SPECIAL_TARGETS = - -ifneq ($(ERL_TOP),) -ifneq ($(PREFIX),) -CONFIGURE_OPTS += --prefix=$(PREFIX) -endif -endif - - -# ---------------------------------------------------- -# Default Subdir Targets -# ---------------------------------------------------- -ifneq ($(ERL_TOP),) -include $(ERL_TOP)/make/otp_subdir.mk -else -include $(DIAMETER_TOP)/make/subdir.mk -endif - -.PHONY: reconf conf info version dialyzer - -reconf: - autoconf - -conf: do_configure - -do_configure: configure - ./configure $(CONFIGURE_OPTS) - -configure: configure.in - autoconf - -info: - @echo "APP_VSN: $(APP_VSN)" - @echo "DIAMETER_VSN: $(DIAMETER_VSN)" - -version: - @echo "$(VSN)" - - -dialyzer: - (cd ./ebin; \ - dialyzer --build_plt \ - --output_plt ../priv/diameter.plt \ - -r ../../diameter/ebin \ - --verbose) diff --git a/lib/diameter/aclocal.m4 b/lib/diameter/aclocal.m4 deleted file mode 100644 index 2abb47dba2..0000000000 --- a/lib/diameter/aclocal.m4 +++ /dev/null @@ -1,65 +0,0 @@ -dnl -dnl %CopyrightBegin% -dnl -dnl Copyright Ericsson AB 1998-2011. All Rights Reserved. -dnl -dnl The contents of this file are subject to the Erlang Public License, -dnl Version 1.1, (the "License"); you may not use this file except in -dnl compliance with the License. You should have received a copy of the -dnl Erlang Public License along with this software. If not, it can be -dnl retrieved online at http://www.erlang.org/. -dnl -dnl Software distributed under the License is distributed on an "AS IS" -dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -dnl the License for the specific language governing rights and limitations -dnl under the License. -dnl -dnl %CopyrightEnd% -dnl - -dnl -dnl aclocal.m4 -dnl -dnl Local macros used in configure.in. The Local Macros which -dnl could/should be part of autoconf are prefixed LM_, macros specific -dnl to the Erlang system are prefixed ERL_. -dnl - -dnl ---------------------------------------------------------------------- -dnl -dnl LM_PROG_INSTALL_DIR -dnl -dnl Figure out how to create directories with parents. -dnl (In my opinion INSTALL_DIR is a bad name, MKSUBDIRS or something is better) -dnl -dnl We prefer 'install -d', but use 'mkdir -p' if it exists. -dnl If none of these methods works, we give up. -dnl - - -AC_DEFUN(LM_PROG_INSTALL_DIR, -[AC_CACHE_CHECK(how to create a directory including parents, -ac_cv_prog_mkdir_p, -[ -temp_name_base=config.$$ -temp_name=$temp_name_base/x/y/z -$INSTALL -d $temp_name >/dev/null 2>&1 -ac_cv_prog_mkdir_p=none -if test -d $temp_name; then - ac_cv_prog_mkdir_p="$INSTALL -d" -else - mkdir -p $temp_name >/dev/null 2>&1 - if test -d $temp_name; then - ac_cv_prog_mkdir_p="mkdir -p" - fi -fi -rm -fr $temp_name_base -]) - -case "${ac_cv_prog_mkdir_p}" in - none) AC_MSG_ERROR(don't know how create directories with parents) ;; - *) INSTALL_DIR="$ac_cv_prog_mkdir_p" AC_SUBST(INSTALL_DIR) ;; -esac -]) - - diff --git a/lib/diameter/autoconf/config.guess b/lib/diameter/autoconf/config.guess deleted file mode 100755 index 38a833903b..0000000000 --- a/lib/diameter/autoconf/config.guess +++ /dev/null @@ -1,1519 +0,0 @@ -#! /bin/sh -# Attempt to guess a canonical system name. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. - -timestamp='2007-05-17' - -# This file is free software; you can redistribute it and/or modify it -# under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Originally written by Per Bothner <[email protected]>. -# Please send patches to <[email protected]>. Submit a context -# diff and a properly formatted ChangeLog entry. -# -# This script attempts to guess a canonical system name similar to -# config.sub. If it succeeds, it prints the system name on stdout, and -# exits with 0. Otherwise, it exits with 1. -# -# The plan is that this can be called by configure scripts if you -# don't specify an explicit build system type. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] - -Output the configuration name of the system \`$me' is run on. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to <[email protected]>." - -version="\ -GNU config.guess ($timestamp) - -Originally written by Per Bothner. -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" >&2 - exit 1 ;; - * ) - break ;; - esac -done - -if test $# != 0; then - echo "$me: too many arguments$help" >&2 - exit 1 -fi - -trap 'exit 1' 1 2 15 - -# CC_FOR_BUILD -- compiler used by this script. Note that the use of a -# compiler to aid in system detection is discouraged as it requires -# temporary files to be created and, as you can see below, it is a -# headache to deal with in a portable fashion. - -# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still -# use `HOST_CC' if defined, but it is deprecated. - -# Portable tmp directory creation inspired by the Autoconf team. - -set_cc_for_build=' -trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; -trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; -: ${TMPDIR=/tmp} ; - { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || - { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || - { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || - { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; -dummy=$tmp/dummy ; -tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; -case $CC_FOR_BUILD,$HOST_CC,$CC in - ,,) echo "int x;" > $dummy.c ; - for c in cc gcc c89 c99 ; do - if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then - CC_FOR_BUILD="$c"; break ; - fi ; - done ; - if test x"$CC_FOR_BUILD" = x ; then - CC_FOR_BUILD=no_compiler_found ; - fi - ;; - ,,*) CC_FOR_BUILD=$CC ;; - ,*,*) CC_FOR_BUILD=$HOST_CC ;; -esac ; set_cc_for_build= ;' - -# This is needed to find uname on a Pyramid OSx when run in the BSD universe. -# ([email protected] 1994-08-24) -if (test -f /.attbin/uname) >/dev/null 2>&1 ; then - PATH=$PATH:/.attbin ; export PATH -fi - -UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown -UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown -UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown -UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown - -# Note: order is significant - the case branches are not exclusive. - -case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in - *:NetBSD:*:*) - # NetBSD (nbsd) targets should (where applicable) match one or - # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, - # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently - # switched to ELF, *-*-netbsd* would select the old - # object file format. This provides both forward - # compatibility and a consistent mechanism for selecting the - # object file format. - # - # Note: NetBSD doesn't particularly care about the vendor - # portion of the name. We always set it to "unknown". - sysctl="sysctl -n hw.machine_arch" - UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ - /usr/sbin/$sysctl 2>/dev/null || echo unknown)` - case "${UNAME_MACHINE_ARCH}" in - armeb) machine=armeb-unknown ;; - arm*) machine=arm-unknown ;; - sh3el) machine=shl-unknown ;; - sh3eb) machine=sh-unknown ;; - sh5el) machine=sh5le-unknown ;; - *) machine=${UNAME_MACHINE_ARCH}-unknown ;; - esac - # The Operating System including object format, if it has switched - # to ELF recently, or will in the future. - case "${UNAME_MACHINE_ARCH}" in - arm*|i386|m68k|ns32k|sh3*|sparc|vax) - eval $set_cc_for_build - if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ - | grep __ELF__ >/dev/null - then - # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). - # Return netbsd for either. FIX? - os=netbsd - else - os=netbsdelf - fi - ;; - *) - os=netbsd - ;; - esac - # The OS release - # Debian GNU/NetBSD machines have a different userland, and - # thus, need a distinct triplet. However, they do not need - # kernel version information, so it can be replaced with a - # suitable tag, in the style of linux-gnu. - case "${UNAME_VERSION}" in - Debian*) - release='-gnu' - ;; - *) - release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` - ;; - esac - # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: - # contains redundant information, the shorter form: - # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. - echo "${machine}-${os}${release}" - exit ;; - *:OpenBSD:*:*) - UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` - echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} - exit ;; - *:ekkoBSD:*:*) - echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} - exit ;; - *:SolidBSD:*:*) - echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} - exit ;; - macppc:MirBSD:*:*) - echo powerpc-unknown-mirbsd${UNAME_RELEASE} - exit ;; - *:MirBSD:*:*) - echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} - exit ;; - alpha:OSF1:*:*) - case $UNAME_RELEASE in - *4.0) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` - ;; - *5.*) - UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` - ;; - esac - # According to Compaq, /usr/sbin/psrinfo has been available on - # OSF/1 and Tru64 systems produced since 1995. I hope that - # covers most systems running today. This code pipes the CPU - # types through head -n 1, so we only detect the type of CPU 0. - ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` - case "$ALPHA_CPU_TYPE" in - "EV4 (21064)") - UNAME_MACHINE="alpha" ;; - "EV4.5 (21064)") - UNAME_MACHINE="alpha" ;; - "LCA4 (21066/21068)") - UNAME_MACHINE="alpha" ;; - "EV5 (21164)") - UNAME_MACHINE="alphaev5" ;; - "EV5.6 (21164A)") - UNAME_MACHINE="alphaev56" ;; - "EV5.6 (21164PC)") - UNAME_MACHINE="alphapca56" ;; - "EV5.7 (21164PC)") - UNAME_MACHINE="alphapca57" ;; - "EV6 (21264)") - UNAME_MACHINE="alphaev6" ;; - "EV6.7 (21264A)") - UNAME_MACHINE="alphaev67" ;; - "EV6.8CB (21264C)") - UNAME_MACHINE="alphaev68" ;; - "EV6.8AL (21264B)") - UNAME_MACHINE="alphaev68" ;; - "EV6.8CX (21264D)") - UNAME_MACHINE="alphaev68" ;; - "EV6.9A (21264/EV69A)") - UNAME_MACHINE="alphaev69" ;; - "EV7 (21364)") - UNAME_MACHINE="alphaev7" ;; - "EV7.9 (21364A)") - UNAME_MACHINE="alphaev79" ;; - esac - # A Pn.n version is a patched version. - # A Vn.n version is a released version. - # A Tn.n version is a released field test version. - # A Xn.n version is an unreleased experimental baselevel. - # 1.2 uses "1.2" for uname -r. - echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - exit ;; - Alpha\ *:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # Should we change UNAME_MACHINE based on the output of uname instead - # of the specific Alpha model? - echo alpha-pc-interix - exit ;; - 21064:Windows_NT:50:3) - echo alpha-dec-winnt3.5 - exit ;; - Amiga*:UNIX_System_V:4.0:*) - echo m68k-unknown-sysv4 - exit ;; - *:[Aa]miga[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-amigaos - exit ;; - *:[Mm]orph[Oo][Ss]:*:*) - echo ${UNAME_MACHINE}-unknown-morphos - exit ;; - *:OS/390:*:*) - echo i370-ibm-openedition - exit ;; - *:z/VM:*:*) - echo s390-ibm-zvmoe - exit ;; - *:OS400:*:*) - echo powerpc-ibm-os400 - exit ;; - arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) - echo arm-acorn-riscix${UNAME_RELEASE} - exit ;; - arm:riscos:*:*|arm:RISCOS:*:*) - echo arm-unknown-riscos - exit ;; - SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) - echo hppa1.1-hitachi-hiuxmpp - exit ;; - Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) - # [email protected] (Earle F. Ake) contributed MIS and NILE. - if test "`(/bin/universe) 2>/dev/null`" = att ; then - echo pyramid-pyramid-sysv3 - else - echo pyramid-pyramid-bsd - fi - exit ;; - NILE*:*:*:dcosx) - echo pyramid-pyramid-svr4 - exit ;; - DRS?6000:unix:4.0:6*) - echo sparc-icl-nx6 - exit ;; - DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) - case `/usr/bin/uname -p` in - sparc) echo sparc-icl-nx7; exit ;; - esac ;; - sun4H:SunOS:5.*:*) - echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) - echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - i86pc:SunOS:5.*:* | ix86xen:SunOS:5.*:*) - echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:6*:*) - # According to config.sub, this is the proper way to canonicalize - # SunOS6. Hard to guess exactly what SunOS6 will be like, but - # it's likely to be more like Solaris than SunOS4. - echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - sun4*:SunOS:*:*) - case "`/usr/bin/arch -k`" in - Series*|S4*) - UNAME_RELEASE=`uname -v` - ;; - esac - # Japanese Language versions have a version number like `4.1.3-JL'. - echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` - exit ;; - sun3*:SunOS:*:*) - echo m68k-sun-sunos${UNAME_RELEASE} - exit ;; - sun*:*:4.2BSD:*) - UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` - test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 - case "`/bin/arch`" in - sun3) - echo m68k-sun-sunos${UNAME_RELEASE} - ;; - sun4) - echo sparc-sun-sunos${UNAME_RELEASE} - ;; - esac - exit ;; - aushp:SunOS:*:*) - echo sparc-auspex-sunos${UNAME_RELEASE} - exit ;; - # The situation for MiNT is a little confusing. The machine name - # can be virtually everything (everything which is not - # "atarist" or "atariste" at least should have a processor - # > m68000). The system name ranges from "MiNT" over "FreeMiNT" - # to the lowercase version "mint" (or "freemint"). Finally - # the system name "TOS" denotes a system which is actually not - # MiNT. But MiNT is downward compatible to TOS, so this should - # be no problem. - atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) - echo m68k-atari-mint${UNAME_RELEASE} - exit ;; - milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) - echo m68k-milan-mint${UNAME_RELEASE} - exit ;; - hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) - echo m68k-hades-mint${UNAME_RELEASE} - exit ;; - *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) - echo m68k-unknown-mint${UNAME_RELEASE} - exit ;; - m68k:machten:*:*) - echo m68k-apple-machten${UNAME_RELEASE} - exit ;; - powerpc:machten:*:*) - echo powerpc-apple-machten${UNAME_RELEASE} - exit ;; - RISC*:Mach:*:*) - echo mips-dec-mach_bsd4.3 - exit ;; - RISC*:ULTRIX:*:*) - echo mips-dec-ultrix${UNAME_RELEASE} - exit ;; - VAX*:ULTRIX*:*:*) - echo vax-dec-ultrix${UNAME_RELEASE} - exit ;; - 2020:CLIX:*:* | 2430:CLIX:*:*) - echo clipper-intergraph-clix${UNAME_RELEASE} - exit ;; - mips:*:*:UMIPS | mips:*:*:RISCos) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c -#ifdef __cplusplus -#include <stdio.h> /* for printf() prototype */ - int main (int argc, char *argv[]) { -#else - int main (argc, argv) int argc; char *argv[]; { -#endif - #if defined (host_mips) && defined (MIPSEB) - #if defined (SYSTYPE_SYSV) - printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_SVR4) - printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); - #endif - #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) - printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); - #endif - #endif - exit (-1); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && - dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && - SYSTEM_NAME=`$dummy $dummyarg` && - { echo "$SYSTEM_NAME"; exit; } - echo mips-mips-riscos${UNAME_RELEASE} - exit ;; - Motorola:PowerMAX_OS:*:*) - echo powerpc-motorola-powermax - exit ;; - Motorola:*:4.3:PL8-*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) - echo powerpc-harris-powermax - exit ;; - Night_Hawk:Power_UNIX:*:*) - echo powerpc-harris-powerunix - exit ;; - m88k:CX/UX:7*:*) - echo m88k-harris-cxux7 - exit ;; - m88k:*:4*:R4*) - echo m88k-motorola-sysv4 - exit ;; - m88k:*:3*:R3*) - echo m88k-motorola-sysv3 - exit ;; - AViiON:dgux:*:*) - # DG/UX returns AViiON for all architectures - UNAME_PROCESSOR=`/usr/bin/uname -p` - if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] - then - if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ - [ ${TARGET_BINARY_INTERFACE}x = x ] - then - echo m88k-dg-dgux${UNAME_RELEASE} - else - echo m88k-dg-dguxbcs${UNAME_RELEASE} - fi - else - echo i586-dg-dgux${UNAME_RELEASE} - fi - exit ;; - M88*:DolphinOS:*:*) # DolphinOS (SVR3) - echo m88k-dolphin-sysv3 - exit ;; - M88*:*:R3*:*) - # Delta 88k system running SVR3 - echo m88k-motorola-sysv3 - exit ;; - XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) - echo m88k-tektronix-sysv3 - exit ;; - Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) - echo m68k-tektronix-bsd - exit ;; - *:IRIX*:*:*) - echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` - exit ;; - ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. - echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id - exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' - i*86:AIX:*:*) - echo i386-ibm-aix - exit ;; - ia64:AIX:*:*) - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} - exit ;; - *:AIX:2:3) - if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include <sys/systemcfg.h> - - main() - { - if (!__power_pc()) - exit(1); - puts("powerpc-ibm-aix3.2.5"); - exit(0); - } -EOF - if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` - then - echo "$SYSTEM_NAME" - else - echo rs6000-ibm-aix3.2.5 - fi - elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then - echo rs6000-ibm-aix3.2.4 - else - echo rs6000-ibm-aix3.2 - fi - exit ;; - *:AIX:*:[45]) - IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` - if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then - IBM_ARCH=rs6000 - else - IBM_ARCH=powerpc - fi - if [ -x /usr/bin/oslevel ] ; then - IBM_REV=`/usr/bin/oslevel` - else - IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} - fi - echo ${IBM_ARCH}-ibm-aix${IBM_REV} - exit ;; - *:AIX:*:*) - echo rs6000-ibm-aix - exit ;; - ibmrt:4.4BSD:*|romp-ibm:BSD:*) - echo romp-ibm-bsd4.4 - exit ;; - ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and - echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to - exit ;; # report: romp-ibm BSD 4.3 - *:BOSX:*:*) - echo rs6000-bull-bosx - exit ;; - DPX/2?00:B.O.S.:*:*) - echo m68k-bull-sysv3 - exit ;; - 9000/[34]??:4.3bsd:1.*:*) - echo m68k-hp-bsd - exit ;; - hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) - echo m68k-hp-bsd4.4 - exit ;; - 9000/[34678]??:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - case "${UNAME_MACHINE}" in - 9000/31? ) HP_ARCH=m68000 ;; - 9000/[34]?? ) HP_ARCH=m68k ;; - 9000/[678][0-9][0-9]) - if [ -x /usr/bin/getconf ]; then - sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` - sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` - case "${sc_cpu_version}" in - 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 - 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 - 532) # CPU_PA_RISC2_0 - case "${sc_kernel_bits}" in - 32) HP_ARCH="hppa2.0n" ;; - 64) HP_ARCH="hppa2.0w" ;; - '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 - esac ;; - esac - fi - if [ "${HP_ARCH}" = "" ]; then - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - - #define _HPUX_SOURCE - #include <stdlib.h> - #include <unistd.h> - - int main () - { - #if defined(_SC_KERNEL_BITS) - long bits = sysconf(_SC_KERNEL_BITS); - #endif - long cpu = sysconf (_SC_CPU_VERSION); - - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1"); break; - case CPU_PA_RISC2_0: - #if defined(_SC_KERNEL_BITS) - switch (bits) - { - case 64: puts ("hppa2.0w"); break; - case 32: puts ("hppa2.0n"); break; - default: puts ("hppa2.0"); break; - } break; - #else /* !defined(_SC_KERNEL_BITS) */ - puts ("hppa2.0"); break; - #endif - default: puts ("hppa1.0"); break; - } - exit (0); - } -EOF - (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` - test -z "$HP_ARCH" && HP_ARCH=hppa - fi ;; - esac - if [ ${HP_ARCH} = "hppa2.0w" ] - then - eval $set_cc_for_build - - # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating - # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler - # generating 64-bit code. GNU and HP use different nomenclature: - # - # $ CC_FOR_BUILD=cc ./config.guess - # => hppa2.0w-hp-hpux11.23 - # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess - # => hppa64-hp-hpux11.23 - - if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | - grep __LP64__ >/dev/null - then - HP_ARCH="hppa2.0w" - else - HP_ARCH="hppa64" - fi - fi - echo ${HP_ARCH}-hp-hpux${HPUX_REV} - exit ;; - ia64:HP-UX:*:*) - HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` - echo ia64-hp-hpux${HPUX_REV} - exit ;; - 3050*:HI-UX:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include <unistd.h> - int - main () - { - long cpu = sysconf (_SC_CPU_VERSION); - /* The order matters, because CPU_IS_HP_MC68K erroneously returns - true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct - results, however. */ - if (CPU_IS_PA_RISC (cpu)) - { - switch (cpu) - { - case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; - case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; - case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; - default: puts ("hppa-hitachi-hiuxwe2"); break; - } - } - else if (CPU_IS_HP_MC68K (cpu)) - puts ("m68k-hitachi-hiuxwe2"); - else puts ("unknown-hitachi-hiuxwe2"); - exit (0); - } -EOF - $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - echo unknown-hitachi-hiuxwe2 - exit ;; - 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) - echo hppa1.1-hp-bsd - exit ;; - 9000/8??:4.3bsd:*:*) - echo hppa1.0-hp-bsd - exit ;; - *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) - echo hppa1.0-hp-mpeix - exit ;; - hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) - echo hppa1.1-hp-osf - exit ;; - hp8??:OSF1:*:*) - echo hppa1.0-hp-osf - exit ;; - i*86:OSF1:*:*) - if [ -x /usr/sbin/sysversion ] ; then - echo ${UNAME_MACHINE}-unknown-osf1mk - else - echo ${UNAME_MACHINE}-unknown-osf1 - fi - exit ;; - parisc*:Lites*:*:*) - echo hppa1.1-hp-lites - exit ;; - C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) - echo c1-convex-bsd - exit ;; - C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) - echo c34-convex-bsd - exit ;; - C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) - echo c38-convex-bsd - exit ;; - C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) - echo c4-convex-bsd - exit ;; - CRAY*Y-MP:*:*:*) - echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*[A-Z]90:*:*:*) - echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ - | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ - -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ - -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*TS:*:*:*) - echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*T3E:*:*:*) - echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - CRAY*SV1:*:*:*) - echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - *:UNICOS/mp:*:*) - echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' - exit ;; - F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) - FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` - echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - 5000:UNIX_System_V:4.*:*) - FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` - FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` - echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" - exit ;; - i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) - echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} - exit ;; - sparc*:BSD/OS:*:*) - echo sparc-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:BSD/OS:*:*) - echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} - exit ;; - *:FreeBSD:*:*) - case ${UNAME_MACHINE} in - pc98) - echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - amd64) - echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - *) - echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; - esac - exit ;; - i*:CYGWIN*:*) - echo ${UNAME_MACHINE}-pc-cygwin - exit ;; - *:MINGW*:*) - echo ${UNAME_MACHINE}-pc-mingw32 - exit ;; - i*:windows32*:*) - # uname -m includes "-pc" on this system. - echo ${UNAME_MACHINE}-mingw32 - exit ;; - i*:PW*:*) - echo ${UNAME_MACHINE}-pc-pw32 - exit ;; - *:Interix*:[3456]*) - case ${UNAME_MACHINE} in - x86) - echo i586-pc-interix${UNAME_RELEASE} - exit ;; - EM64T | authenticamd) - echo x86_64-unknown-interix${UNAME_RELEASE} - exit ;; - esac ;; - [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) - echo i${UNAME_MACHINE}-pc-mks - exit ;; - i*:Windows_NT*:* | Pentium*:Windows_NT*:*) - # How do we know it's Interix rather than the generic POSIX subsystem? - # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we - # UNAME_MACHINE based on the output of uname instead of i386? - echo i586-pc-interix - exit ;; - i*:UWIN*:*) - echo ${UNAME_MACHINE}-pc-uwin - exit ;; - amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) - echo x86_64-unknown-cygwin - exit ;; - p*:CYGWIN*:*) - echo powerpcle-unknown-cygwin - exit ;; - prep*:SunOS:5.*:*) - echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` - exit ;; - *:GNU:*:*) - # the GNU system - echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` - exit ;; - *:GNU/*:*:*) - # other systems with GNU libc and userland - echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu - exit ;; - i*86:Minix:*:*) - echo ${UNAME_MACHINE}-pc-minix - exit ;; - arm*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - avr32*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - cris:Linux:*:*) - echo cris-axis-linux-gnu - exit ;; - crisv32:Linux:*:*) - echo crisv32-axis-linux-gnu - exit ;; - frv:Linux:*:*) - echo frv-unknown-linux-gnu - exit ;; - ia64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m32r*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - m68*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - mips:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips - #undef mipsel - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mipsel - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - mips64:Linux:*:*) - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #undef CPU - #undef mips64 - #undef mips64el - #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) - CPU=mips64el - #else - #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) - CPU=mips64 - #else - CPU= - #endif - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^CPU/{ - s: ::g - p - }'`" - test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } - ;; - or32:Linux:*:*) - echo or32-unknown-linux-gnu - exit ;; - ppc:Linux:*:*) - echo powerpc-unknown-linux-gnu - exit ;; - ppc64:Linux:*:*) - echo powerpc64-unknown-linux-gnu - exit ;; - alpha:Linux:*:*) - case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in - EV5) UNAME_MACHINE=alphaev5 ;; - EV56) UNAME_MACHINE=alphaev56 ;; - PCA56) UNAME_MACHINE=alphapca56 ;; - PCA57) UNAME_MACHINE=alphapca56 ;; - EV6) UNAME_MACHINE=alphaev6 ;; - EV67) UNAME_MACHINE=alphaev67 ;; - EV68*) UNAME_MACHINE=alphaev68 ;; - esac - objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null - if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi - echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} - exit ;; - parisc:Linux:*:* | hppa:Linux:*:*) - # Look for CPU level - case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in - PA7*) echo hppa1.1-unknown-linux-gnu ;; - PA8*) echo hppa2.0-unknown-linux-gnu ;; - *) echo hppa-unknown-linux-gnu ;; - esac - exit ;; - parisc64:Linux:*:* | hppa64:Linux:*:*) - echo hppa64-unknown-linux-gnu - exit ;; - s390:Linux:*:* | s390x:Linux:*:*) - echo ${UNAME_MACHINE}-ibm-linux - exit ;; - sh64*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - sh*:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - sparc:Linux:*:* | sparc64:Linux:*:*) - echo ${UNAME_MACHINE}-unknown-linux-gnu - exit ;; - tile:Linux:*:*) - echo tile-unknown-linux-gnu - exit ;; - vax:Linux:*:*) - echo ${UNAME_MACHINE}-dec-linux-gnu - exit ;; - x86_64:Linux:*:*) - echo x86_64-unknown-linux-gnu - exit ;; - xtensa:Linux:*:*) - echo xtensa-unknown-linux-gnu - exit ;; - i*86:Linux:*:*) - # The BFD linker knows what the default object file format is, so - # first see if it will tell us. cd to the root directory to prevent - # problems with other programs or directories called `ld' in the path. - # Set LC_ALL=C to ensure ld outputs messages in English. - ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ - | sed -ne '/supported targets:/!d - s/[ ][ ]*/ /g - s/.*supported targets: *// - s/ .*// - p'` - case "$ld_supported_targets" in - elf32-i386) - TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" - ;; - a.out-i386-linux) - echo "${UNAME_MACHINE}-pc-linux-gnuaout" - exit ;; - coff-i386) - echo "${UNAME_MACHINE}-pc-linux-gnucoff" - exit ;; - "") - # Either a pre-BFD a.out linker (linux-gnuoldld) or - # one that does not give us useful --help. - echo "${UNAME_MACHINE}-pc-linux-gnuoldld" - exit ;; - esac - # Determine whether the default compiler is a.out or elf - eval $set_cc_for_build - sed 's/^ //' << EOF >$dummy.c - #include <features.h> - #ifdef __ELF__ - # ifdef __GLIBC__ - # if __GLIBC__ >= 2 - LIBC=gnu - # else - LIBC=gnulibc1 - # endif - # else - LIBC=gnulibc1 - # endif - #else - #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) - LIBC=gnu - #else - LIBC=gnuaout - #endif - #endif - #ifdef __dietlibc__ - LIBC=dietlibc - #endif -EOF - eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' - /^LIBC/{ - s: ::g - p - }'`" - test x"${LIBC}" != x && { - echo "${UNAME_MACHINE}-pc-linux-${LIBC}" - exit - } - test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } - ;; - i*86:DYNIX/ptx:4*:*) - # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. - # earlier versions are messed up and put the nodename in both - # sysname and nodename. - echo i386-sequent-sysv4 - exit ;; - i*86:UNIX_SV:4.2MP:2.*) - # Unixware is an offshoot of SVR4, but it has its own version - # number series starting with 2... - # I am not positive that other SVR4 systems won't match this, - # I just have to hope. -- rms. - # Use sysv4.2uw... so that sysv4* matches it. - echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} - exit ;; - i*86:OS/2:*:*) - # If we were able to find `uname', then EMX Unix compatibility - # is probably installed. - echo ${UNAME_MACHINE}-pc-os2-emx - exit ;; - i*86:XTS-300:*:STOP) - echo ${UNAME_MACHINE}-unknown-stop - exit ;; - i*86:atheos:*:*) - echo ${UNAME_MACHINE}-unknown-atheos - exit ;; - i*86:syllable:*:*) - echo ${UNAME_MACHINE}-pc-syllable - exit ;; - i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) - echo i386-unknown-lynxos${UNAME_RELEASE} - exit ;; - i*86:*DOS:*:*) - echo ${UNAME_MACHINE}-pc-msdosdjgpp - exit ;; - i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) - UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` - if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then - echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} - else - echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} - fi - exit ;; - i*86:*:5:[678]*) - # UnixWare 7.x, OpenUNIX and OpenServer 6. - case `/bin/uname -X | grep "^Machine"` in - *486*) UNAME_MACHINE=i486 ;; - *Pentium) UNAME_MACHINE=i586 ;; - *Pent*|*Celeron) UNAME_MACHINE=i686 ;; - esac - echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} - exit ;; - i*86:*:3.2:*) - if test -f /usr/options/cb.name; then - UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name` - echo ${UNAME_MACHINE}-pc-isc$UNAME_REL - elif /bin/uname -X 2>/dev/null >/dev/null ; then - UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` - (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 - (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ - && UNAME_MACHINE=i586 - (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ - && UNAME_MACHINE=i686 - (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ - && UNAME_MACHINE=i686 - echo ${UNAME_MACHINE}-pc-sco$UNAME_REL - else - echo ${UNAME_MACHINE}-pc-sysv32 - fi - exit ;; - pc:*:*:*) - # Left here for compatibility: - # uname -m prints for DJGPP always 'pc', but it prints nothing about - # the processor, so we play safe by assuming i386. - echo i386-pc-msdosdjgpp - exit ;; - Intel:Mach:3*:*) - echo i386-pc-mach3 - exit ;; - paragon:*:*:*) - echo i860-intel-osf1 - exit ;; - i860:*:4.*:*) # i860-SVR4 - if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then - echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 - else # Add other i860-SVR4 vendors below as they are discovered. - echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 - fi - exit ;; - mini*:CTIX:SYS*5:*) - # "miniframe" - echo m68010-convergent-sysv - exit ;; - mc68k:UNIX:SYSTEM5:3.51m) - echo m68k-convergent-sysv - exit ;; - M680?0:D-NIX:5.3:*) - echo m68k-diab-dnix - exit ;; - M68*:*:R3V[5678]*:*) - test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; - 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) - OS_REL='' - test -r /etc/.relid \ - && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4.3${OS_REL}; exit; } - /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ - && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; - 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) - /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ - && { echo i486-ncr-sysv4; exit; } ;; - m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) - echo m68k-unknown-lynxos${UNAME_RELEASE} - exit ;; - mc68030:UNIX_System_V:4.*:*) - echo m68k-atari-sysv4 - exit ;; - TSUNAMI:LynxOS:2.*:*) - echo sparc-unknown-lynxos${UNAME_RELEASE} - exit ;; - rs6000:LynxOS:2.*:*) - echo rs6000-unknown-lynxos${UNAME_RELEASE} - exit ;; - PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) - echo powerpc-unknown-lynxos${UNAME_RELEASE} - exit ;; - SM[BE]S:UNIX_SV:*:*) - echo mips-dde-sysv${UNAME_RELEASE} - exit ;; - RM*:ReliantUNIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - RM*:SINIX-*:*:*) - echo mips-sni-sysv4 - exit ;; - *:SINIX-*:*:*) - if uname -p 2>/dev/null >/dev/null ; then - UNAME_MACHINE=`(uname -p) 2>/dev/null` - echo ${UNAME_MACHINE}-sni-sysv4 - else - echo ns32k-sni-sysv - fi - exit ;; - PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort - # says <[email protected]> - echo i586-unisys-sysv4 - exit ;; - *:UNIX_System_V:4*:FTX*) - # From Gerald Hewes <[email protected]>. - # How about differentiating between stratus architectures? -djm - echo hppa1.1-stratus-sysv4 - exit ;; - *:*:*:FTX*) - # From [email protected]. - echo i860-stratus-sysv4 - exit ;; - i*86:VOS:*:*) - # From [email protected]. - echo ${UNAME_MACHINE}-stratus-vos - exit ;; - *:VOS:*:*) - # From [email protected]. - echo hppa1.1-stratus-vos - exit ;; - mc68*:A/UX:*:*) - echo m68k-apple-aux${UNAME_RELEASE} - exit ;; - news*:NEWS-OS:6*:*) - echo mips-sony-newsos6 - exit ;; - R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) - if [ -d /usr/nec ]; then - echo mips-nec-sysv${UNAME_RELEASE} - else - echo mips-unknown-sysv${UNAME_RELEASE} - fi - exit ;; - BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. - echo powerpc-be-beos - exit ;; - BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. - echo powerpc-apple-beos - exit ;; - BePC:BeOS:*:*) # BeOS running on Intel PC compatible. - echo i586-pc-beos - exit ;; - SX-4:SUPER-UX:*:*) - echo sx4-nec-superux${UNAME_RELEASE} - exit ;; - SX-5:SUPER-UX:*:*) - echo sx5-nec-superux${UNAME_RELEASE} - exit ;; - SX-6:SUPER-UX:*:*) - echo sx6-nec-superux${UNAME_RELEASE} - exit ;; - SX-7:SUPER-UX:*:*) - echo sx7-nec-superux${UNAME_RELEASE} - exit ;; - SX-8:SUPER-UX:*:*) - echo sx8-nec-superux${UNAME_RELEASE} - exit ;; - SX-8R:SUPER-UX:*:*) - echo sx8r-nec-superux${UNAME_RELEASE} - exit ;; - Power*:Rhapsody:*:*) - echo powerpc-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Rhapsody:*:*) - echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} - exit ;; - *:Darwin:*:*) - UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown - case $UNAME_PROCESSOR in - unknown) UNAME_PROCESSOR=powerpc ;; - esac - echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} - exit ;; - *:procnto*:*:* | *:QNX:[0123456789]*:*) - UNAME_PROCESSOR=`uname -p` - if test "$UNAME_PROCESSOR" = "x86"; then - UNAME_PROCESSOR=i386 - UNAME_MACHINE=pc - fi - echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} - exit ;; - *:QNX:*:4*) - echo i386-pc-qnx - exit ;; - NSE-?:NONSTOP_KERNEL:*:*) - echo nse-tandem-nsk${UNAME_RELEASE} - exit ;; - NSR-?:NONSTOP_KERNEL:*:*) - echo nsr-tandem-nsk${UNAME_RELEASE} - exit ;; - *:NonStop-UX:*:*) - echo mips-compaq-nonstopux - exit ;; - BS2000:POSIX*:*:*) - echo bs2000-siemens-sysv - exit ;; - DS/*:UNIX_System_V:*:*) - echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} - exit ;; - *:Plan9:*:*) - # "uname -m" is not consistent, so use $cputype instead. 386 - # is converted to i386 for consistency with other x86 - # operating systems. - if test "$cputype" = "386"; then - UNAME_MACHINE=i386 - else - UNAME_MACHINE="$cputype" - fi - echo ${UNAME_MACHINE}-unknown-plan9 - exit ;; - *:TOPS-10:*:*) - echo pdp10-unknown-tops10 - exit ;; - *:TENEX:*:*) - echo pdp10-unknown-tenex - exit ;; - KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) - echo pdp10-dec-tops20 - exit ;; - XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) - echo pdp10-xkl-tops20 - exit ;; - *:TOPS-20:*:*) - echo pdp10-unknown-tops20 - exit ;; - *:ITS:*:*) - echo pdp10-unknown-its - exit ;; - SEI:*:*:SEIUX) - echo mips-sei-seiux${UNAME_RELEASE} - exit ;; - *:DragonFly:*:*) - echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` - exit ;; - *:*VMS:*:*) - UNAME_MACHINE=`(uname -p) 2>/dev/null` - case "${UNAME_MACHINE}" in - A*) echo alpha-dec-vms ; exit ;; - I*) echo ia64-dec-vms ; exit ;; - V*) echo vax-dec-vms ; exit ;; - esac ;; - *:XENIX:*:SysV) - echo i386-pc-xenix - exit ;; - i*86:skyos:*:*) - echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' - exit ;; - i*86:rdos:*:*) - echo ${UNAME_MACHINE}-pc-rdos - exit ;; -esac - -#echo '(No uname command or uname output not recognized.)' 1>&2 -#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 - -eval $set_cc_for_build -cat >$dummy.c <<EOF -#ifdef _SEQUENT_ -# include <sys/types.h> -# include <sys/utsname.h> -#endif -main () -{ -#if defined (sony) -#if defined (MIPSEB) - /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, - I don't know.... */ - printf ("mips-sony-bsd\n"); exit (0); -#else -#include <sys/param.h> - printf ("m68k-sony-newsos%s\n", -#ifdef NEWSOS4 - "4" -#else - "" -#endif - ); exit (0); -#endif -#endif - -#if defined (__arm) && defined (__acorn) && defined (__unix) - printf ("arm-acorn-riscix\n"); exit (0); -#endif - -#if defined (hp300) && !defined (hpux) - printf ("m68k-hp-bsd\n"); exit (0); -#endif - -#if defined (NeXT) -#if !defined (__ARCHITECTURE__) -#define __ARCHITECTURE__ "m68k" -#endif - int version; - version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; - if (version < 4) - printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); - else - printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); - exit (0); -#endif - -#if defined (MULTIMAX) || defined (n16) -#if defined (UMAXV) - printf ("ns32k-encore-sysv\n"); exit (0); -#else -#if defined (CMU) - printf ("ns32k-encore-mach\n"); exit (0); -#else - printf ("ns32k-encore-bsd\n"); exit (0); -#endif -#endif -#endif - -#if defined (__386BSD__) - printf ("i386-pc-bsd\n"); exit (0); -#endif - -#if defined (sequent) -#if defined (i386) - printf ("i386-sequent-dynix\n"); exit (0); -#endif -#if defined (ns32000) - printf ("ns32k-sequent-dynix\n"); exit (0); -#endif -#endif - -#if defined (_SEQUENT_) - struct utsname un; - - uname(&un); - - if (strncmp(un.version, "V2", 2) == 0) { - printf ("i386-sequent-ptx2\n"); exit (0); - } - if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ - printf ("i386-sequent-ptx1\n"); exit (0); - } - printf ("i386-sequent-ptx\n"); exit (0); - -#endif - -#if defined (vax) -# if !defined (ultrix) -# include <sys/param.h> -# if defined (BSD) -# if BSD == 43 - printf ("vax-dec-bsd4.3\n"); exit (0); -# else -# if BSD == 199006 - printf ("vax-dec-bsd4.3reno\n"); exit (0); -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# endif -# else - printf ("vax-dec-bsd\n"); exit (0); -# endif -# else - printf ("vax-dec-ultrix\n"); exit (0); -# endif -#endif - -#if defined (alliant) && defined (i860) - printf ("i860-alliant-bsd\n"); exit (0); -#endif - - exit (1); -} -EOF - -$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && - { echo "$SYSTEM_NAME"; exit; } - -# Apollos put the system type in the environment. - -test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } - -# Convex versions that predate uname can use getsysinfo(1) - -if [ -x /usr/convex/getsysinfo ] -then - case `getsysinfo -f cpu_type` in - c1*) - echo c1-convex-bsd - exit ;; - c2*) - if getsysinfo -f scalar_acc - then echo c32-convex-bsd - else echo c2-convex-bsd - fi - exit ;; - c34*) - echo c34-convex-bsd - exit ;; - c38*) - echo c38-convex-bsd - exit ;; - c4*) - echo c4-convex-bsd - exit ;; - esac -fi - -cat >&2 <<EOF -$0: unable to guess system type - -This script, last modified $timestamp, has failed to recognize -the operating system you are using. It is advised that you -download the most up to date version of the config scripts from - - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.guess -and - http://savannah.gnu.org/cgi-bin/viewcvs/*checkout*/config/config/config.sub - -If the version you run ($0) is already up to date, please -send the following data and any information you think might be -pertinent to <[email protected]> in order to provide the needed -information to handle your system. - -config.guess timestamp = $timestamp - -uname -m = `(uname -m) 2>/dev/null || echo unknown` -uname -r = `(uname -r) 2>/dev/null || echo unknown` -uname -s = `(uname -s) 2>/dev/null || echo unknown` -uname -v = `(uname -v) 2>/dev/null || echo unknown` - -/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` -/bin/uname -X = `(/bin/uname -X) 2>/dev/null` - -hostinfo = `(hostinfo) 2>/dev/null` -/bin/universe = `(/bin/universe) 2>/dev/null` -/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` -/bin/arch = `(/bin/arch) 2>/dev/null` -/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` -/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` - -UNAME_MACHINE = ${UNAME_MACHINE} -UNAME_RELEASE = ${UNAME_RELEASE} -UNAME_SYSTEM = ${UNAME_SYSTEM} -UNAME_VERSION = ${UNAME_VERSION} -EOF - -exit 1 - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/lib/diameter/autoconf/config.sub b/lib/diameter/autoconf/config.sub deleted file mode 100755 index f43233b104..0000000000 --- a/lib/diameter/autoconf/config.sub +++ /dev/null @@ -1,1630 +0,0 @@ -#! /bin/sh -# Configuration validation subroutine script. -# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, -# 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, -# Inc. - -timestamp='2007-04-29' - -# This file is (in principle) common to ALL GNU software. -# The presence of a machine in this file suggests that SOME GNU software -# can handle that machine. It does not imply ALL GNU software can. -# -# This file is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA -# 02110-1301, USA. -# -# As a special exception to the GNU General Public License, if you -# distribute this file as part of a program that contains a -# configuration script generated by Autoconf, you may include it under -# the same distribution terms that you use for the rest of that program. - - -# Please send patches to <[email protected]>. Submit a context -# diff and a properly formatted ChangeLog entry. -# -# Configuration subroutine to validate and canonicalize a configuration type. -# Supply the specified configuration type as an argument. -# If it is invalid, we print an error message on stderr and exit with code 1. -# Otherwise, we print the canonical config type on stdout and succeed. - -# This file is supposed to be the same for all GNU packages -# and recognize all the CPU types, system types and aliases -# that are meaningful with *any* GNU software. -# Each package is responsible for reporting which valid configurations -# it does not support. The user should be able to distinguish -# a failure to support a valid configuration from a meaningless -# configuration. - -# The goal of this file is to map all the various variations of a given -# machine specification into a single specification in the form: -# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM -# or in some cases, the newer four-part form: -# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM -# It is wrong to echo any other type of specification. - -me=`echo "$0" | sed -e 's,.*/,,'` - -usage="\ -Usage: $0 [OPTION] CPU-MFR-OPSYS - $0 [OPTION] ALIAS - -Canonicalize a configuration name. - -Operation modes: - -h, --help print this help, then exit - -t, --time-stamp print date of last modification, then exit - -v, --version print version number, then exit - -Report bugs and patches to <[email protected]>." - -version="\ -GNU config.sub ($timestamp) - -Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 -Free Software Foundation, Inc. - -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." - -help=" -Try \`$me --help' for more information." - -# Parse command line -while test $# -gt 0 ; do - case $1 in - --time-stamp | --time* | -t ) - echo "$timestamp" ; exit ;; - --version | -v ) - echo "$version" ; exit ;; - --help | --h* | -h ) - echo "$usage"; exit ;; - -- ) # Stop option processing - shift; break ;; - - ) # Use stdin as input. - break ;; - -* ) - echo "$me: invalid option $1$help" - exit 1 ;; - - *local*) - # First pass through any local machine types. - echo $1 - exit ;; - - * ) - break ;; - esac -done - -case $# in - 0) echo "$me: missing argument$help" >&2 - exit 1;; - 1) ;; - *) echo "$me: too many arguments$help" >&2 - exit 1;; -esac - -# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). -# Here we must recognize all the valid KERNEL-OS combinations. -maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` -case $maybe_os in - nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ - uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ - storm-chaos* | os2-emx* | rtmk-nova*) - os=-$maybe_os - basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` - ;; - *) - basic_machine=`echo $1 | sed 's/-[^-]*$//'` - if [ $basic_machine != $1 ] - then os=`echo $1 | sed 's/.*-/-/'` - else os=; fi - ;; -esac - -### Let's recognize common machines as not being operating systems so -### that things like config.sub decstation-3100 work. We also -### recognize some manufacturers as not being operating systems, so we -### can provide default operating systems below. -case $os in - -sun*os*) - # Prevent following clause from handling this invalid input. - ;; - -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ - -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ - -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ - -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ - -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ - -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ - -apple | -axis | -knuth | -cray) - os= - basic_machine=$1 - ;; - -sim | -cisco | -oki | -wec | -winbond) - os= - basic_machine=$1 - ;; - -scout) - ;; - -wrs) - os=-vxworks - basic_machine=$1 - ;; - -chorusos*) - os=-chorusos - basic_machine=$1 - ;; - -chorusrdb) - os=-chorusrdb - basic_machine=$1 - ;; - -hiux*) - os=-hiuxwe2 - ;; - -sco6) - os=-sco5v6 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5) - os=-sco3.2v5 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco4) - os=-sco3.2v4 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2.[4-9]*) - os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco3.2v[4-9]*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco5v6*) - # Don't forget version if it is 3.2v4 or newer. - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -sco*) - os=-sco3.2v2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -udk*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -isc) - os=-isc2.2 - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -clix*) - basic_machine=clipper-intergraph - ;; - -isc*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` - ;; - -lynx*) - os=-lynxos - ;; - -ptx*) - basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` - ;; - -windowsnt*) - os=`echo $os | sed -e 's/windowsnt/winnt/'` - ;; - -psos*) - os=-psos - ;; - -mint | -mint[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; -esac - -# Decode aliases for certain CPU-COMPANY combinations. -case $basic_machine in - # Recognize the basic CPU types without company name. - # Some are omitted here because they have special meanings below. - 1750a | 580 \ - | a29k \ - | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ - | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ - | am33_2.0 \ - | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ - | bfin \ - | c4x | clipper \ - | d10v | d30v | dlx | dsp16xx \ - | fido | fr30 | frv \ - | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ - | i370 | i860 | i960 | ia64 \ - | ip2k | iq2000 \ - | m32c | m32r | m32rle | m68000 | m68k | m88k \ - | maxq | mb | microblaze | mcore | mep \ - | mips | mipsbe | mipseb | mipsel | mipsle \ - | mips16 \ - | mips64 | mips64el \ - | mips64vr | mips64vrel \ - | mips64orion | mips64orionel \ - | mips64vr4100 | mips64vr4100el \ - | mips64vr4300 | mips64vr4300el \ - | mips64vr5000 | mips64vr5000el \ - | mips64vr5900 | mips64vr5900el \ - | mipsisa32 | mipsisa32el \ - | mipsisa32r2 | mipsisa32r2el \ - | mipsisa64 | mipsisa64el \ - | mipsisa64r2 | mipsisa64r2el \ - | mipsisa64sb1 | mipsisa64sb1el \ - | mipsisa64sr71k | mipsisa64sr71kel \ - | mipstx39 | mipstx39el \ - | mn10200 | mn10300 \ - | mt \ - | msp430 \ - | nios | nios2 \ - | ns16k | ns32k \ - | or32 \ - | pdp10 | pdp11 | pj | pjl \ - | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ - | pyramid \ - | score \ - | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ - | sh64 | sh64le \ - | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ - | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ - | spu | strongarm \ - | tahoe | thumb | tic4x | tic80 | tron \ - | v850 | v850e \ - | we32k \ - | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ - | z8k) - basic_machine=$basic_machine-unknown - ;; - m6811 | m68hc11 | m6812 | m68hc12) - # Motorola 68HC11/12. - basic_machine=$basic_machine-unknown - os=-none - ;; - m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) - ;; - ms1) - basic_machine=mt-unknown - ;; - - # We use `pc' rather than `unknown' - # because (1) that's what they normally are, and - # (2) the word "unknown" tends to confuse beginning users. - i*86 | x86_64) - basic_machine=$basic_machine-pc - ;; - # Object if more than one company name word. - *-*-*) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; - # Recognize the basic CPU types with company name. - 580-* \ - | a29k-* \ - | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ - | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ - | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ - | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ - | avr-* | avr32-* \ - | bfin-* | bs2000-* \ - | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ - | clipper-* | craynv-* | cydra-* \ - | d10v-* | d30v-* | dlx-* \ - | elxsi-* \ - | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ - | h8300-* | h8500-* \ - | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ - | i*86-* | i860-* | i960-* | ia64-* \ - | ip2k-* | iq2000-* \ - | m32c-* | m32r-* | m32rle-* \ - | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ - | m88110-* | m88k-* | maxq-* | mcore-* \ - | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ - | mips16-* \ - | mips64-* | mips64el-* \ - | mips64vr-* | mips64vrel-* \ - | mips64orion-* | mips64orionel-* \ - | mips64vr4100-* | mips64vr4100el-* \ - | mips64vr4300-* | mips64vr4300el-* \ - | mips64vr5000-* | mips64vr5000el-* \ - | mips64vr5900-* | mips64vr5900el-* \ - | mipsisa32-* | mipsisa32el-* \ - | mipsisa32r2-* | mipsisa32r2el-* \ - | mipsisa64-* | mipsisa64el-* \ - | mipsisa64r2-* | mipsisa64r2el-* \ - | mipsisa64sb1-* | mipsisa64sb1el-* \ - | mipsisa64sr71k-* | mipsisa64sr71kel-* \ - | mipstx39-* | mipstx39el-* \ - | mmix-* \ - | mt-* \ - | msp430-* \ - | nios-* | nios2-* \ - | none-* | np1-* | ns16k-* | ns32k-* \ - | orion-* \ - | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ - | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ - | pyramid-* \ - | romp-* | rs6000-* \ - | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ - | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ - | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ - | sparclite-* \ - | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ - | tahoe-* | thumb-* \ - | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ - | tron-* \ - | v850-* | v850e-* | vax-* \ - | we32k-* \ - | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ - | xstormy16-* | xtensa-* \ - | ymp-* \ - | z8k-*) - ;; - # Recognize the various machine names and aliases which stand - # for a CPU type and a company and sometimes even an OS. - 386bsd) - basic_machine=i386-unknown - os=-bsd - ;; - 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) - basic_machine=m68000-att - ;; - 3b*) - basic_machine=we32k-att - ;; - a29khif) - basic_machine=a29k-amd - os=-udi - ;; - abacus) - basic_machine=abacus-unknown - ;; - adobe68k) - basic_machine=m68010-adobe - os=-scout - ;; - alliant | fx80) - basic_machine=fx80-alliant - ;; - altos | altos3068) - basic_machine=m68k-altos - ;; - am29k) - basic_machine=a29k-none - os=-bsd - ;; - amd64) - basic_machine=x86_64-pc - ;; - amd64-*) - basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - amdahl) - basic_machine=580-amdahl - os=-sysv - ;; - amiga | amiga-*) - basic_machine=m68k-unknown - ;; - amigaos | amigados) - basic_machine=m68k-unknown - os=-amigaos - ;; - amigaunix | amix) - basic_machine=m68k-unknown - os=-sysv4 - ;; - apollo68) - basic_machine=m68k-apollo - os=-sysv - ;; - apollo68bsd) - basic_machine=m68k-apollo - os=-bsd - ;; - aux) - basic_machine=m68k-apple - os=-aux - ;; - balance) - basic_machine=ns32k-sequent - os=-dynix - ;; - c90) - basic_machine=c90-cray - os=-unicos - ;; - convex-c1) - basic_machine=c1-convex - os=-bsd - ;; - convex-c2) - basic_machine=c2-convex - os=-bsd - ;; - convex-c32) - basic_machine=c32-convex - os=-bsd - ;; - convex-c34) - basic_machine=c34-convex - os=-bsd - ;; - convex-c38) - basic_machine=c38-convex - os=-bsd - ;; - cray | j90) - basic_machine=j90-cray - os=-unicos - ;; - craynv) - basic_machine=craynv-cray - os=-unicosmp - ;; - cr16c) - basic_machine=cr16c-unknown - os=-elf - ;; - crds | unos) - basic_machine=m68k-crds - ;; - crisv32 | crisv32-* | etraxfs*) - basic_machine=crisv32-axis - ;; - cris | cris-* | etrax*) - basic_machine=cris-axis - ;; - crx) - basic_machine=crx-unknown - os=-elf - ;; - da30 | da30-*) - basic_machine=m68k-da30 - ;; - decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) - basic_machine=mips-dec - ;; - decsystem10* | dec10*) - basic_machine=pdp10-dec - os=-tops10 - ;; - decsystem20* | dec20*) - basic_machine=pdp10-dec - os=-tops20 - ;; - delta | 3300 | motorola-3300 | motorola-delta \ - | 3300-motorola | delta-motorola) - basic_machine=m68k-motorola - ;; - delta88) - basic_machine=m88k-motorola - os=-sysv3 - ;; - djgpp) - basic_machine=i586-pc - os=-msdosdjgpp - ;; - dpx20 | dpx20-*) - basic_machine=rs6000-bull - os=-bosx - ;; - dpx2* | dpx2*-bull) - basic_machine=m68k-bull - os=-sysv3 - ;; - ebmon29k) - basic_machine=a29k-amd - os=-ebmon - ;; - elxsi) - basic_machine=elxsi-elxsi - os=-bsd - ;; - encore | umax | mmax) - basic_machine=ns32k-encore - ;; - es1800 | OSE68k | ose68k | ose | OSE) - basic_machine=m68k-ericsson - os=-ose - ;; - fx2800) - basic_machine=i860-alliant - ;; - genix) - basic_machine=ns32k-ns - ;; - gmicro) - basic_machine=tron-gmicro - os=-sysv - ;; - go32) - basic_machine=i386-pc - os=-go32 - ;; - h3050r* | hiux*) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - h8300hms) - basic_machine=h8300-hitachi - os=-hms - ;; - h8300xray) - basic_machine=h8300-hitachi - os=-xray - ;; - h8500hms) - basic_machine=h8500-hitachi - os=-hms - ;; - harris) - basic_machine=m88k-harris - os=-sysv3 - ;; - hp300-*) - basic_machine=m68k-hp - ;; - hp300bsd) - basic_machine=m68k-hp - os=-bsd - ;; - hp300hpux) - basic_machine=m68k-hp - os=-hpux - ;; - hp3k9[0-9][0-9] | hp9[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k2[0-9][0-9] | hp9k31[0-9]) - basic_machine=m68000-hp - ;; - hp9k3[2-9][0-9]) - basic_machine=m68k-hp - ;; - hp9k6[0-9][0-9] | hp6[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hp9k7[0-79][0-9] | hp7[0-79][0-9]) - basic_machine=hppa1.1-hp - ;; - hp9k78[0-9] | hp78[0-9]) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) - # FIXME: really hppa2.0-hp - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][13679] | hp8[0-9][13679]) - basic_machine=hppa1.1-hp - ;; - hp9k8[0-9][0-9] | hp8[0-9][0-9]) - basic_machine=hppa1.0-hp - ;; - hppa-next) - os=-nextstep3 - ;; - hppaosf) - basic_machine=hppa1.1-hp - os=-osf - ;; - hppro) - basic_machine=hppa1.1-hp - os=-proelf - ;; - i370-ibm* | ibm*) - basic_machine=i370-ibm - ;; -# I'm not sure what "Sysv32" means. Should this be sysv3.2? - i*86v32) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv32 - ;; - i*86v4*) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv4 - ;; - i*86v) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-sysv - ;; - i*86sol2) - basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` - os=-solaris2 - ;; - i386mach) - basic_machine=i386-mach - os=-mach - ;; - i386-vsta | vsta) - basic_machine=i386-unknown - os=-vsta - ;; - iris | iris4d) - basic_machine=mips-sgi - case $os in - -irix*) - ;; - *) - os=-irix4 - ;; - esac - ;; - isi68 | isi) - basic_machine=m68k-isi - os=-sysv - ;; - m88k-omron*) - basic_machine=m88k-omron - ;; - magnum | m3230) - basic_machine=mips-mips - os=-sysv - ;; - merlin) - basic_machine=ns32k-utek - os=-sysv - ;; - mingw32) - basic_machine=i386-pc - os=-mingw32 - ;; - mingw32ce) - basic_machine=arm-unknown - os=-mingw32ce - ;; - miniframe) - basic_machine=m68000-convergent - ;; - *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) - basic_machine=m68k-atari - os=-mint - ;; - mips3*-*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` - ;; - mips3*) - basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown - ;; - monitor) - basic_machine=m68k-rom68k - os=-coff - ;; - morphos) - basic_machine=powerpc-unknown - os=-morphos - ;; - msdos) - basic_machine=i386-pc - os=-msdos - ;; - ms1-*) - basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` - ;; - mvs) - basic_machine=i370-ibm - os=-mvs - ;; - ncr3000) - basic_machine=i486-ncr - os=-sysv4 - ;; - netbsd386) - basic_machine=i386-unknown - os=-netbsd - ;; - netwinder) - basic_machine=armv4l-rebel - os=-linux - ;; - news | news700 | news800 | news900) - basic_machine=m68k-sony - os=-newsos - ;; - news1000) - basic_machine=m68030-sony - os=-newsos - ;; - news-3600 | risc-news) - basic_machine=mips-sony - os=-newsos - ;; - necv70) - basic_machine=v70-nec - os=-sysv - ;; - next | m*-next ) - basic_machine=m68k-next - case $os in - -nextstep* ) - ;; - -ns2*) - os=-nextstep2 - ;; - *) - os=-nextstep3 - ;; - esac - ;; - nh3000) - basic_machine=m68k-harris - os=-cxux - ;; - nh[45]000) - basic_machine=m88k-harris - os=-cxux - ;; - nindy960) - basic_machine=i960-intel - os=-nindy - ;; - mon960) - basic_machine=i960-intel - os=-mon960 - ;; - nonstopux) - basic_machine=mips-compaq - os=-nonstopux - ;; - np1) - basic_machine=np1-gould - ;; - nsr-tandem) - basic_machine=nsr-tandem - ;; - op50n-* | op60c-*) - basic_machine=hppa1.1-oki - os=-proelf - ;; - openrisc | openrisc-*) - basic_machine=or32-unknown - ;; - os400) - basic_machine=powerpc-ibm - os=-os400 - ;; - OSE68000 | ose68000) - basic_machine=m68000-ericsson - os=-ose - ;; - os68k) - basic_machine=m68k-none - os=-os68k - ;; - pa-hitachi) - basic_machine=hppa1.1-hitachi - os=-hiuxwe2 - ;; - paragon) - basic_machine=i860-intel - os=-osf - ;; - pbd) - basic_machine=sparc-tti - ;; - pbb) - basic_machine=m68k-tti - ;; - pc532 | pc532-*) - basic_machine=ns32k-pc532 - ;; - pc98) - basic_machine=i386-pc - ;; - pc98-*) - basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium | p5 | k5 | k6 | nexgen | viac3) - basic_machine=i586-pc - ;; - pentiumpro | p6 | 6x86 | athlon | athlon_*) - basic_machine=i686-pc - ;; - pentiumii | pentium2 | pentiumiii | pentium3) - basic_machine=i686-pc - ;; - pentium4) - basic_machine=i786-pc - ;; - pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) - basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumpro-* | p6-* | 6x86-* | athlon-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) - basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pentium4-*) - basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - pn) - basic_machine=pn-gould - ;; - power) basic_machine=power-ibm - ;; - ppc) basic_machine=powerpc-unknown - ;; - ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppcle | powerpclittle | ppc-le | powerpc-little) - basic_machine=powerpcle-unknown - ;; - ppcle-* | powerpclittle-*) - basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64) basic_machine=powerpc64-unknown - ;; - ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ppc64le | powerpc64little | ppc64-le | powerpc64-little) - basic_machine=powerpc64le-unknown - ;; - ppc64le-* | powerpc64little-*) - basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` - ;; - ps2) - basic_machine=i386-ibm - ;; - pw32) - basic_machine=i586-unknown - os=-pw32 - ;; - rdos) - basic_machine=i386-pc - os=-rdos - ;; - rom68k) - basic_machine=m68k-rom68k - os=-coff - ;; - rm[46]00) - basic_machine=mips-siemens - ;; - rtpc | rtpc-*) - basic_machine=romp-ibm - ;; - s390 | s390-*) - basic_machine=s390-ibm - ;; - s390x | s390x-*) - basic_machine=s390x-ibm - ;; - sa29200) - basic_machine=a29k-amd - os=-udi - ;; - sb1) - basic_machine=mipsisa64sb1-unknown - ;; - sb1el) - basic_machine=mipsisa64sb1el-unknown - ;; - sde) - basic_machine=mipsisa32-sde - os=-elf - ;; - sei) - basic_machine=mips-sei - os=-seiux - ;; - sequent) - basic_machine=i386-sequent - ;; - sh) - basic_machine=sh-hitachi - os=-hms - ;; - sh5el) - basic_machine=sh5le-unknown - ;; - sh64) - basic_machine=sh64-unknown - ;; - sparclite-wrs | simso-wrs) - basic_machine=sparclite-wrs - os=-vxworks - ;; - sps7) - basic_machine=m68k-bull - os=-sysv2 - ;; - spur) - basic_machine=spur-unknown - ;; - st2000) - basic_machine=m68k-tandem - ;; - stratus) - basic_machine=i860-stratus - os=-sysv4 - ;; - sun2) - basic_machine=m68000-sun - ;; - sun2os3) - basic_machine=m68000-sun - os=-sunos3 - ;; - sun2os4) - basic_machine=m68000-sun - os=-sunos4 - ;; - sun3os3) - basic_machine=m68k-sun - os=-sunos3 - ;; - sun3os4) - basic_machine=m68k-sun - os=-sunos4 - ;; - sun4os3) - basic_machine=sparc-sun - os=-sunos3 - ;; - sun4os4) - basic_machine=sparc-sun - os=-sunos4 - ;; - sun4sol2) - basic_machine=sparc-sun - os=-solaris2 - ;; - sun3 | sun3-*) - basic_machine=m68k-sun - ;; - sun4) - basic_machine=sparc-sun - ;; - sun386 | sun386i | roadrunner) - basic_machine=i386-sun - ;; - sv1) - basic_machine=sv1-cray - os=-unicos - ;; - symmetry) - basic_machine=i386-sequent - os=-dynix - ;; - t3e) - basic_machine=alphaev5-cray - os=-unicos - ;; - t90) - basic_machine=t90-cray - os=-unicos - ;; - tic54x | c54x*) - basic_machine=tic54x-unknown - os=-coff - ;; - tic55x | c55x*) - basic_machine=tic55x-unknown - os=-coff - ;; - tic6x | c6x*) - basic_machine=tic6x-unknown - os=-coff - ;; - tx39) - basic_machine=mipstx39-unknown - ;; - tx39el) - basic_machine=mipstx39el-unknown - ;; - tile*) - basic_machine=tile-tilera - os=-linux-gnu - ;; - toad1) - basic_machine=pdp10-xkl - os=-tops20 - ;; - tower | tower-32) - basic_machine=m68k-ncr - ;; - tpf) - basic_machine=s390x-ibm - os=-tpf - ;; - udi29k) - basic_machine=a29k-amd - os=-udi - ;; - ultra3) - basic_machine=a29k-nyu - os=-sym1 - ;; - v810 | necv810) - basic_machine=v810-nec - os=-none - ;; - vaxv) - basic_machine=vax-dec - os=-sysv - ;; - vms) - basic_machine=vax-dec - os=-vms - ;; - vpp*|vx|vx-*) - basic_machine=f301-fujitsu - ;; - vxworks960) - basic_machine=i960-wrs - os=-vxworks - ;; - vxworks68) - basic_machine=m68k-wrs - os=-vxworks - ;; - vxworks29k) - basic_machine=a29k-wrs - os=-vxworks - ;; - w65*) - basic_machine=w65-wdc - os=-none - ;; - w89k-*) - basic_machine=hppa1.1-winbond - os=-proelf - ;; - xbox) - basic_machine=i686-pc - os=-mingw32 - ;; - xps | xps100) - basic_machine=xps100-honeywell - ;; - ymp) - basic_machine=ymp-cray - os=-unicos - ;; - z8k-*-coff) - basic_machine=z8k-unknown - os=-sim - ;; - none) - basic_machine=none-none - os=-none - ;; - -# Here we handle the default manufacturer of certain CPU types. It is in -# some cases the only manufacturer, in others, it is the most popular. - w89k) - basic_machine=hppa1.1-winbond - ;; - op50n) - basic_machine=hppa1.1-oki - ;; - op60c) - basic_machine=hppa1.1-oki - ;; - romp) - basic_machine=romp-ibm - ;; - mmix) - basic_machine=mmix-knuth - ;; - rs6000) - basic_machine=rs6000-ibm - ;; - vax) - basic_machine=vax-dec - ;; - pdp10) - # there are many clones, so DEC is not a safe bet - basic_machine=pdp10-unknown - ;; - pdp11) - basic_machine=pdp11-dec - ;; - we32k) - basic_machine=we32k-att - ;; - sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) - basic_machine=sh-unknown - ;; - sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) - basic_machine=sparc-sun - ;; - cydra) - basic_machine=cydra-cydrome - ;; - orion) - basic_machine=orion-highlevel - ;; - orion105) - basic_machine=clipper-highlevel - ;; - mac | mpw | mac-mpw) - basic_machine=m68k-apple - ;; - pmac | pmac-mpw) - basic_machine=powerpc-apple - ;; - *-unknown) - # Make sure to match an already-canonicalized machine name. - ;; - *) - echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 - exit 1 - ;; -esac - -# Here we canonicalize certain aliases for manufacturers. -case $basic_machine in - *-digital*) - basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` - ;; - *-commodore*) - basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` - ;; - *) - ;; -esac - -# Decode manufacturer-specific aliases for certain operating systems. - -if [ x"$os" != x"" ] -then -case $os in - # First match some system type aliases - # that might get confused with valid system types. - # -solaris* is a basic system type, with this one exception. - -solaris1 | -solaris1.*) - os=`echo $os | sed -e 's|solaris1|sunos4|'` - ;; - -solaris) - os=-solaris2 - ;; - -svr4*) - os=-sysv4 - ;; - -unixware*) - os=-sysv4.2uw - ;; - -gnu/linux*) - os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` - ;; - # First accept the basic system types. - # The portable systems comes first. - # Each alternative MUST END IN A *, to match a version number. - # -sysv* is not here because it comes later, after sysvr4. - -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ - | -*vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[34]*\ - | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ - | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ - | -aos* \ - | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ - | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ - | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ - | -openbsd* | -solidbsd* \ - | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ - | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ - | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ - | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ - | -chorusos* | -chorusrdb* \ - | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ - | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ - | -uxpv* | -beos* | -mpeix* | -udk* \ - | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ - | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ - | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ - | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ - | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ - | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ - | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) - # Remember, each alternative MUST END IN *, to match a version number. - ;; - -qnx*) - case $basic_machine in - x86-* | i*86-*) - ;; - *) - os=-nto$os - ;; - esac - ;; - -nto-qnx*) - ;; - -nto*) - os=`echo $os | sed -e 's|nto|nto-qnx|'` - ;; - -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ - | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ - | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) - ;; - -mac*) - os=`echo $os | sed -e 's|mac|macos|'` - ;; - -linux-dietlibc) - os=-linux-dietlibc - ;; - -linux*) - os=`echo $os | sed -e 's|linux|linux-gnu|'` - ;; - -sunos5*) - os=`echo $os | sed -e 's|sunos5|solaris2|'` - ;; - -sunos6*) - os=`echo $os | sed -e 's|sunos6|solaris3|'` - ;; - -opened*) - os=-openedition - ;; - -os400*) - os=-os400 - ;; - -wince*) - os=-wince - ;; - -osfrose*) - os=-osfrose - ;; - -osf*) - os=-osf - ;; - -utek*) - os=-bsd - ;; - -dynix*) - os=-bsd - ;; - -acis*) - os=-aos - ;; - -atheos*) - os=-atheos - ;; - -syllable*) - os=-syllable - ;; - -386bsd) - os=-bsd - ;; - -ctix* | -uts*) - os=-sysv - ;; - -nova*) - os=-rtmk-nova - ;; - -ns2 ) - os=-nextstep2 - ;; - -nsk*) - os=-nsk - ;; - # Preserve the version number of sinix5. - -sinix5.*) - os=`echo $os | sed -e 's|sinix|sysv|'` - ;; - -sinix*) - os=-sysv4 - ;; - -tpf*) - os=-tpf - ;; - -triton*) - os=-sysv3 - ;; - -oss*) - os=-sysv3 - ;; - -svr4) - os=-sysv4 - ;; - -svr3) - os=-sysv3 - ;; - -sysvr4) - os=-sysv4 - ;; - # This must come after -sysvr4. - -sysv*) - ;; - -ose*) - os=-ose - ;; - -es1800*) - os=-ose - ;; - -xenix) - os=-xenix - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - os=-mint - ;; - -aros*) - os=-aros - ;; - -kaos*) - os=-kaos - ;; - -zvmoe) - os=-zvmoe - ;; - -none) - ;; - *) - # Get rid of the `-' at the beginning of $os. - os=`echo $os | sed 's/[^-]*-//'` - echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 - exit 1 - ;; -esac -else - -# Here we handle the default operating systems that come with various machines. -# The value should be what the vendor currently ships out the door with their -# machine or put another way, the most popular os provided with the machine. - -# Note that if you're going to try to match "-MANUFACTURER" here (say, -# "-sun"), then you have to tell the case statement up towards the top -# that MANUFACTURER isn't an operating system. Otherwise, code above -# will signal an error saying that MANUFACTURER isn't an operating -# system, and we'll never get to this point. - -case $basic_machine in - score-*) - os=-elf - ;; - spu-*) - os=-elf - ;; - *-acorn) - os=-riscix1.2 - ;; - arm*-rebel) - os=-linux - ;; - arm*-semi) - os=-aout - ;; - c4x-* | tic4x-*) - os=-coff - ;; - # This must come before the *-dec entry. - pdp10-*) - os=-tops20 - ;; - pdp11-*) - os=-none - ;; - *-dec | vax-*) - os=-ultrix4.2 - ;; - m68*-apollo) - os=-domain - ;; - i386-sun) - os=-sunos4.0.2 - ;; - m68000-sun) - os=-sunos3 - # This also exists in the configure program, but was not the - # default. - # os=-sunos4 - ;; - m68*-cisco) - os=-aout - ;; - mep-*) - os=-elf - ;; - mips*-cisco) - os=-elf - ;; - mips*-*) - os=-elf - ;; - or32-*) - os=-coff - ;; - *-tti) # must be before sparc entry or we get the wrong os. - os=-sysv3 - ;; - sparc-* | *-sun) - os=-sunos4.1.1 - ;; - *-be) - os=-beos - ;; - *-haiku) - os=-haiku - ;; - *-ibm) - os=-aix - ;; - *-knuth) - os=-mmixware - ;; - *-wec) - os=-proelf - ;; - *-winbond) - os=-proelf - ;; - *-oki) - os=-proelf - ;; - *-hp) - os=-hpux - ;; - *-hitachi) - os=-hiux - ;; - i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) - os=-sysv - ;; - *-cbm) - os=-amigaos - ;; - *-dg) - os=-dgux - ;; - *-dolphin) - os=-sysv3 - ;; - m68k-ccur) - os=-rtu - ;; - m88k-omron*) - os=-luna - ;; - *-next ) - os=-nextstep - ;; - *-sequent) - os=-ptx - ;; - *-crds) - os=-unos - ;; - *-ns) - os=-genix - ;; - i370-*) - os=-mvs - ;; - *-next) - os=-nextstep3 - ;; - *-gould) - os=-sysv - ;; - *-highlevel) - os=-bsd - ;; - *-encore) - os=-bsd - ;; - *-sgi) - os=-irix - ;; - *-siemens) - os=-sysv4 - ;; - *-masscomp) - os=-rtu - ;; - f30[01]-fujitsu | f700-fujitsu) - os=-uxpv - ;; - *-rom68k) - os=-coff - ;; - *-*bug) - os=-coff - ;; - *-apple) - os=-macos - ;; - *-atari*) - os=-mint - ;; - *) - os=-none - ;; -esac -fi - -# Here we handle the case where we know the os, and the CPU type, but not the -# manufacturer. We pick the logical manufacturer. -vendor=unknown -case $basic_machine in - *-unknown) - case $os in - -riscix*) - vendor=acorn - ;; - -sunos*) - vendor=sun - ;; - -aix*) - vendor=ibm - ;; - -beos*) - vendor=be - ;; - -hpux*) - vendor=hp - ;; - -mpeix*) - vendor=hp - ;; - -hiux*) - vendor=hitachi - ;; - -unos*) - vendor=crds - ;; - -dgux*) - vendor=dg - ;; - -luna*) - vendor=omron - ;; - -genix*) - vendor=ns - ;; - -mvs* | -opened*) - vendor=ibm - ;; - -os400*) - vendor=ibm - ;; - -ptx*) - vendor=sequent - ;; - -tpf*) - vendor=ibm - ;; - -vxsim* | -vxworks* | -windiss*) - vendor=wrs - ;; - -aux*) - vendor=apple - ;; - -hms*) - vendor=hitachi - ;; - -mpw* | -macos*) - vendor=apple - ;; - -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) - vendor=atari - ;; - -vos*) - vendor=stratus - ;; - esac - basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` - ;; -esac - -echo $basic_machine$os -exit - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "timestamp='" -# time-stamp-format: "%:y-%02m-%02d" -# time-stamp-end: "'" -# End: diff --git a/lib/diameter/autoconf/configure.vxworks b/lib/diameter/autoconf/configure.vxworks deleted file mode 100755 index 33aa497680..0000000000 --- a/lib/diameter/autoconf/configure.vxworks +++ /dev/null @@ -1,147 +0,0 @@ -#!/bin/sh -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: -# Patrik Winroth -# - - -# vxworks_ppc860 vxworks_ppc603 vxworks_ppc603_longcall vxworks_cpu32 vxworks_sparc -# vxworks_ppc750 vxworks_simso - -case $# in -1) host=$1 ;; -*) echo "usage: configure.vxworks host-configuration"; exit 1 ;; -esac - -case $1 in -vxworks_cpu32) ;; -vxworks_ppc750) ;; -vxworks_ppc860) ;; -vxworks_ppc603) ;; -vxworks_ppc603_nolongcall) ;; -vxworks_sparc) ;; -vxworks_simso) ;; -vxworks_simlinux) ;; -vxworks_ppc32) ;; -*) echo "usage: configure.vxworks TARGET"; - echo "where TARGET is one of vxworks_cpu32, vxworks_ppc750, vxworks_ppc860, vxworks_ppc603, vxworks_ppc603_nolongcall, vxworks_sparc, vxworks_simso, vxworks_simlinux, vxworks_ppc32"; exit 1;; -esac - -if [ "x$ERL_TOP" = x ]; then - echo "You need to set ERL_TOP!" - exit 1 -fi - - -target=$host - -# Find out the HOST and WIND_BASE environment -HOST_TYPE=${HOST_TYPE:=sun4-solaris2} -case $1 in -vxworks_ppc750) VXTOP=Tornado2.2 ;; -vxworks_simso) VXTOP=WindRiver ;; -vxworks_simlinux) VXTOP=WindRiver ;; -vxworks_ppc32) VXTOP=WindRiver ;; -*) VXTOP=wind ;; -esac - -WIND_BASE=${WIND_BASE:=`ypmatch tornado passwd | awk -F: '{print $6}'`/$VXTOP} - -# These are created by autoconf. -MKDIRS="${ERL_TOP}/lib/os_mon/priv/bin/$target - ${ERL_TOP}/lib/os_mon/priv/obj/$target - ${ERL_TOP}/lib/orber/priv/obj/$target - ${ERL_TOP}/lib/orber/priv/bin/$target - ${ERL_TOP}/lib/ic/priv/lib/$target - ${ERL_TOP}/lib/ic/priv/obj/$target - ${ERL_TOP}/lib/asn1/priv/lib/$target - ${ERL_TOP}/lib/asn1/priv/obj/$target - ${ERL_TOP}/lib/erl_interface/obj/$target - ${ERL_TOP}/lib/erl_interface/obj.debug/$target - ${ERL_TOP}/lib/erl_interface/bin/$target - ${ERL_TOP}/lib/runtime_tools/priv/lib/$target - ${ERL_TOP}/lib/runtime_tools/priv/obj/$target - ${ERL_TOP}/erts/obj/$target - ${ERL_TOP}/erts/obj.debug/$target - ${ERL_TOP}/bin/$target" - -for dir in $MKDIRS; do - test ! -d "$dir" && mkdir -p "$dir" -done - -# -# Create Makefiles for vxWorks. -# -my_root=${ERL_TOP}/erts/emulator -emu_test=$my_root/test -beam=$my_root/beam -erts_lib_src=${ERL_TOP}/erts/lib_src -erts_incl=${ERL_TOP}/erts/include -erts_incl_intrnl=${ERL_TOP}/erts/include/internal -etcdir=${ERL_TOP}/erts/etc/common -erlint_dir=${ERL_TOP}/lib/erl_interface/src -epmd_dir=${ERL_TOP}/erts/epmd/src -os_mon_dir=${ERL_TOP}/lib/os_mon/c_src -orber_dir=${ERL_TOP}/lib/orber/c_src -ic_dir=${ERL_TOP}/lib/ic/c_src -asn1_dir=${ERL_TOP}/lib/asn1/c_src -internal_tools_dir=${ERL_TOP} -libdir=${ERL_TOP}/lib -tsdir=$libdir/test_server/src -zlibdir=${ERL_TOP}/erts/emulator/zlib -runtime_tools_dir=${ERL_TOP}/lib/runtime_tools/c_src -tools_dir=${ERL_TOP}/lib/tools/c_src - -CONFIG_FILES="${ERL_TOP}/erts/emulator/$host/Makefile - $erts_lib_src/$host/Makefile - $erts_incl/$host/erl_int_sizes_config.h - $erts_incl_intrnl/$host/ethread.mk - $erts_incl_intrnl/$host/ethread_header_config.h - $etcdir/$host/Makefile - $erlint_dir/$host/Makefile - $erlint_dir/$host/eidefs.mk - $epmd_dir/$host/Makefile - $internal_tools_dir/make/$host/otp.mk - $os_mon_dir/$host/Makefile - $zlibdir/$host/Makefile - $ic_dir/$host/Makefile - $asn1_dir/$host/Makefile - $runtime_tools_dir/$host/Makefile - $tools_dir/$host/Makefile - $orber_dir/$host/Makefile" - -for file in $CONFIG_FILES; do - new_name=`echo $file|sed "s%/$host/%/$target/%"` - dir=`echo $new_name|sed 's%/[^/][^/]*$%%'` - if test "$dir" != "$new_name" && test "$dir" != .; then - test ! -d "$dir" && mkdir "$dir" - fi - - sole_name=`echo $file|sed "s%.*$target/%%"` - in_file=`echo $dir|sed "s%/[^/][^/]*$%/$sole_name.in%"` - echo "creating $new_name" - sed -f vxworks/sed.$target -f vxworks/sed.general \ - -e "s,@HOST_TYPE@,$HOST_TYPE,g" \ - -e "s,@WIND_BASE@,$WIND_BASE,g" \ - -e "s,@TARGET@,$target,g" \ - $in_file > $new_name -done - - diff --git a/lib/diameter/autoconf/install-sh b/lib/diameter/autoconf/install-sh deleted file mode 100755 index a5897de6ea..0000000000 --- a/lib/diameter/autoconf/install-sh +++ /dev/null @@ -1,519 +0,0 @@ -#!/bin/sh -# install - install a program, script, or datafile - -scriptversion=2006-12-25.00 - -# This originates from X11R5 (mit/util/scripts/install.sh), which was -# later released in X11R6 (xc/config/util/install.sh) with the -# following copyright and license. -# -# Copyright (C) 1994 X Consortium -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to -# deal in the Software without restriction, including without limitation the -# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or -# sell copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in -# all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN -# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC- -# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Except as contained in this notice, the name of the X Consortium shall not -# be used in advertising or otherwise to promote the sale, use or other deal- -# ings in this Software without prior written authorization from the X Consor- -# tium. -# -# -# FSF changes to this file are in the public domain. -# -# Calling this script install-sh is preferred over install.sh, to prevent -# `make' implicit rules from creating a file called install from it -# when there is no Makefile. -# -# This script is compatible with the BSD install script, but was written -# from scratch. - -nl=' -' -IFS=" "" $nl" - -# set DOITPROG to echo to test this script - -# Don't use :- since 4.3BSD and earlier shells don't like it. -doit=${DOITPROG-} -if test -z "$doit"; then - doit_exec=exec -else - doit_exec=$doit -fi - -# Put in absolute file names if you don't have them in your path; -# or use environment vars. - -chgrpprog=${CHGRPPROG-chgrp} -chmodprog=${CHMODPROG-chmod} -chownprog=${CHOWNPROG-chown} -cmpprog=${CMPPROG-cmp} -cpprog=${CPPROG-cp} -mkdirprog=${MKDIRPROG-mkdir} -mvprog=${MVPROG-mv} -rmprog=${RMPROG-rm} -stripprog=${STRIPPROG-strip} - -posix_glob='?' -initialize_posix_glob=' - test "$posix_glob" != "?" || { - if (set -f) 2>/dev/null; then - posix_glob= - else - posix_glob=: - fi - } -' - -posix_mkdir= - -# Desired mode of installed file. -mode=0755 - -chgrpcmd= -chmodcmd=$chmodprog -chowncmd= -mvcmd=$mvprog -rmcmd="$rmprog -f" -stripcmd= - -src= -dst= -dir_arg= -dst_arg= - -copy_on_change=false -no_target_directory= - -usage="\ -Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE - or: $0 [OPTION]... SRCFILES... DIRECTORY - or: $0 [OPTION]... -t DIRECTORY SRCFILES... - or: $0 [OPTION]... -d DIRECTORIES... - -In the 1st form, copy SRCFILE to DSTFILE. -In the 2nd and 3rd, copy all SRCFILES to DIRECTORY. -In the 4th, create DIRECTORIES. - -Options: - --help display this help and exit. - --version display version info and exit. - - -c (ignored) - -C install only if different (preserve the last data modification time) - -d create directories instead of installing files. - -g GROUP $chgrpprog installed files to GROUP. - -m MODE $chmodprog installed files to MODE. - -o USER $chownprog installed files to USER. - -s $stripprog installed files. - -t DIRECTORY install into DIRECTORY. - -T report an error if DSTFILE is a directory. - -Environment variables override the default commands: - CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG - RMPROG STRIPPROG -" - -while test $# -ne 0; do - case $1 in - -c) ;; - - -C) copy_on_change=true;; - - -d) dir_arg=true;; - - -g) chgrpcmd="$chgrpprog $2" - shift;; - - --help) echo "$usage"; exit $?;; - - -m) mode=$2 - case $mode in - *' '* | *' '* | *' -'* | *'*'* | *'?'* | *'['*) - echo "$0: invalid mode: $mode" >&2 - exit 1;; - esac - shift;; - - -o) chowncmd="$chownprog $2" - shift;; - - -s) stripcmd=$stripprog;; - - -t) dst_arg=$2 - shift;; - - -T) no_target_directory=true;; - - --version) echo "$0 $scriptversion"; exit $?;; - - --) shift - break;; - - -*) echo "$0: invalid option: $1" >&2 - exit 1;; - - *) break;; - esac - shift -done - -if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then - # When -d is used, all remaining arguments are directories to create. - # When -t is used, the destination is already specified. - # Otherwise, the last argument is the destination. Remove it from $@. - for arg - do - if test -n "$dst_arg"; then - # $@ is not empty: it contains at least $arg. - set fnord "$@" "$dst_arg" - shift # fnord - fi - shift # arg - dst_arg=$arg - done -fi - -if test $# -eq 0; then - if test -z "$dir_arg"; then - echo "$0: no input file specified." >&2 - exit 1 - fi - # It's OK to call `install-sh -d' without argument. - # This can happen when creating conditional directories. - exit 0 -fi - -if test -z "$dir_arg"; then - trap '(exit $?); exit' 1 2 13 15 - - # Set umask so as not to create temps with too-generous modes. - # However, 'strip' requires both read and write access to temps. - case $mode in - # Optimize common cases. - *644) cp_umask=133;; - *755) cp_umask=22;; - - *[0-7]) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw='% 200' - fi - cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;; - *) - if test -z "$stripcmd"; then - u_plus_rw= - else - u_plus_rw=,u+rw - fi - cp_umask=$mode$u_plus_rw;; - esac -fi - -for src -do - # Protect names starting with `-'. - case $src in - -*) src=./$src;; - esac - - if test -n "$dir_arg"; then - dst=$src - dstdir=$dst - test -d "$dstdir" - dstdir_status=$? - else - - # Waiting for this to be detected by the "$cpprog $src $dsttmp" command - # might cause directories to be created, which would be especially bad - # if $src (and thus $dsttmp) contains '*'. - if test ! -f "$src" && test ! -d "$src"; then - echo "$0: $src does not exist." >&2 - exit 1 - fi - - if test -z "$dst_arg"; then - echo "$0: no destination specified." >&2 - exit 1 - fi - - dst=$dst_arg - # Protect names starting with `-'. - case $dst in - -*) dst=./$dst;; - esac - - # If destination is a directory, append the input filename; won't work - # if double slashes aren't ignored. - if test -d "$dst"; then - if test -n "$no_target_directory"; then - echo "$0: $dst_arg: Is a directory" >&2 - exit 1 - fi - dstdir=$dst - dst=$dstdir/`basename "$src"` - dstdir_status=0 - else - # Prefer dirname, but fall back on a substitute if dirname fails. - dstdir=` - (dirname "$dst") 2>/dev/null || - expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ - X"$dst" : 'X\(//\)[^/]' \| \ - X"$dst" : 'X\(//\)$' \| \ - X"$dst" : 'X\(/\)' \| . 2>/dev/null || - echo X"$dst" | - sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ - s//\1/ - q - } - /^X\(\/\/\)[^/].*/{ - s//\1/ - q - } - /^X\(\/\/\)$/{ - s//\1/ - q - } - /^X\(\/\).*/{ - s//\1/ - q - } - s/.*/./; q' - ` - - test -d "$dstdir" - dstdir_status=$? - fi - fi - - obsolete_mkdir_used=false - - if test $dstdir_status != 0; then - case $posix_mkdir in - '') - # Create intermediate dirs using mode 755 as modified by the umask. - # This is like FreeBSD 'install' as of 1997-10-28. - umask=`umask` - case $stripcmd.$umask in - # Optimize common cases. - *[2367][2367]) mkdir_umask=$umask;; - .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;; - - *[0-7]) - mkdir_umask=`expr $umask + 22 \ - - $umask % 100 % 40 + $umask % 20 \ - - $umask % 10 % 4 + $umask % 2 - `;; - *) mkdir_umask=$umask,go-w;; - esac - - # With -d, create the new directory with the user-specified mode. - # Otherwise, rely on $mkdir_umask. - if test -n "$dir_arg"; then - mkdir_mode=-m$mode - else - mkdir_mode= - fi - - posix_mkdir=false - case $umask in - *[123567][0-7][0-7]) - # POSIX mkdir -p sets u+wx bits regardless of umask, which - # is incompatible with FreeBSD 'install' when (umask & 300) != 0. - ;; - *) - tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$ - trap 'ret=$?; rmdir "$tmpdir/d" "$tmpdir" 2>/dev/null; exit $ret' 0 - - if (umask $mkdir_umask && - exec $mkdirprog $mkdir_mode -p -- "$tmpdir/d") >/dev/null 2>&1 - then - if test -z "$dir_arg" || { - # Check for POSIX incompatibilities with -m. - # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or - # other-writeable bit of parent directory when it shouldn't. - # FreeBSD 6.1 mkdir -m -p sets mode of existing directory. - ls_ld_tmpdir=`ls -ld "$tmpdir"` - case $ls_ld_tmpdir in - d????-?r-*) different_mode=700;; - d????-?--*) different_mode=755;; - *) false;; - esac && - $mkdirprog -m$different_mode -p -- "$tmpdir" && { - ls_ld_tmpdir_1=`ls -ld "$tmpdir"` - test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1" - } - } - then posix_mkdir=: - fi - rmdir "$tmpdir/d" "$tmpdir" - else - # Remove any dirs left behind by ancient mkdir implementations. - rmdir ./$mkdir_mode ./-p ./-- 2>/dev/null - fi - trap '' 0;; - esac;; - esac - - if - $posix_mkdir && ( - umask $mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir" - ) - then : - else - - # The umask is ridiculous, or mkdir does not conform to POSIX, - # or it failed possibly due to a race condition. Create the - # directory the slow way, step by step, checking for races as we go. - - case $dstdir in - /*) prefix='/';; - -*) prefix='./';; - *) prefix='';; - esac - - eval "$initialize_posix_glob" - - oIFS=$IFS - IFS=/ - $posix_glob set -f - set fnord $dstdir - shift - $posix_glob set +f - IFS=$oIFS - - prefixes= - - for d - do - test -z "$d" && continue - - prefix=$prefix$d - if test -d "$prefix"; then - prefixes= - else - if $posix_mkdir; then - (umask=$mkdir_umask && - $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break - # Don't fail if two instances are running concurrently. - test -d "$prefix" || exit 1 - else - case $prefix in - *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;; - *) qprefix=$prefix;; - esac - prefixes="$prefixes '$qprefix'" - fi - fi - prefix=$prefix/ - done - - if test -n "$prefixes"; then - # Don't fail if two instances are running concurrently. - (umask $mkdir_umask && - eval "\$doit_exec \$mkdirprog $prefixes") || - test -d "$dstdir" || exit 1 - obsolete_mkdir_used=true - fi - fi - fi - - if test -n "$dir_arg"; then - { test -z "$chowncmd" || $doit $chowncmd "$dst"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } && - { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false || - test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1 - else - - # Make a couple of temp file names in the proper directory. - dsttmp=$dstdir/_inst.$$_ - rmtmp=$dstdir/_rm.$$_ - - # Trap to clean up those temp files at exit. - trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0 - - # Copy the file name to the temp name. - (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") && - - # and set any options; do chmod last to preserve setuid bits. - # - # If any of these fail, we abort the whole thing. If we want to - # ignore errors from any of these, just make sure not to ignore - # errors from the above "$doit $cpprog $src $dsttmp" command. - # - { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } && - { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } && - { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } && - { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } && - - # If -C, don't bother to copy if it wouldn't change the file. - if $copy_on_change && - old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` && - new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` && - - eval "$initialize_posix_glob" && - $posix_glob set -f && - set X $old && old=:$2:$4:$5:$6 && - set X $new && new=:$2:$4:$5:$6 && - $posix_glob set +f && - - test "$old" = "$new" && - $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1 - then - rm -f "$dsttmp" - else - # Rename the file to the real destination. - $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null || - - # The rename failed, perhaps because mv can't rename something else - # to itself, or perhaps because mv is so ancient that it does not - # support -f. - { - # Now remove or move aside any old file at destination location. - # We try this two ways since rm can't unlink itself on some - # systems and the destination file might be busy for other - # reasons. In this case, the final cleanup might fail but the new - # file should still install successfully. - { - test ! -f "$dst" || - $doit $rmcmd -f "$dst" 2>/dev/null || - { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null && - { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; } - } || - { echo "$0: cannot unlink or rename $dst" >&2 - (exit 1); exit 1 - } - } && - - # Now rename the file to the real destination. - $doit $mvcmd "$dsttmp" "$dst" - } - fi || exit 1 - - trap '' 0 - fi -done - -# Local variables: -# eval: (add-hook 'write-file-hooks 'time-stamp) -# time-stamp-start: "scriptversion=" -# time-stamp-format: "%:y-%02m-%02d.%02H" -# time-stamp-end: "$" -# End: diff --git a/lib/diameter/autoconf/vxworks/sed.general b/lib/diameter/autoconf/vxworks/sed.general deleted file mode 100644 index 173e4d5dc0..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.general +++ /dev/null @@ -1,124 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2012. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles -# for vxworks from the generic Makefile.in that is found in a number -# of directories (see configure.vxworks). -# -# This is the general part that is common for all architectures. -# - -# Size of data types. -s|^#undef SIZEOF_CHAR|#define SIZEOF_CHAR 1| -s|^#undef SIZEOF_SHORT|#define SIZEOF_SHORT 2| -s|^#undef SIZEOF_INT|#define SIZEOF_INT 4| -s|^#undef SIZEOF_LONG_LONG|#define SIZEOF_LONG_LONG 8| -s|^#undef SIZEOF_LONG$|#define SIZEOF_LONG 4| - -# General stuff. -s|@erts_rootdir@|/clearcase/otp/erts| - -s|@LIBOBJS@|$(OBJDIR)/elib_malloc.o| -s|@DLOAD_LIB@|| -s|@LDFLAGS@|| -# FIXME: A bit strange to clear out remaining DED_* -s|@DED_LDFLAGS@|| -s|@DED_CFLAGS@|| -s|@STATIC_CFLAGS@|| -s|@GCCLIB@|libgcc.a| -s|@DEFS@|| -s|@DEXPORT@|| -s|@DCFLAGS@|| -s|@THR_DEFS@|| -s|@THR_LIBS@|| -s|@THR_LIB_NAME@|| -s|@THR_X_LIBS@|| -s|@ETHR_X_LIBS@|| -s|@ETHR_LIBS@|| -s|@ETHR_LIB_NAME@|| -s|@ETHR_DEFS@|| -s|@ETHR_THR_LIB_BASE@|| -s|@EMU_THR_DEFS@|| -s|@EMU_THR_LIBS@|| -s|@EMU_THR_LIB_NAME@|ethread| -s|@ERTS_ENABLE_KERNEL_POLL@|no| -s|@cc_root@|/clearcase/otp/| -# Define VxWorks even though cross-compiling. -s|@HCFLAGS@|-DVXWORKS| -s|@HCLIBS@|| -s|@ENABLE_ALLOC_TYPE_VARS@|| -s|@TERMCAP_LIB@|| -s|@ERTS_BUILD_SMP_EMU@|no| -s|@HAVE_VALGRIND@|no| -s|@EXEEXT@|| -s|@WITH_SCTP@|| - -# HiPE -s|@HIPE_ENABLED@|| -s|@PERFCTR_PATH@|| -s|@USE_PERFCTR@|| - -# m4 -s|@OPSYS@|noopsys| - -# Conditional inclusion of applications -s|@HIPE_APP@|| -s|@SSL_APP@|ssl| -s|@CRYPTO_APP@|crypto| -s|@SSH_APP@|ssh| - -# The target tools prefix, prepended to all cc,ld,as etc commands -s|@TTPREFIX@|GCC_EXEC_PREFIX=@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/host/@HOST_TYPE@/bin/| - -# Install programs etc -s|@PERL@|perl| -s|@INSTALL@|/usr/ucb/install -c| -s|@INSTALL_PROGRAM@|${INSTALL}| -s|@INSTALL_SCRIPT@|${INSTALL}| -s|@INSTALL_DATA@|${INSTALL} -m 644| -s|@INSTALL_DIR@|$(INSTALL) -d| -s|@RM@|/bin/rm| -s|@MKDIR@|/bin/mkdir| -s|@ERLANG_OSTYPE@|vxworks| -s|@vxworks_reclaim@|reclaim.h| -s|@os_mon_programs@|| -s|@erlexec@|erl.exec| -s|@EMU_LIBOBJS@|| - -# General CFLAGS -s|@GENERAL_CFLAGS@|-DHAVE_LOCALTIME_R -DHAVE_GMTIME_R -DENABLE_ELIB_MALLOC -DELIB_HEAP_USER -DELIB_SORTED_BLOCKS -DWORDS_BIGENDIAN -DELIB_DONT_INITIALIZE -DSIZEOF_CHAR=1 -DSIZEOF_SHORT=2 -DSIZEOF_INT=4 -DSIZEOF_LONG=4 -DSIZEOF_LONG_LONG=8 -DSIZEOF_VOID_P=4 -DERTS_USE_PORT_TASKS=1|g -s|@WFLAGS@|| - -# Thread flags for eidefs.mk (erl_interface) -s|@EI_THREADS@|false| - -# Make java code compile although we don't test it on VxWorks (no license) -s|@JAVAC@|javac| - -# What is this anyway? -# Disable it and see what breaks. -#s|@ded_soname@|| - -# Only variable substituted directly -s|$(LDFLAGS)|-r -d| -s|@LIBRT@|| -# XXX What is EFFLAGS? Not used in the emulator Makefile.in anyway. -s|$(EFLAGS)|-DENABLE_ELIB_MALLOC -DELIB_HEAP_USER -DELIB_SORTED_BLOCKS| - diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 b/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 deleted file mode 100644 index 5a1590e786..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_cpu32 +++ /dev/null @@ -1,45 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_cpu32| -s|@system_type@|vxworks_cpu32| -s|@CC@|@TTPREFIX@cc68k| -s|@HCC@|gcc| -s|@LD@|@TTPREFIX@ld68k| -s|@LIBS@|| -s|@DED_LD@|@TTPREFIX@ld68k| -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_FLAGS@|-g| -s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/m68k-wrs-vxworks/cygnus-2.7.2-960126/m68000/msoft-float/libgcc.a| -s|@RANLIB@|@TTPREFIX@ranlib68k| -s|@AR@|@TTPREFIX@ar68k| -s|@STRIP@|@TTPREFIX@strip68k| -s|@SYMPREFIX@|_| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/m68k-wrs-vxworks/cygnus-2.7.2-960126/m68000/msoft-float -lgcc| - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=CPU32 -mnobitfield -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -fno-builtin -nostdinc -fvolatile -msoft-float| -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=CPU32 -mnobitfield -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -fno-builtin -nostdinc -fvolatile -msoft-float| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 deleted file mode 100644 index 9104b24ed3..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc32 +++ /dev/null @@ -1,52 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2006-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Peter Andersson -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_ppc32| -s|@system_type@|vxworks_ppc32| -s|@ARCH@|ppc32| -s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccppc -mlongcall| -s|@HCC@|gcc| -s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldppc| -s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/workbench-2.3/@HOST_TYPE@/bin/stripppc| -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/ppc/PPC32/common -lgcc| -s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldppc| -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# generate dwarf debug code on PPC .. -s|@DEBUG_FLAGS@|-gdwarf| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/ppc/PPC32/common/libgcc.a| -s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibppc| -s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arppc| -# -Dasm(X)= is for beam - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC32 -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/powerpc-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | - -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC32 -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -I@WIND_BASE@/vxworks-6.3/target/h -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 deleted file mode 100644 index e1dd7c5afd..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603 +++ /dev/null @@ -1,51 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2000-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_ppc603| -s|@system_type@|vxworks_ppc603| -s|@ARCH@|ppc603| -s|@CC@|@TTPREFIX@ccppc -mlongcall| -s|@HCC@|gcc| -s|@LD@|@TTPREFIX@ldppc| -s|@STRIP@|@TTPREFIX@stripppc| -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126 -lgcc| -s|@DED_LD@|@TTPREFIX@ldppc| -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# generate dwarf debug code on PPC .. -s|@DEBUG_FLAGS@|-gdwarf| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/libgcc.a| -s|@RANLIB@|@TTPREFIX@ranlibppc| -s|@AR@|@TTPREFIX@arppc| -# -Dasm(X)= is for beam - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall deleted file mode 100644 index 5d7673d323..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc603_nolongcall +++ /dev/null @@ -1,51 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_ppc603| -s|@system_type@|vxworks_ppc603| -s|@ARCH@|ppc603| -s|@CC@|@TTPREFIX@ccppc| -s|@HCC@|gcc| -s|@LD@|@TTPREFIX@ldppc| -s|@STRIP@|@TTPREFIX@stripppc| -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126 -lgcc| -s|@DED_LD@|@TTPREFIX@ldppc| -s|@DED_CFLAGS@|@CFLAGS@| -# generate dwarf debug code on PPC .. -s|@DEBUG_FLAGS@|-gdwarf| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/libgcc.a| -s|@RANLIB@|@TTPREFIX@ranlibppc| -s|@AR@|@TTPREFIX@arppc| -# -Dasm(X)= is for beam - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC603 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mstrict-align -fvolatile -fno-builtin -fno-for-scope -D_GNU_TOOL| - diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 b/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 deleted file mode 100644 index 7a3c32df5b..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_ppc860 +++ /dev/null @@ -1,50 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_ppc860| -s|@system_type@|vxworks_ppc860| -s|@ARCH@|ppc860| -s|@CC@|@TTPREFIX@ccppc -mlongcall| -s|@HCC@|gcc| -s|@LD@|@TTPREFIX@ldppc| -s|@STRIP@|@TTPREFIX@stripppc| -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/soft-float -lgcc| -s|@DED_LD@|@TTPREFIX@ldppc| -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# generate dwarf debug code on PPC .. -s|@DEBUG_FLAGS@|-gdwarf| -# remove -g option (go for dwarf) -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/host/@HOST_TYPE@/lib/gcc-lib/powerpc-wrs-vxworks/cygnus-2.7.2-960126/soft-float/libgcc.a| -s|@RANLIB@|@TTPREFIX@ranlibppc| -s|@AR@|@TTPREFIX@arppc| - -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC860 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mcpu=860 -fvolatile -fno-builtin -fno-for-scope -msoft-float -D_GNU_TOOL -nostdinc| -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=PPC860 -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DVXWORKS -I@WIND_BASE@/target/h -mcpu=powerpc -fvolatile -fno-builtin -fno-for-scope -msoft-float -D_GNU_TOOL -nostdinc| diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux b/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux deleted file mode 100644 index 56eae6507c..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_simlinux +++ /dev/null @@ -1,59 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2008-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Peter Andersson -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_simlinux| -s|@system_type@|vxworks_simlinux| -s|@ARCH@|simlinux| - -s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccpentium| - -s|@HCC@|gcc| - -s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldpentium| - -#s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/strip| -s|@STRIP@|| - -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/simlinux/SIMLINUX/common -lgcc| - -s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldpentium| - -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/simlinux/SIMLINUX/common/libgcc.a| - -s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibpentium| - -s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arpentium| - -# -Dasm(X)= is for beam -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMLINUX -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/i586-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -fvolatile -fno-builtin | -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMLINUX -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_simso b/lib/diameter/autoconf/vxworks/sed.vxworks_simso deleted file mode 100644 index 6b845d31de..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_simso +++ /dev/null @@ -1,64 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 2005-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Peter Andersson -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# -# -# -s|@host@|vxworks_simso| -s|@system_type@|vxworks_simso| -s|@ARCH@|simso| - -# Tornado2.2: s|@CC@|@TTPREFIX@ccsimso| -s|@CC@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ccsparc| - -s|@HCC@|gcc| - -# Tornado2.2: s|@LD@|@TTPREFIX@ldsimso| -s|@LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldsparc| - -# Tornado2.2: s|@STRIP@|@TTPREFIX@stripsimso| -s|@STRIP@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/stripsparc| - -s|@SYMPREFIX@|| -s|@LIBS@|| -s|@GCCLIBFLAGS@|-L@WIND_BASE@/vxworks-6.3/target/lib/simso/SIMSPARCSOLARIS/common -lgcc| - -# Tornado2.2: s|@DED_LD@|@TTPREFIX@ldsimso| -s|@DED_LD@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ldsparc| - -s|@DED_CFLAGS@|@CFLAGS@| -s|@DEBUG_CFLAGS@|@CFLAGS@| -# remove -g option -s|TYPE_FLAGS = -g |TYPE_FLAGS = | -s|@GCCLIB_PATH@|@WIND_BASE@/vxworks-6.3/target/lib/simso/SIMSPARCSOLARIS/common/libgcc.a| - -# Tornado2.2: s|@RANLIB@|@TTPREFIX@ranlibsimso| -s|@RANLIB@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/ranlibsparc| - -# Tornado2.2: s|@AR@|arsimso| -s|@AR@|GCC_EXEC_PREFIX=@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc-lib/ @WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/bin/arsparc| - -# -Dasm(X)= is for beam -s|@LIB_CFLAGS@|@CFLAGS@| - -s|@CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMSPARCSOLARIS -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/gnu/3.4.4-vxworks-6.3/@HOST_TYPE@/lib/gcc/sparc-wrs-vxworks/3.4.4/include -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -fvolatile -fno-builtin | -#s|@LIB_CFLAGS@|@GENERAL_CFLAGS@ -DCPU=SIMSPARCSOLARIS -DTOOL_FAMILY=gnu -DTOOL=gnu -DWANT_NONBLOCKING -DHAVE_SENS -DHAVE_MEMMOVE -DVXWORKS -DDEBUG -I@WIND_BASE@/vxworks-6.3/target/h -I@WIND_BASE@/vxworks-6.3/target/h/wrn/coreip -mstrict-align -fvolatile -fno-builtin | diff --git a/lib/diameter/autoconf/vxworks/sed.vxworks_sparc b/lib/diameter/autoconf/vxworks/sed.vxworks_sparc deleted file mode 100644 index 6f637d8746..0000000000 --- a/lib/diameter/autoconf/vxworks/sed.vxworks_sparc +++ /dev/null @@ -1,38 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Author: Patrik Winroth -# -# This sed program file is intended to be used when creating Makefiles for vxworks -# from the generic Makefile.in that is found in a number of directories (see configure.vxworks) -# - -# ccsparc -O2 doesn't work when compiling "rundir"/gc.c - signal 11 is generated when trying -# therefore it is compiled with -O1 instead, which works - get a new ccsparc ! -s/\$(COMPILE\.emu) -o \$@ -c gc\.c/$(CC) @CFLAGS@ @DEFS@ -O1 $(BEAM_MODE) -I$(SYSDIR) -I$(EMUDIR) -I. $(CPPFLAGS) -c -o $@ -c gc.c/ -s/@host@/vxworks_sparc/ -s/@system_type@/vxworks_sparc/ -s/@CC@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/bin\/ccsparc/ -s/@HCC@/gcc/ -s/@LD@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/bin\/ldsparc/ -s/@DEBUG_FLAGS@/-g/ -s/@GCCLIB_PATH@/\/home\/gandalf\/bsproj\/tools\/vw-gnu\/solaris.sparc\/lib\/gcc-lib\/sparc-wrs-vxworks\/cygnus-2.2.3.1\/libgcc.a/ -s/@RANLIB@/ranlibsparc/ -s/@AR@/arsparc/ -s/@CFLAGS@/-I\/home\/gandalf\/bsproj\/BS.2\/UOS\/vw\/5.2\/h -DWANT_NONBLOCKING -DHAVE_MEMMOVE -DCPU=SPARC -DVXWORKS -fno-builtin -nostdinc/ - diff --git a/lib/diameter/configure.in b/lib/diameter/configure.in deleted file mode 100644 index 8acfb28fed..0000000000 --- a/lib/diameter/configure.in +++ /dev/null @@ -1,137 +0,0 @@ -dnl Process this file with autoconf to produce a configure script. - -dnl %CopyrightBegin% -dnl -dnl Copyright Ericsson AB 1998-2011. All Rights Reserved. -dnl -dnl The contents of this file are subject to the Erlang Public License, -dnl Version 1.1, (the "License"); you may not use this file except in -dnl compliance with the License. You should have received a copy of the -dnl Erlang Public License along with this software. If not, it can be -dnl retrieved online at http://www.erlang.org/. -dnl -dnl Software distributed under the License is distributed on an "AS IS" -dnl basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -dnl the License for the specific language governing rights and limitations -dnl under the License. -dnl -dnl %CopyrightEnd% - -if test "x$no_recursion" != "xyes" -a "x$OVERRIDE_CONFIG_CACHE" = "x"; then - # We do not want to use a common cache! - cache_file=/dev/null -fi - -AC_INIT(vsn.mk) - -dnl <STANDALONE DIAMETER> -dnl This is needed for diameters own environment to rock, -dnl but since we are now integrated into OTP, we skip it. -dnl In order to build stand-alone we need atleast 2.63... -dnl AC_PREREQ(2.63) -dnl </STANDALONE DIAMETER> - -dnl LM_PRECIOUS_VARS - - -dnl The OTP source tree is the default "top", -dnl but we can also define our own top: DIAMETER_TOP - -if test -n "$ERL_TOP" || test -d $ERL_TOP ; then - erl_top=${ERL_TOP} - AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf) - DIAMETER_TOP=${ERL_TOP}/lib/diameter -else - AC_ARG_VAR(DIAMETER_TOP, [Diameter top source directory]) - if test -n "$DIAMETER_TOP" || test -d $DIAMETER_TOP ; then - AC_CONFIG_AUX_DIRS(autoconf) - fi - - dnl <STANDALONE DIAMETER> - dnl AC_ERLANG_SUBST_ROOT_DIR - dnl AC_ERLANG_SUBST_LIB_DIR - dnl AC_ERLANG_CHECK_LIB([erl_docgen], - dnl [echo "erl_docgen version \"$ERLANG_LIB_VER_erl_docgen\"" - dnl echo "is installed in \"$ERLANG_LIB_DIR_erl_docgen\""], - dnl [AC_MSG_ERROR([erl_docgen was not found!])]) - dnl AC_ERLANG_CHECK_LIB([test_server], - dnl [echo "test_server version \"$ERLANG_LIB_VER_test_server\"" - dnl echo "is installed in \"$ERLANG_LIB_DIR_test_server\""], - dnl [AC_MSG_ERROR([test_server was not found!])]) - dnl </STANDALONE DIAMETER> - -fi - -AC_SUBST(DIAMETER_TOP) -export DIAMETER_TOP - -if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then - AC_CANONICAL_HOST -fi - -TARGET=$host -AC_SUBST(TARGET) - -if test "x$erl_top" = "x"; then - dnl STANDALONE DIAMETER - AC_CHECK_PROGS(XSLTPROC, xsltproc) - if test -z "$XSLTPROC"; then - echo "xsltproc" >> doc/CONF_INFO - AC_MSG_WARN([No 'xsltproc' command found: the documentation can not be built]) - fi - - AC_CHECK_PROGS(FOP, fop) - if test -z "$FOP"; then - AC_MSG_ERROR([No 'fop' command found: the documentation can not be built]) - fi -fi - -dnl -dnl We can live with Solaris /usr/ucb/install -dnl -case $host in - *-*-solaris*|free_source) - if test -x /usr/ucb/install; then - INSTALL="/usr/ucb/install -c" - fi - ;; - *) - ;; -esac -AC_PROG_INSTALL -LM_PROG_INSTALL_DIR - -case $host_os in - darwin*) - dnl Need to preserve modification time on archives; - dnl otherwise, ranlib has to be run on archives - dnl again after installation. - INSTALL_DATA="$INSTALL_DATA -p";; - *) - ;; -esac - -dnl -dnl Fix for Tilera install permissions -dnl - -case $build in - *tile*) - INSTALL_PROGRAM="$INSTALL_PROGRAM -m755" - INSTALL_SCRIPT="$INSTALL_SCRIPT -m755" - ;; - *) - ;; -esac - - -dnl <STANDALONE DIAMETER> -dnl AC_ERLANG_NEED_ERL([$PATH]) -dnl AC_ERLANG_NEED_ERLC([$PATH]) -dnl </STANDALONE DIAMETER> - -AC_OUTPUT( - Makefile:Makefile.in - make/$host/rules.mk:make/rules.mk.in - ) - diff --git a/lib/diameter/doc/.gitignore b/lib/diameter/doc/.gitignore new file mode 100644 index 0000000000..b634bdd7ba --- /dev/null +++ b/lib/diameter/doc/.gitignore @@ -0,0 +1,4 @@ + +/html/ +/man*/ +/pdf/ diff --git a/lib/diameter/doc/src/Makefile b/lib/diameter/doc/src/Makefile index 59ca660797..d1d5e8f869 100644 --- a/lib/diameter/doc/src/Makefile +++ b/lib/diameter/doc/src/Makefile @@ -16,13 +16,8 @@ # # %CopyrightEnd% -ifneq ($(ERL_TOP),) include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk -else -include $(DIAMETER_TOP)/make/target.mk -include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk -endif include ../../vsn.mk @@ -155,11 +150,8 @@ info: # ---------------------------------------------------- # Release Target # ---------------------------------------------------- -ifneq ($(ERL_TOP),) + include $(ERL_TOP)/make/otp_release_targets.mk -else -include $(DIAMETER_TOP)/make/release_targets.mk -endif release_docs_spec: $(LOCAL)docs $(INSTALL_DIR) "$(RELSYSDIR)/doc/pdf" diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml index b8652a7482..80863f8eff 100644 --- a/lib/diameter/doc/src/diameter.xml +++ b/lib/diameter/doc/src/diameter.xml @@ -375,10 +375,15 @@ is meant in the sense of <c>eval([E|A])</c>.</p> <warning> <p> -Beware of using fun expressions of the form <c>fun Name/Arity</c> (not -fun Mod:Name/Arity) in situations in which the fun is not short-lived +Beware of using fun expressions of the form <c>fun Name/Arity</c> in +situations in which the fun is not short-lived and code is to be upgraded at runtime since any processes retaining -such a fun will have a reference to old code.</p> +such a fun will have a reference to old code. +In particular, such a value is typically inappropriate in +configuration passed to <seealso +marker="#start_service">start_service/2</seealso> or +<seealso +marker="#add_transport">add_transport/2</seealso>.</p> </warning> <marker id="peer_filter"/> @@ -699,6 +704,64 @@ the application's <seealso marker="diameter_dict">dictionary</seealso> file.</p> </item> +<tag><c>{restrict_connections, false + | node + | nodes + | [node()] + | diameter:evaluable()}</c></tag> +<item> +<p> +Specifies the degree to which multiple transport connections to the +same peer are accepted by the service.</p> + +<p> +If type <c>[node()]</c> then a connection is rejected if another already +exists on any of the specified nodes. +Values of type <c>false</c>, <c>node</c>, <c>nodes</c> or +<c>diameter:evaluable()</c> are equivalent to values <c>[]</c>, +<c>[node()]</c>, <c>[node()|nodes()]</c> and the evaluated value, +respectively, evaluation of each expression taking place whenever a +new connection is to be established. +Note that <c>false</c> allows an unlimited number of connections to be +established with the same peer.</p> + +<p> +Multiple connections are independent and governed +by their own peer and watchdog state machines.</p> + +<p> +Defaults to <c>nodes</c>.</p> +</item> + +<tag><c>{sequence, {H,N} | <seealso + marker="diameter#evaluable">diameter:evaluable()</seealso>}</c></tag> +<item> +<p> +Specifies a constant value <c>H</c> for the topmost <c>32-N</c> bits of +of 32-bit End-to-End and Hop-by-Hop identifiers generated +by the service, either explicity or as a return value of a function +to be evaluated at <seealso +marker="diameter#start_service">diameter:start_service/2</seealso>. +In particular, an identifier <c>Id</c> is mapped to a new identifier +as follows.</p> +<code> +(H bsl N) bor (Id band ((1 bsl N) - 1)) +</code> +<p> +Note that RFC 3588 requires that End-to-End identifiers remain unique +for a period of at least 4 minutes and that this and the call rate +places a lower bound on the appropriate values of <c>N</c>: +at a rate of <c>R</c> requests per second an <c>N</c>-bit counter +traverses all of its values in <c>(1 bsl N) div (R*60)</c> minutes so +the bound is <c>4*R*60 =< 1 bsl N</c>.</p> + +<p><c>N</c> must lie in the range <c>0..32</c> and <c>H</c> must be a +non-negative integer less than <c>1 bsl (32-N)</c>.</p> + +<p> +Defaults to <c>{0,32}</c>.</p> +</item> + </taglist> <marker id="transport_opt"/> @@ -850,7 +913,7 @@ reconnection attempts, as required by RFC 3539.</p> For a listening transport, the timer specifies the time after which a previously connected peer will be forgotten: a connection after this time is regarded as an initial connection rather than a reestablishment, -causing the RFC 3539 state machine to pass to state OPEN rather than +causing the RFC 3539 state machine to pass to state OKAY rather than REOPEN. Note that these semantics are not goverened by the RFC and that a listening transport's <c>reconnect_timer</c> should be greater @@ -1149,6 +1212,12 @@ DPA or timeout.</p> <desc> <p> Return information about a started service. +Requesting info for an unknown service causes <c>undefined</c> to be +returned. +Requesting a list of items causes a tagged list to be +returned.</p> + +<p> <c>Item</c> can be one of the following.</p> <taglist> @@ -1419,13 +1488,27 @@ The Diameter-level statistics returned by <c>transport</c> and <c>connections</c> info are based upon these entries.</p> </item> -</taglist> - +<tag><c><seealso marker="diameter_app#peer_ref">diameter_app:peer_ref()</seealso></c></tag> +<item> <p> -Requesting info for an unknown service causes <c>undefined</c> to be -returned. -Requesting a list of items causes a tagged list to be -returned.</p> +Return transport configuration associated with a single peer, as +passed to <seealso marker="#add_transport">add_transport/2</seealso>. +The returned list is empty if the peer is unknown. +Otherwise it contains the <c>ref</c>, <c>type</c> and <c>options</c> +tuples as in <c>transport</c> and <c>connections</c> info above. +For example:</p> + +<code> +[{ref,#Ref<0.0.0.61>}, + {type,accept}, + {options,[{transport_module,diameter_tcp}, + {transport_config,[{reuseaddr,true}, + {ip,{127,0,0,1}}, + {port,3868}]}]}] +</code> +</item> + +</taglist> <marker id="services"/> </desc> diff --git a/lib/diameter/doc/src/diameter_app.xml b/lib/diameter/doc/src/diameter_app.xml index 4a4b212787..9d8a6568eb 100644 --- a/lib/diameter/doc/src/diameter_app.xml +++ b/lib/diameter/doc/src/diameter_app.xml @@ -112,7 +112,8 @@ and, for the call-specific callbacks, any extra arguments passed to <item> <p> A record containing the identities of -the local Diameter node and the remote Diameter peer having an established transport +the local Diameter node and the remote Diameter peer having an +established transport connection, as well as the capabilities as determined by capabilities exchange. Each field of the record is a 2-tuple consisting of @@ -168,13 +169,14 @@ Fields should not be set in return values except as documented.</p> <tag><c>peer_ref() = term()</c></tag> <item> <p> -A term identifying a transport connection with a Diameter peer. -Should be treated opaquely.</p> +A term identifying a transport connection with a Diameter peer.</p> </item> <marker id="peer"/> -<tag><c>peer() = {<seealso marker="#peer_ref">peer_ref()</seealso>, <seealso marker="#capabilities">capabilities()</seealso>}</c></tag> +<tag><c>peer() = + {<seealso marker="#peer_ref">peer_ref()</seealso>, + <seealso marker="#capabilities">capabilities()</seealso>}</c></tag> <item> <p> A tuple representing a Diameter peer connection.</p> @@ -219,10 +221,29 @@ process.</p> </type> <desc> <p> -Invoked when a transport connection has been established -and a successful capabilities exchange has indicated that the peer -supports the Diameter application of the application on which -the callback module in question has been configured.</p> +Invoked to signal the availability of a peer connection. +In particular, capabilities exchange with the peer has indicated +support for the application in question, the RFC 3539 watchdog state +machine for the connection has reached state <c>OKAY</c> and Diameter +messages can be both sent and received.</p> + +<note> +<p> +A watchdog state machine can reach state <c>OKAY</c> from state +<c>SUSPECT</c> without a new capabilities exchange taking place. +A new transport connection (and capabilities exchange) results in a +new peer_ref().</p> +</note> + +<note> +<p> +There is no requirement that a callback return before incoming +requests are received: <seealso +marker="#handle_request">handle_request/3</seealso> callbacks must be +handled independently of <seealso +marker="#peer_up">peer_up/3</seealso> and <seealso +marker="#peer_down">peer_down/3</seealso>.</p> +</note> <marker id="peer_down"/> </desc> @@ -238,36 +259,42 @@ the callback module in question has been configured.</p> </type> <desc> <p> -Invoked when a transport connection has been lost following a previous -call to <seealso marker="#peer_up">peer_up/3</seealso>.</p> +Invoked to signal that a peer connection is no longer available +following a previous call to <seealso +marker="#peer_up">peer_up/3</seealso>. +In particular, that the RFC 3539 watchdog state machine for the +connection has left state <c>OKAY</c> and the peer will no longer be a +candidate in <seealso marker="#pick_peer">pick_peer()</seealso> +callbacks.</p> <marker id="pick_peer"/> </desc> </func> <func> -<name>Mod:pick_peer(Candidates, Reserved, SvcName, State) - -> {ok, Peer} | {Peer, NewState} | false</name> +<name>Mod:pick_peer(Candidates, _Reserved, SvcName, State) + -> Selection | false</name> <fsummary>Select a target peer for an outgoing request.</fsummary> <type> <v>Candidates = [<seealso marker="#peer">peer()</seealso>]</v> -<v>Peer = <seealso marker="#peer">peer()</seealso> | false</v> <v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v> <v>State = NewState = <seealso marker="#state">state()</seealso></v> +<v>Selection = {ok, Peer} | {Peer, NewState}</v> +<v>Peer = <seealso marker="#peer">peer()</seealso> | false</v> </type> <desc> <p> Invoked as a consequence of a call to <seealso marker="diameter#call">diameter:call/4</seealso> to select a destination -peer for an outgoing request, the return value indicating the selected -peer.</p> +peer for an outgoing request. +The return value indicates the selected peer.</p> <p> -The candidate peers list will only include those -which are selected by any <c>filter</c> option specified in the call to -<seealso marker="diameter#call">diameter:call/4</seealso>, and only -those which have indicated support for the Diameter application in -question. +The candidate list contains only those peers that have advertised +support for the Diameter application in question during capabilities +exchange, that have not be excluded by a <c>filter</c> option in +the call to <seealso marker="diameter#call">diameter:call/4</seealso> +and whose watchdog state machine is in the <c>OKAY</c> state. The order of the elements is unspecified except that any peers whose Origin-Host and Origin-Realm matches that of the outgoing request (in the sense of a <c>{filter, {all, [host, realm]}}</c> @@ -275,36 +302,40 @@ option to <seealso marker="diameter#call">diameter:call/4</seealso>) will be placed at the head of the list.</p> <p> -The return values <c>false</c> and <c>{false, State}</c> are -equivalent when callback state is mutable, as are -<c>{ok, Peer}</c> and <c>{Peer, State}</c>. -Returning a peer as <c>false</c> causes <c>{error, no_connection}</c> -to be returned from <seealso marker="diameter#call">diameter:call/4</seealso>. -Returning a <seealso marker="#peer">peer()</seealso> from an initial -pick_peer/4 callback will result in a -<seealso marker="#prepare_request">prepare_request/3</seealso> callback -followed by either <seealso -marker="#handle_answer">handle_answer/4</seealso> +A callback that returns a peer() will be followed by a +<seealso marker="#prepare_request">prepare_request/3</seealso> +callback and, if the latter indicates that the request should be sent, +by either <seealso marker="#handle_answer">handle_answer/4</seealso> or <seealso marker="#handle_error">handle_error/4</seealso> depending on whether or not an answer message is received from the peer. -If transport with the peer is lost before this then a new <seealso -marker="#pick_peer">pick_peer/4</seealso> callback takes place to -select an alternate peer.</p> - -<p> -Note that there is no guarantee that a <seealso +If the transport becomes unavailable after <seealso +marker="prepare_request">prepare_request/3</seealso> then a new <seealso +marker="#pick_peer">pick_peer/4</seealso> callback may take place to +failover to an alternate peer, after which <seealso +marker="#prepare_retransmit">prepare_retransmit/3</seealso> takes the +place of <seealso +marker="prepare_request">prepare_request/3</seealso> in resending the +request. +There is no guarantee that a <seealso marker="#pick_peer">pick_peer/4</seealso> callback to select -an alternate peer will be followed by any additional callbacks, only -that the initial <seealso -marker="#pick_peer">pick_peer/4</seealso> will be, since a +an alternate peer will be followed by any additional callbacks since a retransmission to an alternate peer is abandoned if an answer is received from a previously selected peer.</p> +<p> +Returning <c>false</c> or <c>{false, NewState}</c> causes <c>{error, +no_connection}</c> to be returned from <seealso +marker="diameter#call">diameter:call/4</seealso>.</p> + +<p> +The return values <c>false</c> and <c>{false, State}</c> (that is, +<c>NewState = State</c>) are equivalent, as are <c>{ok, Peer}</c> and +<c>{Peer, State}</c>.</p> + <note> <p> -<c>{Peer, NewState}</c> and its equivalents can only be returned if -the Diameter application in question was -configured with the <seealso +The return value <c>{Peer, NewState}</c> is only allowed if +the Diameter application in question was configured with the <seealso marker="diameter#application_opt">diameter:application_opt()</seealso> <c>{call_mutates_state, true}</c>. Otherwise, the <c>State</c> argument is always @@ -325,33 +356,45 @@ or <seealso marker="#peer_down">peer_down/3</seealso> callback.</p> <v>Packet = <seealso marker="#packet">packet()</seealso></v> <v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v> <v>Peer = <seealso marker="#peer">peer()</seealso></v> -<v>Action = {send, <seealso marker="#packet">packet()</seealso> | <seealso marker="#message">message()</seealso>} | {discard, Reason} | discard</v> +<v>Action = Send | Discard | {eval_packet, Action, PostF}</v> +<v>Send = {send, <seealso marker="#packet">packet()</seealso> + | <seealso marker="#message">message()</seealso>}</v> +<v>Discard = {discard, Reason} | discard</v> +<v>PostF = + <seealso marker="diameter#evaluable">diameter:evaluable()</seealso>}</v> </type> <desc> <p> Invoked to return a request for encoding and transport. -Allows the sender to access the selected peer's capabilities -in order to set (for example) <c>Destination-Host</c> and/or -<c>Destination-Realm</c> in the outgoing request, although the -callback need not be limited to this usage. +Allows the sender to use the selected peer's capabilities +to modify the outgoing request. Many implementations may simply want to return <c>{send, Packet}</c></p> <p> -A returned <seealso marker="#packet">packet()</seealso> should set the request to be encoded in its +A returned <seealso marker="#packet">packet()</seealso> should set the +request to be encoded in its <c>msg</c> field and can set the <c>transport_data</c> field in order -to pass information to the transport module. +to pass information to the transport process. Extra arguments passed to <seealso marker="diameter#call">diameter:call/4</seealso> can be used to -communicate transport data to the callback. -A returned <seealso marker="#packet">packet()</seealso> can also set the <c>header</c> field to a -<c>#diameter_header{}</c> record in order to specify values that should -be preserved in the outgoing request, although this should typically -not be necessary and allows the callback to set header values -inappropriately. +communicate transport (or any other) data to the callback.</p> + +<p> +A returned <seealso marker="#packet">packet()</seealso> can set +the <c>header</c> field to a +<c>#diameter_header{}</c> in order to specify values that should +be preserved in the outgoing request, values otherwise being those in +the header record contained in <c>Packet</c>. A returned <c>length</c>, <c>cmd_code</c> or <c>application_id</c> is ignored.</p> <p> +A returned <c>PostF</c> will be evaluated on any encoded +<c>#diameter_packet{}</c> prior to transmission, the <c>bin</c> field +containing the encoded binary. +The return value is ignored.</p> + +<p> Returning <c>{discard, Reason}</c> causes the request to be aborted and the <seealso marker="diameter#call">diameter:call/4</seealso> for which the @@ -364,13 +407,18 @@ discarded}</c>.</p> </func> <func> -<name>Mod:prepare_retransmit(Packet, SvcName, Peer) -> Result</name> +<name>Mod:prepare_retransmit(Packet, SvcName, Peer) -> Action</name> <fsummary>Return a request for encoding and retransmission.</fsummary> <type> <v>Packet = <seealso marker="#packet">packet()</seealso></v> <v>SvcName = <seealso marker="diameter#service_name">diameter:service_name()</seealso></v> -<v>Peer = <seealso marker="#peer">peer()</seealso></v> -<v>Result = {send, <seealso marker="#packet">packet()</seealso> | <seealso marker="#message">message()</seealso>} | {discard, Reason} | discard</v> +<v>Peer = <seealso marker="#peer">peer()</seealso></v> +<v>Action = Send | Discard | {eval_packet, Action, PostF}</v> +<v>Send = {send, <seealso marker="#packet">packet()</seealso> + | <seealso marker="#message">message()</seealso>}</v> +<v>Discard = {discard, Reason} | discard</v> +<v>PostF = + <seealso marker="diameter#evaluable">diameter:evaluable()</seealso>}</v> </type> <desc> <p> @@ -378,8 +426,9 @@ Invoked to return a request for encoding and retransmission. Has the same role as <seealso marker="#prepare_request">prepare_request/3</seealso> in the case that a peer connection is lost an an alternate peer selected but the -argument <seealso marker="#packet">packet()</seealso> is as returned by the initial -<c>prepare_request/3</c>.</p> +argument <seealso marker="#packet">packet()</seealso> is as returned +by the initial <seealso +marker="#prepare_request">prepare_request/3</seealso>.</p> <p> Returning <c>{discard, Reason}</c> causes the request to be aborted @@ -406,40 +455,41 @@ discarded}</c>.</p> <desc> <p> Invoked when an answer message is received from a peer. -The return value is returned from the call to <seealso -marker="diameter#call">diameter:call/4</seealso> for which the -callback takes place unless the <c>detach</c> option was -specified.</p> +The return value is returned from <seealso +marker="diameter#call">diameter:call/4</seealso> unless the +<c>detach</c> option was specified.</p> <p> -The decoded answer record is in the <c>msg</c> field of the argument -<seealso marker="#packet">packet()</seealso>, -the undecoded binary in the <c>packet</c> field. +The decoded answer record and undecoded binary are in the <c>msg</c> +and <c>bin</c> fields of the argument +<seealso marker="#packet">packet()</seealso> respectively. <c>Request</c> is the outgoing request message as was returned from <seealso marker="#prepare_request">prepare_request/3</seealso> or -<seealso marker="#prepare_retransmit">prepare_retransmit/3</seealso> -before the request was passed to the transport.</p> +<seealso + marker="#prepare_retransmit">prepare_retransmit/3</seealso>.</p> <p> For any given call to <seealso marker="diameter#call">diameter:call/4</seealso> there is at most one -call to the handle_answer callback of the application in question: any +<seealso marker="#handle_answer">handle_answer/4</seealso> callback: any duplicate answer (due to retransmission or otherwise) is discarded. -Similarly, only one of <c>handle_answer/4</c> or <c>handle_error/4</c> is -called for any given request.</p> +Similarly, only one of <seealso +marker="#handle_answer">handle_answer/4</seealso> or +<seealso marker="#handle_error">handle_error/4</seealso> is +called.</p> <p> By default, an incoming answer message that cannot be successfully -decoded causes the request process in question to fail, causing the -relevant call to <seealso -marker="diameter#call">diameter:call/4</seealso> -to return <c>{error, failure} (unless the <c>detach</c> option was -specified)</c>. -In particular, there is no <c>handle_error/4</c> callback in this +decoded causes the request process to fail, causing +<seealso marker="diameter#call">diameter:call/4</seealso> +to return <c>{error, failure}</c> unless the <c>detach</c> option was +specified. +In particular, there is no <seealso +marker="#handle_error">handle_error/4</seealso> callback in this case. -Application configuration may change this behaviour as described for -<seealso -marker="diameter#start_service">diameter:start_service/2</seealso>.</p> +The <seealso +marker="diameter#application_opt">diameter:application_opt()</seealso> +<c>answer_errors</c> can be set to change this behaviour.</p> <marker id="handle_error"/> </desc> @@ -457,21 +507,20 @@ marker="diameter#start_service">diameter:start_service/2</seealso>.</p> </type> <desc> <p> -Invoked when an error occurs before an answer message is received from -a peer in response to an outgoing request. -The return value is returned from the call to <seealso -marker="diameter#call">diameter:call/4</seealso> for which the -callback takes place (unless the <c>detach</c> option was -specified).</p> +Invoked when an error occurs before an answer message is received +in response to an outgoing request. +The return value is returned from <seealso +marker="diameter#call">diameter:call/4</seealso> unless the +<c>detach</c> option was specified.</p> <p> Reason <c>timeout</c> indicates that an answer message has not been -received within the required time. +received within the time specified with the corresponding <seealso +marker="diameter#call_opt">diameter:call_opt()</seealso>. Reason <c>failover</c> indicates that the transport connection to the peer to which the request has -been sent has been lost but that not alternate node was available, -possibly because a <seealso marker="#pick_peer">pick_peer/4</seealso> -callback returned false.</p> +been sent has become unavailable and that not alternate peer was +not selected.</p> <marker id="handle_request"/> </desc> @@ -484,7 +533,10 @@ callback returned false.</p> <v>Packet = <seealso marker="#packet">packet()</seealso></v> <v>SvcName = term()</v> <v>Peer = <seealso marker="#peer">peer()</seealso></v> -<v>Action = Reply | {relay, [Opt]} | discard | {eval, Action, PostF}</v> +<v>Action = Reply + | {relay, [Opt]} + | discard + | {eval|eval_packet, Action, PostF}</v> <v>Reply = {reply, <seealso marker="#message">message()</seealso>} | {protocol_error, 3000..3999}</v> <v>Opt = <seealso marker="diameter#call_opt">diameter:call_opt()</seealso></v> @@ -603,14 +655,25 @@ causes the request to be answered with 3002 (DIAMETER_UNABLE_TO_DELIVER).</p> <tag><c>discard</c></tag> <item> <p> -Discard the request.</p> +Discard the request. +No answer message is sent to the peer.</p> </item> <tag><c>{eval, Action, PostF}</c></tag> <item> <p> Handle the request as if <c>Action</c> has been returned and then -evaluate <c>PostF</c> in the request process.</p> +evaluate <c>PostF</c> in the request process. +The return value is ignored.</p> +</item> + +<tag><c>{eval_packet, Action, PostF}</c></tag> +<item> +<p> +Like <c>eval</c> but evaluate <c>PostF</c> on any encoded +<c>#diameter_packet{}</c> prior to transmission, the <c>bin</c> field +containing the encoded binary. +The return value is ignored.</p> </item> </taglist> diff --git a/lib/diameter/doc/src/diameter_transport.xml b/lib/diameter/doc/src/diameter_transport.xml index 9ab750e560..d9b36a1e09 100644 --- a/lib/diameter/doc/src/diameter_transport.xml +++ b/lib/diameter/doc/src/diameter_transport.xml @@ -54,14 +54,14 @@ parent).</p> <funcs> <func> -<name>Mod:start({Type, Ref}, Svc, Opts) +<name>Mod:start({Type, Ref}, Svc, Config) -> {ok, Pid} | {ok, Pid, LAddrs} | {error, Reason}</name> <fsummary>Start a transport process.</fsummary> <type> <v>Type = connect | accept</v> <v>Ref = <seealso marker="diameter#transport_ref">diameter:transport_ref()</seealso></v> <v>Svc = #diameter_service{}</v> -<v>Opts = term()</v> +<v>Config = term()</v> <v>Pid = pid()</v> <v>LAddrs = [<seealso marker="kernel:inet#type-ip_address">inet:ip_address()</seealso>]</v> <v>Reason = term()</v> @@ -75,38 +75,46 @@ order to establish or accept a transport connection respectively. A transport process maintains a connection with a single remote peer.</p> <p> -The first argument indicates whether the transport process in question +<c>Type</c> indicates whether the transport process in question is being started for a connecting (<c>connect</c>) or listening (<c>accept</c>) transport. In the latter case, transport processes are started as required to -accept connections from multiple peers. -Ref is in each case the same value that was returned from the -call to <seealso -marker="diameter#add_transport">diameter:add_transport/2</seealso> -that has lead to starting of a transport process.</p> +accept connections from multiple peers.</p> <p> -A transport process must implement the message interface documented below. -It should retain the pid of its parent, monitor the parent and terminate if -it dies. -It should not link to the parent. -It should exit if its transport connection with its peer is lost.</p> +Ref is the value that was returned from the call to <seealso +marker="diameter#add_transport">diameter:add_transport/2</seealso> +that has lead to starting of a transport process.</p> <p> -The capabilities in the <c>#diameter_service{}</c> record are as -passed to <seealso +<c>Svc</c> contains the capabilities passed to <seealso marker="diameter#start_service">diameter:start_service/2</seealso> and <seealso marker="diameter#add_transport">diameter:add_transport/2</seealso>, -values passed to the latter overriding those passed to the former. +values passed to the latter overriding those passed to the former.</p> + +<p> +<c>Config</c> is as passed in <c>transport_config</c> tuple in the +<seealso marker="diameter#transport_opt">diameter:transport_opt()</seealso> +list passed to <seealso +marker="diameter#add_transport">diameter:add_transport/2</seealso>.</p> + +<p> The start function should use the <c>Host-IP-Address</c> list and/or -<c>Opts</c> to select an appropriate list of local IP addresses, +<c>Config</c> to select an appropriate list of local IP addresses, and should return this list if different from the <c>#diameter_service{}</c> addresses. The returned list is used to populate <c>Host-IP-Address</c> AVPs in outgoing capabilities exchange messages, the <c>#diameter_service{}</c> addresses being used otherwise.</p> +<p> +A transport process must implement the message interface documented below. +It should retain the pid of its parent, monitor the parent and terminate if +it dies. +It should not link to the parent. +It should exit if its transport connection with its peer is lost.</p> + <marker id="MESSAGES"/> </desc> </func> diff --git a/lib/diameter/make/release_targets.mk b/lib/diameter/make/release_targets.mk deleted file mode 100644 index 5a3b585cbc..0000000000 --- a/lib/diameter/make/release_targets.mk +++ /dev/null @@ -1,92 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# - -ifeq ($(TOPDOC),) -$(HTMLDIR)/index.html: $(XML_FILES) - date=`date +"%B %e %Y"`; \ - $(XSLTPROC) --noout --stringparam outdir $(HTMLDIR) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \ - --stringparam pdfdir "$(PDFDIR)" \ - --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \ - -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml -endif - -$(HTMLDIR)/users_guide.html: $(XML_FILES) - date=`date +"%B %e %Y"`; \ - $(XSLTPROC) --noout --stringparam outdir $(HTMLDIR) --stringparam docgen "$(DOCGEN)" --stringparam topdocdir "$(TOPDOCDIR)" \ - --stringparam pdfdir "$(PDFDIR)" \ - --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \ - -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_html.xsl book.xml - - -%.fo: $(XML_FILES) - date=`date +"%B %e %Y"`; \ - $(XSLTPROC) --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" \ - --stringparam appver "$(VSN)" --xinclude \ - -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_pdf.xsl book.xml > $@ - - - -# ------------------------------------------------------------------------ -# The following targets just exist in the documentation directory -# ------------------------------------------------------------------------ -ifneq ($(XML_FILES),) - -# ---------------------------------------------------- -# Generation of application index data -# ---------------------------------------------------- -$(HTMLDIR)/$(APPLICATION).eix: $(XML_FILES) - date=`date +"%B %e %Y"`; \ - $(XSLTPROC) --stringparam docgen "$(DOCGEN)" \ - --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude \ - -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_html_entities $(DOCGEN)/priv/xsl/db_eix.xsl book.xml > $@ - -docs: -#docs: $(HTMLDIR)/$(APPLICATION).eix - -# ---------------------------------------------------- -# Local documentation target for testing -# ---------------------------------------------------- -local_docs: TOPDOCDIR=. -local_docs: local_copy_of_topdefs docs - -local_html: TOPDOCDIR=. -local_html: local_copy_of_topdefs html - -local_copy_of_topdefs: - $(INSTALL) $(DOCGEN)/priv/css/otp_doc.css $(HTMLDIR) - $(INSTALL) $(DOCGEN)/priv/images/erlang-logo.png $(HTMLDIR) - $(INSTALL) $(DOCGEN)/priv/images/erlang-logo.gif $(HTMLDIR) - $(INSTALL_DIR) $(HTMLDIR)/js/flipmenu - $(INSTALL) $(DOCGEN)/priv/js/flipmenu/flip_closed.gif \ - $(DOCGEN)/priv/js/flipmenu/flip_open.gif \ - $(DOCGEN)/priv/js/flipmenu/flip_static.gif \ - $(DOCGEN)/priv/js/flipmenu/flipmenu.js $(HTMLDIR)/js/flipmenu - -endif - -# ---------------------------------------------------- -# Standard release target -# ---------------------------------------------------- - -ifneq ($(PREFIX),) - -release release_docs release_tests release_html: - $(MAKE) $(MFLAGS) RELEASE_PATH=$(PREFIX) $(TARGET_MAKEFILE) $@_spec - -endif diff --git a/lib/diameter/make/rules.mk.in b/lib/diameter/make/rules.mk.in deleted file mode 100644 index cd3c297d75..0000000000 --- a/lib/diameter/make/rules.mk.in +++ /dev/null @@ -1,193 +0,0 @@ -#-*-makefile-*- ; force emacs to enter makefile-mode -# ---------------------------------------------------- -# %CopyrightBegin% -# -# Copyright Ericsson AB 2009-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% - -.SUFFIXES: .erl .beam .yrl .hrl .xml .xmlsrc .html \ - .3 .1 .pdf .fo .el .elc - -# ---------------------------------------------------- -# Common macros -# ---------------------------------------------------- -DEFAULT_TARGETS = opt debug release release_docs clean docs - - -# Slash separated list of return values from $(origin VAR) -# that are untrusted - set default in this file instead. -# The list is not space separated since some return values -# contain space, and we want to use $(findstring ...) to -# search the list. -DUBIOUS_ORIGINS = /undefined/environment/ - - -# # ---------------------------------------------------- -# # TARGET definition -# # ---------------------------------------------------- -# # TARGET = @TARGET@ -# ifneq ($(OVERRIDE_TARGET),) -# ifneq ($(TARGET), $(OVERRIDE_TARGET)) -# $(warning overriding $$(TARGET) = \ -# "$(TARGET)" \ -# with \ -# $$(OVERRIDE_TARGET) = \ -# "$(OVERRIDE_TARGET)") -# override TARGET := $(OVERRIDE_TARGET) -# endif -# endif -# - -# ---------------------------------------------------- -# Command macros -# ---------------------------------------------------- -PREFIX = @prefix@ -INSTALL = @INSTALL@ -INSTALL_DIR = @INSTALL_DIR@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -INSTALL_SCRIPT = @INSTALL_SCRIPT@ -INSTALL_DATA = @INSTALL_DATA@ - - -# ---------------------------------------------------- -# Erlang language section -# ---------------------------------------------------- -ERL_ROOT_DIR = @ERLANG_ROOT_DIR@ -ERL_LIB_DIR = @ERLANG_LIB_DIR@ -DOCGEN_DIR = @ERLANG_LIB_DIR_erl_docgen@ -TEST_SERVER_DIR = @ERLANG_LIB_VER_test_server@ -EMULATOR = beam -ERL_COMPILE_FLAGS += +debug_info -ERLC_WFLAGS = -W -ERLC = $(ERL_ROOT_DIR)/bin/erlc $(ERLC_WFLAGS) $(ERLC_FLAGS) -ERL = $(ERL_ROOT_DIR)/bin/erl -boot start_clean -#ERLC = @ERLC@ $(ERLC_WFLAGS) $(ERLC_FLAGS) -#ERL = @ERL@ -boot start_clean - -ifneq (,$(findstring $(origin EBIN),$(DUBIOUS_ORIGINS))) -EBIN = ../../ebin -endif - -# Generated (non ebin) files... -ifneq (,$(findstring $(origin EGEN),$(DUBIOUS_ORIGINS))) -EGEN = . -endif - -ifneq (,$(findstring $(origin ESRC),$(DUBIOUS_ORIGINS))) -ESRC = . -endif - -$(EBIN)/%.beam: $(EGEN)/%.erl - $(ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $< - -$(EBIN)/%.beam: $(ESRC)/%.erl - $(ERLC) $(ERL_COMPILE_FLAGS) -o$(EBIN) $< - -.erl.beam: - $(ERLC) $(ERL_COMPILE_FLAGS) -o$(dir $@) $< - - -# -# When .erl files are automatically created GNU make removes them if -# they were the result of a chain of implicit rules. To prevent this -# we say that all .erl files are "precious". -# -.PRECIOUS: %.erl %.fo - - -# ---------------------------------------------------- -# Documentation section -# ---------------------------------------------------- -# export VSN - -# TOPDOCDIR=../../../../doc - -DOCDIR = .. - -PDFDIR=$(DOCDIR)/pdf - -HTMLDIR = $(DOCDIR)/html - -MAN1DIR = $(DOCDIR)/man1 -MAN2DIR = $(DOCDIR)/man2 -MAN3DIR = $(DOCDIR)/man3 -MAN4DIR = $(DOCDIR)/man4 -MAN6DIR = $(DOCDIR)/man6 -MAN9DIR = $(DOCDIR)/man9 - -# HTML & GIF files that always are generated and must be delivered -XML_COLL_FILES = $(XML_APPLICATION_FILES) $(XML_PART_FILES) -DEFAULT_HTML_FILES = \ - $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_frame.html) \ - $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_first.html) \ - $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_term.html) \ - $(XML_COLL_FILES:%.xml=$(HTMLDIR)/%_cite.html) \ - $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%_index.html) \ - $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.kwc) \ - $(HTMLDIR)/index.html - -DEFAULT_GIF_FILES = $(HTMLDIR)/min_head.gif - -# -# Flags & Commands -# -XSLTPROC = @XSLTPROC@ -FOP = @FOP@ - -DOCGEN=$(DOCGEN_DIR) - -$(MAN1DIR)/%.1:: %.xml - date=`date +"%B %e %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - - -$(MAN2DIR)/%.2:: %.xml - date=`date +"%B %e %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - - -$(MAN3DIR)/%.3:: %.xml - date=`date +"%B %e %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -# left for compatibility -$(MAN4DIR)/%.4:: %.xml - date=`date +"%B %e %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -$(MAN4DIR)/%.5:: %.xml - date=`date +"%B %e %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -# left for compatibility -$(MAN6DIR)/%.6:: %_app.xml - date=`date +"%B %e %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -$(MAN6DIR)/%.7:: %_app.xml - date=`date +"%B %e %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - -$(MAN9DIR)/%.9:: %.xml - date=`date +"%B %e %Y"`; \ - xsltproc --output "$@" --stringparam company "Ericsson AB" --stringparam docgen "$(DOCGEN)" --stringparam gendate "$$date" --stringparam appname "$(APPLICATION)" --stringparam appver "$(VSN)" --xinclude -path $(DOCGEN)/priv/docbuilder_dtd -path $(DOCGEN)/priv/dtd_man_entities $(DOCGEN)/priv/xsl/db_man.xsl $< - - -.xmlsrc.xml: - escript $(DOCGEN)/priv/bin/codeline_preprocessing.escript $< $@ - -.fo.pdf: - $(FOP) -fo $< -pdf $@ - diff --git a/lib/diameter/make/subdir.mk b/lib/diameter/make/subdir.mk deleted file mode 100644 index 24b08080ae..0000000000 --- a/lib/diameter/make/subdir.mk +++ /dev/null @@ -1,53 +0,0 @@ -# -# %CopyrightBegin% -# -# Copyright Ericsson AB 1997-2011. All Rights Reserved. -# -# The contents of this file are subject to the Erlang Public License, -# Version 1.1, (the "License"); you may not use this file except in -# compliance with the License. You should have received a copy of the -# Erlang Public License along with this software. If not, it can be -# retrieved online at http://www.erlang.org/. -# -# Software distributed under the License is distributed on an "AS IS" -# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See -# the License for the specific language governing rights and limitations -# under the License. -# -# %CopyrightEnd% -# -# Make include file for otp - -.PHONY: debug opt release docs release_docs tests release_tests \ - clean depend valgrind - -# -# Targets that don't affect documentation directories -# -opt debug release docs release_docs tests release_tests clean depend valgrind: - @set -e ; \ - app_pwd=`pwd` ; \ - if test -f vsn.mk; then \ - echo "=== Entering application" `basename $$app_pwd` ; \ - fi ; \ - case "$(MAKE)" in *clearmake*) tflag="-T";; *) tflag="";; esac; \ - for d in $(SUB_DIRS); do \ - if test -f $$d/SKIP ; then \ - echo "=== Skipping subdir $$d, reason:" ; \ - cat $$d/SKIP ; \ - echo "===" ; \ - else \ - if test ! -d $$d ; then \ - echo "=== Skipping subdir $$d, it is missing" ; \ - else \ - xflag="" ; \ - if test -f $$d/ignore_config_record.inf; then \ - xflag=$$tflag ; \ - fi ; \ - (cd $$d && $(MAKE) $$xflag $@) || exit $$? ; \ - fi ; \ - fi ; \ - done ; \ - if test -f vsn.mk; then \ - echo "=== Leaving application" `basename $$app_pwd` ; \ - fi diff --git a/lib/diameter/make/target.mk b/lib/diameter/make/target.mk deleted file mode 100644 index 4ae470b9e2..0000000000 --- a/lib/diameter/make/target.mk +++ /dev/null @@ -1,33 +0,0 @@ -ifeq ($(OVERRIDE_TARGET),) - -ifeq ($(TARGET),) - -TARGET := $(shell $(DIAMETER_TOP)/autoconf/config.guess) - -else - -endif - -else - -ifneq ($(TARGET),) - -ifneq ($(TARGET), $(OVERRIDE_TARGET)) -$(warning overriding $$(TARGET) = \ - "$(TARGET)" \ - with \ - $$(OVERRIDE_TARGET) = \ - "$(OVERRIDE_TARGET)") -else -endif - -override TARGET := $(OVERRIDE_TARGET) - -else - -TARGET := $(OVERRIDE_TARGET) - -endif - -endif - diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile index 99c343275b..060659bce9 100644 --- a/lib/diameter/src/Makefile +++ b/lib/diameter/src/Makefile @@ -16,13 +16,8 @@ # # %CopyrightEnd% -ifeq ($(ERL_TOP),) -include $(DIAMETER_TOP)/make/target.mk -include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk -else include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk -endif # ---------------------------------------------------- # Application version @@ -210,11 +205,7 @@ dialyze: opt $(PLT) # Release targets # ---------------------------------------------------- -ifeq ($(ERL_TOP),) -include $(DIAMETER_TOP)/make/release_targets.mk -else include $(ERL_TOP)/make/otp_release_targets.mk -endif # Can't $(INSTALL_DIR) more than one directory at a time on Solaris. diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl index 4f90b741ae..3e3a6be0ef 100644 --- a/lib/diameter/src/base/diameter.erl +++ b/lib/diameter/src/base/diameter.erl @@ -44,6 +44,8 @@ stop/0]). -export_type([evaluable/0, + restriction/0, + sequence/0, app_alias/0, service_name/0, capability/0, @@ -280,11 +282,23 @@ call(SvcName, App, Message) -> | fun() | maybe_improper_list(evaluable(), list()). +-type sequence() + :: {'Unsigned32'(), 0..32}. + +-type restriction() + :: false + | node + | nodes + | [node()] + | evaluable(). + %% Options passed to start_service/2 -type service_opt() :: capability() - | {application, [application_opt()]}. + | {application, [application_opt()]} + | {restrict_connections, restriction()} + | {sequence, sequence() | evaluable()}. -type application_opt() :: {alias, app_alias()} diff --git a/lib/diameter/src/base/diameter_capx.erl b/lib/diameter/src/base/diameter_capx.erl index 6c4d60ee9b..190d37262b 100644 --- a/lib/diameter/src/base/diameter_capx.erl +++ b/lib/diameter/src/base/diameter_capx.erl @@ -141,7 +141,9 @@ cap('Host-IP-Address', Vs) when is_list(Vs) -> lists:map(fun ipaddr/1, Vs); -cap('Firmware-Revision', V) -> +cap(K, V) + when K == 'Firmware-Revision'; + K == 'Origin-State-Id' -> [V]; cap(_, Vs) @@ -149,7 +151,7 @@ cap(_, Vs) Vs; cap(K, V) -> - ?THROW({invalid, K, V}). + ?THROW({invalid, {K,V}}). ipaddr(A) -> try diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl index 421e280422..a94d37f7a8 100644 --- a/lib/diameter/src/base/diameter_codec.erl +++ b/lib/diameter/src/base/diameter_codec.erl @@ -333,6 +333,9 @@ decode_header(_) -> %% wraparound counter. The 8-bit counter is incremented each time the %% system is restarted. +sequence_numbers({_,_} = T) -> + T; + sequence_numbers(#diameter_packet{bin = Bin}) when is_binary(Bin) -> sequence_numbers(Bin); diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl index e47f63f814..63d28f25a2 100644 --- a/lib/diameter/src/base/diameter_config.erl +++ b/lib/diameter/src/base/diameter_config.erl @@ -97,6 +97,9 @@ -record(monitor, {mref = make_ref() :: reference(), service}). %% name +%% The default sequence mask. +-define(NOMASK, {0,32}). + %% Time to lay low before restarting a dead service. -define(RESTART_SLEEP, 2000). @@ -549,9 +552,11 @@ make_config(SvcName, Opts) -> ok = encode_CER(COpts), - Os = split(Opts, [{[fun erlang:is_boolean/1], false, share_peers}, - {[fun erlang:is_boolean/1], false, use_shared_peers}, - {[fun erlang:is_pid/1, false], false, monitor}]), + Os = split(Opts, fun opt/2, [{false, share_peers}, + {false, use_shared_peers}, + {false, monitor}, + {?NOMASK, sequence}, + {nodes, restrict_connections}]), %% share_peers and use_shared_peers are currently undocumented. #service{name = SvcName, @@ -559,11 +564,66 @@ make_config(SvcName, Opts) -> capabilities = Caps}, options = Os}. +split(Opts, F, Defs) -> + [{K, F(K, get_opt(K, Opts, D))} || {D,K} <- Defs]. + +opt(K, false = B) + when K /= sequence -> + B; + +opt(K, true = B) + when K == share_peer; + K == use_shared_peers -> + B; + +opt(monitor, P) + when is_pid(P) -> + P; + +opt(restrict_connections, T) + when T == node; + T == nodes; + T == []; + is_atom(hd(T)) -> + T; + +opt(restrict_connections = K, F) -> + try diameter_lib:eval(F) of %% no guarantee that it won't fail later + Nodes when is_list(Nodes) -> + F; + V -> + ?THROW({value, {K,V}}) + catch + E:R -> + ?THROW({value, {K, E, R, ?STACK}}) + end; + +opt(sequence, {_,_} = T) -> + sequence(T); + +opt(sequence = K, F) -> + try diameter_lib:eval(F) of + T -> sequence(T) + catch + E:R -> + ?THROW({value, {K, E, R, ?STACK}}) + end; + +opt(K, _) -> + ?THROW({value, K}). + +sequence({H,N} = T) + when 0 =< N, N =< 32, 0 =< H, 0 == H bsr N -> + T; + +sequence(_) -> + ?THROW({value, sequence}). + make_caps(Caps, Opts) -> case diameter_capx:make_caps(Caps, Opts) of {ok, T} -> T; - {error, {Reason, _}} -> + {error, Reason} -> ?THROW(Reason) end. @@ -663,21 +723,6 @@ get_opt(Key, List, Def) -> _ -> ?THROW({arity, Key}) end. -split(Opts, Defs) -> - [{K, value(D, Opts)} || {_,_,K} = D <- Defs]. - -value({Preds, Def, Key}, Opts) -> - V = get_opt(Key, Opts, Def), - lists:any(fun(P) -> pred(P,V) end, Preds) - orelse ?THROW({value, Key}), - V. - -pred(F, V) - when is_function(F) -> - F(V); -pred(T, V) -> - T == V. - cb(M,F) -> try M:F() of V -> V diff --git a/lib/diameter/src/base/diameter_peer.erl b/lib/diameter/src/base/diameter_peer.erl index 46b2ba9465..1b2f32ddff 100644 --- a/lib/diameter/src/base/diameter_peer.erl +++ b/lib/diameter/src/base/diameter_peer.erl @@ -76,7 +76,7 @@ notify(SvcName, T) -> %%% # start/3 %%% --------------------------------------------------------------------------- -%% From old code: make is restart. +%% From old code: make it restart. start(_T, _Opts, #diameter_service{}) -> {error, restart}. diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl index 302540e76b..3f4945f7a6 100644 --- a/lib/diameter/src/base/diameter_peer_fsm.erl +++ b/lib/diameter/src/base/diameter_peer_fsm.erl @@ -55,10 +55,15 @@ -define(TLS, 1). %% Keys in process dictionary. --define(CB_KEY, cb). %% capabilities callback --define(DWA_KEY, dwa). %% outgoing DWA --define(Q_KEY, q). %% transport start queue --define(START_KEY, start). %% start of connected transport +-define(CB_KEY, cb). %% capabilities callback +-define(DWA_KEY, dwa). %% outgoing DWA +-define(Q_KEY, q). %% transport start queue +-define(START_KEY, start). %% start of connected transport +-define(SEQUENCE_KEY, mask). %% mask for sequence numbers +-define(RESTRICT_KEY, restrict). %% nodes for connection check + +%% The default sequence mask. +-define(NOMASK, {0,32}). %% A 2xxx series Result-Code. Not necessarily 2001. -define(IS_SUCCESS(N), 2 == (N) div 1000). @@ -121,7 +126,10 @@ %%% Output: Pid %%% --------------------------------------------------------------------------- --spec start(T, [Opt], #diameter_service{}) +-spec start(T, [Opt], #diameter_service{} %% from old code + | {diameter:sequence(), + diameter:restriction(), + #diameter_service{}}) -> pid() when T :: {connect|accept, diameter:transport_ref()}, Opt :: diameter:transport_opt(). @@ -131,10 +139,8 @@ %% specified on the transport in question. Check here that the list is %% still non-empty. -start({_,_} = Type, Opts, #diameter_service{applications = Apps} = Svc) -> - [] /= Apps orelse ?ERROR({no_apps, Type, Opts}), - T = {self(), Type, Opts, Svc}, - {ok, Pid} = diameter_peer_fsm_sup:start_child(T), +start({_,_} = Type, Opts, MS) -> + {ok, Pid} = diameter_peer_fsm_sup:start_child({self(), Type, Opts, MS}), Pid. start_link(T) -> @@ -153,12 +159,20 @@ init(T) -> proc_lib:init_ack({ok, self()}), gen_server:enter_loop(?MODULE, [], i(T)). -i({WPid, T, Opts, #diameter_service{capabilities = Caps} = Svc}) -> +i({WPid, Type, Opts, #diameter_service{} = Svc}) -> %% from old code + i({WPid, Type, Opts, {?NOMASK, [node() | nodes()], Svc}}); + +i({WPid, T, Opts, {Mask, Nodes, #diameter_service{applications = Apps, + capabilities = Caps} + = Svc}}) -> + [] /= Apps orelse ?ERROR({no_apps, T, Opts}), putr(?DWA_KEY, dwa(Caps)), {M, Ref} = T, diameter_stats:reg(Ref), {[Ts], Rest} = proplists:split(Opts, [capabilities_cb]), putr(?CB_KEY, {Ref, [F || {_,F} <- Ts]}), + putr(?SEQUENCE_KEY, Mask), + putr(?RESTRICT_KEY, Nodes), erlang:monitor(process, WPid), {TPid, Addrs} = start_transport(T, Rest, Svc), #state{parent = WPid, @@ -464,9 +478,24 @@ build_CER(#state{service = #diameter_service{capabilities = Caps}}) -> %% encode/1 encode(Rec) -> - #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Rec), + Seq = diameter_session:sequence(sequence()), + Hdr = #diameter_header{version = ?DIAMETER_VERSION, + end_to_end_id = Seq, + hop_by_hop_id = Seq}, + Pkt = #diameter_packet{header = Hdr, + msg = Rec}, + #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Pkt), Bin. +sequence() -> + case getr(?SEQUENCE_KEY) of + {_,_} = Mask -> + Mask; + undefined -> %% started in old code + putr(?SEQUENCE_KEY, ?NOMASK), + ?NOMASK + end. + %% recv/2 %% RFC 3588 has result code 5015 for an invalid length but if a @@ -965,14 +994,35 @@ dpa_timer() -> %% Register a term and ensure it's not registered elsewhere. Note that %% two process that simultaneously register the same term may well %% both fail to do so this isn't foolproof. +%% +%% Everywhere is no longer everywhere, it's where a +%% restrict_connections service_opt() specifies. register_everywhere(T) -> - diameter_reg:add_new(T) - andalso unregistered(T). + reg(getr(?RESTRICT_KEY), T). + +reg(Nodes, T) -> + add(lists:member(node(), Nodes), T) andalso unregistered(Nodes, T). + +add(true, T) -> + diameter_reg:add_new(T); +add(false, T) -> + diameter_reg:add(T). + +%% unregistered +%% +%% Ensure that the term in question isn't registered on other nodes. + +unregistered(Nodes, T) -> + {ResL, _} = rpc:multicall(Nodes, ?MODULE, match, [{node(), T}]), + lists:all(fun nomatch/1, ResL). + +nomatch({badrpc, {'EXIT', {undef, _}}}) -> %% no diameter on remote node + true; +nomatch(L) -> + [] == L. -unregistered(T) -> - {ResL, _} = rpc:multicall(?MODULE, match, [{node(), T}]), - lists:all(fun(L) -> [] == L end, ResL). +%% match/1 match({Node, _}) when Node == node() -> diff --git a/lib/diameter/src/base/diameter_reg.erl b/lib/diameter/src/base/diameter_reg.erl index 882b9da238..619b12ecad 100644 --- a/lib/diameter/src/base/diameter_reg.erl +++ b/lib/diameter/src/base/diameter_reg.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,7 +30,8 @@ add_new/1, del/1, repl/2, - match/1]). + match/1, + wait/1]). -export([start_link/0]). @@ -65,27 +66,22 @@ %% Table entry containing the Term -> Pid mapping. -define(MAPPING(Term, Pid), {Term, Pid}). --record(state, {id = now()}). - -%%% ---------------------------------------------------------- -%%% # add(T) -%%% -%%% Input: Term = term() -%%% -%%% Output: true -%%% -%%% Description: Associate the specified term with self(). The list of pids -%%% having this or other assocations can be retrieved using -%%% match/1. -%%% -%%% An association is removed when the calling process dies -%%% or as a result of calling del/1. Adding the same term -%%% more than once is equivalent to adding it exactly once. -%%% -%%% Note that since match/1 takes a pattern as argument, -%%% specifying a term that contains match variables is -%%% probably not a good idea -%%% ---------------------------------------------------------- +-record(state, {id = now(), + q = []}). %% [{From, Pat}] + +%% =========================================================================== +%% # add(T) +%% +%% Associate the specified term with self(). The list of pids having +%% this or other assocations can be retrieved using match/1. +%% +%% An association is removed when the calling process dies or as a +%% result of calling del/1. Adding the same term more than once is +%% equivalent to adding it exactly once. +%% +%% Note that since match/1 takes a pattern as argument, specifying a +%% term that contains match variables is probably not a good idea +%% =========================================================================== -spec add(any()) -> true. @@ -93,17 +89,12 @@ add(T) -> call({add, fun ets:insert/2, T, self()}). -%%% ---------------------------------------------------------- -%%% # add_new(T) -%%% -%%% Input: T = term() -%%% -%%% Output: true | false -%%% -%%% Description: Like add/1 but only one process is allowed to have the -%%% the association, false being returned if an association -%%% already exists. -%%% ---------------------------------------------------------- +%% =========================================================================== +%% # add_new(T) +%% +%% Like add/1 but only one process is allowed to have the the +%% association, false being returned if an association already exists. +%% =========================================================================== -spec add_new(any()) -> boolean(). @@ -111,16 +102,12 @@ add(T) -> add_new(T) -> call({add, fun insert_new/2, T, self()}). -%%% ---------------------------------------------------------- -%%% # repl(T, NewT) -%%% -%%% Input: T, NewT = term() -%%% -%%% Output: true | false -%%% -%%% Description: Like add/1 but only replace an existing association on T, -%%% false being returned if it doesn't exist. -%%% ---------------------------------------------------------- +%% =========================================================================== +%% # repl(T, NewT) +%% +%% Like add/1 but only replace an existing association on T, false +%% being returned if it doesn't exist. +%% =========================================================================== -spec repl(any(), any()) -> boolean(). @@ -128,15 +115,11 @@ add_new(T) -> repl(T, U) -> call({repl, T, U, self()}). -%%% ---------------------------------------------------------- -%%% # del(Term) -%%% -%%% Input: Term = term() -%%% -%%% Output: true -%%% -%%% Description: Remove any existing association of Term with self(). -%%% ---------------------------------------------------------- +%% =========================================================================== +%% # del(Term) +%% +%% Remove any existing association of Term with self(). +%% =========================================================================== -spec del(any()) -> true. @@ -144,20 +127,16 @@ repl(T, U) -> del(T) -> call({del, T, self()}). -%%% ---------------------------------------------------------- -%%% # match(Pat) -%%% -%%% Input: Pat = pattern in the sense of ets:match_object/2. -%%% -%%% Output: list of {Term, Pid} -%%% -%%% Description: Return the list of associations whose Term, as specified -%%% to add/1 or add_new/1, matches the specified pattern. -%%% -%%% Note that there's no guarantee that the returned processes -%%% are still alive. (Although one that isn't will soon have -%%% its associations removed.) -%%% ---------------------------------------------------------- +%% =========================================================================== +%% # match(Pat) +%% +%% Return the list of associations whose Term, as specified to add/1 +%% or add_new/1, matches the specified pattern. +%% +%% Note that there's no guarantee that the returned processes are +%% still alive. (Although one that isn't will soon have its +%% associations removed.) +%% =========================================================================== -spec match(tuple()) -> [{term(), pid()}]. @@ -165,9 +144,17 @@ del(T) -> match(Pat) -> ets:match_object(?TABLE, ?MAPPING(Pat, '_')). -%% --------------------------------------------------------- -%% EXPORTED INTERNAL FUNCTIONS -%% --------------------------------------------------------- +%% =========================================================================== +%% # wait(Pat) +%% +%% Like match/1 but return only when the result is non-empty or fails. +%% It's up to the caller to ensure that the wait won't be forever. +%% =========================================================================== + +wait(Pat) -> + call({wait, Pat}). + +%% =========================================================================== start_link() -> ServerName = {local, ?SERVER}, @@ -182,7 +169,7 @@ uptime() -> %% pids/0 %% -%% Output: list of {Pid, [Term, ...]} +%% Return: list of {Pid, [Term, ...]} pids() -> to_list(fun swap/1). @@ -202,89 +189,100 @@ id(T) -> T. %% terms/0 %% -%% Output: list of {Term, [Pid, ...]} +%% Return: list of {Term, [Pid, ...]} terms() -> to_list(fun id/1). swap({X,Y}) -> {Y,X}. -%%% ---------------------------------------------------------- -%%% # init(Role) -%%% -%%% Output: {ok, State} -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # init/1 +%% ---------------------------------------------------------- init(_) -> ets:new(?TABLE, [bag, named_table]), {ok, #state{}}. -%%% ---------------------------------------------------------- -%%% # handle_call(Request, From, State) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # handle_call/3 +%% ---------------------------------------------------------- -handle_call({add, Fun, Key, Pid}, _, State) -> +handle_call(Req, From, S) + when not is_record(S, state) -> + handle_call(Req, From, upgrade(S)); + +handle_call({add, Fun, Key, Pid}, _, S) -> B = Fun(?TABLE, {Key, Pid}), monitor(B andalso no_monitor(Pid), Pid), - {reply, B, State}; + {reply, B, pending(B, S)}; -handle_call({del, Key, Pid}, _, State) -> - {reply, ets:delete_object(?TABLE, ?MAPPING(Key, Pid)), State}; +handle_call({del, Key, Pid}, _, S) -> + {reply, ets:delete_object(?TABLE, ?MAPPING(Key, Pid)), S}; -handle_call({repl, T, U, Pid}, _, State) -> +handle_call({repl, T, U, Pid}, _, S) -> MatchSpec = [{?MAPPING('$1', Pid), [{'=:=', '$1', {const, T}}], ['$_']}], - {reply, repl(ets:select(?TABLE, MatchSpec), U, Pid), State}; + {reply, repl(ets:select(?TABLE, MatchSpec), U, Pid), S}; + +handle_call({wait, Pat}, From, #state{q = Q} = S) -> + case find(Pat) of + {ok, L} -> + {reply, L, S}; + false -> + {noreply, S#state{q = [{From, Pat} | Q]}} + end; -handle_call(state, _, State) -> - {reply, State, State}; +handle_call(state, _, S) -> + {reply, S, S}; -handle_call(uptime, _, #state{id = Time} = State) -> - {reply, diameter_lib:now_diff(Time), State}; +handle_call(uptime, _, #state{id = Time} = S) -> + {reply, diameter_lib:now_diff(Time), S}; -handle_call(Req, From, State) -> +handle_call(Req, From, S) -> ?UNEXPECTED([Req, From]), - {reply, nok, State}. + {reply, nok, S}. -%%% ---------------------------------------------------------- -%%% # handle_cast(Request, State) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # handle_cast/2 +%% ---------------------------------------------------------- -handle_cast(Msg, State)-> +handle_cast(Msg, S)-> ?UNEXPECTED([Msg]), - {noreply, State}. + {noreply, S}. -%%% ---------------------------------------------------------- -%%% # handle_info(Request, State) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # handle_info/2 +%% ---------------------------------------------------------- -handle_info({'DOWN', MRef, process, Pid, _}, State) -> +handle_info({'DOWN', MRef, process, Pid, _}, S) -> ets:delete_object(?TABLE, ?MONITOR(Pid, MRef)), ets:match_delete(?TABLE, ?MAPPING('_', Pid)), - {noreply, State}; + {noreply, S}; -handle_info(Info, State) -> +handle_info(Info, S) -> ?UNEXPECTED([Info]), - {noreply, State}. + {noreply, S}. -%%% ---------------------------------------------------------- -%%% # terminate(Reason, State) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # terminate/2 +%% ---------------------------------------------------------- terminate(_Reason, _State)-> ok. -%%% ---------------------------------------------------------- -%%% # code_change(OldVsn, State, Extra) -%%% ---------------------------------------------------------- +%% ---------------------------------------------------------- +%% # code_change/3 +%% ---------------------------------------------------------- code_change(_OldVsn, State, _Extra) -> {ok, State}. -%% --------------------------------------------------------- -%% INTERNAL FUNCTIONS -%% --------------------------------------------------------- +%% =========================================================================== + +upgrade(S) -> + #state{} = list_to_tuple(tuple_to_list(S) ++ [[]]). monitor(true, Pid) -> ets:insert(?TABLE, ?MONITOR(Pid, erlang:monitor(process, Pid))); @@ -321,6 +319,37 @@ repl([?MAPPING(_, Pid) = M], Key, Pid) -> repl([], _, _) -> false. +%% pending/1 + +pending(true, #state{q = [_|_] = Q} = S) -> + S#state{q = q(lists:reverse(Q), [])}; %% retain reply order +pending(_, S) -> + S. + +q([], Q) -> + Q; +q([{From, Pat} = T | Rest], Q) -> + case find(Pat) of + {ok, L} -> + gen_server:reply(From, L), + q(Rest, Q); + false -> + q(Rest, [T|Q]) + end. + +%% find/1 + +find(Pat) -> + try match(Pat) of + [] -> + false; + L -> + {ok, L} + catch + _:_ -> + {ok, []} + end. + %% call/1 call(Request) -> diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl index 725cccda1e..cffba4fc94 100644 --- a/lib/diameter/src/base/diameter_service.erl +++ b/lib/diameter/src/base/diameter_service.erl @@ -64,7 +64,7 @@ -include_lib("diameter/include/diameter.hrl"). -include("diameter_internal.hrl"). -%% The "old" states maintained in this module historically. +%% The states mirrored by peer_up/peer_down callbacks. -define(STATE_UP, up). -define(STATE_DOWN, down). @@ -107,6 +107,12 @@ %% process. -define(STATE_TABLE, ?MODULE). +%% The default sequence mask. +-define(NOMASK, {0,32}). + +%% The default restrict_connections. +-define(RESTRICT, nodes). + %% Workaround for dialyzer's lack of understanding of match specs. -type match(T) :: T | '_' | '$1' | '$2' | '$3' | '$4'. @@ -114,15 +120,18 @@ %% State of service gen_server. -record(state, {id = now(), - service_name, %% as passed to start_service/2, key in ?STATE_TABLE + service_name, %% as passed to start_service/2, key in ?STATE_TABLE service :: #diameter_service{}, - peerT = ets_new(peers) :: ets:tid(), %% #peer{} at start_fsm - connT = ets_new(conns) :: ets:tid(), %% #conn{} at connection_up - share_peers = false :: boolean(), %% broadcast peers to remote nodes? - use_shared_peers = false :: boolean(), %% use broadcasted peers? + peerT = ets_new(peers) :: ets:tid(),%% #peer{} at start_fsm + connT = ets_new(conns) :: ets:tid(),%% #conn{} at connection_up/reopen shared_peers = ?Dict:new(), %% Alias -> [{TPid, Caps}, ...] local_peers = ?Dict:new(), %% Alias -> [{TPid, Caps}, ...] - monitor = false :: false | pid()}). %% process to die with + monitor = false :: false | pid(), %% process to die with + options + :: [{sequence, diameter:sequence()} %% sequence mask + | {restrict_connections, diameter:restriction()} + | {share_peers, boolean()} %% broadcast peers to remote nodes? + | {use_shared_peers, boolean()}]}).%% use broadcasted peers? %% shared_peers reflects the peers broadcast from remote nodes. Note %% that the state term itself doesn't change, which is relevant for %% the stateless application callbacks since the state is retrieved @@ -130,7 +139,12 @@ %% service record is used to determine whether or not we need to call %% the process for a pick_peer callback. -%% Record representing a watchdog process. +%% Record representing a watchdog process as implemented by +%% diameter_watchdog. The term "peer" here is historical, made +%% especially confusing by the fact that a peer_ref() in the +%% documentation is the key of a #conn{} record, not a #peer{} record. +%% The name is also unfortunate given the meaning of peer in the +%% Diameter sense. -record(peer, {pid :: match(pid()), type :: match(connect | accept), @@ -140,9 +154,15 @@ :: match(op_state() | {op_state(), wd_state()}), started = now(), %% at process start conn = false :: match(boolean() | pid())}). - %% true at accept, pid() at connection_up (connT key) - -%% Record representing a peer_fsm process. + %% true at accepted, pid() at connection_up or reopen + +%% Record representing a peer process as implemented by +%% diameter_peer_fsm. The term "conn" is historical. Despite the name +%% here, comments refer to watchdog and peer processes, that are keys +%% in #peer{} and #conn{} records respectively. To add to the +%% confusion, a #request.transport is a peer process = key in a +%% #conn{} record. The actual transport process (that the peer process +%% knows about and that has a transport connection) isn't seen here. -record(conn, {pid :: pid(), apps :: [{0..16#FFFFFFFF, diameter:app_alias()}], %% {Id, Alias} @@ -156,10 +176,9 @@ handler :: match(pid()), %% request process transport :: match(pid()), %% peer process caps :: match(#diameter_caps{}), - app :: match(diameter:app_alias()), %% #diameter_app.alias - dictionary :: match(module()), %% #diameter_app.dictionary - module :: match([module() | list()]), - %% #diameter_app.module + app :: match(diameter:app_alias()),%% #diameter_app.alias + dictionary :: match(module()), %% #diameter_app.dictionary + module :: match([module() | list()]), %% #diameter_app.module filter :: match(diameter:peer_filter()), packet :: match(#diameter_packet{})}). @@ -170,20 +189,6 @@ timeout = ?DEFAULT_TIMEOUT :: 0..16#FFFFFFFF, detach = false :: boolean()}). -%% Since RFC 3588 requires that a Diameter agent not modify End-to-End -%% Identifiers, the possibility of explicitly setting an End-to-End -%% Identifier would be needed to be able to implement an agent in -%% which one side of the communication is not implemented on top of -%% diameter. For example, Diameter being sent or received encapsulated -%% in some other protocol, or even another Diameter stack in a -%% non-Erlang environment. (Not that this is likely to be a normal -%% case.) -%% -%% The implemented solution is not an option but to respect any header -%% values set in a diameter_header record returned from a -%% prepare_request callback. A call to diameter:call/4 can communicate -%% values to the callback using the 'extra' option if so desired. - %%% --------------------------------------------------------------------------- %%% # start(SvcName) %%% --------------------------------------------------------------------------- @@ -236,20 +241,20 @@ stop_transport(SvcName, [_|_] = Refs) -> %%% --------------------------------------------------------------------------- info(SvcName, Item) -> - info_rc(call_service_by_name(SvcName, {info, Item})). - -info_rc({error, _}) -> - undefined; -info_rc(Info) -> - Info. + case find_state(SvcName) of + #state{} = S -> + service_info(Item, S); + false -> + undefined + end. %%% --------------------------------------------------------------------------- %%% # receive_message(TPid, Pkt, MessageData) %%% --------------------------------------------------------------------------- -%% Handle an incoming message in the watchdog process. This used to -%% come through the service process but this avoids that becoming a -%% bottleneck. +%% Handle an incoming Diameter message in the watchdog process. This +%% used to come through the service process but this avoids that +%% becoming a bottleneck. receive_message(TPid, Pkt, T) when is_pid(TPid) -> @@ -329,21 +334,39 @@ call_rc(_, _, Sent) -> %% In the process spawned for the outgoing request. call(SvcName, App, Msg, Opts, Caller) -> - c(ets:lookup(?STATE_TABLE, SvcName), App, Msg, Opts, Caller). + c(find_state(SvcName), App, Msg, Opts, Caller). -c([#state{service_name = SvcName} = S], App, Msg, Opts, Caller) -> +c(#state{service_name = Svc, options = [{_, Mask} | _]} = S, + App, + Msg, + Opts, + Caller) -> case find_transport(App, Msg, Opts, S) of {_,_,_} = T -> - send_request(T, Msg, Opts, Caller, SvcName); + send_request(T, Mask, Msg, Opts, Caller, Svc); false -> {error, no_connection}; {error, _} = No -> No end; -c([], _, _, _, _) -> +c(false, _, _, _, _) -> {error, no_service}. +%% find_state/1 + +find_state(SvcName) -> + fs(ets:lookup(?STATE_TABLE, SvcName)). + +fs([#state{} = S]) -> + S; + +fs([S]) -> %% inserted from old code + upgrade(S); + +fs([]) -> + false. + %% make_options/1 make_options(Options) -> @@ -439,6 +462,10 @@ i(_, false) -> %%% # handle_call(Req, From, State) %%% --------------------------------------------------------------------------- +handle_call(T, From, S) + when not is_record(S, state) -> + handle_call(T, From, upgrade(S)); + handle_call(state, _, S) -> {reply, S, S}; @@ -462,6 +489,7 @@ handle_call({pick_peer, Local, Remote, App}, _From, S) -> handle_call({call_module, AppMod, Req}, From, S) -> call_module(AppMod, Req, From, S); +%% Call from old code. handle_call({info, Item}, _From, S) -> {reply, service_info(Item, S), S}; @@ -472,6 +500,14 @@ handle_call(stop, _From, S) -> %% gets the reply. We deal with this in the call to the server, %% stating a monitor that waits for DOWN before returning. +%% Watchdog is asking for the sequence mask. +handle_call(sequence, _From, #state{options = [{_, Mask} | _]} = S) -> + {reply, Mask, S}; + +%% Watchdog is asking for the nodes restriction. +handle_call(restriction, _From, #state{options = [_,_,_,{_,R} | _]} = S) -> + {reply, R, S}; + handle_call(Req, From, S) -> unexpected(handle_call, [Req, From], S), {reply, nok, S}. @@ -488,15 +524,16 @@ handle_cast(Req, S) -> %%% # handle_info(Req, State) %%% --------------------------------------------------------------------------- -handle_info(T,S) -> +handle_info(T, #state{} = S) -> case transition(T,S) of ok -> {noreply, S}; - #state{} = NS -> - {noreply, NS}; {stop, Reason} -> {stop, {shutdown, Reason}, S} - end. + end; + +handle_info(T, S) -> + handle_info(T, upgrade(S)). %% transition/2 @@ -507,15 +544,26 @@ transition({accepted, Pid, TPid}, S) -> %% Peer process has a new open connection. transition({connection_up, Pid, T}, S) -> - connection_up(Pid, T, S); + connection_up(Pid, T, S), + ok; + +%% Watchdog has a new connection that will be opened after DW[RA] +%% exchange. This message was added long after connection_up, to +%% communicate the information as soon as it's available. Leave +%% connection_up as is it for now, duplicated information and all. +transition({reopen, Pid, T}, S) -> + reopen(Pid, T, S), + ok; -%% Peer process has left state open. +%% Watchdog has left state OKAY. transition({connection_down, Pid}, S) -> - connection_down(Pid, S); + connection_down(Pid, S), + ok; -%% Peer process has returned to state open. +%% Watchdog has returned to state OKAY. transition({connection_up, Pid}, S) -> - connection_up(Pid, S); + connection_up(Pid, S), + ok; %% Accepting transport has lost connectivity. transition({close, Pid}, S) -> @@ -529,7 +577,7 @@ transition({reconnect, Pid}, S) -> %% Watchdog is sending notification of a state transition. Note that %% the connection_up/down messages are pre-date this message and are -%% still used. A 'watchdog' message will follow these and communicate +%% still used. A watchdog message will follow these and communicate %% the same state as was set in handling connection_up/down. transition({watchdog, Pid, {TPid, From, To}}, #state{service_name = SvcName, peerT = PeerT}) -> @@ -539,21 +587,22 @@ transition({watchdog, Pid, {TPid, From, To}}, #state{service_name = SvcName, insert(PeerT, P#peer{op_state = {OS, To}}), send_event(SvcName, {watchdog, Ref, TPid, {From, To}, {T, Opts}}), ok; -%% Death of a peer process results in the removal of it's peer and any -%% associated conn record when 'DOWN' is received (after this) but the -%% states will be {?STATE_UP, ?WD_DOWN} for a short time. (No real -%% problem since ?WD_* is only used in service_info.) We set ?WD_OKAY -%% as a consequence of connection_up since we know a watchdog is -%% coming. We can't set anything at connection_down since we don't -%% know if the subsequent watchdog message will be ?WD_DOWN or -%% ?WD_SUSPECT. We don't (yet) set ?STATE_* as a consequence of a -%% watchdog message since this requires changing some of the matching -%% on ?STATE_*. -%% -%% Death of a conn process results in connection_down followed by -%% watchdog ?WD_DOWN. The latter doesn't result in the conn record -%% being deleted since 'DOWN' from death of its peer doesn't (yet) -%% deal with the record having been removed. +%% Death of a watchdog process (#peer.pid) results in the removal of +%% it's peer and any associated conn record when 'DOWN' is received +%% (after this) but the states will be {?STATE_UP, ?WD_DOWN} for a +%% short time. (No real problem since ?WD_* is only used in +%% service_info.) We set ?WD_OKAY as a consequence of connection_up +%% since we know a watchdog is coming. We can't set anything at +%% connection_down since we don't know if the subsequent watchdog +%% message will be ?WD_DOWN or ?WD_SUSPECT. We don't (yet) set +%% ?STATE_* as a consequence of a watchdog message since this requires +%% changing some of the matching on ?STATE_*. +%% +%% Death of a peer process process (#conn.pid, #peer.conn) results in +%% connection_down followed by watchdog ?WD_DOWN. The latter doesn't +%% result in the conn record being deleted since 'DOWN' from death of +%% its watchdog doesn't (yet) deal with the record having been +%% removed. %% Monitor process has died. Just die with a reason that tells %% diameter_config about the happening. If a cleaner shutdown is @@ -561,23 +610,26 @@ transition({watchdog, Pid, {TPid, From, To}}, #state{service_name = SvcName, transition({'DOWN', MRef, process, _, Reason}, #state{monitor = MRef}) -> {stop, {monitor, Reason}}; -%% Local peer process has died. +%% Local watchdog process has died. transition({'DOWN', _, process, Pid, Reason}, S) when node(Pid) == node() -> - peer_down(Pid, Reason, S); + peer_down(Pid, Reason, S), + ok; -%% Remote service wants to know about shared transports. +%% Remote service wants to know about shared peers. transition({service, Pid}, S) -> share_peers(Pid, S), ok; %% Remote service is communicating a shared peer. transition({peer, TPid, Aliases, Caps}, S) -> - remote_peer_up(TPid, Aliases, Caps, S); + remote_peer_up(TPid, Aliases, Caps, S), + ok; %% Remote peer process has died. transition({'DOWN', _, process, TPid, _}, S) -> - remote_peer_down(TPid, S); + remote_peer_down(TPid, S), + ok; %% Restart after tc expiry. transition({tc_timeout, T}, S) -> @@ -591,10 +643,39 @@ transition({failover, TRef, Seqs}, S) -> failover(TRef, Seqs, S), ok; +%% Ensure upgraded state is stored in state table. +transition(upgrade, _) -> + ok; + transition(Req, S) -> unexpected(handle_info, [Req], S), ok. +%% upgrade/1 + +upgrade({state, Id, Svc, Name, Svc, PT, CT, SB, UB, SD, LD, MPid}) -> + S = #state{id = Id, + service_name = Name, + service = Svc, + peerT = PT, + connT = CT, + shared_peers = SD, + local_peers = LD, + monitor = MPid, + options = [{sequence, ?NOMASK}, + {share_peers, SB}, + {use_shared_peers, UB}, + {restrict_connections, ?RESTRICT}]}, + upgrade_insert(S), + S. + +upgrade_insert(#state{service = #diameter_service{pid = Pid}} = S) -> + if Pid == self() -> + ets:insert(?STATE_TABLE, S); + true -> + Pid ! upgrade + end. + %%% --------------------------------------------------------------------------- %%% # terminate(Reason, State) %%% --------------------------------------------------------------------------- @@ -710,16 +791,20 @@ shutdown(#state{peerT = PeerT}) -> wait(Fun, T) -> diameter_lib:wait(ets:foldl(Fun, [], T)). -st(#peer{conn = B}, Acc) - when is_boolean(B) -> - Acc; -st(#peer{conn = Pid}, Acc) -> +st(#peer{op_state = {OS,_}} = P, Acc) -> + st(P#peer{op_state = OS}, Acc); +st(#peer{op_state = ?STATE_UP, conn = Pid}, Acc) -> Pid ! shutdown, - [Pid | Acc]. + [Pid | Acc]; +st(#peer{}, Acc) -> + Acc. -sw(#peer{pid = Pid}, Acc) -> +sw(#peer{pid = Pid}, Acc) + when is_pid(Pid) -> exit(Pid, shutdown), - [Pid | Acc]. + [Pid | Acc]; +sw(#peer{}, Acc) -> + Acc. %%% --------------------------------------------------------------------------- %%% # call_service/2 @@ -779,9 +864,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()}, - share_peers = get_value(share_peers, Opts), - use_shared_peers = get_value(use_shared_peers, Opts), - monitor = mref(get_value(monitor, Opts))}, + monitor = mref(get_value(monitor, Opts)), + options = service_options(Opts)}, {S, Acc}; cfg_acc({_Ref, Type, _Opts} = T, {S, Acc}) @@ -789,15 +873,24 @@ cfg_acc({_Ref, Type, _Opts} = T, {S, Acc}) Type == listen -> {S, [T | Acc]}. +service_options(Opts) -> + [{sequence, proplists:get_value(sequence, Opts, ?NOMASK)}, + {share_peers, get_value(share_peers, Opts)}, + {use_shared_peers, get_value(use_shared_peers, Opts)}, + {restrict_connections, proplists:get_value(restrict_connections, + Opts, + ?RESTRICT)}]. +%% The order of options is significant since we match against the list. + mref(false = No) -> No; mref(P) -> erlang:monitor(process, P). -init_shared(#state{use_shared_peers = true, +init_shared(#state{options = [_, _, {_, true} | _], service_name = Svc}) -> diameter_peer:notify(Svc, {service, self()}); -init_shared(#state{use_shared_peers = false}) -> +init_shared(#state{options = [_, _, {_, false} | _]}) -> ok. init_mod(#diameter_app{alias = Alias, @@ -860,9 +953,8 @@ start(Ref, Type, Opts, #state{peerT = PeerT, Pid. %% Note that the service record passed into the watchdog is the merged -%% record so that each watchdog (and peer_fsm) may get a different -%% record. This record is what is passed back into application -%% callbacks. +%% record so that each watchdog may get a different record. This +%% record is what is passed back into application callbacks. s(Type, Ref, T) -> case diameter_watchdog:start({Type, Ref}, T) of @@ -913,8 +1005,8 @@ accepted(Pid, _TPid, #state{peerT = PeerT} = S) -> #peer{ref = Ref, type = accept = T, conn = false, options = Opts} = P = fetch(PeerT, Pid), - insert(PeerT, P#peer{conn = true}), %% mark replacement transport started - start(Ref, T, Opts, S). %% start new peer + insert(PeerT, P#peer{conn = true}), %% mark replacement as started + start(Ref, T, Opts, S). %% start new watchdog fetch(Tid, Key) -> [T] = ets:lookup(Tid, Key), @@ -929,11 +1021,9 @@ fetch(Tid, Key) -> %%% --------------------------------------------------------------------------- %%% # connection_up/3 -%%% -%%% Output: #state{} %%% --------------------------------------------------------------------------- -%% Peer process has reached the open state. +%% Watchdog process has reached state OKAY. connection_up(Pid, {TPid, {Caps, SApps, Pkt}}, #state{peerT = PeerT, connT = ConnT} @@ -948,9 +1038,29 @@ connection_up(Pid, {TPid, {Caps, SApps, Pkt}}, #state{peerT = PeerT, connection_up([Pkt], P#peer{conn = TPid}, C, S). %%% --------------------------------------------------------------------------- +%%% # reopen/3 +%%% --------------------------------------------------------------------------- + +%% Note that this connection_up/3 rewrites the same #conn{} now +%% written here. Both do so in case reopen has not happened in old +%% code. + +reopen(Pid, {TPid, {Caps, SApps, _Pkt}}, #state{peerT = PeerT, + connT = ConnT}) -> + P = fetch(PeerT, Pid), + C = #conn{pid = TPid, + apps = SApps, + caps = Caps, + peer = Pid}, + + insert(ConnT, C), + #peer{op_state = {?STATE_DOWN, _}} + = P, + insert(PeerT, P#peer{op_state = {?STATE_DOWN, ?WD_REOPEN}, + conn = TPid}). + +%%% --------------------------------------------------------------------------- %%% # connection_up/2 -%%% -%%% Output: #state{} %%% --------------------------------------------------------------------------- %% Peer process has transitioned back into the open state. Note that there @@ -979,10 +1089,8 @@ connection_up(T, P, C, #state{peerT = PeerT, insert(PeerT, P#peer{op_state = {?STATE_UP, ?WD_OKAY}}), request_peer_up(TPid), - report_status(up, P, C, S, T), - S#state{local_peers = insert_local_peer(SApps, - {{TPid, Caps}, {SvcName, Apps}}, - LDict)}. + insert_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict), + report_status(up, P, C, S, T). insert_local_peer(SApps, T, LDict) -> lists:foldl(fun(A,D) -> ilp(A, T, D) end, LDict, SApps). @@ -1024,11 +1132,9 @@ peer_cb(MFA, Alias) -> %%% --------------------------------------------------------------------------- %%% # connection_down/2 -%%% -%%% Output: #state{} %%% --------------------------------------------------------------------------- -%% Peer process has transitioned out of the open state. +%% Watchdog has transitioned out of state OKAY. connection_down(Pid, #state{peerT = PeerT, connT = ConnT} @@ -1044,8 +1150,8 @@ connection_down(Pid, #state{peerT = PeerT, %% connection_down/3 -connection_down(#peer{op_state = {?STATE_DOWN, _}}, _, S) -> - S; +connection_down(#peer{op_state = {?STATE_DOWN, _}}, _, _) -> + ok; connection_down(#peer{conn = TPid, op_state = {?STATE_UP, _}} @@ -1058,12 +1164,8 @@ connection_down(#peer{conn = TPid, local_peers = LDict} = S) -> report_status(down, P, C, S, []), - NewS = S#state{local_peers - = remove_local_peer(SApps, - {{TPid, Caps}, {SvcName, Apps}}, - LDict)}, - request_peer_down(TPid, NewS), - NewS. + remove_local_peer(SApps, {{TPid, Caps}, {SvcName, Apps}}, LDict), + request_peer_down(TPid, S). remove_local_peer(SApps, T, LDict) -> lists:foldl(fun(A,D) -> rlp(A, T, D) end, LDict, SApps). @@ -1082,11 +1184,9 @@ down_conn(Id, Alias, TC, {SvcName, Apps}) -> %%% --------------------------------------------------------------------------- %%% # peer_down/3 -%%% -%%% Output: #state{} %%% --------------------------------------------------------------------------- -%% Peer process has died. +%% Watchdog process has died. peer_down(Pid, Reason, #state{peerT = PeerT} = S) -> P = fetch(PeerT, Pid), @@ -1106,12 +1206,12 @@ closed({shutdown, {close, _TPid, Reason}}, closed(_, _, _) -> ok. -%% The peer has never come up ... -peer_down(#peer{conn = B}, S) +%% The watchdog has never reached OKAY ... +peer_down(#peer{conn = B}, _) when is_boolean(B) -> - S; + ok; -%% ... or it has. +%% ... or maybe it has. peer_down(#peer{conn = TPid} = P, #state{connT = ConnT} = S) -> #conn{} = C = fetch(ConnT, TPid), ets:delete_object(ConnT, C), @@ -1139,7 +1239,7 @@ restart(#peer{ref = Ref, started = Time}) -> {Time, {Ref, T, Opts}}; -%% ... or it has: a replacement transport has already been spawned. +%% ... or it has: a replacement has already been spawned. restart(#peer{type = accept}) -> false. @@ -1165,8 +1265,8 @@ default_tc(connect, Opts) -> default_tc(accept, _) -> 0. -%% Bound tc below if the peer was restarted recently to avoid -%% continuous in case of faulty config or other problems. +%% Bound tc below if the watchdog was restarted recently to avoid +%% continuous restarted in case of faulty config or other problems. tc(Time, Tc) -> choose(Tc > ?RESTART_TC orelse timer:now_diff(now(), Time) > 1000*?RESTART_TC, @@ -1288,7 +1388,7 @@ cm([_,_|_], _, _, _) -> multiple. %%% --------------------------------------------------------------------------- -%%% # send_request/5 +%%% # send_request/6 %%% --------------------------------------------------------------------------- %% Send an outgoing request in its dedicated process. @@ -1301,71 +1401,89 @@ cm([_,_|_], _, _, _) -> %% The mod field of the #diameter_app{} here includes any extra %% arguments passed to diameter:call/2. -send_request({TPid, Caps, App}, Msg, Opts, Caller, SvcName) -> +send_request({TPid, Caps, App} = T, Mask, Msg, Opts, Caller, SvcName) -> #diameter_app{module = ModX} = App, - Pkt = make_request_packet(Msg), - - case cb(ModX, prepare_request, [Pkt, SvcName, {TPid, Caps}]) of - {send, P} -> - send_request(make_request_packet(P, Pkt), - TPid, - Caps, - App, - Opts, - Caller, - SvcName); - {discard, Reason} -> - {error, Reason}; - discard -> - {error, discarded}; - T -> - ?ERROR({invalid_return, prepare_request, App, T}) - end. + Pkt = make_prepare_packet(Mask, Msg), + + send_req(cb(ModX, prepare_request, [Pkt, SvcName, {TPid, Caps}]), + Pkt, + T, + Opts, + Caller, + SvcName, + []). + +send_req({send, P}, Pkt, T, Opts, Caller, SvcName, Fs) -> + send_req(make_request_packet(P, Pkt), T, Opts, Caller, SvcName, Fs); -%% make_request_packet/1 +send_req({discard, Reason} , _, _, _, _, _, _) -> + {error, Reason}; + +send_req(discard, _, _, _, _, _, _) -> + {error, discarded}; + +send_req({eval_packet, RC, F}, Pkt, T, Opts, Caller, SvcName, Fs) -> + send_req(RC, Pkt, T, Opts, Caller, SvcName, [F|Fs]); + +send_req(E, _, {_, _, App}, _, _, _, _) -> + ?ERROR({invalid_return, prepare_request, App, E}). + +%% make_prepare_packet/2 %% %% Turn an outgoing request as passed to call/4 into a diameter_packet %% record in preparation for a prepare_request callback. -make_request_packet(Bin) +make_prepare_packet(_, Bin) when is_binary(Bin) -> #diameter_packet{header = diameter_codec:decode_header(Bin), bin = Bin}; -make_request_packet(#diameter_packet{msg = [#diameter_header{} = Hdr | Avps]} - = Pkt) -> - Pkt#diameter_packet{msg = [make_request_header(Hdr) | Avps]}; +make_prepare_packet(Mask, #diameter_packet{msg = [#diameter_header{} = Hdr + | Avps]} + = Pkt) -> + Pkt#diameter_packet{msg = [make_prepare_header(Mask, Hdr) | Avps]}; -make_request_packet(#diameter_packet{header = Hdr} = Pkt) -> - Pkt#diameter_packet{header = make_request_header(Hdr)}; +make_prepare_packet(Mask, #diameter_packet{header = Hdr} = Pkt) -> + Pkt#diameter_packet{header = make_prepare_header(Mask, Hdr)}; -make_request_packet(Msg) -> - make_request_packet(#diameter_packet{msg = Msg}). +make_prepare_packet(Mask, Msg) -> + make_prepare_packet(Mask, #diameter_packet{msg = Msg}). -%% make_request_header/1 +%% make_prepare_header/1 -make_request_header(undefined) -> - Seq = diameter_session:sequence(), - make_request_header(#diameter_header{end_to_end_id = Seq, +make_prepare_header(Mask, undefined) -> + Seq = diameter_session:sequence(Mask), + make_prepare_header(#diameter_header{end_to_end_id = Seq, hop_by_hop_id = Seq}); -make_request_header(#diameter_header{version = undefined} = Hdr) -> - make_request_header(Hdr#diameter_header{version = ?DIAMETER_VERSION}); +make_prepare_header(Mask, #diameter_header{end_to_end_id = undefined, + hop_by_hop_id = undefined}) -> + Seq = diameter_session:sequence(Mask), + make_prepare_header(#diameter_header{end_to_end_id = Seq, + hop_by_hop_id = Seq}); + +make_prepare_header(Mask, #diameter_header{end_to_end_id = undefined} = H) -> + Seq = diameter_session:sequence(Mask), + make_prepare_header(H#diameter_header{end_to_end_id = Seq}); + +make_prepare_header(Mask, #diameter_header{hop_by_hop_id = undefined} = H) -> + Seq = diameter_session:sequence(Mask), + make_prepare_header(H#diameter_header{hop_by_hop_id = Seq}); + +make_prepare_header(_, Hdr) -> + make_prepare_header(Hdr). -make_request_header(#diameter_header{end_to_end_id = undefined} = H) -> - Seq = diameter_session:sequence(), - make_request_header(H#diameter_header{end_to_end_id = Seq}); +%% make_prepare_header/1 -make_request_header(#diameter_header{hop_by_hop_id = undefined} = H) -> - Seq = diameter_session:sequence(), - make_request_header(H#diameter_header{hop_by_hop_id = Seq}); +make_prepare_header(#diameter_header{version = undefined} = Hdr) -> + make_prepare_header(Hdr#diameter_header{version = ?DIAMETER_VERSION}); -make_request_header(#diameter_header{} = Hdr) -> +make_prepare_header(#diameter_header{} = Hdr) -> Hdr; -make_request_header(T) -> +make_prepare_header(T) -> ?ERROR({invalid_header, T}). %% make_request_packet/2 @@ -1375,7 +1493,7 @@ make_request_header(T) -> make_request_packet(Bin, _) when is_binary(Bin) -> - make_request_packet(Bin); + make_prepare_packet(false, Bin); make_request_packet(#diameter_packet{msg = [#diameter_header{} | _]} = Pkt, @@ -1387,7 +1505,7 @@ make_request_packet(#diameter_packet{msg = [#diameter_header{} | _]} %% This is primarily so that the end to end and hop by hop identifiers %% are retained. make_request_packet(#diameter_packet{header = Hdr} = Pkt, - #diameter_packet{header = Hdr0}) -> + #diameter_packet{header = Hdr0}) -> Pkt#diameter_packet{header = fold_record(Hdr0, Hdr)}; make_request_packet(Msg, Pkt) -> @@ -1400,16 +1518,16 @@ fold_record(undefined, R) -> fold_record(Rec, R) -> diameter_lib:fold_tuple(2, Rec, R). -%% send_request/7 +%% send_req/6 -send_request(Pkt, TPid, Caps, App, Opts, Caller, SvcName) -> +send_req(Pkt, {TPid, Caps, App}, Opts, Caller, SvcName, Fs) -> #diameter_app{alias = Alias, dictionary = Dict, module = ModX, options = [{answer_errors, AE} | _]} = App, - EPkt = encode(Dict, Pkt), + EPkt = encode(Dict, Pkt, Fs), #options{filter = Filter, timeout = Timeout} @@ -1490,6 +1608,13 @@ msg(#diameter_packet{msg = undefined, bin = Bin}) -> msg(#diameter_packet{msg = Msg}) -> Msg. +%% encode/3 + +encode(Dict, Pkt, Fs) -> + P = encode(Dict, Pkt), + eval_packet(P, Fs), + P. + %% encode/2 %% Note that prepare_request can return a diameter_packet containing @@ -1571,38 +1696,47 @@ send(Pid, Pkt) -> %% retransmit/4 -retransmit({TPid, Caps, #diameter_app{alias = Alias} = App}, - #request{app = Alias, - packet = Pkt} +retransmit({TPid, Caps, #diameter_app{alias = Alias} = App} = T, + #request{app = Alias, packet = Pkt} = Req, SvcName, Timeout) -> have_request(Pkt, TPid) %% Don't failover to a peer we've andalso ?THROW(timeout), %% already sent to. - case cb(App, prepare_retransmit, [Pkt, SvcName, {TPid, Caps}]) of - {send, P} -> - retransmit(make_request_packet(P, Pkt), TPid, Caps, Req, Timeout); - {discard, Reason} -> - ?THROW(Reason); - discard -> - ?THROW(discarded); - T -> - ?ERROR({invalid_return, prepare_retransmit, App, T}) - end. + resend_req(cb(App, prepare_retransmit, [Pkt, SvcName, {TPid, Caps}]), + T, + Req, + Timeout, + []). + +resend_req({send, P}, T, #request{packet = Pkt} = Req, Timeout, Fs) -> + retransmit(make_request_packet(P, Pkt), T, Req, Timeout, Fs); + +resend_req({discard, Reason}, _, _, _, _) -> + ?THROW(Reason); + +resend_req(discard, _, _, _, _) -> + ?THROW(discarded); -%% retransmit/5 +resend_req({eval_packet, RC, F}, T, Req, Timeout, Fs) -> + resend_req(RC, T, Req, Timeout, [F|Fs]); + +resend_req(T, {_, _, App}, _, _, _) -> + ?ERROR({invalid_return, prepare_retransmit, App, T}). + +%% retransmit/6 -retransmit(Pkt, TPid, Caps, #request{dictionary = Dict} = Req, Timeout) -> - EPkt = encode(Dict, Pkt), +retransmit(Pkt, {TPid, Caps, _}, #request{dictionary = D} = Req0, Tmo, Fs) -> + EPkt = encode(D, Pkt, Fs), - NewReq = Req#request{transport = TPid, - packet = Pkt, - caps = Caps}, + Req = Req0#request{transport = TPid, + packet = Pkt, + caps = Caps}, - ?LOG(retransmission, NewReq), - TRef = send_request(TPid, EPkt, NewReq, Timeout), - {TRef, NewReq}. + ?LOG(retransmission, Req), + TRef = send_request(TPid, EPkt, Req, Tmo), + {TRef, Req}. %% store_request/4 @@ -1674,10 +1808,13 @@ request_peer_down(TPid, S) -> %%% recv_request/3 %%% --------------------------------------------------------------------------- -recv_request(TPid, Pkt, {ConnT, SvcName, Apps}) -> +recv_request(TPid, Pkt, {ConnT, SvcName, Apps}) -> %% upgrade + recv_request(TPid, Pkt, {ConnT, SvcName, Apps, ?NOMASK}); + +recv_request(TPid, Pkt, {ConnT, SvcName, Apps, Mask}) -> try ets:lookup(ConnT, TPid) of [C] -> - recv_request(C, TPid, Pkt, SvcName, Apps); + recv_request(C, TPid, Pkt, SvcName, Apps, Mask); [] -> %% transport has gone down ok catch @@ -1687,7 +1824,12 @@ recv_request(TPid, Pkt, {ConnT, SvcName, Apps}) -> %% recv_request/5 -recv_request(#conn{apps = SApps, caps = Caps}, TPid, Pkt, SvcName, Apps) -> +recv_request(#conn{apps = SApps, caps = Caps}, + TPid, + Pkt, + SvcName, + Apps, + Mask) -> #diameter_caps{origin_host = {OH,_}, origin_realm = {OR,_}} = Caps, @@ -1699,6 +1841,7 @@ recv_request(#conn{apps = SApps, caps = Caps}, TPid, Pkt, SvcName, Apps) -> {SvcName, OH, OR}, TPid, Apps, + Mask, Caps, Pkt). @@ -1724,20 +1867,24 @@ keyfind([Key | Rest], Pos, L) -> T end. -%% recv_request/6 +%% recv_request/7 -recv_request({Id, Alias}, T, TPid, Apps, Caps, Pkt) -> +recv_request({Id, Alias}, T, TPid, Apps, Mask, Caps, Pkt) -> #diameter_app{dictionary = Dict} = A = find_app(Alias, Apps), - recv_request(T, {TPid, Caps}, A, diameter_codec:decode(Id, Dict, Pkt)); + recv_request(T, + {TPid, Caps}, + A, + Mask, + diameter_codec:decode(Id, Dict, Pkt)); %% Note that the decode is different depending on whether or not Id is %% ?APP_ID_RELAY. %% DIAMETER_APPLICATION_UNSUPPORTED 3007 %% A request was sent for an application that is not supported. -recv_request(false, T, TPid, _, _, Pkt) -> +recv_request(false, T, TPid, _, _, _, Pkt) -> As = collect_avps(Pkt), protocol_error(3007, T, TPid, Pkt#diameter_packet{avps = As}). @@ -1749,7 +1896,7 @@ collect_avps(Pkt) -> As end. -%% recv_request/4 +%% recv_request/5 %% Wrong number of bits somewhere in the message: reply. %% @@ -1758,7 +1905,7 @@ collect_avps(Pkt) -> %% set to an unrecognized value, or that is inconsistent with the %% AVP's definition. %% -recv_request(T, {TPid, _}, _, #diameter_packet{errors = [Bs | _]} = Pkt) +recv_request(T, {TPid, _}, _, _, #diameter_packet{errors = [Bs | _]} = Pkt) when is_bitstring(Bs) -> protocol_error(3009, T, TPid, Pkt); @@ -1773,6 +1920,7 @@ recv_request(T, {TPid, _}, _, #diameter_packet{errors = [Bs | _]} = Pkt) recv_request(T, {TPid, _}, #diameter_app{id = Id}, + _, #diameter_packet{header = #diameter_header{is_proxiable = P}, msg = M} = Pkt) @@ -1790,6 +1938,7 @@ recv_request(T, recv_request(T, {TPid, _}, _, + _, #diameter_packet{header = #diameter_header{is_error = true}} = Pkt) -> protocol_error(3008, T, TPid, Pkt); @@ -1798,14 +1947,20 @@ recv_request(T, %% in the relay application. Don't distinguish between the two since %% each application has its own callback config. That is, the user can %% easily distinguish between the two cases. -recv_request(T, TC, App, Pkt) -> - request_cb(T, TC, App, examine(Pkt)). +recv_request(T, TC, App, Mask, Pkt) -> + request_cb(T, TC, App, Mask, examine(Pkt)). %% Note that there may still be errors but these aren't protocol %% (3xxx) errors that lead to an answer-message. -request_cb({SvcName, _OH, _OR} = T, TC, App, Pkt) -> - request_cb(cb(App, handle_request, [Pkt, SvcName, TC]), App, T, TC, Pkt). +request_cb({SvcName, _OH, _OR} = T, TC, App, Mask, Pkt) -> + request_cb(cb(App, handle_request, [Pkt, SvcName, TC]), + App, + Mask, + T, + TC, + [], + Pkt). %% examine/1 %% @@ -1825,7 +1980,7 @@ examine(#diameter_packet{errors = Es} = Pkt) -> Pkt#diameter_packet{errors = [5011 | Es]}. %% It's odd/unfortunate that this isn't a protocol error. -%% request_cb/5 +%% request_cb/7 %% A reply may be an answer-message, constructed either here or by %% the handle_request callback. The header from the incoming request @@ -1835,21 +1990,23 @@ examine(#diameter_packet{errors = Es} = Pkt) -> request_cb({reply, Ans}, #diameter_app{dictionary = Dict}, _, + _, {TPid, _}, + Fs, Pkt) -> - reply(Ans, Dict, TPid, Pkt); + reply(Ans, Dict, TPid, Fs, Pkt); %% An 3xxx result code, for which the E-bit is set in the header. -request_cb({protocol_error, RC}, _, T, {TPid, _}, Pkt) +request_cb({protocol_error, RC}, _, _, T, {TPid, _}, Fs, Pkt) when 3000 =< RC, RC < 4000 -> - protocol_error(RC, T, TPid, Pkt); + protocol_error(RC, T, TPid, Fs, Pkt); %% RFC 3588 says we must reply 3001 to anything unrecognized or %% unsupported. 'noreply' is undocumented (and inappropriately named) %% backwards compatibility for this, protocol_error the documented %% alternative. -request_cb(noreply, _, T, {TPid, _}, Pkt) -> - protocol_error(3001, T, TPid, Pkt); +request_cb(noreply, _, _, T, {TPid, _}, Fs, Pkt) -> + protocol_error(3001, T, TPid, Fs, Pkt); %% Relay a request to another peer. This is equivalent to doing an %% explicit call/4 with the message in question except that (1) a loop @@ -1869,38 +2026,51 @@ request_cb(noreply, _, T, {TPid, _}, Pkt) -> request_cb({A, Opts}, #diameter_app{id = Id} = App, + Mask, T, TC, + Fs, Pkt) when A == relay, Id == ?APP_ID_RELAY; A == proxy, Id /= ?APP_ID_RELAY; A == resend -> - resend(Opts, App, T, TC, Pkt); + resend(Opts, App, Mask, T, TC, Fs, Pkt); -request_cb(discard, _, _, _, _) -> +request_cb(discard, _, _, _, _, _, _) -> ok; -request_cb({eval, RC, F}, App, T, TC, Pkt) -> - request_cb(RC, App, T, TC, Pkt), +request_cb({eval_packet, RC, F}, App, Mask, T, TC, Fs, Pkt) -> + request_cb(RC, App, Mask, T, TC, [F|Fs], Pkt); + +request_cb({eval, RC, F}, App, Mask, T, TC, Fs, Pkt) -> + request_cb(RC, App, Mask, T, TC, Pkt, Fs), diameter_lib:eval(F). -%% protocol_error/4 +%% protocol_error/5 -protocol_error(RC, {_, OH, OR}, TPid, #diameter_packet{avps = Avps} = Pkt) -> +protocol_error(RC, {_, OH, OR}, TPid, Fs, Pkt) -> + #diameter_packet{avps = Avps} = Pkt, ?LOG({error, RC}, Pkt), - reply(answer_message({OH, OR, RC}, Avps), ?BASE, TPid, Pkt). + reply(answer_message({OH, OR, RC}, Avps), ?BASE, TPid, Fs, Pkt). + +%% protocol_error/4 -%% resend/5 +protocol_error(RC, T, TPid, Pkt) -> + protocol_error(RC, T, TPid, [], Pkt). + +%% resend/7 %% %% Resend a message as a relay or proxy agent. resend(Opts, #diameter_app{} = App, + Mask, {_SvcName, OH, _OR} = T, {_TPid, _Caps} = TC, + Fs, #diameter_packet{avps = Avps} = Pkt) -> {Code, _Flags, Vid} = ?BASE:avp_header('Route-Record'), - resend(is_loop(Code, Vid, OH, Avps), Opts, App, T, TC, Pkt). + resend(is_loop(Code, Vid, OH, Avps), Opts, App, Mask, T, TC, Fs, Pkt). %% DIAMETER_LOOP_DETECTED 3005 %% An agent detected a loop while trying to get the message to the @@ -1908,8 +2078,8 @@ resend(Opts, %% if one is available, but the peer reporting the error has %% identified a configuration problem. -resend(true, _, _, T, {TPid, _}, Pkt) -> %% Route-Record loop - protocol_error(3005, T, TPid, Pkt); +resend(true, _, _, _, T, {TPid, _}, Fs, Pkt) -> %% Route-Record loop + protocol_error(3005, T, TPid, Fs, Pkt); %% 6.1.8. Relaying and Proxying Requests %% @@ -1920,16 +2090,18 @@ resend(true, _, _, T, {TPid, _}, Pkt) -> %% Route-Record loop resend(false, Opts, App, + Mask, {SvcName, _, _} = T, {TPid, #diameter_caps{origin_host = {_, OH}}}, + Fs, #diameter_packet{header = Hdr0, avps = Avps} = Pkt) -> Route = #diameter_avp{data = {?BASE, 'Route-Record', OH}}, - Seq = diameter_session:sequence(), + Seq = diameter_session:sequence(Mask), Hdr = Hdr0#diameter_header{hop_by_hop_id = Seq}, Msg = [Hdr, Route | Avps], - resend(call(SvcName, App, Msg, Opts), T, TPid, Pkt). + resend(call(SvcName, App, Msg, Opts), T, TPid, Fs, Pkt). %% The incoming request is relayed with the addition of a %% Route-Record. Note the requirement on the return from call/4 below, %% which places a requirement on the value returned by the @@ -1955,15 +2127,18 @@ resend(#diameter_packet{bin = B} = Pkt, _, TPid, + Fs, #diameter_packet{header = #diameter_header{hop_by_hop_id = Id}, transport_data = TD}) -> - send(TPid, Pkt#diameter_packet{bin = diameter_codec:hop_by_hop_id(Id, B), - transport_data = TD}); + P = Pkt#diameter_packet{bin = diameter_codec:hop_by_hop_id(Id, B), + transport_data = TD}, + eval_packet(P, Fs), + send(TPid, P); %% TODO: counters %% Or not: DIAMETER_UNABLE_TO_DELIVER. -resend(_, T, TPid, Pkt) -> - protocol_error(3002, T, TPid, Pkt). +resend(_, T, TPid, Fs, Pkt) -> + protocol_error(3002, T, TPid, Fs, Pkt). %% is_loop/4 %% @@ -1985,33 +2160,38 @@ is_loop(Code, Vid, OH, [_ | Avps]) is_loop(Code, Vid, OH, Avps) -> is_loop(Code, Vid, ?BASE:avp(encode, OH, 'Route-Record'), Avps). -%% reply/4 +%% reply/5 %% %% Send a locally originating reply. %% Skip the setting of Result-Code and Failed-AVP's below. -reply([Msg], Dict, TPid, Pkt) +reply([Msg], Dict, TPid, Fs, Pkt) when is_list(Msg); is_tuple(Msg) -> - reply(Msg, Dict, TPid, Pkt#diameter_packet{errors = []}); + reply(Msg, Dict, TPid, Fs, Pkt#diameter_packet{errors = []}); %% No errors or a diameter_header/avp list. -reply(Msg, Dict, TPid, #diameter_packet{errors = Es, - transport_data = TD} - = ReqPkt) +reply(Msg, Dict, TPid, Fs, #diameter_packet{errors = Es, + transport_data = TD} + = ReqPkt) when [] == Es; is_record(hd(Msg), diameter_header) -> Pkt = diameter_codec:encode(Dict, make_answer_packet(Msg, ReqPkt)), + eval_packet(Pkt, Fs), incr(send, Pkt, Dict, TPid), %% count result codes in sent answers send(TPid, Pkt#diameter_packet{transport_data = TD}); %% Or not: set Result-Code and Failed-AVP AVP's. -reply(Msg, Dict, TPid, #diameter_packet{errors = [H|_] = Es} = Pkt) -> +reply(Msg, Dict, TPid, Fs, #diameter_packet{errors = [H|_] = Es} = Pkt) -> reply(rc(Msg, rc(H), [A || {_,A} <- Es], Dict), Dict, TPid, + Fs, Pkt#diameter_packet{errors = []}). +eval_packet(Pkt, Fs) -> + lists:foreach(fun(F) -> diameter_lib:eval([F,Pkt]) end, Fs). + %% make_answer_packet/2 %% Binaries and header/avp lists are sent as-is. @@ -2071,7 +2251,7 @@ rc([MsgName | _], {'Result-Code' = K, RC} = T, Dict) -> rc(Rec, T, Dict) -> rc([Dict:rec2msg(element(1, Rec))], T, Dict). - + %% failed_avp/3 failed_avp(_, [] = No, _) -> @@ -2307,7 +2487,7 @@ a(#diameter_packet{errors = Es} = Pkt, SvcName, AE, #request{transport = TPid, when [] == Es; callback == AE -> cb(Req, handle_answer, [Pkt, msg(P), SvcName, {TPid, Caps}]); - + a(Pkt, SvcName, report, Req) -> x(errors, handle_answer, [SvcName, Req, Pkt]); @@ -2469,7 +2649,7 @@ send_event(#diameter_event{service = SvcName} = E) -> %%% # share_peer/5 %%% --------------------------------------------------------------------------- -share_peer(up, Caps, Aliases, TPid, #state{share_peers = true, +share_peer(up, Caps, Aliases, TPid, #state{options = [_, {_, true} | _], service_name = Svc}) -> diameter_peer:notify(Svc, {peer, TPid, Aliases, Caps}); @@ -2480,11 +2660,11 @@ share_peer(_, _, _, _, _) -> %%% # share_peers/2 %%% --------------------------------------------------------------------------- -share_peers(Pid, #state{share_peers = true, +share_peers(Pid, #state{options = [_, {_, true} | _], local_peers = PDict}) -> ?Dict:fold(fun(A,Ps,ok) -> sp(Pid, A, Ps), ok end, ok, PDict); -share_peers(_, #state{share_peers = false}) -> +share_peers(_, _) -> ok. sp(Pid, Alias, Peers) -> @@ -2494,39 +2674,31 @@ sp(Pid, Alias, Peers) -> %%% # remote_peer_up/4 %%% --------------------------------------------------------------------------- -remote_peer_up(Pid, Aliases, Caps, #state{use_shared_peers = true, +remote_peer_up(Pid, Aliases, Caps, #state{options = [_, _, {_, true} | _], service = Svc, - shared_peers = PDict} - = S) -> + shared_peers = PDict}) -> #diameter_service{applications = Apps} = Svc, - Update = lists:filter(fun(A) -> - lists:keymember(A, #diameter_app.alias, Apps) - end, - Aliases), - S#state{shared_peers = rpu(Pid, Caps, PDict, Update)}; + Key = #diameter_app.alias, + As = lists:filter(fun(A) -> lists:keymember(A, Key, Apps) end, Aliases), + rpu(Pid, Caps, PDict, As); -remote_peer_up(_, _, _, #state{use_shared_peers = false} = S) -> - S. +remote_peer_up(_, _, _, #state{options = [_, _, {_, false} | _]}) -> + ok. rpu(_, _, PDict, []) -> PDict; rpu(Pid, Caps, PDict, Aliases) -> erlang:monitor(process, Pid), T = {Pid, Caps}, - lists:foldl(fun(A,D) -> ?Dict:append(A, T, D) end, - PDict, - Aliases). + lists:foreach(fun(A) -> ?Dict:append(A, T, PDict) end, Aliases). %%% --------------------------------------------------------------------------- %%% # remote_peer_down/2 %%% --------------------------------------------------------------------------- -remote_peer_down(Pid, #state{use_shared_peers = true, - shared_peers = PDict} - = S) -> - S#state{shared_peers = lists:foldl(fun(A,D) -> rpd(Pid, A, D) end, - PDict, - ?Dict:fetch_keys(PDict))}. +remote_peer_down(Pid, #state{options = [_, _, {_, true} | _], + shared_peers = PDict}) -> + lists:foreach(fun(A) -> rpd(Pid, A, PDict) end, ?Dict:fetch_keys(PDict)). rpd(Pid, Alias, PDict) -> ?Dict:update(Alias, fun(Ps) -> lists:keydelete(Pid, 1, Ps) end, PDict). @@ -2851,7 +3023,8 @@ transports(#state{peerT = PeerT}) -> -define(ALL_INFO, [capabilities, applications, transport, - pending]). + pending, + options]). %% The rest. -define(OTHER_INFO, [connections, @@ -2878,6 +3051,19 @@ tagged_info(Item, S) undefined end; +tagged_info(TPid, #state{peerT = PT, connT = CT}) + when is_pid(TPid) -> + try + [#conn{peer = Pid}] = ets:lookup(CT, TPid), + [#peer{ref = Ref, type = Type, options = Opts}] = ets:lookup(PT, Pid), + [{ref, Ref}, + {type, Type}, + {options, Opts}] + catch + error:_ -> + [] + end; + tagged_info(Items, S) when is_list(Items) -> [T || I <- Items, T <- [tagged_info(I,S)], T /= undefined, T /= []]; @@ -2928,6 +3114,7 @@ complete_info(Item, #state{service = Svc} = S) -> capabilities -> service_info(?CAP_INFO, S); applications -> info_apps(S); transport -> info_transport(S); + options -> info_options(S); pending -> info_pending(S); keys -> ?ALL_INFO ++ ?CAP_INFO ++ ?OTHER_INFO; all -> service_info(?ALL_INFO, S); @@ -2955,7 +3142,12 @@ info_stats(#state{peerT = PeerT}) -> MatchSpec = [{#peer{ref = '$1', conn = '$2', _ = '_'}, [{'is_pid', '$2'}], [['$1', '$2']]}], - diameter_stats:read(lists:append(ets:select(PeerT, MatchSpec))). + try ets:select(PeerT, MatchSpec) of + L -> + diameter_stats:read(lists:append(L)) + catch + error: badarg -> [] %% service has gone down + end. %% info_transport/1 %% @@ -3000,7 +3192,12 @@ transport([[{type, accept}, {options, Opts} | _] | _] = Ls) -> {accept, [lists:nthtail(2,L) || L <- Ls]}]. peer_dict(#state{peerT = PeerT, connT = ConnT}, Dict0) -> - ets:foldl(fun(T,A) -> peer_acc(ConnT, A, T) end, Dict0, PeerT). + try ets:tab2list(PeerT) of + L -> + lists:foldl(fun(T,A) -> peer_acc(ConnT, A, T) end, Dict0, L) + catch + error: badarg -> Dict0 %% service has gone down + end. peer_acc(ConnT, Acc, #peer{pid = Pid, type = Type, @@ -3017,9 +3214,16 @@ peer_acc(ConnT, Acc, #peer{pid = Pid, | info_conn(ConnT, TPid, WS /= ?WD_DOWN)], Acc). +info_conn(ConnT, [TPid], B) -> + info_conn(ConnT, TPid, B); + info_conn(ConnT, TPid, true) when is_pid(TPid) -> - info_conn(ets:lookup(ConnT, TPid)); + try ets:lookup(ConnT, TPid) of + T -> info_conn(T) + catch + error: badarg -> [] %% service has gone down + end; info_conn(_, _, _) -> []. @@ -3096,7 +3300,11 @@ info_pending(#state{} = S) -> {{transport, '$2'}}, {{from, '$3'}}]}}]}], - ets:select(?REQUEST_TABLE, MatchSpec). + try + ets:select(?REQUEST_TABLE, MatchSpec) + catch + error: badarg -> [] %% service has gone down + end. %% info_connections/1 %% @@ -3151,3 +3359,8 @@ peer_acc(Peer, {PeerD, RefD}) -> [{TPid, _}, [{origin_host, {_, OH}} | _]] = [proplists:get_value(K, Peer) || K <- [peer, caps]], {dict:append(OH, Peer, PeerD), dict:append(OH, TPid, RefD)}. + +%% info_options/1 + +info_options(S) -> + S#state.options. diff --git a/lib/diameter/src/base/diameter_session.erl b/lib/diameter/src/base/diameter_session.erl index 4c468f207c..3b236f109a 100644 --- a/lib/diameter/src/base/diameter_session.erl +++ b/lib/diameter/src/base/diameter_session.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -20,6 +20,7 @@ -module(diameter_session). -export([sequence/0, + sequence/1, session_id/1, origin_state_id/0]). @@ -30,7 +31,7 @@ -define(INT32, 16#FFFFFFFF). %% --------------------------------------------------------------------------- -%% # sequence/0 +%% # sequence/0-1 %% %% Output: 32-bit %% --------------------------------------------------------------------------- @@ -77,6 +78,15 @@ sequence() -> Instr = {_Pos = 2, _Incr = 1, _Threshold = ?INT32, _SetVal = 0}, ets:update_counter(diameter_sequence, sequence, Instr). +-spec sequence(diameter:sequence()) + -> diameter:'Unsigned32'(). + +sequence({_,32}) -> + sequence(); + +sequence({H,N}) -> + (H bsl N) bor (sequence() band (1 bsl N - 1)). + %% --------------------------------------------------------------------------- %% # origin_state_id/0 %% --------------------------------------------------------------------------- diff --git a/lib/diameter/src/base/diameter_watchdog.erl b/lib/diameter/src/base/diameter_watchdog.erl index d7474e5c56..d814f1afe2 100644 --- a/lib/diameter/src/base/diameter_watchdog.erl +++ b/lib/diameter/src/base/diameter_watchdog.erl @@ -43,6 +43,7 @@ -include("diameter_internal.hrl"). -define(DEFAULT_TW_INIT, 30000). %% RFC 3539 ch 3.4.1 +-define(NOMASK, {0,32}). %% default sequence mask -record(watchdog, {%% PCB - Peer Control Block; see RFC 3539, Appendix A @@ -56,7 +57,9 @@ parent = self() :: pid(), transport :: pid() | undefined, tref :: reference(), %% reference for current watchdog timer - message_data}). %% term passed into diameter_service with message + message_data, %% term passed into diameter_service with message + sequence :: diameter:sequence(), %% mask + restrict :: {diameter:restriction(), boolean()}}). %% start/2 %% @@ -118,12 +121,23 @@ make_state({T, Pid, {RecvData, random:seed(now()), putr(restart, {T, Opts, Svc}), %% save seeing it in trace putr(dwr, dwr(Caps)), %% + {_,_} = Mask = call(Pid, sequence), + Restrict = call(Pid, restriction), + Nodes = restrict_nodes(Restrict), #watchdog{parent = Pid, - transport = monitor(diameter_peer_fsm:start(T, Opts, Svc)), + transport = monitor(diameter_peer_fsm:start(T, + Opts, + {Mask, Nodes, Svc})), tw = proplists:get_value(watchdog_timer, Opts, ?DEFAULT_TW_INIT), - message_data = {RecvData, SvcName, Apps}}. + message_data = {RecvData, SvcName, Apps, Mask}, + sequence = Mask, + restrict = {Restrict, lists:member(node(), Nodes)}}. + +%% Retrieve the sequence mask from the parent from the parent, rather +%% than having it passed into init/1, for upgrade reasons: the call to +%% diameter_service:receive_message/3 passes back the mask. %% handle_call/3 @@ -137,7 +151,7 @@ handle_cast(_, State) -> %% handle_info/2 -handle_info(T, State) -> +handle_info(T, #watchdog{} = State) -> case transition(T, State) of ok -> {noreply, State}; @@ -148,7 +162,13 @@ handle_info(T, State) -> ?LOG(stop, T), event(State, State#watchdog{status = down}), {stop, {shutdown, T}, State} - end. + end; + +handle_info(T, S) -> + handle_info(T, upgrade(S)). + +upgrade(S) -> + #watchdog{} = list_to_tuple(tuple_to_list(S) ++ [?NOMASK, {nodes, true}]). event(#watchdog{status = T}, #watchdog{status = T}) -> ok; @@ -241,9 +261,10 @@ transition({close, TPid, _Reason}, #watchdog{transport = TPid}) -> transition({open, TPid, Hosts, T} = Open, #watchdog{transport = TPid, status = initial, - parent = Pid} + parent = Pid, + restrict = {_, R}} = S) -> - case okay(getr(restart), Hosts) of + case okay(getr(restart), Hosts, R) of okay -> open(Pid, {TPid, T}), set_watchdog(S#watchdog{status = okay}); @@ -258,12 +279,15 @@ transition({open, TPid, Hosts, T} = Open, transition({open = P, TPid, _Hosts, T}, #watchdog{transport = TPid, + parent = Pid, status = down} = S) -> %% Store the info we need to notify the parent to reopen the %% connection after the requisite DWA's are received, at which - %% time we eraser(open). + %% time we eraser(open). The reopen message is a later addition, + %% to communicate the new capabilities as soon as they're known. putr(P, {TPid, T}), + Pid ! {reopen, self(), {TPid, T}}, set_watchdog(send_watchdog(S#watchdog{status = reopen, num_dwa = 0})); @@ -312,6 +336,15 @@ transition({state, Pid}, #watchdog{status = S}) -> %% =========================================================================== +%% Only call "upwards", to the parent service. +call(Pid, Req) -> + try + gen_server:call(Pid, Req, infinity) + catch + exit: Reason -> + exit({shutdown, {Req, Reason}}) + end. + monitor(Pid) -> erlang:monitor(process, Pid), Pid. @@ -325,26 +358,36 @@ getr(Key) -> eraser(Key) -> erase({?MODULE, Key}). -%% encode/1 +%% encode/2 -encode(Msg) -> - #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg), +encode(Msg, Mask) -> + Seq = diameter_session:sequence(Mask), + Hdr = #diameter_header{version = ?DIAMETER_VERSION, + end_to_end_id = Seq, + hop_by_hop_id = Seq}, + Pkt = #diameter_packet{header = Hdr, + msg = Msg}, + #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Pkt), Bin. -%% okay/2 +%% okay/3 -okay({{accept, Ref}, _, _}, Hosts) -> +okay({{accept, Ref}, _, _}, Hosts, Restrict) -> T = {?MODULE, connection, Ref, Hosts}, diameter_reg:add(T), - okay(diameter_reg:match(T)); + if Restrict -> + okay(diameter_reg:match(T)); + true -> + okay + end; %% Register before matching so that at least one of two registering -%% processes will match the other. (Which can't happen as long as -%% diameter_peer_fsm guarantees at most one open connection to the same -%% peer.) +%% processes will match the other. -okay({{connect, _}, _, _}, _) -> +okay({{connect, _}, _, _}, _, _) -> okay. +%% okay/2 + %% The peer hasn't been connected recently ... okay([{_,P}]) -> P = self(), %% assert @@ -400,9 +443,10 @@ close(#watchdog{parent = Pid}) -> %% send_watchdog/1 send_watchdog(#watchdog{pending = false, - transport = TPid} + transport = TPid, + sequence = Mask} = S) -> - TPid ! {send, encode(getr(dwr))}, + TPid ! {send, encode(getr(dwr), Mask)}, ?LOG(send, 'DWR'), S#watchdog{pending = true}. @@ -555,7 +599,7 @@ timeout(#watchdog{status = T, = S) when T == suspect; T == reopen, P, N < 0 -> - exit(TPid, shutdown), + exit(TPid, {shutdown, watchdog_timeout}), close(S), S#watchdog{status = down}; @@ -600,19 +644,40 @@ restart(#watchdog{transport = undefined} = S) -> restart(S) -> S. +%% restart/2 +%% %% Only restart the transport in the connecting case. For an accepting -%% transport, we've registered the peer connection when leaving state -%% initial and this is used by a new accepting process to realize that -%% it's actually in state down rather then initial when receiving -%% notification of an open connection. - -restart({{connect, _} = T, Opts, Svc}, #watchdog{parent = Pid} = S) -> +%% transport, there's no guarantee that an accepted connection in a +%% restarted transport if from the peer we've lost contact with so +%% have to be prepared for another watchdog to handle it. This is what +%% the diameter_reg registration in this module is for: the peer +%% connection is registered when leaving state initial and this is +%% used by a new accepting watchdog to realize that it's actually in +%% state down rather then initial when receiving notification of an +%% open connection. + +restart({{connect, _} = T, Opts, Svc}, #watchdog{parent = Pid, + sequence = Mask, + restrict = {R,_}} + = S) -> Pid ! {reconnect, self()}, - S#watchdog{transport = monitor(diameter_peer_fsm:start(T, Opts, Svc))}; + Nodes = restrict_nodes(R), + S#watchdog{transport = monitor(diameter_peer_fsm:start(T, + Opts, + {Mask, Nodes, Svc})), + restrict = {R, lists:member(node(), Nodes)}}; + +%% No restriction on the number of connections to the same peer: just +%% die. Note that a state machine never enters state REOPEN in this +%% case. +restart({{accept, _}, _, _}, #watchdog{restrict = {_, false}}) -> + stop; + +%% Otherwise hang around until told to die. restart({{accept, _}, _, _}, S) -> S. -%% Don't currently use Opts/Svc in the accept case but having them in -%% the process dictionary is helpful if the process dies unexpectedly. + +%% Don't currently use Opts/Svc in the accept case. %% dwr/1 @@ -622,3 +687,22 @@ dwr(#diameter_caps{origin_host = OH, ['DWR', {'Origin-Host', OH}, {'Origin-Realm', OR}, {'Origin-State-Id', OSI}]. + +%% restrict_nodes/1 + +restrict_nodes(false) -> + []; + +restrict_nodes(nodes) -> + [node() | nodes()]; + +restrict_nodes(node) -> + [node()]; + +restrict_nodes(Nodes) + when [] == Nodes; + is_atom(hd(Nodes)) -> + Nodes; + +restrict_nodes(F) -> + diameter_lib:eval(F). diff --git a/lib/diameter/test/Makefile b/lib/diameter/test/Makefile index e3a57553c1..866d135bd9 100644 --- a/lib/diameter/test/Makefile +++ b/lib/diameter/test/Makefile @@ -16,13 +16,8 @@ # # %CopyrightEnd% -ifeq ($(ERL_TOP),) -include $(DIAMETER_TOP)/make/target.mk -include $(DIAMETER_TOP)/make/$(TARGET)/rules.mk -else include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk -endif # ---------------------------------------------------- # Application version @@ -148,11 +143,7 @@ log: /%: % force sed -f release.sed $< > "$(RELSYSDIR)$@" -ifeq ($(ERL_TOP),) -include $(DIAMETER_TOP)/make/release_targets.mk -else include $(ERL_TOP)/make/otp_release_targets.mk -endif release_spec release_docs_spec: diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl index 669918f757..5744ff0307 100644 --- a/lib/diameter/test/diameter_traffic_SUITE.erl +++ b/lib/diameter/test/diameter_traffic_SUITE.erl @@ -81,11 +81,11 @@ %% diameter callbacks -export([peer_up/3, peer_down/3, - pick_peer/5, pick_peer/6, - prepare_request/4, prepare_request/5, - prepare_retransmit/4, - handle_answer/5, handle_answer/6, - handle_error/5, + pick_peer/6, pick_peer/7, + prepare_request/5, prepare_request/6, + prepare_retransmit/5, + handle_answer/6, handle_answer/7, + handle_error/6, handle_request/3]). -include("diameter.hrl"). @@ -108,10 +108,16 @@ -define(BASE, ?DIAMETER_DICT_COMMON). -define(ACCT, ?DIAMETER_DICT_ACCOUNTING). +%% Sequence mask for End-to-End and Hop-by-Hop identifiers. +-define(CLIENT_MASK, {1,26}). %% 1 in top 6 bits + %% Run tests cases in different encoding variants. Send outgoing %% messages as lists or records. -define(ENCODINGS, [list, record]). +%% Identifers for client connections. +-define(CONNECTIONS, [c1,c2,c3]). + %% Not really what we should be setting unless the message is sent in %% the common application but diameter doesn't care. -define(APP_ID, ?DIAMETER_APP_ID_COMMON). @@ -124,7 +130,8 @@ {'Vendor-Id', 12345}, {'Product-Name', "OTP/diameter"}, {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, - {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]} + {'Acct-Application-Id', [?DIAMETER_APP_ID_ACCOUNTING]}, + {restrict_connections, false} | [{application, [{dictionary, D}, {module, ?MODULE}, {answer_errors, callback}]} @@ -175,12 +182,14 @@ suite() -> all() -> [start, start_services, add_transports, result_codes] - ++ [{group, name([E]), P} || E <- ?ENCODINGS, P <- [[], [parallel]]] + ++ [{group, name([E,C]), P} || E <- ?ENCODINGS, + C <- ?CONNECTIONS, + P <- [[], [parallel]]] ++ [remove_transports, stop_services, stop]. groups() -> Ts = tc(), - [{name([E]), [], Ts} || E <- ?ENCODINGS]. + [{name([E,C]), [], Ts} || E <- ?ENCODINGS, C <- ?CONNECTIONS]. init_per_group(Name, Config) -> [{group, Name} | Config]. @@ -244,16 +253,17 @@ start(_Config) -> start_services(_Config) -> ok = diameter:start_service(?SERVER, ?SERVICE(?SERVER)), - ok = diameter:start_service(?CLIENT, ?SERVICE(?CLIENT)). + ok = diameter:start_service(?CLIENT, [{sequence, ?CLIENT_MASK} + | ?SERVICE(?CLIENT)]). add_transports(Config) -> LRef = ?util:listen(?SERVER, tcp, [{capabilities_cb, fun capx/2}]), - CRef = ?util:connect(?CLIENT, tcp, LRef), - ?util:write_priv(Config, "transport", {LRef, CRef}). + Cs = [?util:connect(?CLIENT, tcp, LRef, [{id, C}]) || C <- ?CONNECTIONS], + ?util:write_priv(Config, "transport", [LRef | Cs]). remove_transports(Config) -> - {LRef, CRef} = ?util:read_priv(Config, "transport"), - ?util:disconnect(?CLIENT, CRef, ?SERVER, LRef). + [LRef | Cs] = ?util:read_priv(Config, "transport"), + [?util:disconnect(?CLIENT, C, ?SERVER, LRef) || C <- Cs]. stop_services(_Config) -> ok = diameter:stop_service(?CLIENT), @@ -539,11 +549,11 @@ call(Config, Req) -> call(Config, Req, Opts) -> Name = proplists:get_value(testcase, Config), - [Enc] = name(proplists:get_value(group, Config)), + [Encoding, Client] = name(proplists:get_value(group, Config)), diameter:call(?CLIENT, dict(Req), - req(Req, Enc), - [{extra, [Name]} | Opts]). + req(Req, Encoding), + [{extra, [Name, Client]} | Opts]). req(['ACR' = H | T], record) -> ?ACCT:'#new-'(?ACCT:msg2rec(H), T); @@ -580,7 +590,7 @@ set(_, _, _, Rec) -> Rec. %% Contruct and deconstruct names to work around group names being -%% restricted to atoms. (Not really used yet.) +%% restricted to atoms. name(Names) when is_list(Names) -> @@ -603,28 +613,40 @@ peer_up(_SvcName, _Peer, State) -> peer_down(_SvcName, _Peer, State) -> State. -%% pick_peer/5/6 +%% pick_peer/6-7 -pick_peer([Peer], _, ?CLIENT, _State, Name) +pick_peer(Peers, _, ?CLIENT, _State, Name, Id) when Name /= send_detach -> - {ok, Peer}. + find(Id, Peers). -pick_peer([_Peer], _, ?CLIENT, _State, send_nopeer, ?EXTRA) -> +pick_peer(_Peers, _, ?CLIENT, _State, send_nopeer, _, ?EXTRA) -> false; -pick_peer([Peer], _, ?CLIENT, _State, send_detach, {_,_}) -> - {ok, Peer}. +pick_peer(Peers, _, ?CLIENT, _State, send_detach, Id, {_,_}) -> + find(Id, Peers). + +find(Id, Peers) -> + [P] = [P || P <- Peers, id(Id, P)], + {ok, P}. -%% prepare_request/4/5 +id(Id, {Pid, _Caps}) -> + [{ref, _}, {type, _}, {options, Opts} | _] + = diameter:service_info(?CLIENT, Pid), + lists:member({id, Id}, Opts). -prepare_request(_Pkt, ?CLIENT, {_Ref, _Caps}, send_discard) -> +%% prepare_request/5-6 + +prepare_request(_Pkt, ?CLIENT, {_Ref, _Caps}, send_discard, _) -> {discard, unprepared}; -prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Name) -> +prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, Name, _) -> {send, prepare(Pkt, Caps, Name)}. -prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, send_detach, _) -> - {send, prepare(Pkt, Caps)}. +prepare_request(Pkt, ?CLIENT, {_Ref, Caps}, send_detach, _, _) -> + {eval_packet, {send, prepare(Pkt, Caps)}, [fun log/2, detach]}. + +log(#diameter_packet{} = P, T) -> + io:format("~p: ~p~n", [T,P]). prepare(Pkt, Caps, send_unsupported) -> Req = prepare(Pkt, Caps), @@ -707,25 +729,25 @@ prepare(#diameter_packet{msg = Req}, Caps) {'Destination-Realm', DR}, {'Auth-Application-Id', ?APP_ID}]). -%% prepare_retransmit/4 +%% prepare_retransmit/5 -prepare_retransmit(_Pkt, false, _Peer, _Name) -> +prepare_retransmit(_Pkt, false, _Peer, _Name, _Id) -> discard. -%% handle_answer/5/6 +%% handle_answer/6-7 -handle_answer(Pkt, Req, ?CLIENT, Peer, Name) -> +handle_answer(Pkt, Req, ?CLIENT, Peer, Name, _Id) -> answer(Pkt, Req, Peer, Name). -handle_answer(Pkt, _Req, ?CLIENT, _Peer, send_detach, {Pid, Ref}) -> +handle_answer(Pkt, _Req, ?CLIENT, _Peer, send_detach, _Id, {Pid, Ref}) -> Pid ! {Ref, Pkt}. answer(#diameter_packet{msg = Rec, errors = []}, _Req, _Peer, _) -> Rec. -%% handle_error/5 +%% handle_error/6 -handle_error(Reason, _Req, ?CLIENT, _Peer, _Name) -> +handle_error(Reason, _Req, ?CLIENT, _Peer, _Name, _Id) -> {error, Reason}. %% handle_request/3 @@ -733,12 +755,18 @@ handle_error(Reason, _Req, ?CLIENT, _Peer, _Name) -> %% Note that diameter will set Result-Code and Failed-AVPs if %% #diameter_packet.errors is non-null. -handle_request(#diameter_packet{msg = M}, ?SERVER, {_Ref, Caps}) -> +handle_request(#diameter_packet{header = H, msg = M}, ?SERVER, {_Ref, Caps}) -> + #diameter_header{end_to_end_id = EI, + hop_by_hop_id = HI} + = H, + {V,B} = ?CLIENT_MASK, + V = EI bsr B, %% assert + V = HI bsr B, %% request(M, Caps). request(#diameter_base_accounting_ACR{'Accounting-Record-Number' = 0}, _) -> - {protocol_error, ?INVALID_AVP_BITS}; + {eval_packet, {protocol_error, ?INVALID_AVP_BITS}, [fun log/2, invalid]}; request(#diameter_base_accounting_ACR{'Session-Id' = SId, 'Accounting-Record-Type' = RT, diff --git a/lib/diameter/test/diameter_watchdog_SUITE.erl b/lib/diameter/test/diameter_watchdog_SUITE.erl index ff40326947..7ce09e93ca 100644 --- a/lib/diameter/test/diameter_watchdog_SUITE.erl +++ b/lib/diameter/test/diameter_watchdog_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2012. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -30,11 +30,21 @@ end_per_suite/1]). %% testcases --export([reopen/1, reopen/4]). +-export([reopen/1, reopen/4, reopen/7]). --export([start/3, %% diameter_transport callback - id/1, %% jitter callback - run/1]). +-export([id/1, %% jitter callback + run1/1]). + +%% diameter_app callbacks +-export([peer_up/3, + peer_down/3]). + +%% gen_tcp-ish interface +-export([listen/2, + accept/1, + connect/3, + send/2, + setopts/2]). -include("diameter.hrl"). -include("diameter_ct.hrl"). @@ -43,33 +53,21 @@ -define(util, diameter_util). --define(BASE, diameter_gen_base_rfc3588). --define(APPL_ID, diameter_gen_base_rfc3588:id()). --define(SUCCESS, 2001). %% DIAMETER_SUCCESS - -%% Addresses for the local and remote diameter nodes. The values don't -%% matter since we're faking transport. --define(LOCALHOST, {127,0,0,1}). --define(REMOTEHOST, {10,0,0,1}). - --define(CAPS, #diameter_caps{origin_host = "node.innan.com", - origin_realm = "innan.com", - host_ip_address = [?LOCALHOST], - vendor_id = 1022, - product_name = "remote", - auth_application_id = [?APPL_ID]}). - --define(APPL, #diameter_app{alias = ?MODULE, - dictionary = ?BASE, - module = [?MODULE], - init_state = now(), - id = ?APPL_ID, - mutable = false}). - -%% Service record maintained by our faked service process. --define(SERVICE, #diameter_service{pid = self(), - capabilities = ?CAPS, - applications = [?APPL]}). +-define(BASE, ?DIAMETER_DICT_COMMON). +-define(REALM, "erlang.org"). +-define(ADDR, {127,0,0,1}). + +%% Config for diameter:start_service/2. +-define(SERVICE(Name), + [{'Origin-Host', Name ++ "." ++ ?REALM}, + {'Origin-Realm', ?REALM}, + {'Host-IP-Address', [?ADDR]}, + {'Vendor-Id', 42}, + {'Product-Name', "OTP/diameter"}, + {'Auth-Application-Id', [?DIAMETER_APP_ID_COMMON]}, + {application, [{alias, Name}, + {dictionary, ?BASE}, + {module, ?MODULE}]}]). %% Watchdog timer as a callback. -define(WD(T), {?MODULE, id, [T]}). @@ -82,28 +80,28 @@ F_ <- [fun(T__) -> T__ end, fun(T__) -> ?WD(T__) end]]]). -%% Transport types. --define(TRANSPORTS, [connect, accept]). +%% Watchdog timer of the misbehaving peer. +-define(PEER_WD, 10000). -%% Message over the transport interface. --define(TMSG(T), {diameter, T}). - -%% Receive a message within a specified time. --define(RECV(T, Timeout), - receive T -> now() - after Timeout -> ?ERROR({timeout, Timeout}) +%% Receive a watchdog event within a specified time. +-define(EVENT(T, Tmo), + receive #diameter_event{info = T} -> now() + after Tmo -> ?ERROR({timeout, Tmo}) end). -%% Receive a message in a given number of watchdogs, plus or minus +%% Receive an event in a given number of watchdogs, plus or minus %% half. Note that the call to now_diff assumes left to right %% evaluation order. --define(RECV(T, N, WdL, WdH), +-define(EVENT(T, N, WdL, WdH), [?ERROR({received, _Elapsed_, _LowerBound_, N, WdL}) || _UpperBound_ <- [(N)*(WdH) + (WdH) div 2], - _Elapsed_ <- [now_diff(now(), ?RECV(T, _UpperBound_))], + _Elapsed_ <- [now_diff(now(), ?EVENT(T, _UpperBound_))], _LowerBound_ <- [(N)*(WdL) - (WdL) div 2], _Elapsed_ =< _LowerBound_*1000]). +-define(EVENT(T, N, Wd), + ?EVENT(T, N, Wd, Wd)). + %% A timeout that ensures one watchdog. The ensure only one watchdog %% requires (Wd + 2000) + 1000 < 2*(Wd - 2000) ==> 7000 < Wd for the %% case with random jitter. @@ -112,7 +110,7 @@ %% =========================================================================== suite() -> - [{timetrap, {minutes, 6}}].%% enough for 11 watchdogs @ 30 sec plus jitter + [{timetrap, {minutes, 10}}].%% enough for 17 watchdogs @ 30 sec plus jitter all() -> [reopen]. @@ -134,52 +132,97 @@ end_per_suite(_Config) -> %% implement a transport process that plays the role of the peer %% Diameter node. +%reopen(_) -> +% reopen(connect, ?WD(10000), 1, 'DWR'); + reopen(_) -> - [] = ?util:run([{?MODULE, [run, [reopen, Wd, T, N, M]]} - || Wd <- ?WD_TIMERS, - T <- ?TRANSPORTS, - N <- [0,1,2], - M <- ['DWR', 'DWA', other]]). + [] = run([[reopen, T, Wd, N, M] + || Wd <- ?WD_TIMERS, %% watchdog_timer value + T <- [listen, connect], %% watchdog to test + N <- [0,1,2], %% DWR's to answer before ignoring + M <- ['DWR', 'DWA', 'RAA']]). %% how to induce failback -reopen(Wd, Type, N, What) -> - Ref = make_ref(), +reopen(Type, Wd, N, M) -> + Server = start_service(), + Client = start_service(), - %% The maker of transport processes. - TPid = start({N, Wd, What, Ref}), + %% The peer to the transport whose watchdog is tested is given a + %% long watchdog timeout so that it doesn't send DWR of its own. + {Node, Peer} = {{[], Wd}, {[{module, ?MODULE}], ?WD(?PEER_WD)}}, - %% Act like diameter_service and start the watchdog process, which - %% in turn starts a peer_fsm process, which in turn starts a - %% transport process by way of start/3. Messages received by the - %% testcase are those sent by diameter_watchdog to the service - %% process (= process starting the watchdog). - WPid1 = watchdog(Type, Ref, TPid, Wd), + {{LH,LW},{CH,CW}} = case Type of + listen -> {Node, Peer}; + connect -> {Peer, Node} + end, - %% Low/high watchdog timeouts. - WdL = jitter(Wd, -2000), - WdH = jitter(Wd, 2000), + LO = [{transport_module, diameter_tcp}, + {transport_config, LH ++ [{ip, ?ADDR}, {port, 0}]}, + {watchdog_timer, LW}], + + {ok, LRef} = diameter:add_transport(Server, {listen, LO}), + + [LP] = ?util:lport(tcp, LRef, 20), + + CO = [{transport_module, diameter_tcp}, + {transport_config, CH ++ [{ip, ?ADDR}, {port, 0}, + {raddr, ?ADDR}, {rport, LP}]}, + {watchdog_timer, CW}], + + %% Use a temporary process to ensure the connecting transport is + %% added only once events from the listening transport are + %% subscribed to. + Pid = spawn(fun() -> receive _ -> ok end end), + + [] = run([[reopen, Type, T, LRef, Pid, Wd, N, M] + || T <- [{listen, Server}, {connect, Client, CO}]]). + +%% start_service/1 + +start_service() -> + Name = hostname(), + ok = diameter:start_service(Name, [{monitor, self()} | ?SERVICE(Name)]), + Name. + +%% reopen/7 +reopen(Type, {listen = T, SvcName}, Ref, Pid, Wd, N, M) -> + diameter:subscribe(SvcName), + Pid ! ok, + recv(Type, T, SvcName, Ref, Wd, N, M); + +reopen(Type, {connect = T, SvcName, Opts}, _, Pid, Wd, N, M) -> + diameter:subscribe(SvcName), + MRef = erlang:monitor(process, Pid), + receive {'DOWN', MRef, process, _, _} -> ok end, + {ok, Ref} = diameter:add_transport(SvcName, {T, Opts}), + recv(Type, T, SvcName, Ref, Wd, N, M). + +%% recv/7 + +%% The watchdog to be tested. +recv(Type, Type, _SvcName, Ref, Wd, N, M) -> %% Connection should come up immediately as a consequence of %% starting the watchdog process. In the accepting case this %% results in a new watchdog on a transport waiting for a new %% connection. - ?RECV({connection_up, WPid1, _}, 1000), - WPid2 = case Type of - connect -> - WPid1; - accept -> - watchdog(Type, Ref, TPid, Wd) - end, + ?EVENT({watchdog, Ref, _, {initial, okay}, _}, 2000), + ?EVENT({up, Ref, _, _, #diameter_packet{}}, 0), + + %% Low/high watchdog timeouts. + WdL = jitter(Wd, -2000), + WdH = jitter(Wd, 2000), %% OKAY Timer expires & Failover() %% Pending SetWatchdog() SUSPECT %% - %% Since our transport is replying to N DWR's before becoming - %% silent, we should go down after N+2 watchdog_timer expirations: - %% that is, after the first unanswered DWR. Knowing the min/max - %% watchdog timeout values gives the time interval in which the - %% down message is expected. - ?RECV({connection_down, WPid1}, N+2, WdL, WdH), + %% The peer replies to N DWR's before becoming silent, we should + %% go down after N+2 watchdog_timer expirations: that is, after + %% the first unanswered DWR. Knowing the min/max watchdog timeout + %% values gives the time interval in which the event is expected. + + ?EVENT({watchdog, Ref, _, {okay, suspect}, _}, N+2, WdL, WdH), + ?EVENT({down, Ref, _, _}, 0), %% SUSPECT Receive DWA Pending = FALSE %% Failback() @@ -188,9 +231,11 @@ reopen(Wd, Type, N, What) -> %% SUSPECT Receive non-DWA Failback() %% SetWatchdog() OKAY %% - %% The transport receives a message before the expiry of another - %% watchdog to induce failback. - ?RECV({connection_up, WPid1}, WdH), + %% The peer sends a message before the expiry of another watchdog + %% to induce failback. + + ?EVENT({watchdog, Ref, _, {suspect, okay}, _}, WdH + 2000), + ?EVENT({up, Ref, _, _}, 0), %% OKAY Timer expires & SendWatchdog() %% !Pending SetWatchdog() @@ -199,30 +244,35 @@ reopen(Wd, Type, N, What) -> %% OKAY Timer expires & Failover() %% Pending SetWatchdog() SUSPECT %% - %% The transport is still not responding to watchdogs so the - %% connection should go back down after either one or two watchdog - %% expiries, depending on whether or not DWA restored the connection. - F = choose(What == 'DWA', 2, 1), - ?RECV({connection_down, WPid1}, F, WdL, WdH), + %% The peer is now ignoring all watchdogs so the connection goes + %% back down after either one or two watchdog expiries, depending + %% on whether or not DWA restored the connection. + + F = choose(M == 'DWA', 2, 1), + ?EVENT({watchdog, Ref, _, {okay, suspect}, _}, F, WdL, WdH), + ?EVENT({down, Ref, _, _}, 0), %% SUSPECT Timer expires CloseConnection() %% SetWatchdog() DOWN %% + %% Non-response brings the connection down after another timeout. + + ?EVENT({watchdog, Ref, _, {suspect, down}, _}, 1, WdL, WdH), + %% DOWN Timer expires AttemptOpen() %% SetWatchdog() DOWN %% - %% Our transport tells us when the fake connection is - %% reestablished, which should happen after another couple of - %% watchdog expiries, the first bringing the watchdog to state - %% DOWN, the second triggering an attempt to reopen the - %% connection. - ?RECV({reopen, Ref}, 2, WdL, WdH), - %% DOWN Connection up NumDWA = 0 %% SendWatchdog() %% SetWatchdog() %% Pending = TRUE REOPEN %% + %% The connection is reestablished after another timeout. + + recv_reopen(Type, Ref, WdL, WdH), + + %% REOPEN Receive non-DWA Throwaway() REOPEN + %% %% REOPEN Receive DWA & Pending = FALSE %% NumDWA < 2 NumDWA++ REOPEN %% @@ -230,312 +280,259 @@ reopen(Wd, Type, N, What) -> %% NumDWA == 2 NumDWA++ %% Failback() OKAY %% - %% Now the watchdog should require three received DWA's before - %% taking the connection back up. The first DWR is sent directly - %% after capabilities exchange so it should take no more than two - %% watchdog expiries. - ?RECV({connection_up, WPid2, _}, 2, WdL, WdH). + %% REOPEN Timer expires & SendWatchdog() + %% !Pending SetWatchdog() + %% Pending = TRUE REOPEN + %% + %% An exchange of 3 watchdogs (the first directly after + %% capabilities exchange) brings the connection back up. -%% =========================================================================== + ?EVENT({watchdog, Ref, _, {reopen, okay}, _}, 2, WdL, WdH), + ?EVENT({up, Ref, _, _, #diameter_packet{}}, 0), -%% Start the fake transport process. From diameter's point of view -%% it's started when diameter calls start/3. We start it before this -%% happens since we use the same fake transport each time diameter -%% calls start/3. The process lives and dies with the test case. -start(Config) -> - Pid = self(), - spawn(fun() -> loop(init(Pid, Config)) end). - -%% Transport start from diameter. This may be called multiple times -%% depending on the testcase. -start({Type, _Ref}, #diameter_service{}, Pid) -> - Ref = make_ref(), - MRef = erlang:monitor(process, Pid), - Pid ! {start, self(), Type, Ref}, - {Ref, TPid} = receive - {Ref, _} = T -> - T; - {'DOWN', MRef, process, _, _} = T -> - T - end, - erlang:demonitor(MRef, [flush]), - {ok, TPid}. + %% Non-response brings it down again. -%% id/1 + ?EVENT({watchdog, Ref, _, {okay, suspect}, _}, 2, WdL, WdH), + ?EVENT({down, Ref, _, _}, 0), + ?EVENT({watchdog, Ref, _, {suspect, down}, _}, 1, WdL, WdH), -id(T) -> - T. + %% Reestablish after another watchdog. -%% =========================================================================== + recv_reopen(Type, Ref, WdL, WdH), -choose(true, X, _) -> X; -choose(false, _, X) -> X. + %% REOPEN Timer expires & NumDWA = -1 + %% Pending & SetWatchdog() + %% NumDWA >= 0 REOPEN + %% + %% REOPEN Timer expires & CloseConnection() + %% Pending & SetWatchdog() + %% NumDWA < 0 DOWN + %% + %% Peer is now ignoring all watchdogs go down again after 2 + %% timeouts. -%% run/1 -%% -%% A more useful badmatch in case of failure. + ?EVENT({watchdog, Ref, _, {reopen, down}, _}, 2, WdL, WdH); -run([F|A]) -> - ok = try - apply(?MODULE, F, A), - ok - catch - E:R -> - {A, E, R, erlang:get_stacktrace()} - end. +%% The misbehaving peer. +recv(_, Type, SvcName, Ref, Wd, N, M) -> + %% First transport process. + ?EVENT({watchdog, Ref, _, {initial, okay}, _}, 1000), + ?EVENT({up, Ref, _, _, #diameter_packet{}}, 0), + reg(Type, Ref, SvcName, {SvcName, {Wd,N,M}}), + ?EVENT({watchdog, Ref, _, {okay, down}, _}, infinity), -%% now_diff/2 + %% Second transport process. + ?EVENT({watchdog, Ref, _, {_, reopen}, _}, infinity), + reg(Type, Ref, SvcName, 3), + ?EVENT({watchdog, Ref, _, {_, down}, _}, infinity), -now_diff(T1, T2) -> - timer:now_diff(T2, T1). + %% Third transport process. + ?EVENT({watchdog, Ref, _, {_, reopen}, _}, infinity), + reg(Type, Ref, SvcName, 0), + ?EVENT({watchdog, Ref, _, {_, down}, _}, infinity), -%% jitter/2 + ok. -jitter(?WD(T), _) -> - T; -jitter(T,D) -> - T+D. +%% recv_reopen/4 -%% watchdog/4 -%% -%% Fake the call from diameter_service. The watchdog process will send -%% messages to the calling "service" process so our tests are that the -%% watchdog responds as expected. - -watchdog(Type, Ref, TPid, Wd) -> - Opts = [{transport_module, ?MODULE}, - {transport_config, TPid}, - {watchdog_timer, Wd}], - {_MRef, Pid} = diameter_watchdog:start({Type, Ref}, - {false, Opts, false, ?SERVICE}), - Pid. +recv_reopen(connect, Ref, WdL, WdH) -> + ?EVENT({watchdog, Ref, _, {_, reopen}, _}, 1, WdL, WdH), + ?EVENT({reconnect, Ref, _}, 0); -%% =========================================================================== +recv_reopen(listen, Ref, _, _) -> + ?EVENT({watchdog, Ref, _, {_, reopen}, _}, 1, ?PEER_WD). -%% Transport process implmentation. Fakes reception of messages by -%% sending fakes to the parent (peer fsm) process that called start/3. - --record(transport, - {type, %% connect | accept | manager - parent, %% pid() of peer_fsm/ervice process - open = false, %% done with capabilities exchange? - config}).%% testcase-specific config - -%% init/2 - -%% Testcase starting the manager. -init(SvcPid, {_,_,_,_} = Config) -> - putr(peer, [{'Origin-Host', hostname() ++ ".utan.com"}, - {'Origin-Realm', "utan.com"}]), - #transport{type = manager, - parent = monitor(SvcPid), - config = Config}; - -%% Manager starting a transport. -init(_, {Type, ParentPid, SvcPid, TwinPid, Peer, {N,_,_,_} = Config}) -> - putr(peer, Peer), - putr(service, SvcPid), - putr(count, init(Type, ParentPid, TwinPid, N)),%% number of DWR's to answer - #transport{type = Type, - parent = monitor(ParentPid), - config = Config}. - -init(Type, ParentPid, undefined, N) -> - connected(ParentPid, Type), - N; -init(_, _, TPid, _) -> - monitor(TPid), - 3. - -monitor(Pid) -> - erlang:monitor(process, Pid), - Pid. +%% reg/4 +%% +%% Lookup the pid of the transport process and publish a term for +%% send/2 to lookup. +reg(Type, Ref, SvcName, T) -> + TPid = tpid(Type, Ref, diameter:service_info(SvcName, transport)), + true = diameter_reg:add_new({?MODULE, TPid, T}). + +%% tpid/3 + +tpid(connect, Ref, [[{ref, Ref}, + {type, connect}, + {options, _}, + {watchdog, _}, + {peer, _}, + {apps, _}, + {caps, _}, + {port, [{owner, TPid} | _]} + | _]]) -> + TPid; + +tpid(listen, Ref, [[{ref, Ref}, + {type, listen}, + {options, _}, + {accept, As} + | _]]) -> + [[{watchdog, _}, + {peer, _}, + {apps, _}, + {caps, _}, + {port, [{owner, TPid} | _]} + | _]] + = lists:filter(fun([{watchdog, {_,_,S}} | _]) -> + S == okay orelse S == reopen + end, + As), + TPid. -%% Generate a unique hostname for the faked peer. -hostname() -> - lists:flatten(io_lib:format("~p-~p-~p", tuple_to_list(now()))). +%% =========================================================================== -%% loop/1 - -loop(S) -> - loop(msg(receive T -> T end, S)). - -msg(T,S) -> - case transition(T,S) of - ok -> - S; - #transport{} = NS -> - NS; - {stop, Reason} -> - x(Reason) - end. - -x(Reason) -> - exit(Reason). - -%% transition/2 - -%% Manager is being asked for a new transport process. -transition({start, Pid, Type, Ref}, #transport{type = manager, - parent = SvcPid, - config = Config}) -> - TPid = start({Type, Pid, SvcPid, getr(transport), getr(peer), Config}), - Pid ! {Ref, TPid}, - putr(transport, TPid), +listen(PortNr, Opts) -> + gen_tcp:listen(PortNr, Opts). + +accept(LSock) -> + gen_tcp:accept(LSock). + +connect(Addr, Port, Opts) -> + gen_tcp:connect(Addr, Port, Opts). + +setopts(Sock, Opts) -> + inet:setopts(Sock, Opts). + +send(Sock, Bin) -> + send(getr(config), Sock, Bin). + +%% send/3 + +%% First outgoing message from a new transport process is CER/CEA. +%% Remaining outgoing messages are either DWR or DWA. +send(undefined, Sock, Bin) -> + putr(config, init), + gen_tcp:send(Sock, Bin); + +%% Outgoing DWR: fake reception of DWA. Use the fact that AVP values +%% are ignored. This is to ensure that the peer's watchdog state +%% transitions are only induced by responses to messages it sends. +send(_, Sock, <<_:32, 1:1, _:7, 280:24, _:32, EId:32, HId:32, _/binary>>) -> + Pkt = #diameter_packet{header = #diameter_header{version = 1, + end_to_end_id = EId, + hop_by_hop_id = HId}, + msg = ['DWA', {'Result-Code', 2001}, + {'Origin-Host', "XXX"}, + {'Origin-Realm', ?REALM}]}, + #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Pkt), + self() ! {tcp, Sock, Bin}, ok; -%% Peer fsm or testcase process has died. -transition({'DOWN', _, process, Pid, _} = T, #transport{parent = Pid}) -> - {stop, T}; - -%% Twin transport process has gone down. In the connect case, the -%% transport isn't started until this happens in the first place so -%% connect immediately. In the accept case, fake the peer reconnecting -%% only after another watchdog expiry. -transition({'DOWN', _, process, _, _}, #transport{type = Type, - config = {_, Wd, _, _}}) -> - Tmo = case Type of - connect -> - 0; - accept -> - ?ONE_WD(Wd) - end, - erlang:send_after(Tmo, self(), reconnect), +%% First outgoing DWA. +send(init, Sock, Bin) -> + [{{?MODULE, _, T}, _}] = diameter_reg:wait({?MODULE, self(), '_'}), + putr(config, T), + send(Sock, Bin); + +%% First transport process. +send({SvcName, {_,_,_} = T}, Sock, Bin) -> + [{'Origin-Host', _} = OH, {'Origin-Realm', _} = OR | _] + = ?SERVICE(SvcName), + putr(origin, [OH, OR]), + putr(config, T), + send(Sock, Bin); + +%% Discard DWA, failback after another timeout in the peer. +send({Wd, 0 = No, Msg}, Sock, Bin) -> + Origin = getr(origin), + spawn(fun() -> failback(?ONE_WD(Wd), Msg, Sock, Bin, Origin) end), + putr(config, No), ok; -transition(reconnect, #transport{type = Type, - parent = Pid, - config = {_,_,_,Ref}}) -> - getr(service) ! {reopen, Ref}, - connected(Pid, Type), - ok; +%% Send DWA while we're in the mood (aka 0 < N). +send({Wd, N, Msg}, Sock, Bin) -> + putr(config, {Wd, N-1, Msg}), + gen_tcp:send(Sock, Bin); -%% Peer fsm process is sending CER: fake the peer's CEA. -transition(?TMSG({send, Bin}), #transport{type = connect, - open = false, - parent = Pid} - = S) -> - {Code, Flags, _} = ?BASE:msg_header('CER'), - <<_:32, Flags:8, Code:24, _:96, _/binary>> = Bin, - Hdr = make_header(Bin), - recv(Pid, {Hdr, make_cea()}), - S#transport{open = true}; - -%% Peer fsm process is sending CEA. -transition(?TMSG({send, Bin}), #transport{type = accept, - open = false} - = S) -> - {Code, Flags, _} = ?BASE:msg_header('CEA'), - <<_:32, Flags:8, Code:24, _:96, _/binary>> = Bin, - S#transport{open = true}; - -%% Watchdog is sending DWR or DWA. -transition(?TMSG({send, Bin}), #transport{open = true} = S) -> - {Code, _, _} = ?BASE:msg_header('DWR'), - {Code, _, _} = ?BASE:msg_header('DWA'), - <<_:32, R:1, 0:7, Code:24, _:96, _/binary>> = Bin, - Hdr = make_header(Bin), - dwa(1 == R, S, Hdr), +%% Discard DWA. +send(0, _Sock, _Bin) -> ok; -%% We're telling ourselves to fake a received message. -transition({recv, Msg}, #transport{parent = Pid}) -> - recv(Pid, Msg), - ok; +%% Send DWA. +send(N, Sock, <<_:32, 0:1, _:7, 280:24, _/binary>> = Bin) -> + putr(config, N-1), + gen_tcp:send(Sock, Bin). -%% We're telling ourselves to receive a message to induce failback. -transition(failback = T, #transport{parent = Pid}) -> - recv(Pid, eraser(T)), - ok. +failback(Tmo, Msg, Sock, Bin, Origin) -> + timer:sleep(Tmo), + ok = gen_tcp:send(Sock, msg(Msg, Bin, Origin)). -make_header(Bin) -> - #diameter_header{end_to_end_id = E, - hop_by_hop_id = H} - = diameter_codec:decode_header(Bin), - #diameter_header{end_to_end_id = E, - hop_by_hop_id = H}. - -recv(Pid, Msg) -> - Pid ! ?TMSG({recv, encode(Msg)}). - -%% Replace the end-to-end/hop-by-hop identifiers with those from an -%% incoming request to which we're constructing a reply. -encode({Hdr, [_|_] = Msg}) -> - #diameter_header{hop_by_hop_id = HBH, - end_to_end_id = E2E} - = Hdr, - #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg), - <<H:12/binary, _:64, T/binary>> = Bin, - <<H/binary, HBH:32, E2E:32, T/binary>>; - -encode([_|_] = Msg) -> - #diameter_packet{bin = Bin} = diameter_codec:encode(?BASE, Msg), +%% msg/2 + +msg('DWA', Bin, _Origin) -> + Bin; +msg(Msg, _Bin, Origin) -> + #diameter_packet{bin = Bin} + = diameter_codec:encode(?BASE, msg(Msg, Origin)), Bin. -connected(Pid, connect) -> - Pid ! ?TMSG({self(), connected, make_ref()}); -connected(Pid, accept) -> - Pid ! ?TMSG({self(), connected}), - recv(Pid, make_cer()). +msg('DWR' = M, T) -> + [M | T]; -make_cer() -> - ['CER' | getr(peer)] ++ [{'Host-IP-Address', [?REMOTEHOST]}, - {'Vendor-Id', 1028}, - {'Product-Name', "Utan"}, - {'Auth-Application-Id', [?APPL_ID]}]. +msg('RAA', T) -> + ['RAA', {'Session-Id', diameter:session_id("abc")}, + {'Result-Code', 2001} + | T]. +%% An unexpected answer is discarded after passing through the +%% watchdog state machine. -make_cea() -> - ['CER' | Rest] = make_cer(), - ['CEA', {'Result-Code', ?SUCCESS} | Rest]. +%% =========================================================================== -make_dwr() -> - ['DWR' | getr(peer)]. +peer_up(_SvcName, _Peer, S) -> + S. -make_dwa() -> - ['DWR' | Rest] = make_dwr(), - ['DWA', {'Result-Code', ?SUCCESS} | Rest]. +peer_down(_SvcName, _Peer, S) -> + S. -dwa(false, _, _) -> %% outgoing was DWA ... - ok; -dwa(true, S, Hdr) -> %% ... or DWR - dwa(getr(count), Hdr, S); - -%% React to the DWR only after another watchdog expiry. We shouldn't -%% get another DWR while the answer is pending. -dwa(0, Hdr, #transport{config = {_, Wd, What, _}}) -> - erlang:send_after(?ONE_WD(Wd), self(), failback), - putr(failback, make_msg(What, Hdr)), - eraser(count); - -dwa(undefined, _, _) -> - undefined = getr(failback), %% ensure this is after failback - ok; +%% =========================================================================== -%% Reply with DWA. -dwa(N, Hdr, #transport{parent = Pid}) -> - putr(count, N-1), - recv(Pid, {Hdr, make_dwa()}). +choose(true, X, _) -> X; +choose(false, _, X) -> X. -%% Answer to received DWR. -make_msg('DWA', Hdr) -> - {Hdr, make_dwa()}; +%% id/1 +%% +%% Jitter callback. -%% DWR from peer. -make_msg('DWR', _) -> - make_dwr(); +id(T) -> + T. -%% An unexpected answer is discarded after passing through the -%% watchdog state machine. -make_msg(other, _) -> - ['RAA', {'Session-Id', diameter:session_id("abc")}, - {'Result-Code', 2001} - | getr(peer)]. +%% run/1 +%% +%% A more useful badmatch in case of failure. + +run(Fs) -> + ?util:run([{?MODULE, [run1, F]} || F <- Fs]). + +run1([F|A]) -> + ok = try + apply(?MODULE, F, A), + ok + catch + E:R -> + S = erlang:get_stacktrace(), + io:format("~p~n", [{A, E, R, S}]), + S + end. + +%% now_diff/2 + +now_diff(T1, T2) -> + timer:now_diff(T2, T1). + +%% jitter/2 + +jitter(?WD(T), _) -> + T; +jitter(T,D) -> + T+D. + +%% Generate a unique hostname for the faked peer. +hostname() -> + lists:flatten(io_lib:format("~p-~p-~p", tuple_to_list(now()))). putr(Key, Val) -> put({?MODULE, Key}, Val). getr(Key) -> get({?MODULE, Key}). - -eraser(Key) -> - erase({?MODULE, Key}). diff --git a/lib/hipe/cerl/erl_types.erl b/lib/hipe/cerl/erl_types.erl index 1579735773..bc7ea17077 100644 --- a/lib/hipe/cerl/erl_types.erl +++ b/lib/hipe/cerl/erl_types.erl @@ -687,8 +687,8 @@ t_solve_remote(?tuple(Types, _Arity, _Tag), ET, R, C) -> {RL, RR} = list_solve_remote(Types, ET, R, C), {t_tuple(RL), RR}; t_solve_remote(?tuple_set(Set), ET, R, C) -> - {NewSet, RR} = tuples_solve_remote(Set, ET, R, C), - {?tuple_set(NewSet), RR}; + {NewTuples, RR} = tuples_solve_remote(Set, ET, R, C), + {t_sup(NewTuples), RR}; t_solve_remote(?remote(Set), ET, R, C) -> RemoteList = ordsets:to_list(Set), {RL, RR} = list_solve_remote_type(RemoteList, ET, R, C), @@ -788,10 +788,10 @@ opaques_solve_remote([#opaque{struct = Struct} = Remote|Tail], ET, R, C) -> tuples_solve_remote([], _ET, _R, _C) -> {[], []}; -tuples_solve_remote([{Sz, Tuples}|Tail], ET, R, C) -> +tuples_solve_remote([{_Sz, Tuples}|Tail], ET, R, C) -> {RL, RR1} = list_solve_remote(Tuples, ET, R, C), {LSzTpls, RR2} = tuples_solve_remote(Tail, ET, R, C), - {[{Sz, RL}|LSzTpls], RR1 ++ RR2}. + {RL ++ LSzTpls, RR1 ++ RR2}. %%----------------------------------------------------------------------------- %% Unit type. Signals non termination. diff --git a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src index c106261efd..ac8f2e619f 100644 --- a/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src +++ b/lib/ic/test/java_client_erl_server_SUITE_data/Makefile.src @@ -66,8 +66,11 @@ CLASS_FILES = $(JAVA_FILES:.java=.class) ERL_FILES = $(GEN_ERL_FILES) m_i_impl.erl EBINS = $(ERL_FILES:.erl=.@EMULATOR@) - +@IFEQ@ (@jinterface_classpath@,) +all: +@ELSE all: $(CLASS_FILES) $(EBINS) +@ENDIF@ $(GEN_ERL_FILES) $(GEN_HRL_FILES): java_erl_test.built_erl $(GEN_JAVA_FILES): java_erl_test.built_java diff --git a/lib/inets/test/inets_app_test.erl b/lib/inets/test/inets_app_test.erl index db2218f3b6..d32f7e290b 100644 --- a/lib/inets/test/inets_app_test.erl +++ b/lib/inets/test/inets_app_test.erl @@ -35,6 +35,15 @@ init_per_testcase(undef_funcs, Config) -> NewConfig = lists:keydelete(watchdog, 1, Config), Dog = test_server:timetrap(inets_test_lib:minutes(10)), + + %% We need to check if there is a point to run this test. + %% On some platforms, crypto will not build, which in turn + %% causes ssl to not build (at this time, this will + %% change in the future). + %% So, we first check if we can start crypto, and if not, + %% we skip this test case! + ?ENSURE_STARTED(crypto), + [{watchdog, Dog}| NewConfig]; init_per_testcase(_, Config) -> Config. @@ -240,13 +249,6 @@ undef_funcs(suite) -> undef_funcs(doc) -> []; undef_funcs(Config) when is_list(Config) -> - %% We need to check if there is a point to run this test. - %% On some platforms, crypto will not build, which in turn - %% causes ssl to not build (at this time, this will - %% change in the future). - %% So, we first check if we can start crypto, and if not, - %% we skip this test case! - ?ENSURE_STARTED(crypto), App = inets, AppFile = key1search(app_file, Config), Mods = key1search(modules, AppFile), diff --git a/lib/jinterface/test/jitu.erl b/lib/jinterface/test/jitu.erl index c57fb9bfad..fb262cf9d7 100644 --- a/lib/jinterface/test/jitu.erl +++ b/lib/jinterface/test/jitu.erl @@ -89,13 +89,19 @@ classpath(Dir) -> {win32, _} -> ";"; _ -> ":" end, - Dir++PS++ + es(Dir++PS++ filename:join([code:lib_dir(jinterface),"priv","OtpErlang.jar"])++PS++ case os:getenv("CLASSPATH") of false -> ""; Classpath -> Classpath - end. - + end). + +es(L) -> + lists:flatmap(fun($ ) -> + "\\ "; + (C) -> + [C] + end,lists:flatten(L)). cmd(Cmd) -> PortOpts = [{line,80},eof,exit_status,stderr_to_stdout], diff --git a/lib/kernel/doc/src/heart.xml b/lib/kernel/doc/src/heart.xml index 26d1e27822..2826d3d00a 100644 --- a/lib/kernel/doc/src/heart.xml +++ b/lib/kernel/doc/src/heart.xml @@ -71,6 +71,39 @@ timeout and try to reboot the system. This can happen, for example, if the system clock is adjusted automatically by use of NTP (Network Time Protocol).</p> + + <p> If a crash occurs, an <c><![CDATA[erl_crash.dump]]></c> will <em>not</em> be written + unless the environment variable <c><![CDATA[ERL_CRASH_DUMP_SECONDS]]></c> is set. + </p> + + <pre> +% <input>erl -heart -env ERL_CRASH_DUMP_SECONDS 10 ...</input></pre> + <p> + Furthermore, <c><![CDATA[ERL_CRASH_DUMP_SECONDS]]></c> has the following behaviour on + <c>heart</c>: + </p> + <taglist> + <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=0]]></c></tag> + <item><p> + Suppresses the writing a crash dump file entirely, + thus rebooting the runtime system immediately. + This is the same as not setting the environment variable. + </p> + </item> + <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=-1]]></c></tag> + <item><p> Setting the environment variable to a negative value will not reboot + the runtime system until the crash dump file has been completly written. + </p> + </item> + <tag><c><![CDATA[ERL_CRASH_DUMP_SECONDS=S]]></c></tag> + <item><p> + Heart will wait for <c>S</c> seconds to let the crash dump file be written. + After <c>S</c> seconds <c>heart</c> will reboot the runtime system regardless of + the crash dump file has been written or not. + </p> + </item> + </taglist> + <p>In the following descriptions, all function fails with reason <c>badarg</c> if <c>heart</c> is not started.</p> </description> diff --git a/lib/kernel/src/heart.erl b/lib/kernel/src/heart.erl index 28452a377e..de287bfa43 100644 --- a/lib/kernel/src/heart.erl +++ b/lib/kernel/src/heart.erl @@ -42,6 +42,7 @@ -define(CLEAR_CMD, 5). -define(GET_CMD, 6). -define(HEART_CMD, 7). +-define(PREPARING_CRASH, 8). % Used in beam vm -define(TIMEOUT, 5000). -define(CYCLE_TIMEOUT, 10000). @@ -130,6 +131,8 @@ start_portprogram() -> Port when is_port(Port) -> case wait_ack(Port) of ok -> + %% register port so the vm can find it if need be + register(heart_port, Port), {ok, Port}; {error, Reason} -> report_problem({{port_problem, Reason}, diff --git a/lib/kernel/test/global_SUITE.erl b/lib/kernel/test/global_SUITE.erl index 60035b50a0..6eb2134644 100644 --- a/lib/kernel/test/global_SUITE.erl +++ b/lib/kernel/test/global_SUITE.erl @@ -168,7 +168,7 @@ end_per_testcase(_Case, Config) -> register_1(suite) -> []; register_1(Config) when is_list(Config) -> Timeout = 15, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), P = spawn_link(?MODULE, lock_global, [self(), Config]), @@ -195,7 +195,6 @@ register_1(Config) when is_list(Config) -> ?line _ = global:unregister_name(foo), write_high_level_trace(Config), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. lock_global(Parent, Config) -> @@ -238,7 +237,7 @@ lock_global(Parent, Config) -> both_known_1(suite) -> []; both_known_1(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), @@ -316,7 +315,6 @@ both_known_1(Config) when is_list(Config) -> stop_node(Cp3), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. lost_unregister(suite) -> []; @@ -324,7 +322,7 @@ lost_unregister(doc) -> ["OTP-6428. An unregistered name reappears."]; lost_unregister(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), @@ -361,7 +359,6 @@ lost_unregister(Config) when is_list(Config) -> stop_node(B), stop_node(C), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. -define(UNTIL_LOOP, 300). @@ -448,7 +445,7 @@ lock_global2(Id, Parent) -> names(suite) -> []; names(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -532,7 +529,6 @@ names(Config) when is_list(Config) -> ?line ?UNTIL(undefined =:= global:whereis_name(test)), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. names_hidden(suite) -> []; @@ -541,7 +537,7 @@ names_hidden(doc) -> "visible nodes."]; names_hidden(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -639,13 +635,12 @@ names_hidden(Config) when is_list(Config) -> stop_node(Cp3), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. locks(suite) -> []; locks(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line {ok, Cp1} = start_node(cp1, Config), @@ -750,7 +745,6 @@ locks(Config) when is_list(Config) -> ?line test_server:sleep(10), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. @@ -760,7 +754,7 @@ locks_hidden(doc) -> "visible nodes."]; locks_hidden(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNodes = nodes(), @@ -833,14 +827,13 @@ locks_hidden(Config) when is_list(Config) -> stop_node(Cp3), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. bad_input(suite) -> []; bad_input(Config) when is_list(Config) -> Timeout = 15, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), Pid = whereis(global_name_server), @@ -854,13 +847,12 @@ bad_input(Config) when is_list(Config) -> ?line {'EXIT', _} = (catch global:trans({id, self()}, {m,f}, [node()], -1)), ?line Pid = whereis(global_name_server), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. names_and_locks(suite) -> []; names_and_locks(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -922,7 +914,6 @@ names_and_locks(Config) when is_list(Config) -> stop_node(Cp3), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. lock_die(suite) -> []; @@ -930,7 +921,7 @@ lock_die(doc) -> ["OTP-6341. Remove locks using monitors."]; lock_die(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -964,7 +955,6 @@ lock_die(Config) when is_list(Config) -> stop_node(Cp1), stop_node(Cp2), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. name_die(suite) -> []; @@ -972,7 +962,7 @@ name_die(doc) -> ["OTP-6341. Remove names using monitors."]; name_die(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1027,7 +1017,6 @@ name_die(Config) when is_list(Config) -> write_high_level_trace(Config), stop_nodes(Cps), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. kill_pid(Pid, File, Config) -> @@ -1040,7 +1029,7 @@ basic_partition(doc) -> ["Tests that two partitioned networks exchange correct info."]; basic_partition(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1088,7 +1077,6 @@ basic_partition(Config) when is_list(Config) -> stop_node(Cp2), stop_node(Cp3), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. basic_name_partition(suite) -> @@ -1099,7 +1087,7 @@ basic_name_partition(doc) -> "during connect phase are handled correctly."]; basic_name_partition(Config) when is_list(Config) -> Timeout = 60, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1167,7 +1155,6 @@ basic_name_partition(Config) when is_list(Config) -> stop_node(Cp2), stop_node(Cp3), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. %Peer nodes cp0 - cp6 are started. Break apart the connections from @@ -1190,7 +1177,7 @@ advanced_partition(doc) -> "partitioned networks connect."]; advanced_partition(Config) when is_list(Config) -> Timeout = 60, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1278,7 +1265,6 @@ advanced_partition(Config) when is_list(Config) -> stop_node(Cp5), stop_node(Cp6), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. %Peer nodes cp0 - cp6 are started, and partitioned just like in @@ -1297,7 +1283,7 @@ stress_partition(doc) -> "go up/down a bit."]; stress_partition(Config) when is_list(Config) -> Timeout = 90, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1377,7 +1363,6 @@ stress_partition(Config) when is_list(Config) -> stop_node(Cp7), stop_node(Cp8), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. @@ -1408,7 +1393,7 @@ ring(doc) -> "Make sure that there's just one winner."]; ring(Config) when is_list(Config) -> Timeout = 60, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1486,7 +1471,6 @@ ring(Config) when is_list(Config) -> stop_node(Cp7), stop_node(Cp8), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. simple_ring(suite) -> @@ -1499,7 +1483,7 @@ simple_ring(doc) -> "Make sure that there's just one winner."]; simple_ring(Config) when is_list(Config) -> Timeout = 60, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1565,7 +1549,6 @@ simple_ring(Config) when is_list(Config) -> stop_node(Cp4), stop_node(Cp5), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. line(suite) -> @@ -1576,7 +1559,7 @@ line(doc) -> "Make sure that there's just one winner."]; line(Config) when is_list(Config) -> Timeout = 60, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1655,7 +1638,6 @@ line(Config) when is_list(Config) -> stop_node(Cp7), stop_node(Cp8), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. @@ -1669,7 +1651,7 @@ simple_line(doc) -> "Make sure that there's just one winner."]; simple_line(Config) when is_list(Config) -> Timeout = 60, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -1735,7 +1717,6 @@ simple_line(Config) when is_list(Config) -> stop_node(Cp4), stop_node(Cp5), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. otp_1849(suite) -> []; @@ -1743,7 +1724,7 @@ otp_1849(doc) -> ["Test ticket: Global should keep track of all pids that set the same lock."]; otp_1849(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line {ok, Cp1} = start_node(cp1, Config), @@ -1822,7 +1803,6 @@ otp_1849(Config) when is_list(Config) -> stop_node(Cp2), stop_node(Cp3), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. @@ -1840,7 +1820,7 @@ otp_3162(Config) when is_list(Config) -> do_otp_3162(StartFun, Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line [Cp1, Cp2, Cp3] = StartFun(), @@ -1898,7 +1878,6 @@ do_otp_3162(StartFun, Config) -> stop_node(Cp2), stop_node(Cp3), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. @@ -1907,7 +1886,7 @@ otp_5640(doc) -> ["OTP-5640. 'allow' multiple names for registered processes."]; otp_5640(Config) when is_list(Config) -> Timeout = 25, - ?line Dog = test_server:timetrap(test_server:seconds(Timeout)), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), init_condition(Config), ?line {ok, B} = start_node(b, Config), @@ -1965,7 +1944,6 @@ otp_5640(Config) when is_list(Config) -> write_high_level_trace(Config), stop_node(B), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. otp_5640_proc(_Parent) -> @@ -1979,7 +1957,7 @@ otp_5737(doc) -> ["OTP-5737. set_lock/3 and trans/4 accept Retries = 0."]; otp_5737(Config) when is_list(Config) -> Timeout = 25, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), @@ -2000,7 +1978,6 @@ otp_5737(Config) when is_list(Config) -> write_high_level_trace(Config), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. otp_6931(suite) -> []; @@ -2025,7 +2002,7 @@ simple_disconnect(suite) -> []; simple_disconnect(doc) -> ["OTP-5563. Disconnected nodes (not partitions)"]; simple_disconnect(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -2075,7 +2052,6 @@ simple_disconnect(Config) when is_list(Config) -> write_high_level_trace(Config), stop_nodes(Cps), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. %% Not used right now. @@ -2118,7 +2094,7 @@ simple_resolve(suite) -> []; simple_resolve(doc) -> ["OTP-5563. Partitions and names."]; simple_resolve(Config) when is_list(Config) -> Timeout = 360, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -2245,7 +2221,6 @@ simple_resolve(Config) when is_list(Config) -> write_high_level_trace(Config), stop_nodes(Cps), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. simple_resolve2(suite) -> []; @@ -2255,7 +2230,7 @@ simple_resolve2(Config) when is_list(Config) -> %% always work to re-start z_2. "Cannot be a global bug." Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -2283,7 +2258,6 @@ simple_resolve2(Config) when is_list(Config) -> write_high_level_trace(Config), stop_nodes(Cps), % Not all nodes may be present, but it works anyway. ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. simple_resolve3(suite) -> []; @@ -2292,7 +2266,7 @@ simple_resolve3(Config) when is_list(Config) -> %% Continuation of simple_resolve. Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -2320,7 +2294,6 @@ simple_resolve3(Config) when is_list(Config) -> write_high_level_trace(Config), stop_nodes(Cps), % Not all nodes may be present, but it works anyway. ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. res({Res,Resolver}, [N1, A2, Z2], Cf) -> @@ -2504,7 +2477,7 @@ leftover_name(suite) -> []; leftover_name(doc) -> ["OTP-5563. Bug: nodedown while synching."]; leftover_name(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -2565,7 +2538,6 @@ leftover_name(Config) when is_list(Config) -> write_high_level_trace(Config), stop_nodes(Cps), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. %% Runs on n_1 @@ -2604,7 +2576,7 @@ re_register_name(Config) when is_list(Config) -> %% occupied by links, that's all. %% Later: now monitors are checked. Timeout = 15, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), Me = self(), @@ -2618,7 +2590,6 @@ re_register_name(Config) when is_list(Config) -> receive {Pid2, MonitoredBy2} -> [_] = MonitoredBy2 end, ?line _ = global:unregister_name(name), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. proc(Parent) -> @@ -2652,7 +2623,7 @@ do_name_exit(StartFun, Version, Config) -> %% The current release uses monitors so this test is not so relevant. Timeout = 60, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -2692,7 +2663,6 @@ do_name_exit(StartFun, Version, Config) -> write_high_level_trace(Config), stop_nodes(Cps), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. long_lock(Parent) -> @@ -2709,7 +2679,7 @@ external_nodes(suite) -> []; external_nodes(doc) -> ["OTP-5563. External nodes (cnodes)."]; external_nodes(Config) when is_list(Config) -> Timeout = 30, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -2793,7 +2763,6 @@ external_nodes(Config) when is_list(Config) -> ?line ?UNTIL(length(get_ext_names()) =:= 0), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. get_ext_names() -> @@ -2845,8 +2814,8 @@ many_nodes(suite) -> many_nodes(doc) -> ["OTP-5770. Start many nodes. Make them connect at the same time."]; many_nodes(Config) when is_list(Config) -> - Timeout = 180, - ?line Dog = test_server:timetrap({seconds,Timeout}), + Timeout = 240, + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -2902,7 +2871,6 @@ many_nodes(Config) when is_list(Config) -> write_high_level_trace(Config), ?line stop_nodes(Cps), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), Diff = Time2 - Time, Return = lists:flatten(io_lib:format("~w nodes took ~w ms", [N_cps, Diff])), @@ -2988,7 +2956,7 @@ sync_0(doc) -> ["OTP-5770. sync/0."]; sync_0(Config) when is_list(Config) -> Timeout = 180, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), @@ -3013,7 +2981,6 @@ sync_0(Config) when is_list(Config) -> stop_nodes(Cps), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. start_and_sync([]) -> @@ -3031,7 +2998,7 @@ global_groups_change(suite) -> []; global_groups_change(doc) -> ["Test change of global_groups parameter."]; global_groups_change(Config) -> Timeout = 90, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line M = from($@, atom_to_list(node())), @@ -3376,7 +3343,6 @@ global_groups_change(Config) -> stop_node(CpE), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. sync_and_wait(Node) -> @@ -3919,7 +3885,7 @@ global_lost_nodes(doc) -> ["Tests that locally loaded nodes do not loose contact with other nodes."]; global_lost_nodes(Config) when is_list(Config) -> Timeout = 60, - Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), @@ -3943,7 +3909,6 @@ global_lost_nodes(Config) when is_list(Config) -> ?line stop_node(Node1), ?line stop_node(Node2), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. global_load(MyName, OtherNode, OtherName) -> @@ -3994,7 +3959,7 @@ mass_death(doc) -> ["Tests the simultaneous death of many processes with registered names"]; mass_death(Config) when is_list(Config) -> Timeout = 90, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line OrigNames = global:registered_names(), @@ -4023,9 +3988,9 @@ mass_death(Config) when is_list(Config) -> {H,M,S} = time(), io:format("Started probing: ~.4.0w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w~n", [YYYY,MM,DD,H,M,S]), - wait_mass_death(Dog, Nodes, OrigNames, erlang:now(), Config). + wait_mass_death(Nodes, OrigNames, erlang:now(), Config). -wait_mass_death(Dog, Nodes, OrigNames, Then, Config) -> +wait_mass_death(Nodes, OrigNames, Then, Config) -> ?line Names = global:registered_names(), ?line case Names--OrigNames of @@ -4036,12 +4001,11 @@ wait_mass_death(Dog, Nodes, OrigNames, Then, Config) -> stop_node(Node) end, Nodes), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), {comment,lists:flatten(io_lib:format("~.3f s~n", [T/1000.0]))}; Ndiff -> ?line io:format("Ndiff: ~p~n", [Ndiff]), ?line test_server:sleep(1000), - ?line wait_mass_death(Dog, Nodes, OrigNames, Then, Config) + ?line wait_mass_death(Nodes, OrigNames, Then, Config) end. mass_spawn([]) -> @@ -4213,7 +4177,7 @@ garbage_messages(suite) -> []; garbage_messages(Config) when is_list(Config) -> Timeout = 25, - ?line Dog = test_server:timetrap({seconds,Timeout}), + ct:timetrap({seconds,Timeout}), init_high_level_trace(Timeout), ?line init_condition(Config), ?line [Slave] = start_nodes([garbage_messages], slave, Config), @@ -4233,7 +4197,6 @@ garbage_messages(Config) when is_list(Config) -> write_high_level_trace(Config), ?line stop_node(Slave), ?line init_condition(Config), - ?line test_server:timetrap_cancel(Dog), ok. wait_for_ready_net(Config) -> diff --git a/lib/kernel/test/heart_SUITE.erl b/lib/kernel/test/heart_SUITE.erl index 233e438dc9..e64d2914c4 100644 --- a/lib/kernel/test/heart_SUITE.erl +++ b/lib/kernel/test/heart_SUITE.erl @@ -22,7 +22,10 @@ -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, start/1, restart/1, - reboot/1, set_cmd/1, clear_cmd/1, get_cmd/1, + reboot/1, + node_start_immediately_after_crash/1, + node_start_soon_after_crash/1, + set_cmd/1, clear_cmd/1, get_cmd/1, dont_drop/1, kill_pid/1]). -export([init_per_testcase/2, end_per_testcase/2]). @@ -38,15 +41,15 @@ init_per_testcase(_Func, Config) -> end_per_testcase(_Func, Config) -> Nodes = nodes(), lists:foreach(fun(X) -> - NNam = list_to_atom(hd(string:tokens(atom_to_list(X),"@"))), - case NNam of - heart_test -> - ?t:format(1, "WARNING: Killed ~p~n", [X]), - rpc:cast(X, erlang, halt, []); - _ -> - ok - end - end, Nodes), + NNam = list_to_atom(hd(string:tokens(atom_to_list(X),"@"))), + case NNam of + heart_test -> + ?t:format(1, "WARNING: Killed ~p~n", [X]), + rpc:cast(X, erlang, halt, []); + _ -> + ok + end + end, Nodes), Dog=?config(watchdog, Config), test_server:timetrap_cancel(Dog). @@ -57,8 +60,13 @@ end_per_testcase(_Func, Config) -> %%----------------------------------------------------------------- suite() -> [{ct_hooks,[ts_install_cth]}]. -all() -> - [start, restart, reboot, set_cmd, clear_cmd, get_cmd, kill_pid]. +all() -> [ + start, restart, reboot, + node_start_immediately_after_crash, + node_start_soon_after_crash, + set_cmd, clear_cmd, get_cmd, + kill_pid + ]. groups() -> []. @@ -80,17 +88,22 @@ init_per_suite(Config) when is_list(Config) -> end_per_suite(Config) when is_list(Config) -> Config. + start_check(Type, Name) -> + start_check(Type, Name, []). +start_check(Type, Name, Envs) -> Args = case ?t:os_type() of - {win32,_} -> "-heart -env HEART_COMMAND no_reboot"; - _ -> "-heart" - end, + {win32,_} -> + "-heart " ++ env_encode([{"HEART_COMMAND", no_reboot}|Envs]); + _ -> + "-heart " ++ env_encode(Envs) + end, {ok, Node} = case Type of - loose -> - loose_node:start(Name, Args, ?DEFAULT_TIMEOUT_SECS); - _ -> - ?t:start_node(Name, Type, [{args, Args}]) - end, + loose -> + loose_node:start(Name, Args, ?DEFAULT_TIMEOUT_SECS); + _ -> + ?t:start_node(Name, Type, [{args, Args}]) + end, erlang:monitor_node(Node, true), case rpc:call(Node, erlang, whereis, [heart]) of Pid when is_pid(Pid) -> @@ -103,21 +116,19 @@ start_check(Type, Name) -> start(doc) -> []; start(suite) -> {req, [{time, 10}]}; start(Config) when is_list(Config) -> - ?line {ok, Node} = start_check(slave, heart_test), - ?line rpc:call(Node, init, reboot, []), + {ok, Node} = start_check(slave, heart_test), + rpc:call(Node, init, reboot, []), receive - {nodedown, Node} -> - ok - after 2000 -> - test_server:fail(node_not_closed) + {nodedown, Node} -> ok + after 2000 -> test_server:fail(node_not_closed) end, test_server:sleep(5000), - ?line case net_adm:ping(Node) of - pang -> - ok; - _ -> - test_server:fail(node_rebooted) - end, + case net_adm:ping(Node) of + pang -> + ok; + _ -> + test_server:fail(node_rebooted) + end, test_server:stop_node(Node). %% Also test fixed bug in R1B (it was not possible to @@ -125,6 +136,10 @@ start(Config) when is_list(Config) -> %% Slave executes erlang:halt() on master nodedown. %% Therefore the slave process has to be killed %% before restart. + +%% restart +%% Purpose: +%% Check that a node is up and running after a init:restart/0 restart(doc) -> []; restart(suite) -> case ?t:os_type() of @@ -134,8 +149,8 @@ restart(suite) -> {skip, "Only run on unix and win32"} end; restart(Config) when is_list(Config) -> - ?line {ok, Node} = start_check(loose, heart_test), - ?line rpc:call(Node, init, restart, []), + {ok, Node} = start_check(loose, heart_test), + rpc:call(Node, init, restart, []), receive {nodedown, Node} -> ok @@ -143,32 +158,21 @@ restart(Config) when is_list(Config) -> test_server:fail(node_not_closed) end, test_server:sleep(5000), - - ?line case net_adm:ping(Node) of - pong -> - erlang:monitor_node(Node, true), - ?line rpc:call(Node, init, stop, []), - receive - {nodedown, Node} -> - ok - after 2000 -> - test_server:fail(node_not_closed2) - end, - ok; - _ -> - test_server:fail(node_not_restarted) - end, + node_check_up_down(Node, 2000), loose_node:stop(Node). +%% reboot +%% Purpose: +%% Check that a node is up and running after a init:reboot/0 reboot(doc) -> []; reboot(suite) -> {req, [{time, 10}]}; reboot(Config) when is_list(Config) -> {ok, Node} = start_check(slave, heart_test), - ?line ok = rpc:call(Node, heart, set_cmd, + ok = rpc:call(Node, heart, set_cmd, [atom_to_list(lib:progname()) ++ " -noshell -heart " ++ name(Node) ++ "&"]), - ?line rpc:call(Node, init, reboot, []), + rpc:call(Node, init, reboot, []), receive {nodedown, Node} -> ok @@ -176,44 +180,119 @@ reboot(Config) when is_list(Config) -> test_server:fail(node_not_closed) end, test_server:sleep(5000), - ?line case net_adm:ping(Node) of - pong -> - erlang:monitor_node(Node, true), - ?line rpc:call(Node, init, reboot, []), - receive - {nodedown, Node} -> - ok - after 2000 -> - test_server:fail(node_not_closed2) - end, - ok; - _ -> - test_server:fail(node_not_rebooted) - end, + node_check_up_down(Node, 2000), ok. +%% node_start_immediately_after_crash +%% Purpose: +%% Check that a node is up and running after a crash. +%% This test exhausts the atom table on the remote node. +%% ERL_CRASH_DUMP_SECONDS=0 will force beam not to dump an erl_crash.dump. +node_start_immediately_after_crash(suite) -> {req, [{time, 10}]}; +node_start_immediately_after_crash(Config) when is_list(Config) -> + {ok, Node} = start_check(loose, heart_test_imm, [{"ERL_CRASH_DUMP_SECONDS", "0"}]), + + ok = rpc:call(Node, heart, set_cmd, + [atom_to_list(lib:progname()) ++ + " -noshell -heart " ++ name(Node) ++ "&"]), + + Mod = exhaust_atoms, + + Code = generate(Mod, [], [ + "do() -> " + " Set = lists:seq($a,$z), " + " [ list_to_atom([A,B,C,D,E]) || " + " A <- Set, B <- Set, C <- Set, E <- Set, D <- Set ]." + ]), + + %% crash it with atom exhaustion + rpc:call(Node, erlang, load_module, [Mod, Code]), + rpc:cast(Node, Mod, do, []), + + T0 = now(), + + receive {nodedown, Node} -> + test_server:format("Took ~.2f s. for node to go down~n", [timer:now_diff(now(), T0)/1000000]), + ok + %% timeout is very liberal here. nodedown is received in about 1 s. on linux (palantir) + %% and in about 10 s. on solaris (carcharoth) + after (15000*test_server:timetrap_scale_factor()) -> test_server:fail(node_not_closed) + end, + test_server:sleep(3000), + node_check_up_down(Node, 2000), + loose_node:stop(Node). + +%% node_start_soon_after_crash +%% Purpose: +%% Check that a node is up and running after a crash. +%% This test exhausts the atom table on the remote node. +%% ERL_CRASH_DUMP_SECONDS=10 will force beam +%% to only dump an erl_crash.dump for 10 seconds. +node_start_soon_after_crash(suite) -> {req, [{time, 10}]}; +node_start_soon_after_crash(Config) when is_list(Config) -> + {ok, Node} = start_check(loose, heart_test_soon, [{"ERL_CRASH_DUMP_SECONDS", "10"}]), + + ok = rpc:call(Node, heart, set_cmd, + [atom_to_list(lib:progname()) ++ + " -noshell -heart " ++ name(Node) ++ "&"]), + + Mod = exhaust_atoms, + + Code = generate(Mod, [], [ + "do() -> " + " Set = lists:seq($a,$z), " + " [ list_to_atom([A,B,C,D,E]) || " + " A <- Set, B <- Set, C <- Set, E <- Set, D <- Set ]." + ]), + + %% crash it with atom exhaustion + rpc:call(Node, erlang, load_module, [Mod, Code]), + rpc:cast(Node, Mod, do, []), + + receive {nodedown, Node} -> ok + after (15000*test_server:timetrap_scale_factor()) -> test_server:fail(node_not_closed) + end, + test_server:sleep(20000), + node_check_up_down(Node, 15000), + loose_node:stop(Node). + + +node_check_up_down(Node, Tmo) -> + case net_adm:ping(Node) of + pong -> + erlang:monitor_node(Node, true), + rpc:call(Node, init, reboot, []), + receive + {nodedown, Node} -> ok + after Tmo -> + test_server:fail(node_not_closed2) + end; + _ -> + test_server:fail(node_not_rebooted) + end. + %% Only tests bad command, correct behaviour is tested in reboot/1. set_cmd(suite) -> []; set_cmd(Config) when is_list(Config) -> - ?line {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, heart_test), Cmd = wrong_atom, - ?line {error, {bad_cmd, Cmd}} = rpc:call(Node, heart, set_cmd, [Cmd]), + {error, {bad_cmd, Cmd}} = rpc:call(Node, heart, set_cmd, [Cmd]), Cmd1 = lists:duplicate(2047, $a), - ?line {error, {bad_cmd, Cmd1}} = rpc:call(Node, heart, set_cmd, [Cmd1]), + {error, {bad_cmd, Cmd1}} = rpc:call(Node, heart, set_cmd, [Cmd1]), Cmd2 = lists:duplicate(28, $a), - ?line ok = rpc:call(Node, heart, set_cmd, [Cmd2]), + ok = rpc:call(Node, heart, set_cmd, [Cmd2]), Cmd3 = lists:duplicate(2000, $a), - ?line ok = rpc:call(Node, heart, set_cmd, [Cmd3]), + ok = rpc:call(Node, heart, set_cmd, [Cmd3]), stop_node(Node), ok. clear_cmd(suite) -> {req,[{time,15}]}; clear_cmd(Config) when is_list(Config) -> - ?line {ok, Node} = start_check(slave, heart_test), - ?line ok = rpc:call(Node, heart, set_cmd, + {ok, Node} = start_check(slave, heart_test), + ok = rpc:call(Node, heart, set_cmd, [atom_to_list(lib:progname()) ++ " -noshell -heart " ++ name(Node) ++ "&"]), - ?line rpc:call(Node, init, reboot, []), + rpc:call(Node, init, reboot, []), receive {nodedown, Node} -> ok @@ -221,16 +300,16 @@ clear_cmd(Config) when is_list(Config) -> test_server:fail(node_not_closed) end, test_server:sleep(5000), - ?line case net_adm:ping(Node) of - pong -> - erlang:monitor_node(Node, true); - _ -> - test_server:fail(node_not_rebooted) - end, - ?line ok = rpc:call(Node, heart, set_cmd, + case net_adm:ping(Node) of + pong -> + erlang:monitor_node(Node, true); + _ -> + test_server:fail(node_not_rebooted) + end, + ok = rpc:call(Node, heart, set_cmd, ["erl -noshell -heart " ++ name(Node) ++ "&"]), - ?line ok = rpc:call(Node, heart, clear_cmd, []), - ?line rpc:call(Node, init, reboot, []), + ok = rpc:call(Node, heart, clear_cmd, []), + rpc:call(Node, init, reboot, []), receive {nodedown, Node} -> ok @@ -238,20 +317,20 @@ clear_cmd(Config) when is_list(Config) -> test_server:fail(node_not_closed) end, test_server:sleep(5000), - ?line case net_adm:ping(Node) of - pang -> - ok; - _ -> - test_server:fail(node_rebooted) - end, + case net_adm:ping(Node) of + pang -> + ok; + _ -> + test_server:fail(node_rebooted) + end, ok. get_cmd(suite) -> []; get_cmd(Config) when is_list(Config) -> - ?line {ok, Node} = start_check(slave, heart_test), + {ok, Node} = start_check(slave, heart_test), Cmd = "test", - ?line ok = rpc:call(Node, heart, set_cmd, [Cmd]), - ?line {ok, Cmd} = rpc:call(Node, heart, get_cmd, []), + ok = rpc:call(Node, heart, set_cmd, [Cmd]), + {ok, Cmd} = rpc:call(Node, heart, get_cmd, []), stop_node(Node), ok. @@ -274,57 +353,53 @@ dont_drop(Config) when is_list(Config) -> ok end. -do_dont_drop(_,0) -> - []; +do_dont_drop(_,0) -> []; do_dont_drop(Config,N) -> %% Name of first slave node - ?line NN1 = atom_to_list(?MODULE) ++ "slave_1", + NN1 = atom_to_list(?MODULE) ++ "slave_1", %% Name of node started by heart on failure - ?line NN2 = atom_to_list(?MODULE) ++ "slave_2", + NN2 = atom_to_list(?MODULE) ++ "slave_2", %% Name of node started by heart on success - ?line NN3 = atom_to_list(?MODULE) ++ "slave_3", - ?line Host = hd(tl(string:tokens(atom_to_list(node()),"@"))), + NN3 = atom_to_list(?MODULE) ++ "slave_3", + Host = hd(tl(string:tokens(atom_to_list(node()),"@"))), %% The initial heart command - ?line FirstCmd = erl() ++ name(NN2 ++ "@" ++ Host), + FirstCmd = erl() ++ name(NN2 ++ "@" ++ Host), %% Separated the parameters to start_node_run for clarity... - ?line Name = list_to_atom(NN1), - ?line Env = [{"HEART_COMMAND", FirstCmd}], - ?line Func = "start_heart_stress", - ?line Arg = NN3 ++ "@" ++ Host ++ " " ++ + Name = list_to_atom(NN1), + Env = [{"HEART_COMMAND", FirstCmd}], + Func = "start_heart_stress", + Arg = NN3 ++ "@" ++ Host ++ " " ++ filename:join(?config(data_dir, Config), "simple_echo"), - ?line start_node_run(Name,Env,Func,Arg), - ?line case wait_for_any_of(list_to_atom(NN2 ++ "@" ++ Host), - list_to_atom(NN3 ++ "@" ++ Host)) of - 2 -> - ?line [ok | do_dont_drop(Config,N-1)]; - _ -> - ?line false - end. + start_node_run(Name,Env,Func,Arg), + case wait_for_any_of(list_to_atom(NN2 ++ "@" ++ Host), + list_to_atom(NN3 ++ "@" ++ Host)) of + 2 -> + [ok | do_dont_drop(Config,N-1)]; + _ -> + false + end. wait_for_any_of(N1,N2) -> - ?line wait_for_any_of(N1,N2,45). + wait_for_any_of(N1,N2,45). wait_for_any_of(_N1,_N2,0) -> - ?line false; + false; wait_for_any_of(N1,N2,Times) -> - ?line receive - after 1000 -> - ?line ok - end, - ?line case net_adm:ping(N1) of - pang -> - ?line case net_adm:ping(N2) of - pang -> - ?line wait_for_any_of(N1,N2,Times - 1); - pong -> - ?line rpc:call(N2,init,stop,[]), - ?line 2 - end; - pong -> - ?line rpc:call(N1,init,stop,[]), - ?line 1 - end. + receive after 1000 -> ok end, + case net_adm:ping(N1) of + pang -> + case net_adm:ping(N2) of + pang -> + wait_for_any_of(N1,N2,Times - 1); + pong -> + rpc:call(N2,init,stop,[]), + 2 + end; + pong -> + rpc:call(N1,init,stop,[]), + 1 + end. kill_pid(suite) -> @@ -347,9 +422,7 @@ do_kill_pid(_Config) -> {ok,Node} = start_node_run(Name,Env,suicide_by_heart,[]), ok = wait_for_node(Node,15), erlang:monitor_node(Node, true), - receive - {nodedown,Node} -> - ok + receive {nodedown,Node} -> ok after 30000 -> false end. @@ -357,23 +430,16 @@ do_kill_pid(_Config) -> wait_for_node(_,0) -> false; wait_for_node(Node,N) -> - receive - after 1000 -> - ok - end, + receive after 1000 -> ok end, case net_adm:ping(Node) of - pong -> - ok; - pang -> - wait_for_node(Node,N-1) + pong -> ok; + pang -> wait_for_node(Node,N-1) end. erl() -> case os:type() of - {win32,_} -> - "werl "; - _ -> - "erl " + {win32,_} -> "werl "; + _ -> "erl " end. name(Node) when is_list(Node) -> name(Node,[]); @@ -390,15 +456,13 @@ name([H|T], Name) -> name(T, [H|Name]). -atom_conv(A) when is_atom(A) -> - atom_to_list(A); -atom_conv(A) when is_list(A) -> - A. +enc(A) when is_atom(A) -> atom_to_list(A); +enc(A) when is_binary(A) -> binary_to_list(A); +enc(A) when is_list(A) -> A. -env_conv([]) -> - []; -env_conv([{X,Y}|T]) -> - atom_conv(X) ++ " \"" ++ atom_conv(Y) ++ "\" " ++ env_conv(T). +env_encode([]) -> []; +env_encode([{X,Y}|T]) -> + "-env " ++ enc(X) ++ " \"" ++ enc(Y) ++ "\" " ++ env_encode(T). %%% %%% Starts a node and runs a function in this @@ -409,12 +473,12 @@ env_conv([{X,Y}|T]) -> %%% Argument is the argument(s) to send through erl -s %%% start_node_run(Name, Env, Function, Argument) -> - ?line PA = filename:dirname(code:which(?MODULE)), - ?line Params = "-heart -env " ++ env_conv(Env) ++ " -pa " ++ PA ++ - " -s " ++ - atom_conv(?MODULE) ++ " " ++ atom_conv(Function) ++ " " ++ - atom_conv(Argument), - ?line start_node(Name, Params). + PA = filename:dirname(code:which(?MODULE)), + Params = "-heart " ++ env_encode(Env) ++ " -pa " ++ PA ++ + " -s " ++ + enc(?MODULE) ++ " " ++ enc(Function) ++ " " ++ + enc(Argument), + start_node(Name, Params). start_node(Name, Param) -> test_server:start_node(Name, slave, [{args, Param}]). @@ -480,3 +544,24 @@ suicide_by_heart() -> {makaronipudding} -> sallad end. + + +%% generate a module from binary +generate(Module, Attributes, FunStrings) -> + FunForms = function_forms(FunStrings), + Forms = [ + {attribute,1,module,Module}, + {attribute,2,export,[FA || {FA,_} <- FunForms]} + ] ++ [{attribute, 3, A, V}|| {A, V} <- Attributes] ++ + [ Function || {_, Function} <- FunForms], + {ok, Module, Bin} = compile:forms(Forms), + Bin. + + +function_forms([]) -> []; +function_forms([S|Ss]) -> + {ok, Ts,_} = erl_scan:string(S), + {ok, Form} = erl_parse:parse_form(Ts), + Fun = element(3, Form), + Arity = element(4, Form), + [{{Fun,Arity}, Form}|function_forms(Ss)]. diff --git a/lib/kernel/test/interactive_shell_SUITE.erl b/lib/kernel/test/interactive_shell_SUITE.erl index 4787f19250..7549e2c83e 100644 --- a/lib/kernel/test/interactive_shell_SUITE.erl +++ b/lib/kernel/test/interactive_shell_SUITE.erl @@ -30,19 +30,10 @@ init_per_testcase(_Func, Config) -> Dog = test_server:timetrap(test_server:seconds(60)), - Term = case os:getenv("TERM") of - List when is_list(List) -> - List; - _ -> - "dumb" - end, - os:putenv("TERM","vt100"), - [{watchdog,Dog},{term,Term}|Config]. + [{watchdog,Dog}|Config]. end_per_testcase(_Func, Config) -> Dog = ?config(watchdog, Config), - Term = ?config(term,Config), - os:putenv("TERM",Term), test_server:timetrap_cancel(Dog). @@ -56,9 +47,19 @@ groups() -> []. init_per_suite(Config) -> - Config. + Term = case os:getenv("TERM") of + List when is_list(List) -> + List; + _ -> + "dumb" + end, + os:putenv("TERM","vt100"), + DefShell = get_default_shell(), + [{default_shell,DefShell},{term,Term}|Config]. -end_per_suite(_Config) -> +end_per_suite(Config) -> + Term = ?config(term,Config), + os:putenv("TERM",Term), ok. init_per_group(_GroupName, Config) -> @@ -78,70 +79,118 @@ end_per_group(_GroupName, Config) -> get_columns_and_rows(suite) -> []; get_columns_and_rows(doc) -> ["Test that the shell can access columns and rows"]; get_columns_and_rows(Config) when is_list(Config) -> - ?line rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline,"io:columns()."}, -%% Behaviour change in R12B-5, returns 80 -%% {getline,"{error,enotsup}"}, - {getline,"{ok,80}"}, - {putline,"io:rows()."}, -%% Behaviour change in R12B-5, returns 24 -%% {getline,"{error,enotsup}"} - {getline,"{ok,24}"} - ],[]), - ?line rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline,"io:columns()."}, - {getline,"{ok,90}"}, - {putline,"io:rows()."}, - {getline,"{ok,40}"}], - [], - "stty rows 40; stty columns 90; "). + case proplists:get_value(default_shell,Config) of + old -> + %% Old shell tests + ?dbg(old_shell), + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline,"io:columns()."}, + {getline_re,".*{error,enotsup}"}, + {putline,"io:rows()."}, + {getline_re,".*{error,enotsup}"} + + ],[]), + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline,"io:columns()."}, + {getline_re,".*{ok,90}"}, + {putline,"io:rows()."}, + {getline_re,".*{ok,40}"}], + [], + "stty rows 40; stty columns 90; "); + new -> + % New shell tests + ?dbg(new_shell), + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline,"io:columns()."}, + %% Behaviour change in R12B-5, returns 80 + %% {getline,"{error,enotsup}"}, + {getline,"{ok,80}"}, + {putline,"io:rows()."}, + %% Behaviour change in R12B-5, returns 24 + %% {getline,"{error,enotsup}"} + {getline,"{ok,24}"} + ],[]), + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline,"io:columns()."}, + {getline,"{ok,90}"}, + {putline,"io:rows()."}, + {getline,"{ok,40}"}], + [], + "stty rows 40; stty columns 90; ") + end. exit_initial(suite) -> []; exit_initial(doc) -> ["Tests that exit of initial shell restarts shell"]; exit_initial(Config) when is_list(Config) -> - ?line rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline,"exit()."}, - {getline,""}, - {getline,"Eshell"}, - {putline,""}, - {putline,"35."}, - {getline,"35"}],[]). + case proplists:get_value(default_shell,Config) of + old -> + rtnode([{putline,""}, + {putline, "2."}, + {getline_re, ".*2"}, + {putline,"exit()."}, + {getline,""}, + {getline,"Eshell"}, + {putline,""}, + {putline,"35."}, + {getline_re,".*35"}],[]); + new -> + rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline,"exit()."}, + {getline,""}, + {getline,"Eshell"}, + {putline,""}, + {putline,"35."}, + {getline_re,"35"}],[]) + end. job_control_local(suite) -> []; job_control_local(doc) -> [ "Tests that local shell can be " "started by means of job control" ]; job_control_local(Config) when is_list(Config) -> - ?line rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline,[7]}, - {sleep,timeout(short)}, - {putline,""}, - {getline," -->"}, - {putline,"s"}, - {putline,"c"}, - {putline_raw,""}, - {getline,"Eshell"}, - {putline_raw,""}, - {getline,"1>"}, - {putline,"35."}, - {getline,"35"}],[]). + case proplists:get_value(default_shell,Config) of + old -> + %% Old shell tests + {skip,"No new shell found"}; + new -> + %% New shell tests + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline,[7]}, + {sleep,timeout(short)}, + {putline,""}, + {getline," -->"}, + {putline,"s"}, + {putline,"c"}, + {putline_raw,""}, + {getline,"Eshell"}, + {putline_raw,""}, + {getline,"1>"}, + {putline,"35."}, + {getline,"35"}],[]) + end. job_control_remote(suite) -> []; job_control_remote(doc) -> [ "Tests that remote shell can be " "started by means of job control" ]; job_control_remote(Config) when is_list(Config) -> - case node() of - nonode@nohost -> + case {node(),proplists:get_value(default_shell,Config)} of + {nonode@nohost,_} -> ?line exit(not_distributed); + {_,old} -> + {skip,"No new shell found"}; _ -> ?line RNode = create_nodename(), ?line MyNode = atom_to_list(node()), @@ -190,9 +239,11 @@ job_control_remote_noshell(doc) -> [ "Tests that remote shell can be " "started by means of job control to -noshell node" ]; job_control_remote_noshell(Config) when is_list(Config) -> - case node() of - nonode@nohost -> + case {node(),proplists:get_value(default_shell,Config)} of + {nonode@nohost,_} -> ?line exit(not_distributed); + {_,old} -> + {skip,"No new shell found"}; _ -> ?line RNode = create_nodename(), ?line NSNode = start_noshell_node(interactive_shell_noshell), @@ -351,6 +402,33 @@ get_and_put(CPid, [{getline, Match}|T],N) -> end end; +%% Hey ho copy paste from stdlib/io_proto_SUITE +get_and_put(CPid, [{getline_re, Match}|T],N) -> + ?dbg({getline_re, Match}), + CPid ! {self(), {get_line, timeout(normal)}}, + receive + {get_line, timeout} -> + error_logger:error_msg("~p: getline_re timeout waiting for \"~s\" " + "(command number ~p, skipped: ~p)~n", + [?MODULE, Match,N,get(getline_skipped)]), + {error, timeout}; + {get_line, Data} -> + ?dbg({data,Data}), + case re:run(Data, Match,[{capture,none}]) of + match -> + erase(getline_skipped), + get_and_put(CPid, T,N+1); + _ -> + case get(getline_skipped) of + undefined -> + put(getline_skipped,[Data]); + List -> + put(getline_skipped,List ++ [Data]) + end, + get_and_put(CPid, [{getline_re, Match}|T],N) + end + end; + get_and_put(CPid, [{putline_raw, Line}|T],N) -> ?dbg({putline_raw, Line}), CPid ! {self(), {send_line, Line}}, @@ -631,6 +709,13 @@ get_data_within(Port, Timeout, Acc) -> timeout end. - - - +get_default_shell() -> + try + rtnode([{putline,""}, + {putline, "whereis(user_drv)."}, + {getline, "undefined"}],[]), + old + catch E:R -> + ?dbg({E,R}), + new + end. diff --git a/lib/kernel/test/wrap_log_reader_SUITE.erl b/lib/kernel/test/wrap_log_reader_SUITE.erl index 96dc3e6d33..6c47fda9c5 100644 --- a/lib/kernel/test/wrap_log_reader_SUITE.erl +++ b/lib/kernel/test/wrap_log_reader_SUITE.erl @@ -557,7 +557,7 @@ rec(M, Where) -> M -> ok; Else -> ?t:fail({error, {Where, Else}}) - after 1000 -> ?t:fail({error, {Where, time_out}}) + after 5000 -> ?t:fail({error, {Where, time_out}}) end. pps() -> diff --git a/lib/kernel/vsn.mk b/lib/kernel/vsn.mk index c494f8a864..7254d714eb 100644 --- a/lib/kernel/vsn.mk +++ b/lib/kernel/vsn.mk @@ -1 +1 @@ -KERNEL_VSN = 2.15.2 +KERNEL_VSN = 2.15.3 diff --git a/lib/percept/src/percept.app.src b/lib/percept/src/percept.app.src index c70fede721..7b20093ece 100644 --- a/lib/percept/src/percept.app.src +++ b/lib/percept/src/percept.app.src @@ -17,14 +17,26 @@ %% %CopyrightEnd% %% -{application,percept, - [{description, "PERCEPT Erlang Concurrency Profiling Tool"}, - {vsn, "%VSN%"}, - {modules, [percept,percept_db,percept_html,percept_graph,percept_analyzer]}, - {registered, [percept_db,percept_port]}, - {applications, [kernel,stdlib]}, - {env, []} - ]}. - +{application,percept, [ + {description, "PERCEPT Erlang Concurrency Profiling Tool"}, + {vsn, "%VSN%"}, + {modules, [ + egd, + egd_font, + egd_png, + egd_primitives, + egd_render, + percept, + percept_analyzer, + percept_db, + percept_graph, + percept_html, + percept_image + ]}, + {registered, [percept_db,percept_port]}, + {applications, [kernel,stdlib]}, + {env,[]} +]}. +%% vim: syntax=erlang diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml index b84b3a3dcb..57f09c0cf0 100644 --- a/lib/ssh/doc/src/ssh.xml +++ b/lib/ssh/doc/src/ssh.xml @@ -142,6 +142,11 @@ some reason, the other algorithm is tried. The default is to try <c><![CDATA[ssh_rsa]]></c> first.</p> </item> + <tag><c><![CDATA[{pref_public_key_algs, list()}]]></c></tag> + <item> + <p>List of public key algorithms to try to use, ssh_rsa and ssh_dsa available. + Will override <c><![CDATA[{public_key_alg, ssh_rsa | ssh_dsa}]]></c></p> + </item> <tag><c><![CDATA[{connect_timeout, timeout()}]]></c></tag> <item> <p>Sets a timeout on the transport layer connection. Defaults to infinity.</p> @@ -178,6 +183,10 @@ <c><![CDATA[add_host_key/3]]></c>. This is considered somewhat experimental and will be better documented later on.</p> </item> + <tag><c><![CDATA[{quiet_mode, atom() = boolean()}]]></c></tag> + <item> + <p>If true, the client will not print out anything on authorization.</p> + </item> <tag><c><![CDATA[{fd, file_descriptor()}]]></c></tag> <item> <p>Allow an existing file-descriptor to be used diff --git a/lib/ssh/src/ssh.appup.src b/lib/ssh/src/ssh.appup.src index d08dbafc32..8914aeffdb 100644 --- a/lib/ssh/src/ssh.appup.src +++ b/lib/ssh/src/ssh.appup.src @@ -19,10 +19,15 @@ {"%VSN%", [ + {<<"2.1.1">>, [{load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_connection_manager, soft_purge, soft_purge, []}, + {load_module, ssh_auth, soft_purge, soft_purge, []}, + {load_module, ssh, soft_purge, soft_purge, []}]}, {<<"2.1">>, [{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []}, {load_module, ssh_connection, soft_purge, soft_purge, []}, {load_module, ssh_connection_manager, soft_purge, soft_purge, []}, {load_module, ssh_auth, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, {load_module, ssh_channel, soft_purge, soft_purge, []}, {load_module, ssh_file, soft_purge, soft_purge, []}]}, {load_module, ssh, soft_purge, soft_purge, []}]}, @@ -30,14 +35,19 @@ {<<"1\\.*">>, [{restart_application, ssh}]} ], [ + {<<"2.1.1">>, [{load_module, ssh_connection_handler, soft_purge, soft_purge, []}, + {load_module, ssh_connection_manager, soft_purge, soft_purge, []}, + {load_module, ssh_auth, soft_purge, soft_purge, []}, + {load_module, ssh, soft_purge, soft_purge, []}]}, {<<"2.1">>,[{load_module, ssh_sftpd_file_api, soft_purge, soft_purge, []}, {load_module, ssh_connection, soft_purge, soft_purge, []}, {load_module, ssh_connection_manager, soft_purge, soft_purge, []}, {load_module, ssh_auth, soft_purge, soft_purge, []}, + {load_module, ssh_connection_handler, soft_purge, soft_purge, []}, {load_module, ssh_channel, soft_purge, soft_purge, []}, {load_module, ssh_file, soft_purge, soft_purge, []}]}, {load_module, ssh, soft_purge, soft_purge, []}]}, {<<"2.0\\.*">>, [{restart_application, ssh}]}, {<<"1\\.*">>, [{restart_application, ssh}]} ] -}. +}.
\ No newline at end of file diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl index 3395f73884..d09f6cf34b 100644 --- a/lib/ssh/src/ssh.erl +++ b/lib/ssh/src/ssh.erl @@ -342,6 +342,10 @@ handle_option([{exec, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([{auth_methods, _} = Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{pref_public_key_algs, _} = Opt | Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); +handle_option([{quiet_mode, _} = Opt|Rest], SocketOptions, SshOptions) -> + handle_option(Rest, SocketOptions, [handle_ssh_option(Opt) | SshOptions]); handle_option([Opt | Rest], SocketOptions, SshOptions) -> handle_option(Rest, [handle_inet_option(Opt) | SocketOptions], SshOptions). @@ -357,6 +361,13 @@ handle_ssh_option({user_interaction, Value} = Opt) when Value == true; Value == Opt; handle_ssh_option({public_key_alg, Value} = Opt) when Value == ssh_rsa; Value == ssh_dsa -> Opt; +handle_ssh_option({pref_public_key_algs, Value} = Opt) when is_list(Value), length(Value) >= 1 -> + case check_pref_algs(Value) of + true -> + Opt; + _ -> + throw({error, {eoptions, Opt}}) + end; handle_ssh_option({connect_timeout, Value} = Opt) when is_integer(Value); Value == infinity -> Opt; handle_ssh_option({user, Value} = Opt) when is_list(Value) -> @@ -407,6 +418,9 @@ handle_ssh_option({shell, {Module, Function, _}} = Opt) when is_atom(Module), Opt; handle_ssh_option({shell, Value} = Opt) when is_function(Value) -> Opt; +handle_ssh_option({quiet_mode, Value} = Opt) when Value == true; + Value == false -> + Opt; handle_ssh_option(Opt) -> throw({error, {eoptions, Opt}}). @@ -424,7 +438,18 @@ handle_inet_option({reuseaddr, _} = Opt) -> %% Option verified by inet handle_inet_option(Opt) -> Opt. - +%% Check preferred algs +check_pref_algs([]) -> + true; +check_pref_algs([H|T]) -> + case H of + ssh_dsa -> + check_pref_algs(T); + ssh_rsa -> + check_pref_algs(T); + _ -> + false + end. %% Has IPv6 been disabled? inetopt(true) -> inet; diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl index aa452a8e09..27e44df554 100644 --- a/lib/ssh/src/ssh_auth.erl +++ b/lib/ssh/src/ssh_auth.erl @@ -118,15 +118,37 @@ init_userauth_request_msg(#ssh{opts = Opts} = Ssh) -> service = "ssh-connection", method = "none", data = <<>>}, - FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts, - ?PREFERRED_PK_ALG)), - SecondAlg = other_alg(FirstAlg), - AllowUserInt = proplists:get_value(user_interaction, Opts, true), - Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), - ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, - userauth_preference = Prefs, - userauth_methods = none, - service = "ssh-connection"}); + case proplists:get_value(pref_public_key_algs, Opts, false) of + false -> + FirstAlg = algorithm(proplists:get_value(public_key_alg, Opts, + ?PREFERRED_PK_ALG)), + SecondAlg = other_alg(FirstAlg), + AllowUserInt = proplists:get_value(user_interaction, Opts, true), + Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), + ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, + userauth_preference = Prefs, + userauth_methods = none, + service = "ssh-connection"}); + Algs -> + FirstAlg = algorithm(lists:nth(1, Algs)), + case length(Algs) =:= 2 of + true -> + SecondAlg = other_alg(FirstAlg), + AllowUserInt = proplists:get_value(user_interaction, Opts, true), + Prefs = method_preference(FirstAlg, SecondAlg, AllowUserInt), + ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, + userauth_preference = Prefs, + userauth_methods = none, + service = "ssh-connection"}); + _ -> + AllowUserInt = proplists:get_value(user_interaction, Opts, true), + Prefs = method_preference(FirstAlg, AllowUserInt), + ssh_transport:ssh_packet(Msg, Ssh#ssh{user = User, + userauth_preference = Prefs, + userauth_methods = none, + service = "ssh-connection"}) + end + end; {error, no_user} -> ErrStr = "Could not determine the users name", throw(#ssh_msg_disconnect{code = ?SSH_DISCONNECT_ILLEGAL_USER_NAME, @@ -287,6 +309,15 @@ method_preference(Alg1, Alg2, false) -> {"publickey", ?MODULE, publickey_msg,[Alg2]}, {"password", ?MODULE, password_msg, []} ]. +method_preference(Alg1, true) -> + [{"publickey", ?MODULE, publickey_msg, [Alg1]}, + {"password", ?MODULE, password_msg, []}, + {"keyboard-interactive", ?MODULE, keyboard_interactive_msg, []} + ]; +method_preference(Alg1, false) -> + [{"publickey", ?MODULE, publickey_msg, [Alg1]}, + {"password", ?MODULE, password_msg, []} + ]. user_name(Opts) -> Env = case os:type() of diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl index 5b3d1b8a1b..d8950a7b67 100644 --- a/lib/ssh/src/ssh_connection_handler.erl +++ b/lib/ssh/src/ssh_connection_handler.erl @@ -718,8 +718,18 @@ init_ssh(server = Role, Vsn, Version, Options, Socket) -> available_host_keys = supported_host_keys(Role, KeyCb, Options) }. -supported_host_keys(client, _, _) -> - ["ssh-rsa", "ssh-dss"]; +supported_host_keys(client, _, Options) -> + try + case extract_algs(proplists:get_value(pref_public_key_algs, Options, false), []) of + false -> + ["ssh-rsa", "ssh-dss"]; + Algs -> + Algs + end + catch + exit:Reason -> + {stop, {shutdown, Reason}} + end; supported_host_keys(server, KeyCb, Options) -> lists:foldl(fun(Type, Acc) -> case available_host_key(KeyCb, Type, Options) of @@ -731,7 +741,19 @@ supported_host_keys(server, KeyCb, Options) -> end, [], %% Prefered alg last so no need to reverse ["ssh-dss", "ssh-rsa"]). - +extract_algs(false, _) -> + false; +extract_algs([],[]) -> + false; +extract_algs([], NewList) -> + lists:reverse(NewList); +extract_algs([H|T], NewList) -> + case H of + ssh_dsa -> + extract_algs(T, ["ssh-dss"|NewList]); + ssh_rsa -> + extract_algs(T, ["ssh-rsa"|NewList]) + end. available_host_key(KeyCb, "ssh-dss"= Alg, Opts) -> case KeyCb:host_key('ssh-dss', Opts) of {ok, _} -> diff --git a/lib/ssh/src/ssh_connection_manager.erl b/lib/ssh/src/ssh_connection_manager.erl index e53cd4f4f7..5aa79f978c 100644 --- a/lib/ssh/src/ssh_connection_manager.erl +++ b/lib/ssh/src/ssh_connection_manager.erl @@ -523,7 +523,7 @@ handle_info({same_user, _}, State) -> handle_info(ssh_connected, #state{role = client, client = Pid} = State) -> Pid ! {self(), is_connected}, - {noreply, State#state{connected = true}}; + {noreply, State#state{connected = true, opts = handle_password(State#state.opts)}}; handle_info(ssh_connected, #state{role = server} = State) -> {noreply, State#state{connected = true}}; @@ -536,6 +536,47 @@ handle_info({'DOWN', _Ref, process, ChannelPid, _Reason}, State) -> handle_info({'EXIT', _Sup, Reason}, State) -> {stop, Reason, State}. +handle_password(Opts) -> + handle_rsa_password(handle_dsa_password(handle_normal_password(Opts))). +handle_normal_password(Opts) -> + case proplists:get_value(ssh_opts, Opts, false) of + false -> + Opts; + SshOpts -> + case proplists:get_value(password, SshOpts, false) of + false -> + Opts; + _Password -> + NewOpts = [{password, undefined}|lists:keydelete(password, 1, SshOpts)], + [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)] + end + end. +handle_dsa_password(Opts) -> + case proplists:get_value(ssh_opts, Opts, false) of + false -> + Opts; + SshOpts -> + case proplists:get_value(dsa_pass_phrase, SshOpts, false) of + false -> + Opts; + _Password -> + NewOpts = [{dsa_pass_phrase, undefined}|lists:keydelete(dsa_pass_phrase, 1, SshOpts)], + [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)] + end + end. +handle_rsa_password(Opts) -> + case proplists:get_value(ssh_opts, Opts, false) of + false -> + Opts; + SshOpts -> + case proplists:get_value(rsa_pass_phrase, SshOpts, false) of + false -> + Opts; + _Password -> + NewOpts = [{rsa_pass_phrase, undefined}|lists:keydelete(rsa_pass_phrase, 1, SshOpts)], + [{ssh_opts, NewOpts}|lists:keydelete(ssh_opts, 1, Opts)] + end + end. %%-------------------------------------------------------------------- %% Function: terminate(Reason, State) -> void() %% Description: This function is called by a gen_server when it is about to diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk index defa47f824..921ec2206a 100644 --- a/lib/ssh/vsn.mk +++ b/lib/ssh/vsn.mk @@ -1,5 +1,5 @@ #-*-makefile-*- ; force emacs to enter makefile-mode -SSH_VSN = 2.1.1 +SSH_VSN = 2.1.2 APP_VSN = "ssh-$(SSH_VSN)" diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl index ff2556c488..ce64f0543f 100644 --- a/lib/ssl/src/ssl_connection.erl +++ b/lib/ssl/src/ssl_connection.erl @@ -118,7 +118,7 @@ send(Pid, Data) -> sync_send_all_state_event(Pid, {application_data, %% iolist_to_binary should really %% be called iodata_to_binary() - erlang:iolist_to_binary(Data)}, infinity). + erlang:iolist_to_binary(Data)}). %%-------------------------------------------------------------------- -spec recv(pid(), integer(), timeout()) -> @@ -127,7 +127,7 @@ send(Pid, Data) -> %% Description: Receives data when active = false %%-------------------------------------------------------------------- recv(Pid, Length, Timeout) -> - sync_send_all_state_event(Pid, {recv, Length}, Timeout). + sync_send_all_state_event(Pid, {recv, Length, Timeout}). %%-------------------------------------------------------------------- -spec connect(host(), inet:port_number(), port(), {#ssl_options{}, #socket_options{}}, pid(), tuple(), timeout()) -> @@ -164,7 +164,7 @@ ssl_accept(Port, Socket, Opts, User, CbInfo, Timeout) -> %% Description: Starts ssl handshake. %%-------------------------------------------------------------------- handshake(#sslsocket{pid = Pid}, Timeout) -> - case sync_send_all_state_event(Pid, start, Timeout) of + case sync_send_all_state_event(Pid, {start, Timeout}) of connected -> ok; Error -> @@ -335,15 +335,15 @@ init([Role, Host, Port, Socket, {SSLOpts0, _} = Options, User, CbInfo]) -> #state{}) -> gen_fsm_state_return(). %%-------------------------------------------------------------------- hello(start, #state{host = Host, port = Port, role = client, - ssl_options = SslOpts, - session = #session{own_certificate = Cert} = Session0, - session_cache = Cache, session_cache_cb = CacheCb, - transport_cb = Transport, socket = Socket, - connection_states = ConnectionStates0, - renegotiation = {Renegotiation, _}} = State0) -> + ssl_options = SslOpts, + session = #session{own_certificate = Cert} = Session0, + session_cache = Cache, session_cache_cb = CacheCb, + transport_cb = Transport, socket = Socket, + connection_states = ConnectionStates0, + renegotiation = {Renegotiation, _}} = State0) -> Hello = ssl_handshake:client_hello(Host, Port, ConnectionStates0, SslOpts, Cache, CacheCb, Renegotiation, Cert), - + Version = Hello#client_hello.client_version, Handshake0 = ssl_handshake:init_handshake_history(), {BinMsg, ConnectionStates, Handshake} = @@ -768,7 +768,8 @@ handle_sync_event({application_data, Data}, From, StateName, State#state{send_queue = queue:in({From, Data}, Queue)}, get_timeout(State)}; -handle_sync_event(start, StartFrom, hello, State) -> +handle_sync_event({start, Timeout} = Start, StartFrom, hello, State) -> + start_or_recv_cancel_timer(Timeout, StartFrom), hello(start, State#state{start_or_recv_from = StartFrom}); %% The two clauses below could happen if a server upgrades a socket in @@ -778,12 +779,14 @@ handle_sync_event(start, StartFrom, hello, State) -> %% mode before telling the client that it is willing to upgrade %% and before calling ssl:ssl_accept/2. These clauses are %% here to make sure it is the users problem and not owers if -%% they upgrade a active socket. -handle_sync_event(start, _, connection, State) -> +%% they upgrade an active socket. +handle_sync_event({start,_}, _, connection, State) -> {reply, connected, connection, State, get_timeout(State)}; -handle_sync_event(start, _From, error, {Error, State = #state{}}) -> +handle_sync_event({start,_}, _From, error, {Error, State = #state{}}) -> {stop, {shutdown, Error}, {error, Error}, State}; -handle_sync_event(start, StartFrom, StateName, State) -> + +handle_sync_event({start, Timeout}, StartFrom, StateName, State) -> + start_or_recv_cancel_timer(Timeout, StartFrom), {next_state, StateName, State#state{start_or_recv_from = StartFrom}, get_timeout(State)}; handle_sync_event(close, _, StateName, State) -> @@ -815,12 +818,14 @@ handle_sync_event({shutdown, How0}, _, StateName, {stop, normal, Error, State} end; -handle_sync_event({recv, N}, RecvFrom, connection = StateName, State0) -> +handle_sync_event({recv, N, Timeout}, RecvFrom, connection = StateName, State0) -> + start_or_recv_cancel_timer(Timeout, RecvFrom), passive_receive(State0#state{bytes_to_read = N, start_or_recv_from = RecvFrom}, StateName); %% Doing renegotiate wait with handling request until renegotiate is %% finished. Will be handled by next_state_is_connection/2. -handle_sync_event({recv, N}, RecvFrom, StateName, State) -> +handle_sync_event({recv, N, Timeout}, RecvFrom, StateName, State) -> + start_or_recv_cancel_timer(Timeout, RecvFrom), {next_state, StateName, State#state{bytes_to_read = N, start_or_recv_from = RecvFrom}, get_timeout(State)}; @@ -990,7 +995,14 @@ handle_info({'DOWN', MonitorRef, _, _, _}, _, handle_info(allow_renegotiate, StateName, State) -> {next_state, StateName, State#state{allow_renegotiate = true}, get_timeout(State)}; - + +handle_info({cancel_start_or_recv, RecvFrom}, connection = StateName, #state{start_or_recv_from = RecvFrom} = State) -> + gen_fsm:reply(RecvFrom, {error, timeout}), + {next_state, StateName, State#state{start_or_recv_from = undefined}, get_timeout(State)}; + +handle_info({cancel_start_or_recv, _RecvFrom}, StateName, State) -> + {next_state, StateName, State, get_timeout(State)}; + handle_info(Msg, StateName, State) -> Report = io_lib:format("SSL: Got unexpected info: ~p ~n", [Msg]), error_logger:info_report(Report), @@ -1201,15 +1213,10 @@ init_diffie_hellman(DbHandle,_, DHParamFile, server) -> end. sync_send_all_state_event(FsmPid, Event) -> - sync_send_all_state_event(FsmPid, Event, infinity). - -sync_send_all_state_event(FsmPid, Event, Timeout) -> - try gen_fsm:sync_send_all_state_event(FsmPid, Event, Timeout) + try gen_fsm:sync_send_all_state_event(FsmPid, Event, infinity) catch exit:{noproc, _} -> {error, closed}; - exit:{timeout, _} -> - {error, timeout}; exit:{normal, _} -> {error, closed}; exit:{shutdown, _} -> @@ -2465,3 +2472,8 @@ default_hashsign(_Version, KeyExchange) default_hashsign(_Version, KeyExchange) when KeyExchange == dh_anon -> {null, anon}. + +start_or_recv_cancel_timer(infinity, _RecvFrom) -> + ok; +start_or_recv_cancel_timer(Timeout, RecvFrom) -> + erlang:send_after(Timeout, self(), {cancel_start_or_recv, RecvFrom}). diff --git a/lib/ssl/src/ssl_manager.erl b/lib/ssl/src/ssl_manager.erl index af2bfa394d..0cf4f2ce33 100644 --- a/lib/ssl/src/ssl_manager.erl +++ b/lib/ssl/src/ssl_manager.erl @@ -191,7 +191,7 @@ init([Name, Opts]) -> proplists:get_value(session_lifetime, Opts, ?'24H_in_sec'), CertDb = ssl_certificate_db:create(), SessionCache = CacheCb:init(proplists:get_value(session_cb_init_args, Opts, [])), - Timer = erlang:send_after(SessionLifeTime * 1000, + Timer = erlang:send_after(SessionLifeTime * 1000 + 5000, self(), validate_sessions), erlang:send_after(?CLEAR_PEM_CACHE, self(), clear_pem_cache), {ok, #state{certificate_db = CertDb, diff --git a/lib/ssl/test/ssl_basic_SUITE.erl b/lib/ssl/test/ssl_basic_SUITE.erl index 93f7209aea..6cf712fa6f 100644 --- a/lib/ssl/test/ssl_basic_SUITE.erl +++ b/lib/ssl/test/ssl_basic_SUITE.erl @@ -39,6 +39,7 @@ -define(EXPIRE, 10). -define(SLEEP, 500). -define(RENEGOTIATION_DISABLE_TIME, 12000). +-define(CLEAN_SESSION_DB, 60000). %% Test server callback functions %%-------------------------------------------------------------------- @@ -108,12 +109,12 @@ init_per_testcase(protocol_versions, Config) -> init_per_testcase(reuse_session_expired, Config0) -> Config = lists:keydelete(watchdog, 1, Config0), - Dog = ssl_test_lib:timetrap(?EXPIRE * 1000 * 5), ssl:stop(), application:load(ssl), application:set_env(ssl, session_lifetime, ?EXPIRE), + application:set_env(ssl, session_delay_cleanup_time, 500), ssl:start(), - [{watchdog, Dog} | Config]; + Config; init_per_testcase(empty_protocol_versions, Config) -> ssl:stop(), @@ -141,6 +142,7 @@ init_per_testcase(_TestCase, Config0) -> %%-------------------------------------------------------------------- end_per_testcase(reuse_session_expired, Config) -> application:unset_env(ssl, session_lifetime), + application:unset_env(ssl, session_delay_cleanup_time), end_per_testcase(default_action, Config); end_per_testcase(_TestCase, Config) -> @@ -2089,13 +2091,14 @@ reuse_session_expired(Config) when is_list(Config) -> %% Make sure session is unregistered due to expiration test_server:sleep((?EXPIRE+1)), [{session_id, Id} |_] = SessionInfo, + make_sure_expired(Hostname, Port, Id), Client2 = ssl_test_lib:start_client([{node, ClientNode}, - {port, Port}, {host, Hostname}, + {port, Port}, {host, Hostname}, {mfa, {ssl_test_lib, session_info_result, []}}, - {from, self()}, {options, ClientOpts}]), + {from, self()}, {options, ClientOpts}]), receive {Client2, SessionInfo} -> test_server:fail(session_reused_when_session_expired); @@ -2113,16 +2116,16 @@ make_sure_expired(Host, Port, Id) -> [_, _,_, _, Prop] = StatusInfo, State = ssl_test_lib:state(Prop), Cache = element(2, State), - case ssl_session_cache:lookup(Cache, {{Host, Port}, Id}) of + + case ssl_session_cache:lookup(Cache, {{Host, Port}, Id}) of undefined -> - ok; + ok; #session{is_resumable = false} -> - ok; + ok; _ -> test_server:sleep(?SLEEP), make_sure_expired(Host, Port, Id) - end. - + end. %%-------------------------------------------------------------------- server_does_not_want_to_reuse_session(doc) -> diff --git a/lib/stdlib/test/io_proto_SUITE.erl b/lib/stdlib/test/io_proto_SUITE.erl index 661d57c85b..17e69f7c1c 100644 --- a/lib/stdlib/test/io_proto_SUITE.erl +++ b/lib/stdlib/test/io_proto_SUITE.erl @@ -96,7 +96,8 @@ groups() -> []. init_per_suite(Config) -> - Config. + DefShell = get_default_shell(), + [{default_shell,DefShell}|Config]. end_per_suite(_Config) -> ok. @@ -124,20 +125,25 @@ unicode_prompt(doc) -> ["Test that an Unicode prompt does not crash the shell"]; unicode_prompt(Config) when is_list(Config) -> ?line PA = filename:dirname(code:which(?MODULE)), - ?line rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."}, - {getline, "default"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "\"hej\\n\""}, - {putline, "io:setopts([{binary,true}])."}, - {getline, "ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "<<\"hej\\n\">>"} - ],[],[],"-pa \""++ PA++"\""), + case proplists:get_value(default_shell,Config) of + old -> + ok; + new -> + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline, "shell:prompt_func({io_proto_SUITE,uprompt})."}, + {getline, "default"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {getline, "\"hej\\n\""}, + {putline, "io:setopts([{binary,true}])."}, + {getline, "ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {getline, "<<\"hej\\n\">>"} + ],[],[],"-pa \""++ PA++"\"") + end, %% And one with oldshell ?line rtnode([{putline,""}, {putline, "2."}, @@ -234,21 +240,26 @@ setopts_getopts(Config) when is_list(Config) -> lists:sort(io:getopts(RFile)), ?line eof = io:get_line(RFile,''), ?line file:close(RFile), - %% So, lets test another node with new interactive shell - ?line rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "lists:keyfind(binary,1,io:getopts())."}, - {getline, "{binary,false}"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "\"hej\\n\""}, - {putline, "io:setopts([{binary,true}])."}, - {getline, "ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "<<\"hej\\n\">>"} - ],[]), + case proplists:get_value(default_shell,Config) of + old -> + ok; + new -> + %% So, lets test another node with new interactive shell + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline, "lists:keyfind(binary,1,io:getopts())."}, + {getline, "{binary,false}"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {getline, "\"hej\\n\""}, + {putline, "io:setopts([{binary,true}])."}, + {getline, "ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {getline, "<<\"hej\\n\">>"} + ],[]) + end, %% And one with oldshell ?line rtnode([{putline,""}, {putline, "2."}, @@ -433,21 +444,27 @@ unicode_options(Config) when is_list(Config) -> end, ?line [ ok = CannotWriteFile(F,FailDir) || F <- AllNoBom ], - %% OK, time for the group_leaders... - ?line rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "lists:keyfind(encoding,1,io:getopts())."}, - {getline, "{encoding,latin1}"}, - {putline, "io:format(\"~ts~n\",[[1024]])."}, - {getline, "\\x{400}"}, - {putline, "io:setopts([unicode])."}, - {getline, "ok"}, - {putline, "io:format(\"~ts~n\",[[1024]])."}, - {getline, - binary_to_list(unicode:characters_to_binary( - [1024],unicode,utf8))} - ],[],"LC_CTYPE=\""++get_lc_ctype()++"\"; export LC_CTYPE; "), + case proplists:get_value(default_shell,Config) of + old -> + ok; + new -> + %% OK, time for the group_leaders... + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline, "lists:keyfind(encoding,1,io:getopts())."}, + {getline, "{encoding,latin1}"}, + {putline, "io:format(\"~ts~n\",[[1024]])."}, + {getline, "\\x{400}"}, + {putline, "io:setopts([unicode])."}, + {getline, "ok"}, + {putline, "io:format(\"~ts~n\",[[1024]])."}, + {getline, + binary_to_list(unicode:characters_to_binary( + [1024],unicode,utf8))} + ],[],"LC_CTYPE=\""++get_lc_ctype()++"\"; " + "export LC_CTYPE; ") + end, ?line rtnode([{putline,""}, {putline, "2."}, {getline_re, ".*2."}, @@ -680,23 +697,28 @@ binary_options(Config) when is_list(Config) -> ?line file:close(F3), %% OK, time for the group_leaders... %% io:format(standard_error,"Hmmm:~w~n",["<<\""++binary_to_list(<<"\345\344\366"/utf8>>)++"\\n\">>"]), - ?line rtnode([{putline,""}, - {putline, "2."}, - {getline, "2"}, - {putline, "lists:keyfind(binary,1,io:getopts())."}, - {getline, "{binary,false}"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "\"hej\\n\""}, - {putline, "io:setopts([{binary,true},unicode])."}, - {getline, "ok"}, - {putline, "io:get_line('')."}, - {putline, "hej"}, - {getline, "<<\"hej\\n\">>"}, - {putline, "io:get_line('')."}, - {putline, binary_to_list(<<"\345\344\366"/utf8>>)}, - {getline, "<<\""++binary_to_list(unicode:characters_to_binary(<<"\345\344\366"/utf8>>,latin1,utf8))++"\\n\">>"} - ],[]), + case proplists:get_value(default_shell,Config) of + old -> + ok; + new -> + ?line rtnode([{putline,""}, + {putline, "2."}, + {getline, "2"}, + {putline, "lists:keyfind(binary,1,io:getopts())."}, + {getline, "{binary,false}"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {getline, "\"hej\\n\""}, + {putline, "io:setopts([{binary,true},unicode])."}, + {getline, "ok"}, + {putline, "io:get_line('')."}, + {putline, "hej"}, + {getline, "<<\"hej\\n\">>"}, + {putline, "io:get_line('')."}, + {putline, binary_to_list(<<"\345\344\366"/utf8>>)}, + {getline, "<<\""++binary_to_list(unicode:characters_to_binary(<<"\345\344\366"/utf8>>,latin1,utf8))++"\\n\">>"} + ],[]) + end, %% And one with oldshell ?line rtnode([{putline,""}, {putline, "2."}, @@ -1146,9 +1168,11 @@ read_modes_gl(suite) -> read_modes_gl(doc) -> ["Test various modes when reading from the group leade from another machine"]; read_modes_gl(Config) when is_list(Config) -> - case get_progs() of - {error,Reason} -> + case {get_progs(),proplists:get_value(default_shell,Config)} of + {{error,Reason},_} -> {skipped,Reason}; + {_,old} -> + {skipper,"No new shell"}; _ -> read_modes_gl_1(Config,answering_machine1) end. @@ -1754,6 +1778,17 @@ get_data_within(Port, Timeout, Acc) -> timeout end. +get_default_shell() -> + try + rtnode([{putline,""}, + {putline, "whereis(user_drv)."}, + {getline, "undefined"}],[]), + old + catch E:R -> + ?dbg({E,R}), + new + end. + %% %% Test I/O-server %% diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk index 3df7495ec4..6524d83689 100644 --- a/lib/stdlib/vsn.mk +++ b/lib/stdlib/vsn.mk @@ -1 +1 @@ -STDLIB_VSN = 1.18.2 +STDLIB_VSN = 1.18.3 diff --git a/lib/test_server/src/ts.erl b/lib/test_server/src/ts.erl index 4899f38d2b..42b286ef64 100644 --- a/lib/test_server/src/ts.erl +++ b/lib/test_server/src/ts.erl @@ -291,12 +291,19 @@ run(Testspec, Config) when is_atom(Testspec), is_list(Config) -> Options=check_test_get_opts(Testspec, Config), File=atom_to_list(Testspec), Spec = case code:lib_dir(Testspec) of - {error, bad_name} when Testspec /= emulator, - Testspec /= system, - Testspec /= epmd -> + _ when Testspec == emulator; + Testspec == system; + Testspec == epmd -> + File++".spec"; + {error, bad_name} -> create_skip_spec(Testspec, tests(Testspec)); - _ -> - File++".spec" + Path -> + case file:read_file_info(filename:join(Path,"ebin")) of + {ok,_} -> + File++".spec"; + _ -> + create_skip_spec(Testspec, tests(Testspec)) + end end, run_test(File, [{spec,[Spec]}], Options); %% Runs one module in a spec (interactive) diff --git a/lib/tools/src/tools.app.src b/lib/tools/src/tools.app.src index cd9b622f15..94998fb763 100644 --- a/lib/tools/src/tools.app.src +++ b/lib/tools/src/tools.app.src @@ -24,6 +24,7 @@ eprof, fprof, instrument, + lcnt, make, xref, xref_base, diff --git a/xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf b/xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf index 0e0c2f2337..c245b493a5 100644 --- a/xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf +++ b/xcomp/erl-xcomp-powerpc-dso-linux-gnu.conf @@ -55,11 +55,11 @@ erl_xcomp_build=guess # It does not have to be a full `CPU-VENDOR-OS' triplet, but can be. The # full `CPU-VENDOR-OS' triplet will be created by # `$ERL_TOP/erts/autoconf/config.sub $erl_xcomp_host'. -erl_xcomp_host=powerpc-dso-linux-gnu +erl_xcomp_host=powerpc-linux-gnu # * `erl_xcomp_configure_flags' - Extra configure flags to pass to the # `configure' script. -erl_xcomp_configure_flags=--without-termcap +erl_xcomp_configure_flags="--without-termcap" ## -- Cross Compiler and Other Tools ------------------------------------------- @@ -70,7 +70,7 @@ erl_xcomp_configure_flags=--without-termcap ## All variables in this section can also be used when native compiling. # * `CC' - C compiler. -CC=powerpc-dso-linux-gnu-gcc +CC=powerpc-linux-gnu-gcc # * `CFLAGS' - C compiler flags. #CFLAGS= @@ -90,13 +90,13 @@ CC=powerpc-dso-linux-gnu-gcc #CPPFLAGS= # * `CXX' - C++ compiler. -CXX=powerpc-dso-linux-gnu-g++ +CXX=powerpc-linux-gnu-g++ # * `CXXFLAGS' - C++ compiler flags. #CXXFLAGS= # * `LD' - Linker. -LD=powerpc-dso-linux-gnu-ld +LD=powerpc-linux-gnu-ld # * `LDFLAGS' - Linker flags. #LDFLAGS= @@ -134,10 +134,10 @@ LD=powerpc-dso-linux-gnu-ld ## -- Other Tools -- # * `RANLIB' - `ranlib' archive index tool. -RANLIB=powerpc-dso-linux-gnu-ranlib +RANLIB=powerpc-linux-gnu-ranlib # * `AR' - `ar' archiving tool. -AR=powerpc-dso-linux-gnu-ar +AR=powerpc-linux-gnu-ar # * `GETCONF' - `getconf' system configuration inspection tool. `getconf' is # currently used for finding out large file support flags to use, and @@ -178,7 +178,7 @@ erl_xcomp_sysroot="$DSO_SYSROOT_POWERPC" # the target system must have a working `__after_morecore_hook' that can be # used for tracking used `malloc()' implementations core memory usage. # This is currently only used by unsupported features. -erl_xcomp_after_morecore_hook=yes +#erl_xcomp_after_morecore_hook= # * `erl_xcomp_bigendian' - `yes|no'. No default. If `yes', the target system # must be big endian. If `no', little endian. This can often be |