summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.travis.yml4
-rw-r--r--OTP_VERSION2
-rw-r--r--erts/aclocal.m46
-rw-r--r--erts/configure.in43
-rw-r--r--erts/doc/src/absform.xml4
-rw-r--r--erts/doc/src/alt_disco.xml14
-rw-r--r--erts/doc/src/epmd.xml6
-rw-r--r--erts/doc/src/erl.xml22
-rw-r--r--erts/doc/src/erl_driver.xml22
-rw-r--r--erts/doc/src/erlang.xml65
-rw-r--r--erts/doc/src/init.xml2
-rw-r--r--erts/doc/src/notes.xml281
-rw-r--r--erts/doc/src/socket.xml63
-rw-r--r--erts/emulator/Makefile.in2
-rw-r--r--erts/emulator/beam/atom.names3
-rw-r--r--erts/emulator/beam/beam_bif_load.c14
-rw-r--r--erts/emulator/beam/bif.c8
-rw-r--r--erts/emulator/beam/break.c4
-rw-r--r--erts/emulator/beam/dist.c2
-rw-r--r--erts/emulator/beam/erl_bif_info.c18
-rw-r--r--erts/emulator/beam/erl_bif_port.c63
-rw-r--r--erts/emulator/beam/erl_bif_trace.c5
-rw-r--r--erts/emulator/beam/erl_db_catree.c5
-rw-r--r--erts/emulator/beam/erl_db_hash.c5
-rw-r--r--erts/emulator/beam/erl_db_tree.c13
-rw-r--r--erts/emulator/beam/erl_db_tree_util.h4
-rw-r--r--erts/emulator/beam/erl_db_util.c3
-rw-r--r--erts/emulator/beam/erl_drv_thread.c16
-rw-r--r--erts/emulator/beam/erl_dyn_lock_check.c553
-rw-r--r--erts/emulator/beam/erl_dyn_lock_check.h61
-rw-r--r--erts/emulator/beam/erl_init.c4
-rw-r--r--erts/emulator/beam/erl_lock_check.c1
-rw-r--r--erts/emulator/beam/erl_nif.c40
-rw-r--r--erts/emulator/beam/erl_node_tables.c5
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.c23
-rw-r--r--erts/emulator/beam/erl_proc_sig_queue.h8
-rw-r--r--erts/emulator/beam/erl_process.c211
-rw-r--r--erts/emulator/beam/erl_sys_driver.h31
-rw-r--r--erts/emulator/beam/erl_threads.h44
-rw-r--r--erts/emulator/beam/io.c18
-rw-r--r--erts/emulator/beam/sys.h23
-rw-r--r--erts/emulator/drivers/common/inet_drv.c10
-rw-r--r--erts/emulator/nifs/common/prim_net_nif.c2
-rw-r--r--erts/emulator/nifs/common/socket_int.h5
-rw-r--r--erts/emulator/nifs/common/socket_nif.c1384
-rw-r--r--erts/emulator/nifs/common/socket_util.c120
-rw-r--r--erts/emulator/nifs/common/socket_util.h5
-rw-r--r--erts/emulator/sys/common/erl_poll.c18
-rw-r--r--erts/emulator/sys/unix/sys.c5
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c93
-rw-r--r--erts/emulator/sys/win32/sys.c128
-rw-r--r--erts/emulator/test/dirty_nif_SUITE.erl48
-rw-r--r--erts/emulator/test/esock_misc/esock_iow_client.erl94
-rw-r--r--erts/emulator/test/esock_misc/esock_iow_lib.erl123
-rw-r--r--erts/emulator/test/esock_misc/esock_iow_server.erl83
-rw-r--r--erts/emulator/test/list_bif_SUITE.erl57
-rw-r--r--erts/emulator/test/nif_SUITE.erl62
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.c78
-rw-r--r--erts/emulator/test/nif_SUITE_data/nif_mod.erl4
-rw-r--r--erts/emulator/test/port_bif_SUITE.erl172
-rw-r--r--erts/emulator/test/port_bif_SUITE_data/Makefile.src8
-rw-r--r--erts/emulator/test/port_bif_SUITE_data/sleeper.c66
-rw-r--r--erts/emulator/test/process_SUITE.erl15
-rw-r--r--erts/emulator/test/scheduler_SUITE.erl77
-rw-r--r--erts/emulator/test/signal_SUITE.erl68
-rw-r--r--erts/emulator/test/socket_SUITE.erl934
-rw-r--r--erts/emulator/test/socket_test_lib.erl51
-rw-r--r--erts/emulator/test/timer_bif_SUITE.erl31
-rw-r--r--erts/preloaded/ebin/atomics.beambin3312 -> 3316 bytes
-rw-r--r--erts/preloaded/ebin/counters.beambin3112 -> 3116 bytes
-rw-r--r--erts/preloaded/ebin/erl_init.beambin2304 -> 2312 bytes
-rw-r--r--erts/preloaded/ebin/erl_prim_loader.beambin52560 -> 52732 bytes
-rw-r--r--erts/preloaded/ebin/erl_tracer.beambin2224 -> 2228 bytes
-rw-r--r--erts/preloaded/ebin/erlang.beambin100344 -> 100440 bytes
-rw-r--r--erts/preloaded/ebin/erts_code_purger.beambin10996 -> 10996 bytes
-rw-r--r--erts/preloaded/ebin/erts_dirty_process_signal_handler.beambin2784 -> 2784 bytes
-rw-r--r--erts/preloaded/ebin/erts_internal.beambin20428 -> 20984 bytes
-rw-r--r--erts/preloaded/ebin/erts_literal_area_collector.beambin3272 -> 3272 bytes
-rw-r--r--erts/preloaded/ebin/init.beambin50224 -> 50236 bytes
-rw-r--r--erts/preloaded/ebin/persistent_term.beambin1860 -> 1864 bytes
-rw-r--r--erts/preloaded/ebin/prim_buffer.beambin3612 -> 3620 bytes
-rw-r--r--erts/preloaded/ebin/prim_eval.beambin1540 -> 1544 bytes
-rw-r--r--erts/preloaded/ebin/prim_file.beambin28008 -> 28016 bytes
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin81472 -> 81480 bytes
-rw-r--r--erts/preloaded/ebin/prim_net.beambin5140 -> 5144 bytes
-rw-r--r--erts/preloaded/ebin/prim_zip.beambin22452 -> 22460 bytes
-rw-r--r--erts/preloaded/ebin/socket.beambin78684 -> 79020 bytes
-rw-r--r--erts/preloaded/ebin/socket_registry.beambin0 -> 5676 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin19728 -> 19732 bytes
-rw-r--r--erts/preloaded/src/Makefile3
-rw-r--r--erts/preloaded/src/erl_prim_loader.erl18
-rw-r--r--erts/preloaded/src/erlang.erl4
-rw-r--r--erts/preloaded/src/erts_internal.erl14
-rw-r--r--erts/preloaded/src/prim_file.erl10
-rw-r--r--erts/preloaded/src/socket.erl1889
-rw-r--r--erts/preloaded/src/socket_registry.erl196
-rw-r--r--erts/vsn.mk2
-rw-r--r--lib/asn1/src/Makefile3
-rw-r--r--lib/common_test/doc/src/Makefile1
-rw-r--r--lib/common_test/doc/src/ct_property_test.xml240
-rw-r--r--lib/common_test/doc/src/ct_property_test_chapter.xml249
-rw-r--r--lib/common_test/doc/src/ct_slave.xml2
-rw-r--r--lib/common_test/doc/src/part.xml1
-rw-r--r--lib/common_test/include/ct_property_test.hrl40
-rw-r--r--lib/common_test/src/Makefile3
-rw-r--r--lib/common_test/src/ct_property_test.erl313
-rw-r--r--lib/common_test/test/Makefile5
-rw-r--r--lib/common_test/test/ct_property_test_SUITE.erl24
-rw-r--r--lib/common_test/test/property_test/ct_prop.erl18
-rw-r--r--lib/compiler/doc/src/notes.xml51
-rw-r--r--lib/compiler/src/beam_except.erl3
-rw-r--r--lib/compiler/src/beam_jump.erl14
-rw-r--r--lib/compiler/src/beam_kernel_to_ssa.erl16
-rw-r--r--lib/compiler/src/beam_peep.erl4
-rw-r--r--lib/compiler/src/beam_ssa_bsm.erl19
-rw-r--r--lib/compiler/src/beam_validator.erl304
-rw-r--r--lib/compiler/src/sys_core_fold.erl6
-rw-r--r--lib/compiler/test/beam_except_SUITE.erl6
-rw-r--r--lib/compiler/test/beam_validator_SUITE.erl30
-rw-r--r--lib/compiler/test/beam_validator_SUITE_data/safe_instructions.S102
-rw-r--r--lib/compiler/test/bs_match_SUITE.erl16
-rw-r--r--lib/compiler/test/core_fold_SUITE.erl14
-rw-r--r--lib/compiler/test/fun_SUITE.erl12
-rw-r--r--lib/compiler/test/map_SUITE.erl26
-rw-r--r--lib/compiler/vsn.mk2
-rw-r--r--lib/crypto/c_src/api_ng.c6
-rw-r--r--lib/crypto/doc/src/crypto.xml2
-rw-r--r--lib/crypto/doc/src/notes.xml45
-rw-r--r--lib/crypto/src/crypto.erl30
-rw-r--r--lib/crypto/test/crypto_bench_SUITE.erl2
-rw-r--r--lib/crypto/test/crypto_property_test_SUITE.erl33
-rw-r--r--lib/crypto/test/engine_SUITE.erl4
-rw-r--r--lib/crypto/test/property_test/crypto_ng_api.erl60
-rw-r--r--lib/crypto/test/property_test/crypto_ng_api_stateful.erl161
-rw-r--r--lib/crypto/test/property_test/crypto_prop_generators.erl44
-rw-r--r--lib/crypto/vsn.mk2
-rw-r--r--lib/dialyzer/doc/src/typer.xml2
-rw-r--r--lib/diameter/doc/src/diameter.xml14
-rw-r--r--lib/diameter/doc/src/notes.xml51
-rw-r--r--lib/diameter/examples/code/GNUmakefile6
-rw-r--r--lib/diameter/examples/code/README105
-rw-r--r--lib/diameter/examples/code/client.erl171
-rw-r--r--lib/diameter/examples/code/client_cb.erl29
-rw-r--r--lib/diameter/examples/code/node.erl202
-rw-r--r--lib/diameter/examples/code/redirect.erl66
-rw-r--r--lib/diameter/examples/code/redirect_cb.erl62
-rw-r--r--lib/diameter/examples/code/relay.erl73
-rw-r--r--lib/diameter/examples/code/relay_cb.erl55
-rw-r--r--lib/diameter/examples/code/server.erl121
-rw-r--r--lib/diameter/examples/code/server_cb.erl101
-rw-r--r--lib/diameter/src/Makefile17
-rw-r--r--lib/diameter/src/base/diameter.erl49
-rw-r--r--lib/diameter/src/base/diameter_codec.erl4
-rw-r--r--lib/diameter/src/base/diameter_config.erl20
-rw-r--r--lib/diameter/src/base/diameter_dist.erl17
-rw-r--r--lib/diameter/src/base/diameter_peer_fsm.erl2
-rw-r--r--lib/diameter/src/base/diameter_service.erl83
-rw-r--r--lib/diameter/src/base/diameter_traffic.erl56
-rw-r--r--lib/diameter/src/diameter.appup.src22
-rw-r--r--lib/diameter/src/modules.mk5
-rw-r--r--lib/diameter/src/transport/diameter_tcp.erl6
-rw-r--r--lib/diameter/test/diameter_dist_SUITE.erl53
-rw-r--r--lib/diameter/test/diameter_event_SUITE.erl47
-rw-r--r--lib/diameter/test/diameter_examples_SUITE.erl25
-rw-r--r--lib/diameter/test/diameter_traffic_SUITE.erl18
-rw-r--r--lib/diameter/vsn.mk2
-rw-r--r--lib/erl_interface/configure.in6
-rw-r--r--lib/erl_interface/src/misc/ei_portio.h2
-rw-r--r--lib/eunit/src/eunit_surefire.erl5
-rw-r--r--lib/eunit/test/Makefile1
-rw-r--r--lib/eunit/test/eunit_SUITE.erl23
-rw-r--r--lib/eunit/test/tc0.erl14
-rw-r--r--lib/hipe/icode/hipe_beam_to_icode.erl45
-rw-r--r--lib/hipe/icode/hipe_icode_primops.erl1
-rw-r--r--lib/hipe/test/basic_SUITE_data/basic_exceptions.erl15
-rw-r--r--lib/kernel/doc/src/erl_epmd.xml4
-rw-r--r--lib/kernel/doc/src/notes.xml4
-rw-r--r--lib/kernel/src/code_server.erl25
-rw-r--r--lib/kernel/src/dist_util.erl11
-rw-r--r--lib/kernel/src/inet_dns.erl6
-rw-r--r--lib/kernel/src/inet_res.erl204
-rw-r--r--lib/kernel/src/logger_config.erl12
-rw-r--r--lib/kernel/src/logger_proxy.erl18
-rw-r--r--lib/kernel/src/net_kernel.erl160
-rw-r--r--lib/kernel/test/code_SUITE.erl5
-rw-r--r--lib/kernel/test/gen_udp_SUITE.erl29
-rw-r--r--lib/kernel/test/inet_res_SUITE.erl121
-rw-r--r--lib/kernel/test/init_SUITE.erl23
-rw-r--r--lib/kernel/test/logger_proxy_SUITE.erl14
-rw-r--r--lib/kernel/test/net_SUITE.erl2
-rw-r--r--lib/megaco/src/app/megaco.erl15
-rw-r--r--lib/megaco/test/megaco_codec_flex_lib.erl2
-rw-r--r--lib/megaco/test/megaco_load_SUITE.erl225
-rw-r--r--lib/megaco/test/megaco_mess_SUITE.erl854
-rw-r--r--lib/megaco/test/megaco_mib_SUITE.erl166
-rw-r--r--lib/megaco/test/megaco_mreq_SUITE.erl376
-rw-r--r--lib/megaco/test/megaco_pending_limit_SUITE.erl104
-rw-r--r--lib/megaco/test/megaco_segment_SUITE.erl507
-rw-r--r--lib/megaco/test/megaco_tcp_SUITE.erl1105
-rw-r--r--lib/megaco/test/megaco_test_command_handler.erl193
-rw-r--r--lib/megaco/test/megaco_test_generator.erl56
-rw-r--r--lib/megaco/test/megaco_test_generator_lib.erl29
-rw-r--r--lib/megaco/test/megaco_test_lib.erl885
-rw-r--r--lib/megaco/test/megaco_test_lib.hrl11
-rw-r--r--lib/megaco/test/megaco_test_megaco_generator.erl134
-rw-r--r--lib/megaco/test/megaco_test_mg.erl217
-rw-r--r--lib/megaco/test/megaco_test_mgc.erl110
-rw-r--r--lib/megaco/test/megaco_test_tcp_generator.erl13
-rw-r--r--lib/megaco/test/megaco_trans_SUITE.erl1081
-rw-r--r--lib/megaco/test/megaco_udp_SUITE.erl1157
-rw-r--r--lib/megaco/test/modules.mk3
-rw-r--r--lib/mnesia/src/mnesia_bup.erl1
-rw-r--r--lib/public_key/asn1/PKIX1Algorithms88.asn18
-rw-r--r--lib/public_key/src/pubkey_cert_records.erl8
-rw-r--r--lib/public_key/src/public_key.erl4
-rw-r--r--lib/public_key/test/Makefile3
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE.erl417
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/auth_keys (renamed from lib/public_key/test/public_key_SUITE_data/auth_keys)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/known_hosts (renamed from lib/public_key/test/public_key_SUITE_data/known_hosts)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_pub (renamed from lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_with_comment_pub (renamed from lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/openssh_ecdsa_pub (renamed from lib/public_key/test/public_key_SUITE_data/openssh_ecdsa_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/openssh_rsa_pub (renamed from lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_auth_keys (renamed from lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_known_hosts (renamed from lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_comment_pub (renamed from lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_pub (renamed from lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_ecdsa_pub (renamed from lib/public_key/test/public_key_SUITE_data/ssh2_ecdsa_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_comment_pub (renamed from lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_pub (renamed from lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_subject_pub (renamed from lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_comment_pub (renamed from lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub)0
-rw-r--r--lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_header_pub (renamed from lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub)0
-rw-r--r--lib/public_key/test/public_key_SUITE.erl348
-rw-r--r--lib/sasl/src/systools_make.erl2
-rw-r--r--lib/snmp/doc/src/notes.xml26
-rw-r--r--lib/snmp/doc/src/snmp_agent_netif.xml4
-rw-r--r--lib/snmp/doc/src/snmp_app.xml34
-rw-r--r--lib/snmp/doc/src/snmp_config.xml38
-rw-r--r--lib/snmp/doc/src/snmp_manager_netif.xml257
-rw-r--r--lib/snmp/doc/src/snmp_pdus.xml17
-rw-r--r--lib/snmp/doc/src/snmpm.xml17
-rw-r--r--lib/snmp/doc/src/snmpm_mpd.xml2
-rw-r--r--lib/snmp/doc/src/snmpm_user.xml10
-rw-r--r--lib/snmp/src/manager/snmpm.erl20
-rw-r--r--lib/snmp/src/manager/snmpm_config.erl21
-rw-r--r--lib/snmp/src/manager/snmpm_net_if.erl40
-rw-r--r--lib/snmp/src/manager/snmpm_server.erl375
-rw-r--r--lib/snmp/src/manager/snmpm_user.erl4
-rw-r--r--lib/snmp/src/misc/snmp_verbosity.erl1
-rw-r--r--lib/snmp/src/misc/snmp_verbosity.hrl34
-rw-r--r--lib/snmp/test/Makefile12
-rw-r--r--lib/snmp/test/modules.mk10
-rw-r--r--lib/snmp/test/snmp_agent_SUITE.erl1212
-rw-r--r--lib/snmp/test/snmp_agent_conf_SUITE.erl4
-rw-r--r--lib/snmp/test/snmp_agent_mibs_SUITE.erl145
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl251
-rw-r--r--lib/snmp/test/snmp_compiler_SUITE.erl187
-rw-r--r--lib/snmp/test/snmp_conf_SUITE.erl40
-rw-r--r--lib/snmp/test/snmp_log_SUITE.erl145
-rw-r--r--lib/snmp/test/snmp_manager_SUITE.erl1561
-rw-r--r--lib/snmp/test/snmp_manager_config_SUITE.erl1135
-rw-r--r--lib/snmp/test/snmp_manager_user_SUITE.erl290
-rw-r--r--lib/snmp/test/snmp_note_store_SUITE.erl185
-rw-r--r--lib/snmp/test/snmp_pdus_SUITE.erl166
-rw-r--r--lib/snmp/test/snmp_test_lib.erl1110
-rw-r--r--lib/snmp/test/snmp_test_lib.hrl74
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl323
-rw-r--r--lib/snmp/test/snmp_test_mgr_misc.erl64
-rw-r--r--lib/snmp/test/snmp_to_snmpnet_SUITE.erl67
-rw-r--r--lib/ssh/doc/src/notes.xml102
-rw-r--r--lib/ssh/doc/src/ssh.xml35
-rw-r--r--lib/ssh/src/Makefile19
-rw-r--r--lib/ssh/src/ssh.app.src3
-rw-r--r--lib/ssh/src/ssh.erl20
-rw-r--r--lib/ssh/src/ssh.hrl3
-rw-r--r--lib/ssh/src/ssh_acceptor.erl24
-rw-r--r--lib/ssh/src/ssh_auth.erl2
-rw-r--r--lib/ssh/src/ssh_cli.erl16
-rw-r--r--lib/ssh/src/ssh_client_channel.erl61
-rw-r--r--lib/ssh/src/ssh_connection.erl7
-rw-r--r--lib/ssh/src/ssh_connection_handler.erl124
-rw-r--r--lib/ssh/src/ssh_dbg.erl85
-rw-r--r--lib/ssh/src/ssh_message.erl34
-rw-r--r--lib/ssh/src/ssh_sftp.erl20
-rw-r--r--lib/ssh/src/ssh_sftpd.erl17
-rw-r--r--lib/ssh/src/ssh_shell.erl16
-rw-r--r--lib/ssh/src/ssh_transport.erl88
-rw-r--r--lib/ssh/src/ssh_xfer.erl6
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl32
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_client_server.erl203
-rw-r--r--lib/ssh/test/property_test/ssh_eqc_encode_decode.erl31
-rw-r--r--lib/ssh/test/ssh_basic_SUITE.erl53
-rw-r--r--lib/ssh/test/ssh_connection_SUITE.erl29
-rw-r--r--lib/ssh/test/ssh_relay.erl21
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE.erl388
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/F一.txt1
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/big.txt16384
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f11
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f21
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f2.txt1
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f3.txt1
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/g四.txt1
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/test_data/big.txt (renamed from lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/big.txt)0
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/test_data/d1/f1 (renamed from lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/d1/f1)0
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/test_data/d1/f2 (renamed from lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/d1/f2)0
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/test_data/f1.txt (renamed from lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/f1.txt)0
-rw-r--r--lib/ssh/test/ssh_sftp_SUITE_data/test_data/f2.txt (renamed from lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/f2.txt)0
-rw-r--r--lib/ssh/test/ssh_sup_SUITE.erl33
-rw-r--r--lib/ssh/test/ssh_test_lib.erl87
-rw-r--r--lib/ssh/test/ssh_to_openssh_SUITE.erl68
-rw-r--r--lib/ssh/test/ssh_upgrade_SUITE.erl3
-rw-r--r--lib/ssh/vsn.mk2
-rw-r--r--lib/ssl/doc/src/notes.xml59
-rw-r--r--lib/ssl/doc/src/ssl.xml100
-rw-r--r--lib/ssl/doc/src/standards_compliance.xml12
-rw-r--r--lib/ssl/src/dtls_connection.erl14
-rw-r--r--lib/ssl/src/dtls_listener_sup.erl4
-rw-r--r--lib/ssl/src/dtls_packet_demux.erl10
-rw-r--r--lib/ssl/src/dtls_socket.erl9
-rw-r--r--lib/ssl/src/ssl.app.src2
-rw-r--r--lib/ssl/src/ssl.erl44
-rw-r--r--lib/ssl/src/ssl_alert.erl8
-rw-r--r--lib/ssl/src/ssl_alert.hrl2
-rw-r--r--lib/ssl/src/ssl_connection.erl81
-rw-r--r--lib/ssl/src/ssl_handshake.erl68
-rw-r--r--lib/ssl/src/ssl_internal.hrl7
-rw-r--r--lib/ssl/src/ssl_logger.erl5
-rw-r--r--lib/ssl/src/ssl_record.hrl4
-rw-r--r--lib/ssl/src/tls_client_ticket_store.erl2
-rw-r--r--lib/ssl/src/tls_connection.erl167
-rw-r--r--lib/ssl/src/tls_connection_1_3.erl5
-rw-r--r--lib/ssl/src/tls_handshake.erl2
-rw-r--r--lib/ssl/src/tls_handshake_1_3.erl328
-rw-r--r--lib/ssl/src/tls_handshake_1_3.hrl3
-rw-r--r--lib/ssl/src/tls_record.erl22
-rw-r--r--lib/ssl/src/tls_record_1_3.erl21
-rw-r--r--lib/ssl/src/tls_sender.erl159
-rw-r--r--lib/ssl/src/tls_server_session_ticket.erl4
-rw-r--r--lib/ssl/src/tls_v1.erl6
-rw-r--r--lib/ssl/test/Makefile3
-rw-r--r--lib/ssl/test/dtls_api_SUITE.erl48
-rw-r--r--lib/ssl/test/openssl_alpn_SUITE.erl4
-rw-r--r--lib/ssl/test/openssl_key_update_SUITE.erl134
-rw-r--r--lib/ssl/test/openssl_session_ticket_SUITE.erl409
-rw-r--r--lib/ssl/test/openssl_sni_SUITE.erl12
-rw-r--r--lib/ssl/test/property_test/ssl_eqc_handshake.erl2
-rw-r--r--lib/ssl/test/ssl_alert_SUITE.erl2
-rw-r--r--lib/ssl/test/ssl_cipher_suite_SUITE.erl95
-rw-r--r--lib/ssl/test/ssl_key_update_SUITE.erl136
-rw-r--r--lib/ssl/test/ssl_packet_SUITE.erl9
-rw-r--r--lib/ssl/test/ssl_payload_SUITE.erl32
-rw-r--r--lib/ssl/test/ssl_renegotiate_SUITE.erl12
-rw-r--r--lib/ssl/test/ssl_session_SUITE.erl184
-rw-r--r--lib/ssl/test/ssl_session_ticket_SUITE.erl385
-rw-r--r--lib/ssl/test/ssl_sni_SUITE.erl70
-rw-r--r--lib/ssl/test/ssl_test_lib.erl590
-rw-r--r--lib/ssl/test/tls_1_3_record_SUITE.erl10
-rw-r--r--lib/ssl/vsn.mk2
-rw-r--r--lib/stdlib/doc/src/gen_statem.xml175
-rw-r--r--lib/stdlib/doc/src/notes.xml57
-rw-r--r--lib/stdlib/doc/src/queue.xml2
-rw-r--r--lib/stdlib/src/calendar.erl8
-rw-r--r--lib/stdlib/src/erl_parse.yrl48
-rw-r--r--lib/stdlib/src/erl_pp.erl59
-rw-r--r--lib/stdlib/src/erl_tar.erl49
-rw-r--r--lib/stdlib/src/gen_statem.erl410
-rw-r--r--lib/stdlib/src/ms_transform.erl5
-rw-r--r--lib/stdlib/src/shell.erl4
-rw-r--r--lib/stdlib/src/stdlib.app.src3
-rw-r--r--lib/stdlib/src/stdlib.appup.src6
-rw-r--r--lib/stdlib/src/uri_string.erl25
-rw-r--r--lib/stdlib/test/calendar_SUITE.erl3
-rw-r--r--lib/stdlib/test/erl_eval_SUITE.erl18
-rw-r--r--lib/stdlib/test/erl_pp_SUITE.erl104
-rw-r--r--lib/stdlib/test/ets_SUITE.erl48
-rw-r--r--lib/stdlib/test/gen_statem_SUITE.erl72
-rw-r--r--lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl29
-rw-r--r--lib/stdlib/test/tar_SUITE.erl30
-rw-r--r--lib/stdlib/test/uri_string_SUITE.erl12
-rw-r--r--lib/stdlib/vsn.mk2
-rw-r--r--lib/tools/emacs/erlang.el16
-rw-r--r--lib/tools/src/cover.erl5
-rw-r--r--lib/tools/src/fprof.erl2
-rw-r--r--lib/tools/test/cover_SUITE.erl13
-rw-r--r--lib/tools/test/cover_SUITE_data/otp_16476/obvious_booleans.erl17
-rw-r--r--lib/tools/test/emacs_SUITE.erl3
-rw-r--r--lib/tools/test/emacs_SUITE_data/type_specs24
-rw-r--r--lib/tools/test/fprof_SUITE.erl33
-rw-r--r--make/otp_version_tickets_in_merge6
-rw-r--r--otp_versions.table13
-rwxr-xr-xscripts/bundle-otp4
-rw-r--r--system/doc/design_principles/distributed_applications.xml2
-rw-r--r--system/doc/design_principles/release_handling.xml4
-rw-r--r--system/doc/design_principles/statem.xml80
-rw-r--r--system/doc/reference_manual/expressions.xml8
396 files changed, 23087 insertions, 27281 deletions
diff --git a/.travis.yml b/.travis.yml
index 51453639b0..5a87bd3fd1 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -100,8 +100,8 @@ matrix:
api_key:
secure: vW5PN6zng5H5+TCvwfwpGZsABrdCWYcFwDm3KXq+plsecBmTayu/0jgNso5Z97FbzDGVTLHWchvywEYQWnmrEByyOrqH73v1LN6JEfN99VpSrdFr15IzhblcyU1R9ugYc3WEoYjX0Q1uGelDSWRuuQOPbzy8mZf3D4rSGonyraP7jPTdHhs5P3ZWk6OMFz+tCdF4XohXqbhXIBOeH/EKg0svX2u5IcV01/YOL8LHWz6G7+gqBryEXx1+ngjQXQmMQwd7Yg3WOKE4XV9gX8ixZsbpUPZXAQKF+VOYdEgeiIr1hI0tBQUYX7FYEzYH5MCxqng5RdaPTOAm1oQroyGkIcWSXzDwN4AhJ7xqa/0NRdEaBPdQzPBCc+pVUDkxBR1ytXjBQqdQMnI6184TDiU5XBnj3kmieLkkKPKQNoPve/Y8Q8zutw4GNc7gixGcQCjtAFUbrT73QVRrezQH0qIdt23rivvf2R7CCOWSmgzowrswmtHdgeEVbodUIBPTNp7qzlUk9gDp6vW0XrOC4qEFI+VaY5PsEOXrrxZmI3gGGJgsbfzRvzvvupQcLNERniJ67r/uumbForpL0x1c65scKuMWwcn1wqt2OLbDoIIuM31Ph2HX/09TTqECU7CTvqLT5MnbZHXGjY9c3ch+sY3tSfaEX6aazl/Dqx28c7boCEw=
file:
- - ${TRAVIS_TAG}-bundle.txt
- - ${TRAVIS_TAG}-bundle.tar.gz
+ - ${TRAVIS_TAG}.0-bundle.txt
+ - ${TRAVIS_TAG}.0-bundle.tar.gz
on:
# We only deploy on pushes to tags that match the regexp
tags: true
diff --git a/OTP_VERSION b/OTP_VERSION
index 0398faf11c..3abee4573a 100644
--- a/OTP_VERSION
+++ b/OTP_VERSION
@@ -1 +1 @@
-22.2.1
+22.2.8
diff --git a/erts/aclocal.m4 b/erts/aclocal.m4
index 5fefd72d5d..5d274e69c3 100644
--- a/erts/aclocal.m4
+++ b/erts/aclocal.m4
@@ -2935,6 +2935,12 @@ fi
# DED_EMU_THR_DEFS=$EMU_THR_DEFS
DED_CFLAGS="$CFLAGS $CPPFLAGS $DED_CFLAGS"
if test "x$GCC" = xyes; then
+ # Use -fno-common for gcc, that is link error if multiple definitions of
+ # global variables are encountered. This is ISO C compliant.
+ # Until version 10, gcc has had -fcommon as default, which allows and merges
+ # such dubious duplicates.
+ LM_TRY_ENABLE_CFLAG([-fno-common], [DED_CFLAGS])
+
DED_STATIC_CFLAGS="$DED_CFLAGS"
DED_CFLAGS="$DED_CFLAGS -fPIC"
fi
diff --git a/erts/configure.in b/erts/configure.in
index a887f86621..609c457393 100644
--- a/erts/configure.in
+++ b/erts/configure.in
@@ -2,7 +2,7 @@ dnl Process this file with autoconf to produce a configure script. -*-m4-*-
dnl %CopyrightBegin%
dnl
-dnl Copyright Ericsson AB 1997-2019. All Rights Reserved.
+dnl Copyright Ericsson AB 1997-2020. All Rights Reserved.
dnl
dnl Licensed under the Apache License, Version 2.0 (the "License");
dnl you may not use this file except in compliance with the License.
@@ -566,6 +566,12 @@ if test "x$GCC" = xyes; then
WFLAGS="$WFLAGS -Wdeclaration-after-statement"
fi
CFLAGS=$saved_CFLAGS
+
+ # Use -fno-common for gcc, that is link error if multiple definitions of
+ # global variables are encountered. This is ISO C compliant.
+ # Until version 10, gcc has had -fcommon as default, which allows and merges
+ # such dubious duplicates.
+ LM_TRY_ENABLE_CFLAG([-fno-common], [CFLAGS])
else
WFLAGS=""
WERRORFLAGS=""
@@ -1384,6 +1390,40 @@ fi
AC_SUBST(USE_ESOCK)
+AC_ARG_WITH(esock-counter-size,
+AS_HELP_STRING([--with-esock-counter-size=SZ],
+ [Size of the esock counters, in number of bits: 16 | 24 | 32 | 48 | 64; default is 64]),
+[],
+[with_esock_counter_size=64])
+
+case "$with_esock_counter_size" in
+ 16)
+ AC_DEFINE(ESOCK_COUNTER_SIZE, [16], [ESOCK counter size])
+ ;;
+ 24)
+ AC_DEFINE(ESOCK_COUNTER_SIZE, [24], [ESOCK counter size])
+ ;;
+ 32)
+ AC_DEFINE(ESOCK_COUNTER_SIZE, [32], [ESOCK counter size])
+ ;;
+ 48)
+ AC_DEFINE(ESOCK_COUNTER_SIZE, [48], [ESOCK counter size])
+ ;;
+ 64)
+ AC_DEFINE(ESOCK_COUNTER_SIZE, [64], [ESOCK counter size])
+ ;;
+ *)
+ AC_MSG_WARN([Invalid esock counter size ($with_esock_counter_size), using default (64)])
+ AC_DEFINE(ESOCK_COUNTER_SIZE, [64], [ESOCK counter size])
+ dnl with_esock_counter_size=64
+ ;;
+esac
+dnl ESOCK_COUNTER_SIZE=$with_esock_counter_size
+
+dnl We don't actually (currently) use this in erlang
+dnl AC_SUBST(ESOCK_COUNTER_SIZE)
+
+
dnl
dnl This test kindly borrowed from Tcl
dnl
@@ -1778,6 +1818,7 @@ AC_CHECK_SIZEOF(long long)
AC_CHECK_SIZEOF(size_t)
AC_CHECK_SIZEOF(off_t)
AC_CHECK_SIZEOF(time_t)
+AC_CHECK_SIZEOF(suseconds_t)
BITS64=
diff --git a/erts/doc/src/absform.xml b/erts/doc/src/absform.xml
index d77d989057..fd4cdac03f 100644
--- a/erts/doc/src/absform.xml
+++ b/erts/doc/src/absform.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2001</year><year>2018</year>
+ <year>2001</year><year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -134,7 +134,7 @@
<item>
<p>If F is a type declaration <c>-Type Name(V_1, ..., V_k) :: T</c>,
where <c>Type</c> is either the atom <c>type</c> or the atom
- <c>opaque</c>, each <c>V_i</c> is a variable, and <c>T</c> is a type,
+ <c>opaque</c>, each <c>V_i</c> is a type variable, and <c>T</c> is a type,
then Rep(F) =
<c>{attribute,LINE,Type,{Name,Rep(T),[Rep(V_1), ...,
Rep(V_k)]}}</c>.</p>
diff --git a/erts/doc/src/alt_disco.xml b/erts/doc/src/alt_disco.xml
index 067eb4992d..d95e62bc8a 100644
--- a/erts/doc/src/alt_disco.xml
+++ b/erts/doc/src/alt_disco.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2018</year><year>2018</year>
+ <year>2018</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -22,7 +22,7 @@
</legalnotice>
- <title>How to Implement an Alternative Service Discovery for Erlang Distribution
+ <title>How to Implement an Alternative Node Discovery for Erlang Distribution
</title>
<prepared>Timmo Verlaan</prepared>
<responsible></responsible>
@@ -34,20 +34,20 @@
<file>alt_disco.xml</file>
</header>
<p>
- This section describes how to implement an alternative discovery mechanism
- for Erlang distribution. Discovery is normally done using DNS and the
- Erlang Port Mapper Daemon (EPMD) for port discovery.
+ This section describes how to implement an alternative node discovery
+ mechanism for Erlang distribution. Node discovery is normally done using DNS
+ and the Erlang Port Mapper Daemon (EPMD) for port registration and lookup.
</p>
<note><p>
- Support for alternative service discovery mechanisms was added in Erlang/OTP
+ Support for alternative node discovery mechanisms was added in Erlang/OTP
21.
</p></note>
<section>
<title>Introduction</title>
- <p>To implement your own service discovery module you have to write your own
+ <p>To implement your own node discovery module you have to write your own
EPMD module. The <seealso marker="kernel:erl_epmd">EPMD module</seealso> is
responsible for providing the location of another node. The distribution
modules (<c>inet_tcp_dist</c>/<c>inet_tls_dist</c>) call the EPMD module to
diff --git a/erts/doc/src/epmd.xml b/erts/doc/src/epmd.xml
index 311483022d..75353cbc07 100644
--- a/erts/doc/src/epmd.xml
+++ b/erts/doc/src/epmd.xml
@@ -72,6 +72,12 @@
therefore required for an Erlang network to function
correctly.</p>
+ <note><p>On Windows the maximum number of nodes allowed in one
+ epmd instance is 60. This is because of limitations in the current
+ implementation. If you need more nodes, you should look into using
+ and erlang based epmd implementation such as
+ <url href="https://github.com/erlang/epmd">Erlang EPMD</url>.</p></note>
+
<taglist>
<tag>Starting the port mapper daemon</tag>
<item>
diff --git a/erts/doc/src/erl.xml b/erts/doc/src/erl.xml
index ed1b0880b4..a37707f7f9 100644
--- a/erts/doc/src/erl.xml
+++ b/erts/doc/src/erl.xml
@@ -575,7 +575,11 @@
<tag><marker id="async_thread_pool_size"/><c><![CDATA[+A size]]></c></tag>
<item>
<p>Sets the number of threads in async thread pool. Valid range
- is 0-1024. Defaults to 1.</p>
+ is 0-1024. The async thread pool is used by linked-in drivers to
+ handle work that may take a very long time. Since OTP-21 there are
+ very few linked-in drivers in the default Erlang/OTP distribution
+ that uses the async thread pool. Most of them have been migrated to
+ dirty IO schedulers. Defaults to 1.</p>
</item>
<tag><c><![CDATA[+B [c | d | i]]]></c></tag>
<item>
@@ -1015,6 +1019,12 @@
executing on ordinary schedulers. If the amount of dirty CPU
schedulers was allowed to be unlimited, dirty CPU bound jobs would
potentially starve normal jobs.</p>
+ <p>Typical users of the dirty CPU schedulers are large garbage collections,
+ json protocol encode/decoders written as nifs and matrix manipulation
+ libraries.</p>
+ <p>You can use <seealso marker="runtime_tools:msacc">msacc(3)</seealso>
+ in order to see the current load of the dirty CPU schedulers threads
+ and adjust the number used accordingly.</p>
</item>
<tag><marker id="+SDPcpu"/><c><![CDATA[+SDPcpu
DirtyCPUSchedulersPercentage:DirtyCPUSchedulersOnlinePercentage]]></c></tag>
@@ -1043,16 +1053,18 @@
<tag><marker id="+SDio"/><c><![CDATA[+SDio DirtyIOSchedulers]]></c></tag>
<item>
<p>Sets the number of dirty I/O scheduler threads to create.
- Valid range is 0-1024. By
- default, the number of dirty I/O scheduler threads created is 10,
- same as the default number of threads in the <seealso
- marker="#async_thread_pool_size">async thread pool</seealso>.</p>
+ Valid range is 1-1024. By
+ default, the number of dirty I/O scheduler threads created is 10.</p>
<p>The amount of dirty IO schedulers is not limited by the amount of
normal schedulers <seealso marker="#+SDcpu">like the amount of
dirty CPU schedulers</seealso>. This since only I/O bound work is
expected to execute on dirty I/O schedulers. If the user should schedule CPU
bound jobs on dirty I/O schedulers, these jobs might starve ordinary
jobs executing on ordinary schedulers.</p>
+ <p>Typical users of the dirty IO schedulers are reading and writing to files.</p>
+ <p>You can use <seealso marker="runtime_tools:msacc">msacc(3)</seealso>
+ in order to see the current load of the dirty IO schedulers threads
+ and adjust the number used accordingly.</p>
</item>
<tag><c><![CDATA[+sFlag Value]]></c></tag>
<item>
diff --git a/erts/doc/src/erl_driver.xml b/erts/doc/src/erl_driver.xml
index 3e2d3bb447..07af7621ff 100644
--- a/erts/doc/src/erl_driver.xml
+++ b/erts/doc/src/erl_driver.xml
@@ -2372,10 +2372,26 @@ r = driver_async(myPort, &myKey, myData, myFunc); ]]></code>
<marker id="erl_drv_mutex_create"></marker>
<p>Creates a mutex and returns a pointer to it.</p>
<p><c>name</c> is a string identifying the created mutex. It is used
- to identify the mutex in planned future debug functionality.</p>
+ to identify the mutex in debug functionality (see note).</p>
<p>Returns <c>NULL</c> on failure. The driver creating the mutex is
responsible for destroying it before the driver is unloaded.</p>
<p>This function is thread-safe.</p>
+ <marker id="lock_checker"></marker>
+ <note><p>
+ One such debug functionality is the <em>lock checker</em>, which
+ can detect locking order violations and thereby potential deadlock
+ bugs. For the lock checker to work the <c>name</c> should be on the
+ format <c>"App.Type"</c> or <c>"App.Type[Instance]"</c>, where App is
+ the name of the application, Type is the name of the lock type and
+ Instance is optional information about each lock instance. "App.Type"
+ should be a unique name for the lock checker to detect lock order
+ violations between locks of different types. The Instance information
+ is currently ignored.</p><p>
+ For example, if we have mutexes of types "myapp.xtable" and
+ "myapp.xitem" then the lock checker will make sure either
+ "myapp.xtable" locks are never locked after "myapp.xitem" locks or
+ vice versa.
+ </p></note>
</desc>
</func>
@@ -2675,8 +2691,8 @@ erl_drv_output_term(driver_mk_port(drvport), spec, sizeof(spec) / sizeof(spec[0]
<marker id="erl_drv_rwlock_create"></marker>
<p>Creates an rwlock and returns a pointer to it.</p>
<p><c>name</c> is a string identifying the created rwlock.
- It is used to identify the rwlock in planned future
- debug functionality.</p>
+ It is used to identify the rwlock in debug functionality (see note
+ about the <seealso marker="#lock_checker">lock checker</seealso>).</p>
<p>Returns <c>NULL</c> on failure. The driver creating the rwlock
is responsible for destroying it before the driver is unloaded.</p>
<p>This function is thread-safe.</p>
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index 2183f75487..2f3d2f9624 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -4121,6 +4121,71 @@ RealSystem = system + MissedSystem</code>
<seealso marker="erl#+spp"><c>+spp</c></seealso> to
<c>erl(1)</c>.</p>
</item>
+ <tag><c>{busy_limits_port, {Low, High} | disabled}</c></tag>
+ <item>
+ <p>Sets limits that will be used for controlling the
+ busy state of the port.</p>
+ <p>When the ports internal output queue size becomes
+ larger than or equal to <c>High</c> bytes, it enters
+ the busy state. When it becomes less than <c>Low</c>
+ bytes it leaves the busy state. When the port is in
+ the busy state, processes sending commands to it will
+ be suspended until the port leaves the busy state.
+ Commands are in this context either
+ <c>Port ! {Owner, {command, Data}}</c> or
+ <c>port_command/[2,3]</c>.</p>
+ <p>
+ The <c>Low</c> limit is automatically adjusted to the
+ same as <c>High</c> if it is set larger then <c>High</c>.
+ Valid range of values for <c>Low</c> and <c>High</c> is
+ <c>[1, (1 bsl (8*erlang:system_info(wordsize)))-2]</c>.
+ If the atom <c>disabled</c> is passed, the port will
+ never enter the busy state.</p>
+ <p>The defaults are <c>Low = 4096</c> and
+ <c>High = 8192</c>.</p>
+ <p><em>Note</em> that this option is only valid when
+ spawning an executable (port program) by opening the
+ spawn driver and when opening the <c>fd</c> driver.
+ This option will cause a failure with a <c>badarg</c>
+ exception when opening other drivers.</p>
+ </item>
+ <tag><c>{busy_limits_msgq, {Low, High} | disabled}</c></tag>
+ <item>
+ <p>Sets limits that will be used for controlling the
+ busy state of the port message queue.</p>
+ <p>When the ports message queue size becomes larger
+ than or equal to <c>High</c> bytes it enters the busy
+ state. When it becomes less than <c>Low</c> bytes it
+ leaves the busy state. When the port message queue is
+ in the busy state, processes sending commands to it
+ will be suspended until the port message queue leaves
+ the busy state. Commands are in this context either
+ <c>Port ! {Owner, {command, Data}}</c> or
+ <c>port_command/[2,3]</c>.</p>
+ <p>The <c>Low</c> limit is automatically adjusted to the
+ same as <c>High</c> if it is set larger then <c>High</c>.
+ Valid range of values for <c>Low</c> and <c>High</c> is
+ <c>[1, (1 bsl (8*erlang:system_info(wordsize)))-2]</c>.
+ If the atom <c>disabled</c> is passed, the port
+ message queue will never enter the busy state.</p>
+ <p><em>Note</em> that if the driver statically has
+ disabled the use of this feature, a failure with a
+ <c>badarg</c> exception will be raised unless this
+ option also is set to <c>disable</c> or not passed
+ at all.</p>
+ <p>The defaults are <c>Low = 4096</c> and
+ <c>High = 8192</c> unless the driver itself does
+ modifications of these values.</p>
+ <p><em>Note</em> that the driver might fail if
+ it also adjust these limits by itself and you
+ have disabled this feature.</p>
+ <p>The spawn driver (used when spawning an executable)
+ and the <c>fd</c> driver do not disable this feature
+ and do not adjust these limits by themselves.</p>
+ <p>For more information see the documentation
+ <seealso marker="erl_driver#erl_drv_busy_msgq_limits"><c>erl_drv_busy_msgq_limits()</c></seealso>.
+ </p>
+ </item>
</taglist>
<p>Default is <c>stream</c> for all port types and
<c>use_stdio</c> for spawned ports.</p>
diff --git a/erts/doc/src/init.xml b/erts/doc/src/init.xml
index c824e37976..d6c73a02ec 100644
--- a/erts/doc/src/init.xml
+++ b/erts/doc/src/init.xml
@@ -101,7 +101,7 @@
</item>
<tag><c>home</c></tag>
<item>
- <p>The home directory:</p>
+ <p>The home directory (on Unix, the value of $HOME):</p>
<pre>
4> <input>init:get_argument(home).</input>
{ok,[["/home/harry"]]}</pre>
diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml
index 2776407af9..48208574d1 100644
--- a/erts/doc/src/notes.xml
+++ b/erts/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2018</year>
+ <year>2004</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -31,6 +31,107 @@
</header>
<p>This document describes the changes made to the ERTS application.</p>
+<section><title>Erts 10.6.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A process could get into an inconsistent state where it
+ was runnable, but never scheduled for execution. This
+ could occur when a mix of <c>normal</c> and <c>low</c>
+ priority processes where scheduled on the same type of
+ dirty scheduler simultaneously.</p>
+ <p>
+ Own Id: OTP-16446 Aux Id: ERL-1157 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A process could end up in a state where it got endlessly
+ rescheduled without making any progress. This occurred
+ when a system task, such as check of process code (part
+ of a code purge), was scheduled on a high priority
+ process trying to execute on a dirty scheduler.</p>
+ <p>
+ Own Id: OTP-16436 Aux Id: ERL-1152 </p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Improved signal handling for processes executing dirty.
+ For example, avoid busy wait in dirty signal handler
+ process when process is doing garbage collection on dirty
+ scheduler.</p>
+ <p>
+ Own Id: OTP-16358</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.6.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Taking a scheduler offline could cause timers set while
+ executing on that scheduler to be delayed until the
+ scheduler was put online again. This bug was introduced
+ in ERTS version 10.0 (OTP 21.0).</p>
+ <p>
+ Own Id: OTP-16371</p>
+ </item>
+ <item>
+ <p>
+ The <c>ets:update_counter/4</c> core dumped when given an
+ ordered_set with write_concurrency enabled and an invalid
+ position. This bug has been fixed.</p>
+ <p>
+ Own Id: OTP-16378 Aux Id: ERL-1125 </p>
+ </item>
+ <item>
+ <p>
+ A process calling <seealso
+ marker="erts:erlang#system_flag_multi_scheduling"><c>erlang:system_flag(multi_scheduling,
+ block)</c></seealso> could end up blocked waiting for the
+ operation to complete indefinitely.</p>
+ <p>
+ Own Id: OTP-16379</p>
+ </item>
+ </list>
+ </section>
+
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Duplicate entries for [socket:]getopt and [socket:]setopt
+ in man page.</p>
+ <p>
+ Own Id: OTP-16333 Aux Id: ERL-1104 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.6.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -1445,6 +1546,101 @@
</section>
+<section><title>Erts 10.3.5.10</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed bug in <c>ets:update_counter/4</c>, when called
+ with an invalid <c>UpdateOp</c> and a <c>Key</c> that
+ does not exist, causing <c>ets:info(T,size)</c> to return
+ incorrect values. Bug exists since OTP-19.0.2.</p>
+ <p>
+ Own Id: OTP-16404 Aux Id: ERL-1127 </p>
+ </item>
+ <item>
+ <p>
+ A process could get into an inconsistent state where it
+ was runnable, but never scheduled for execution. This
+ could occur when a mix of <c>normal</c> and <c>low</c>
+ priority processes where scheduled on the same type of
+ dirty scheduler simultaneously.</p>
+ <p>
+ Own Id: OTP-16446 Aux Id: ERL-1157 </p>
+ </item>
+ <item>
+ <p>
+ Corrected the valid range of the <c>erl</c> command line
+ argument <seealso marker="erts:erl#+SDio"><c>+SDio
+ &lt;NumberOfDirtyIoSchedulers&gt;</c></seealso> from
+ <c>0..1024</c> to <c>1..1024</c>. <c>+SDio 0</c> was
+ erroneously allowed which just caused the VM to crash on
+ the first dirty I/O job scheduled.</p>
+ <p>
+ Own Id: OTP-16481</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.3.5.9</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A process could end up in a state where it got endlessly
+ rescheduled without making any progress. This occurred
+ when a system task, such as check of process code (part
+ of a code purge), was scheduled on a high priority
+ process trying to execute on a dirty scheduler.</p>
+ <p>
+ Own Id: OTP-16436 Aux Id: ERL-1152 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>erlang:list_to_ref/1</c> when called with
+ a reference created by a remote note. Function
+ <c>list_to_ref/1</c> is intended for debugging and not to
+ be used in application programs. Bug exist since OTP
+ 20.0.</p>
+ <p>
+ Own Id: OTP-16438</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 10.3.5.8</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Taking a scheduler offline could cause timers set while
+ executing on that scheduler to be delayed until the
+ scheduler was put online again. This bug was introduced
+ in ERTS version 10.0 (OTP 21.0).</p>
+ <p>
+ Own Id: OTP-16371</p>
+ </item>
+ <item>
+ <p>
+ A process calling <seealso
+ marker="erts:erlang#system_flag_multi_scheduling"><c>erlang:system_flag(multi_scheduling,
+ block)</c></seealso> could end up blocked waiting for the
+ operation to complete indefinitely.</p>
+ <p>
+ Own Id: OTP-16379</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 10.3.5.7</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -3708,7 +3904,7 @@
marker="kernel:erl_epmd"><c>erl_epmd</c></seealso>
reference manual and ERTS User's Guide <seealso
marker="erts:alt_disco">How to Implement an Alternative
- Service Discovery for Erlang Distribution</seealso>.</p>
+ Node Discovery for Erlang Distribution</seealso>.</p>
<p>
Own Id: OTP-15086 Aux Id: PR-1694 </p>
</item>
@@ -3717,6 +3913,87 @@
</section>
+<section><title>Erts 9.3.3.15</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A process could end up in a state where it got endlessly
+ rescheduled without making any progress. This occurred
+ when a system task, such as check of process code (part
+ of a code purge), was scheduled on a high priority
+ process trying to execute on a dirty scheduler.</p>
+ <p>
+ Own Id: OTP-16436 Aux Id: ERL-1152 </p>
+ </item>
+ <item>
+ <p>
+ Fixed bug in <c>erlang:list_to_ref/1</c> when called with
+ a reference created by a remote note. Function
+ <c>list_to_ref/1</c> is intended for debugging and not to
+ be used in application programs. Bug exist since OTP
+ 20.0.</p>
+ <p>
+ Own Id: OTP-16438</p>
+ </item>
+ <item>
+ <p>
+ A process could get into an inconsistent state where it
+ was runnable, but never scheduled for execution. This
+ could occur when a mix of <c>normal</c> and <c>low</c>
+ priority processes where scheduled on the same type of
+ dirty scheduler simultaneously.</p>
+ <p>
+ Own Id: OTP-16446 Aux Id: ERL-1157 </p>
+ </item>
+ <item>
+ <p>
+ Fixed erroneous mapping of exit reason from <c>kill</c>
+ to <c>killed</c> on reception of some exit signals due to
+ a broken link. This bug has existed since ERTS version
+ 5.5.2 (OTP R11).</p>
+ <p>
+ This bug was also unknowingly fixed in ERTS version 10.0
+ (OTP 21.0) due to a new ERTS internal implementation of
+ signaling between processes.</p>
+ <p>
+ Own Id: OTP-16465 Aux Id: ERL-1165, OTP-6160, OTP-14589 </p>
+ </item>
+ <item>
+ <p>
+ Corrected the valid range of the <c>erl</c> command line
+ argument <seealso marker="erts:erl#+SDio"><c>+SDio
+ &lt;NumberOfDirtyIoSchedulers&gt;</c></seealso> from
+ <c>0..1024</c> to <c>1..1024</c>. <c>+SDio 0</c> was
+ erroneously allowed which just caused the VM to crash on
+ the first dirty I/O job scheduled.</p>
+ <p>
+ Own Id: OTP-16481</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Erts 9.3.3.14</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ A process calling <seealso
+ marker="erts:erlang#system_flag_multi_scheduling"><c>erlang:system_flag(multi_scheduling,
+ block)</c></seealso> could end up blocked waiting for the
+ operation to complete indefinitely.</p>
+ <p>
+ Own Id: OTP-16379</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Erts 9.3.3.13</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/erts/doc/src/socket.xml b/erts/doc/src/socket.xml
index c54fe38bfd..2d16ff2074 100644
--- a/erts/doc/src/socket.xml
+++ b/erts/doc/src/socket.xml
@@ -505,6 +505,14 @@
</func>
<func>
+ <name name="number_of" arity="0" since="OTP @OTP-16309@"/>
+ <fsummary>Get the number of active sockets.</fsummary>
+ <desc>
+ <p>Returns the number of active sockets.</p>
+ </desc>
+ </func>
+
+ <func>
<name name="open" arity="2" since="OTP 22.0"/>
<name name="open" arity="3" since="OTP 22.0"/>
<name name="open" arity="4" since="OTP 22.0"/>
@@ -900,9 +908,9 @@
<name name="supports" arity="1" clause_i="1" since="OTP 22.0"/>
<name name="supports" arity="1" clause_i="2" since="OTP 22.0"/>
<name name="supports" arity="1" clause_i="3" since="OTP 22.0"/>
- <name name="supports" arity="1" clause_i="4" since="OTP-22.0"/>
- <name name="supports" arity="1" clause_i="5" since="@OTP-16153@"/>
- <name name="supports" arity="1" clause_i="6" since="@OTP-16153@"/>
+ <name name="supports" arity="1" clause_i="4" since="OTP 22.0"/>
+ <name name="supports" arity="1" clause_i="5" since="OTP @OTP-16153@"/>
+ <name name="supports" arity="1" clause_i="6" since="OTP @OTP-16153@"/>
<name name="supports" arity="1" clause_i="7" since="OTP 22.0"/>
<name name="supports" arity="2" clause_i="1" since="OTP 22.0"/>
<name name="supports" arity="2" clause_i="2" since="OTP 22.0"/>
@@ -910,8 +918,8 @@
<name name="supports" arity="2" clause_i="4" since="OTP 22.0"/>
<name name="supports" arity="2" clause_i="5" since="OTP 22.0"/>
<name name="supports" arity="2" clause_i="6" since="OTP 22.0"/>
- <name name="supports" arity="2" clause_i="7" since="@OTP-16153@"/>
- <name name="supports" arity="2" clause_i="8" since="@OTP-16153@"/>
+ <name name="supports" arity="2" clause_i="7" since="OTP @OTP-16153@"/>
+ <name name="supports" arity="2" clause_i="8" since="OTP @OTP-16153@"/>
<name name="supports" arity="2" clause_i="9" since="OTP 22.0"/>
<name name="supports" arity="3" clause_i="1" since="OTP 22.0"/>
<name name="supports" arity="3" clause_i="2" since="OTP 22.0"/>
@@ -928,6 +936,51 @@
</desc>
</func>
+ <func>
+ <name name="which_sockets" arity="0" since="OTP @OTP-16309@"/>
+ <name name="which_sockets" arity="1" since="OTP @OTP-16309@"/>
+ <fsummary>Get the current active sockets.</fsummary>
+ <desc>
+ <p>Returns a list of all sockets, according to the
+ filter rule.</p>
+ <p>There are several pre-made filter rule(s) and one general: </p>
+ <taglist>
+ <tag><c><![CDATA[inet | inet6]]></c></tag>
+ <item>
+ <p>Selection based on the domain of the socket.
+ <br/>Only a subset is valid. </p>
+ </item>
+
+ <tag><c><![CDATA[stream | dgram | seqpacket]]></c></tag>
+ <item>
+ <p>Selection based on the type of the socket.
+ <br/>Only a subset is valid. </p>
+ </item>
+
+ <tag><c><![CDATA[sctp | tcp | udp]]></c></tag>
+ <item>
+ <p>Selection based on the protocol of the socket.
+ <br/>Only a subset is valid. </p>
+ </item>
+
+ <tag><c><![CDATA[pid()]]></c></tag>
+ <item>
+ <p>Selection base on which sockets has this pid as
+ Controlling Process. </p>
+ </item>
+
+ <tag><c><![CDATA[fun((socket_info()) -> boolean())]]></c></tag>
+ <item>
+ <p>The general filter rule.
+ <br/>A fun that takes the socket info and returns a
+ <c><![CDATA[boolean()]]></c>
+ (<c><![CDATA[true]]></c> if the socket sould be included and
+ <c><![CDATA[false]]></c> if should not). </p>
+ </item>
+ </taglist>
+ </desc>
+ </func>
+
</funcs>
<section>
<title>Examples</title>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 7f50372532..fb56eadf39 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -635,6 +635,7 @@ GENERATE += $(TTF_DIR)/driver_tab.c
ifeq ($(USE_ESOCK), yes)
ESOCK_PRELOAD_BEAM = \
+ $(ERL_TOP)/erts/preloaded/ebin/socket_registry.beam \
$(ERL_TOP)/erts/preloaded/ebin/socket.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_net.beam
else
@@ -904,6 +905,7 @@ RUN_OBJS += \
$(OBJDIR)/module.o $(OBJDIR)/export.o \
$(OBJDIR)/register.o $(OBJDIR)/break.o \
$(OBJDIR)/erl_async.o $(OBJDIR)/erl_lock_check.o \
+ $(OBJDIR)/erl_dyn_lock_check.o \
$(OBJDIR)/erl_gc.o $(OBJDIR)/erl_lock_count.o \
$(OBJDIR)/erl_posix_str.o \
$(OBJDIR)/erl_bits.o $(OBJDIR)/erl_math.o \
diff --git a/erts/emulator/beam/atom.names b/erts/emulator/beam/atom.names
index 57f3a53481..7046eb5e65 100644
--- a/erts/emulator/beam/atom.names
+++ b/erts/emulator/beam/atom.names
@@ -144,6 +144,8 @@ atom bsr_unicode
atom build_type
atom busy
atom busy_dist_port
+atom busy_limits_port
+atom busy_limits_msgq
atom busy_port
atom call
atom call_count
@@ -291,6 +293,7 @@ atom gc_minor_start
atom Ge='>='
atom generational
atom get_all_trap
+atom get_internal_state_blocked
atom get_seq_token
atom get_size
atom get_tcw
diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c
index 857c929880..c530063fa1 100644
--- a/erts/emulator/beam/beam_bif_load.c
+++ b/erts/emulator/beam/beam_bif_load.c
@@ -377,6 +377,7 @@ finish_loading_1(BIF_ALIST_1)
/* tracing or hipe need thread blocking */
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
+ erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
is_blocking = 1;
break;
}
@@ -464,7 +465,6 @@ staging_epilogue(Process* c_p, int commit, Eterm res, int is_blocking,
}
if (is_blocking) {
erts_thr_progress_unblock();
- erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
}
erts_release_code_write_permission();
return res;
@@ -605,8 +605,12 @@ BIF_RETTYPE erts_internal_check_dirty_process_code_2(BIF_ALIST_2)
BIF_RET(am_false);
state = erts_atomic32_read_nob(&rp->state);
- dirty = (state & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS));
+ dirty = (state & ERTS_PSFLG_DIRTY_RUNNING);
+ /*
+ * Ignore ERTS_PSFLG_DIRTY_RUNNING_SYS (see
+ * comment in erts_execute_dirty_system_task()
+ * in erl_process.c).
+ */
if (!dirty)
BIF_RET(am_normal);
@@ -661,6 +665,7 @@ BIF_RETTYPE delete_module_1(BIF_ALIST_1)
/* tracing or hipe need to go single threaded */
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
+ erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
is_blocking = 1;
if (modp->curr.num_breakpoints) {
erts_clear_module_break(modp);
@@ -794,6 +799,7 @@ BIF_RETTYPE finish_after_on_load_2(BIF_ALIST_2)
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
+ erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
is_blocking = 1;
}
@@ -1457,12 +1463,14 @@ rla_resume(void *literal_area)
}
+#ifdef DEBUG
static ERTS_INLINE Sint
rla_bc_read(int sched_ix, int block_ix)
{
return (Sint) erts_atomic_read_nob(
&release_literal_areas.bc[sched_ix].u.block.counter[block_ix]);
}
+#endif
static ERTS_INLINE Sint
rla_bc_read_acqb(int sched_ix, int block_ix)
diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c
index 97eac05260..04e9db1f8e 100644
--- a/erts/emulator/beam/bif.c
+++ b/erts/emulator/beam/bif.c
@@ -4352,12 +4352,16 @@ BIF_RETTYPE list_to_ref_1(BIF_ALIST_1)
make_boxed(&etp->header));
ASSERT(enp != erts_this_node);
- etp->header = make_external_ref_header(n/2);
+#if defined(ARCH_64)
+ etp->header = make_external_ref_header(n/2 + 1);
+#else
+ etp->header = make_external_ref_header(n);
+#endif
etp->next = BIF_P->off_heap.first;
etp->node = enp;
i = 0;
#if defined(ARCH_64)
- etp->data.ui32[i] = n;
+ etp->data.ui32[i++] = n;
#endif
for (j = 0; j < n; j++) {
etp->data.ui32[i] = refn[j];
diff --git a/erts/emulator/beam/break.c b/erts/emulator/beam/break.c
index 6379e4e04d..c1af14cc89 100644
--- a/erts/emulator/beam/break.c
+++ b/erts/emulator/beam/break.c
@@ -578,8 +578,8 @@ do_break(void)
ASSERT(erts_thr_progress_is_blocking());
erts_printf("\n"
- "BREAK: (a)bort (c)ontinue (p)roc info (i)nfo (l)oaded\n"
- " (v)ersion (k)ill (D)b-tables (d)istribution\n");
+ "BREAK: (a)bort (A)bort with dump (c)ontinue (p)roc info (i)nfo\n"
+ " (l)oaded (v)ersion (k)ill (D)b-tables (d)istribution\n");
while (1) {
if ((i = sys_get_key(0)) <= 0)
diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c
index ecb5291400..1293ad2d83 100644
--- a/erts/emulator/beam/dist.c
+++ b/erts/emulator/beam/dist.c
@@ -5164,6 +5164,7 @@ erts_processes_monitoring_nodes(Process *c_p)
erts_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
+ erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
erts_mtx_lock(&nodes_monitors_mtx);
@@ -5194,7 +5195,6 @@ erts_processes_monitoring_nodes(Process *c_p)
erts_mtx_unlock(&nodes_monitors_mtx);
erts_thr_progress_unblock();
- erts_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
return ctxt.res;
}
diff --git a/erts/emulator/beam/erl_bif_info.c b/erts/emulator/beam/erl_bif_info.c
index 01b40abe2d..1064c89d84 100644
--- a/erts/emulator/beam/erl_bif_info.c
+++ b/erts/emulator/beam/erl_bif_info.c
@@ -75,7 +75,7 @@ static Export *gather_gc_info_res_trap;
static Export *gather_system_check_res_trap;
static Export *is_process_alive_trap;
-
+static Export *get_internal_state_blocked;
#define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
@@ -3881,8 +3881,7 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
}
else if (ERTS_IS_ATOM_STR("node_and_dist_references", BIF_ARG_1)) {
/* Used by node_container_SUITE (emulator) */
- Eterm res = erts_get_node_and_dist_references(BIF_P);
- BIF_RET(res);
+ BIF_TRAP1(get_internal_state_blocked, BIF_P, BIF_ARG_1);
}
else if (ERTS_IS_ATOM_STR("monitoring_nodes", BIF_ARG_1)) {
BIF_RET(erts_processes_monitoring_nodes(BIF_P));
@@ -4050,7 +4049,14 @@ BIF_RETTYPE erts_debug_get_internal_state_1(BIF_ALIST_1)
Eterm* tp = tuple_val(BIF_ARG_1);
switch (arityval(tp[0])) {
case 2: {
- if (ERTS_IS_ATOM_STR("process_status", tp[1])) {
+ if (ERTS_IS_ATOM_STR("node_and_dist_references", tp[1])) {
+ if (tp[2] == am_blocked
+ && erts_is_multi_scheduling_blocked() > 0) {
+ Eterm res = erts_get_node_and_dist_references(BIF_P);
+ BIF_RET(res);
+ }
+ }
+ else if (ERTS_IS_ATOM_STR("process_status", tp[1])) {
/* Used by timer process_SUITE, timer_bif_SUITE, and
node_container_SUITE (emulator) */
if (is_internal_pid(tp[2])) {
@@ -5213,6 +5219,10 @@ erts_bif_info_init(void)
= erts_export_put(am_erts_internal, am_gather_system_check_result, 1);
is_process_alive_trap = erts_export_put(am_erts_internal, am_is_process_alive, 1);
+
+ get_internal_state_blocked = erts_export_put(am_erts_internal,
+ am_get_internal_state_blocked,
+ 1);
process_info_init();
diff --git a/erts/emulator/beam/erl_bif_port.c b/erts/emulator/beam/erl_bif_port.c
index ed825d3dda..63bfaf8572 100644
--- a/erts/emulator/beam/erl_bif_port.c
+++ b/erts/emulator/beam/erl_bif_port.c
@@ -691,6 +691,10 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
opts.spawn_type = ERTS_SPAWN_ANY;
opts.argv = NULL;
opts.parallelism = erts_port_parallelism;
+ opts.high_watermark = 8192;
+ opts.low_watermark = opts.high_watermark / 2;
+ opts.port_watermarks_set = 0;
+ opts.msgq_watermarks_set = 0;
erts_osenv_init(&opts.envir);
linebuf = 0;
@@ -782,6 +786,62 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
opts.parallelism = 0;
else
goto badarg;
+ } else if (option == am_busy_limits_port) {
+ Uint high, low;
+ if (*tp == am_disabled)
+ low = high = ERL_DRV_BUSY_MSGQ_DISABLED;
+ else if (!is_tuple_arity(*tp, 2))
+ goto badarg;
+ else {
+ Eterm *wtp = tuple_val(*tp);
+ if (!term_to_Uint(wtp[1], &low))
+ goto badarg;
+ if (!term_to_Uint(wtp[2], &high))
+ goto badarg;
+ if (high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ goto badarg;
+ if (high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ goto badarg;
+ if (low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ goto badarg;
+ if (low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ goto badarg;
+ if (high == ~((Uint) 0) || low == ~((Uint) 0))
+ goto badarg;
+ if (low > high)
+ low = high;
+ }
+ opts.low_watermark = low;
+ opts.high_watermark = high;
+ opts.port_watermarks_set = !0;
+ } else if (option == am_busy_limits_msgq) {
+ Uint high, low;
+ if (*tp == am_disabled)
+ low = high = ERL_DRV_BUSY_MSGQ_DISABLED;
+ else if (!is_tuple_arity(*tp, 2))
+ goto badarg;
+ else {
+ Eterm *wtp = tuple_val(*tp);
+ if (!term_to_Uint(wtp[1], &low))
+ goto badarg;
+ if (!term_to_Uint(wtp[2], &high))
+ goto badarg;
+ if (high < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ goto badarg;
+ if (high > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ goto badarg;
+ if (low < ERL_DRV_BUSY_MSGQ_LIM_MIN)
+ goto badarg;
+ if (low > ERL_DRV_BUSY_MSGQ_LIM_MAX)
+ goto badarg;
+ if (high == ~((Uint) 0) || low == ~((Uint) 0))
+ goto badarg;
+ if (low > high)
+ low = high;
+ }
+ opts.low_msgq_watermark = low;
+ opts.high_msgq_watermark = high;
+ opts.msgq_watermarks_set = !0;
} else {
goto badarg;
}
@@ -820,6 +880,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
nargs = list_val(*nargs);
}
}
+
if (opts.read_write == 0) /* implement default */
opts.read_write = DO_READ|DO_WRITE;
@@ -827,7 +888,7 @@ open_port(Process* p, Eterm name, Eterm settings, int *err_typep, int *err_nump)
if((linebuf && opts.packet_bytes) ||
(opts.redir_stderr && !opts.use_stdio)) {
goto badarg;
-}
+ }
/* If we lacked an env option, fill in the global environment without
* changes. */
diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c
index b31d5b86cb..4162a6c591 100644
--- a/erts/emulator/beam/erl_bif_trace.c
+++ b/erts/emulator/beam/erl_bif_trace.c
@@ -1125,6 +1125,7 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
if ( (key == am_call_time) || (key == am_all)) {
erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
+ erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
}
erts_mtx_lock(&erts_dirty_bp_ix_mtx);
@@ -1134,7 +1135,6 @@ trace_info_func(Process* p, Eterm func_spec, Eterm key)
erts_mtx_unlock(&erts_dirty_bp_ix_mtx);
if ( (key == am_call_time) || (key == am_all)) {
erts_thr_progress_unblock();
- erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
}
switch (r) {
@@ -2194,6 +2194,7 @@ system_monitor(Process *p, Eterm monitor_pid, Eterm list)
system_blocked = 1;
erts_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
+ erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
if (!erts_pid2proc(p, ERTS_PROC_LOCK_MAIN, monitor_pid, 0))
goto error;
@@ -2233,7 +2234,6 @@ system_monitor(Process *p, Eterm monitor_pid, Eterm list)
erts_system_monitor_flags.busy_dist_port = !!busy_dist_port;
erts_thr_progress_unblock();
- erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
BIF_RET(prev);
}
@@ -2241,7 +2241,6 @@ system_monitor(Process *p, Eterm monitor_pid, Eterm list)
if (system_blocked) {
erts_thr_progress_unblock();
- erts_proc_lock(p, ERTS_PROC_LOCK_MAIN);
}
BIF_ERROR(p, BADARG);
diff --git a/erts/emulator/beam/erl_db_catree.c b/erts/emulator/beam/erl_db_catree.c
index 176966edb5..4e08f89692 100644
--- a/erts/emulator/beam/erl_db_catree.c
+++ b/erts/emulator/beam/erl_db_catree.c
@@ -2289,7 +2289,10 @@ static int db_lookup_dbterm_catree(Process *p, DbTable *tbl, Eterm key, Eterm ob
static void db_finalize_dbterm_catree(int cret, DbUpdateHandle *handle)
{
DbTableCATree *tb = &(handle->tb->catree);
- db_finalize_dbterm_tree_common(cret, handle, NULL);
+ db_finalize_dbterm_tree_common(cret,
+ handle,
+ &handle->u.catree.base_node->u.base.root,
+ NULL);
wunlock_adapt_base_node(tb, handle->u.catree.base_node,
handle->u.catree.parent,
handle->u.catree.current_level);
diff --git a/erts/emulator/beam/erl_db_hash.c b/erts/emulator/beam/erl_db_hash.c
index 17d20b2f77..5508f5c34e 100644
--- a/erts/emulator/beam/erl_db_hash.c
+++ b/erts/emulator/beam/erl_db_hash.c
@@ -3148,16 +3148,19 @@ db_finalize_dbterm_hash(int cret, DbUpdateHandle* handle)
}
WUNLOCK_HASH(lck);
- DEC_NITEMS(tb);
+ if (!(handle->flags & DB_INC_TRY_GROW))
+ DEC_NITEMS(tb);
try_shrink(tb);
} else {
if (handle->flags & DB_MUST_RESIZE) {
+ ASSERT(cret == DB_ERROR_NONE);
db_finalize_resize(handle, offsetof(HashDbTerm,dbterm));
free_me = b;
}
if (handle->flags & DB_INC_TRY_GROW) {
int nactive;
int nitems = INC_NITEMS(tb);
+ ASSERT(cret == DB_ERROR_NONE);
WUNLOCK_HASH(lck);
nactive = NACTIVE(tb);
diff --git a/erts/emulator/beam/erl_db_tree.c b/erts/emulator/beam/erl_db_tree.c
index 723b3c5d29..49158108a2 100644
--- a/erts/emulator/beam/erl_db_tree.c
+++ b/erts/emulator/beam/erl_db_tree.c
@@ -3287,7 +3287,9 @@ db_lookup_dbterm_tree(Process *p, DbTable *tbl, Eterm key, Eterm obj,
return db_lookup_dbterm_tree_common(p, tbl, &tb->root, key, obj, handle, tb);
}
-void db_finalize_dbterm_tree_common(int cret, DbUpdateHandle *handle,
+void db_finalize_dbterm_tree_common(int cret,
+ DbUpdateHandle *handle,
+ TreeDbTerm **root,
DbTableTree *stack_container)
{
DbTable *tbl = handle->tb;
@@ -3295,7 +3297,12 @@ void db_finalize_dbterm_tree_common(int cret, DbUpdateHandle *handle,
if (handle->flags & DB_NEW_OBJECT && cret != DB_ERROR_NONE) {
Eterm ret;
- db_erase_tree(tbl, GETKEY(&tbl->common, bp->dbterm.tpl), &ret);
+ db_erase_tree_common(tbl,
+ root,
+ GETKEY(&tbl->common, bp->dbterm.tpl),
+ &ret,
+ (stack_container == NULL ?
+ NULL : &stack_container->static_stack));
} else if (handle->flags & DB_MUST_RESIZE) {
db_finalize_resize(handle, offsetof(TreeDbTerm,dbterm));
reset_static_stack(stack_container);
@@ -3313,7 +3320,7 @@ db_finalize_dbterm_tree(int cret, DbUpdateHandle *handle)
{
DbTable *tbl = handle->tb;
DbTableTree *tb = &tbl->tree;
- db_finalize_dbterm_tree_common(cret, handle, tb);
+ db_finalize_dbterm_tree_common(cret, handle, &tb->root, tb);
}
static int db_get_binary_info_tree(Process *p, DbTable *tbl, Eterm key, Eterm *ret)
diff --git a/erts/emulator/beam/erl_db_tree_util.h b/erts/emulator/beam/erl_db_tree_util.h
index 14afbd56f7..90ac8c7ba7 100644
--- a/erts/emulator/beam/erl_db_tree_util.h
+++ b/erts/emulator/beam/erl_db_tree_util.h
@@ -167,7 +167,9 @@ void db_foreach_offheap_tree_common(TreeDbTerm *root,
int db_lookup_dbterm_tree_common(Process *p, DbTable *tbl, TreeDbTerm **root,
Eterm key, Eterm obj, DbUpdateHandle* handle,
DbTableTree *stack_container);
-void db_finalize_dbterm_tree_common(int cret, DbUpdateHandle *handle,
+void db_finalize_dbterm_tree_common(int cret,
+ DbUpdateHandle *handle,
+ TreeDbTerm **root,
DbTableTree *stack_container);
Sint cmp_partly_bound(Eterm partly_bound_key, Eterm bound_key);
diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c
index ed09a34ae4..2a0b28f232 100644
--- a/erts/emulator/beam/erl_db_util.c
+++ b/erts/emulator/beam/erl_db_util.c
@@ -2865,9 +2865,6 @@ Eterm db_add_counter(Eterm** hpp, Wterm counter, Eterm incr)
/* Must be called to read elements after db_lookup_dbterm.
** Will decompress if needed.
-** HEALFWORD_HEAP:
-** Will convert from relative to Wterm format if needed.
-** (but only on top level, tuples and lists will still contain rterms)
*/
Wterm db_do_read_element(DbUpdateHandle* handle, Sint position)
{
diff --git a/erts/emulator/beam/erl_drv_thread.c b/erts/emulator/beam/erl_drv_thread.c
index c5dbc87dee..d90b8b5e07 100644
--- a/erts/emulator/beam/erl_drv_thread.c
+++ b/erts/emulator/beam/erl_drv_thread.c
@@ -23,6 +23,7 @@
#endif
#include "global.h"
+#include "erl_dyn_lock_check.h"
#include <string.h>
#if defined(__APPLE__) && defined(__MACH__) && !defined(__DARWIN__)
@@ -57,6 +58,9 @@ struct ErlDrvMutex_ {
erts_lcnt_ref_t lcnt;
#endif
char *name;
+#ifdef ERTS_DYN_LOCK_CHECK
+ erts_dlc_t dlc;
+#endif
};
struct ErlDrvCond_ {
@@ -163,6 +167,9 @@ erl_drv_mutex_create(char *name)
} else {
dmtx->name = no_name;
}
+#ifdef ERTS_DYN_LOCK_CHECK
+ erts_dlc_create_lock(&dmtx->dlc, name);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_init_ref_x(&dmtx->lcnt, dmtx->name, NIL,
ERTS_LOCK_TYPE_MUTEX | ERTS_LOCK_FLAGS_CATEGORY_IO);
@@ -198,6 +205,9 @@ erl_drv_mutex_trylock(ErlDrvMutex *dmtx)
if (!dmtx)
fatal_error(EINVAL, "erl_drv_mutex_trylock()");
res = ethr_mutex_trylock(&dmtx->mtx);
+#ifdef ERTS_DYN_LOCK_CHECK
+ erts_dlc_trylock(&dmtx->dlc, res != EBUSY);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_trylock(&dmtx->lcnt, res);
#endif
@@ -209,6 +219,9 @@ erl_drv_mutex_lock(ErlDrvMutex *dmtx)
{
if (!dmtx)
fatal_error(EINVAL, "erl_drv_mutex_lock()");
+#ifdef ERTS_DYN_LOCK_CHECK
+ erts_dlc_lock(&dmtx->dlc);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock(&dmtx->lcnt);
#endif
@@ -223,6 +236,9 @@ erl_drv_mutex_unlock(ErlDrvMutex *dmtx)
{
if (!dmtx)
fatal_error(EINVAL, "erl_drv_mutex_unlock()");
+#ifdef ERTS_DYN_LOCK_CHECK
+ erts_dlc_unlock(&dmtx->dlc);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock(&dmtx->lcnt);
#endif
diff --git a/erts/emulator/beam/erl_dyn_lock_check.c b/erts/emulator/beam/erl_dyn_lock_check.c
new file mode 100644
index 0000000000..000d5cf247
--- /dev/null
+++ b/erts/emulator/beam/erl_dyn_lock_check.c
@@ -0,0 +1,553 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2001-2017. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/* Description: A dynamic lock order checker.
+ * A global locking order is recorded during runtime
+ * and continuously checked against itself.
+ *
+ * Author: Sverker Eriksson
+ */
+
+/*
+ * The primary objective is to check the order in which locks are seized
+ * to avoid deadlocks. The strategy is to continuously construct a directed
+ * graph describing the order in which locks have been seized. Each edge A->B in
+ * the graph describes a locking order; I held lock A while locking B. Trylocks
+ * do not introduce edges in the graph. For each added edge we check that we
+ * don't introduce cycles in the graph. A cycle would indicate a potential
+ * deadlock bug, waiting to happen.
+ *
+ * We assume that locks are primarily ordered by their lock _types_
+ * and secondarily by instance information of locks of the same type. No lock
+ * order checking is implemented between lock instances of the same type (yet).
+ *
+ * The name given when a lock is created is used as identifying its type.
+ * The '[' character can be used as a delimiter between lock type and
+ * instance information. Example: "esock.wrt[17]" is of type "esock.wrt".
+ *
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "erl_dyn_lock_check.h"
+#ifdef ERTS_DYN_LOCK_CHECK
+
+#include "sys.h"
+#include "erl_threads.h"
+
+#define DLC_ASSERT(X) ERTS_ASSERT(X)
+
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+# define MAX_LOCK_TYPES (64*2)
+#else
+# define MAX_LOCK_TYPES (32)
+#endif
+
+#define BITS_PER_WORD (sizeof(UWord)*8)
+#define LOCK_TYPE_WORDS ((MAX_LOCK_TYPES-1)/BITS_PER_WORD + 1)
+#define MAX_LOCK_NAME_SZ 64
+
+static erts_atomic_t n_lock_types;
+static erts_mtx_t lock_types_mtx;
+
+struct lock_type
+{
+ char name[MAX_LOCK_NAME_SZ];
+};
+
+static struct lock_type lock_types[MAX_LOCK_TYPES];
+
+static erts_tsd_key_t dlc_thread_key;
+
+/* Thread specific data */
+typedef struct
+{
+ UWord locked_now[LOCK_TYPE_WORDS];
+ /* Bit vector with all lock types currently held by this thread */
+
+ UWord locked_before[LOCK_TYPE_WORDS];
+ /* Bit vector same as 'locked_now' PLUS all unlocked locks that were locked
+ * by this thread ~before~ the locks in 'locked_now'.
+ * A lock in 'locked_before' is only cleared when all locked after it
+ * have been unlocked.
+ *
+ * Example 1:
+ * 1. Lock A: locked_now = A locked_before = A
+ * 2. Lock B: locked_now = A|B locked_before = A|B
+ * 3. Unlock A: locked_now = B locked_before = A|B
+ * 4. Lock C: locked_now = B|C locked_before = A|B|C
+ * 5. Unlock B: locked_now = C locked_before = A|B|C
+ * 6. Unlock C: locked_now = locked_before =
+ *
+ * Example 2:
+ * 1. Lock A: locked_now = A locked_before = A
+ * 2. Trylock B: locked_now = A|B locked_before = A|B
+ * 3. Unlock A: locked_now = B locked_before = B
+ * 4. Lock C: locked_now = B|C locked_before = B|C
+ * 5. Unlock B: locked_now = C locked_before = B|C
+ * 6. Unlock C: locked_now = locked_before =
+ *
+ * The trylock of B imposes no ordering dependency to A (locked before B),
+ * but it will have a dependency to C (locked after B).
+ */
+
+ struct {
+ unsigned ix; /* lock type id (bit index) */
+ unsigned cnt; /* nr of locked instances of this type (may be 0) */
+ unsigned trylock; /* true if only trylocked instances */
+ } lock_order[MAX_LOCK_TYPES];
+ /* The locks in 'locked_before' ordered the way they were locked by this thread */
+
+ unsigned n_locked;
+ /* Number or lock types in 'locked_before' and 'lock_order' */
+
+} dlc_thread_t;
+
+static erts_atomic_t locked_before[MAX_LOCK_TYPES][LOCK_TYPE_WORDS];
+/* The recorded global lock order as a bit matrix.
+ *
+ * Bit A is set in locked_before[B] if A has been locked before B.
+ */
+
+static int check_lock_order(dlc_thread_t*, erts_dlc_t*);
+
+/*#define DLC_UNIT_TEST*/
+#ifdef DLC_UNIT_TEST
+static int is_dlc_unit_test = 0;
+static void dlc_unit_test(void);
+# define DLC_IS_UNIT_TEST() (is_dlc_unit_test)
+#else
+# define DLC_IS_UNIT_TEST() (0)
+#endif
+
+static int dlc_initialized = 0;
+
+void erts_dlc_init(void)
+{
+ int i, j;
+ erts_atomic_init_nob(&n_lock_types, 0);
+ erts_tsd_key_create(&dlc_thread_key, "dyn_lock_check");
+
+ for (i = 0; i < MAX_LOCK_TYPES; i++) {
+ for (j = 0; j < LOCK_TYPE_WORDS; j++)
+ erts_atomic_init_nob(&locked_before[i][j], 0);
+ }
+
+ erts_mtx_init(&lock_types_mtx, "dyn_lock_check", NIL,
+ (ERTS_LOCK_FLAGS_PROPERTY_STATIC |
+ ERTS_LOCK_FLAGS_CATEGORY_GENERIC));
+
+ dlc_initialized = 1;
+
+#ifdef DLC_UNIT_TEST
+ dlc_unit_test();
+#endif
+}
+
+void erts_dlc_create_lock(erts_dlc_t* dlc, const char* name)
+{
+ erts_aint_t i, n = erts_atomic_read_nob(&n_lock_types);
+ int name_len;
+
+ for (i = 0; name[i]; i++) {
+ if (name[i] == '[')
+ break;
+ }
+ name_len = i;
+
+ for (i=0; i < n; i++) {
+ if (sys_strncmp(name, lock_types[i].name, name_len) == 0) {
+ dlc->ix = i;
+ return; /* already exists */
+ }
+ }
+
+ if (dlc_initialized)
+ erts_mtx_lock(&lock_types_mtx);
+ else
+ DLC_ASSERT(n == 0);
+
+ n = erts_atomic_read_nob(&n_lock_types);
+
+ for ( ; i < n; i++) {
+ if (sys_strncmp(name, lock_types[i].name, name_len) == 0) {
+ dlc->ix = i;
+ goto done; /* already exists (race) */
+ }
+ }
+
+ ERTS_ASSERT(n < MAX_LOCK_TYPES);
+ ERTS_ASSERT(name_len < MAX_LOCK_NAME_SZ);
+ sys_strncpy(lock_types[n].name, name, name_len);
+ lock_types[n].name[name_len] = 0;
+ erts_atomic_set_nob(&n_lock_types, n+1);
+ dlc->ix = n;
+
+done:
+ if (dlc_initialized)
+ erts_mtx_unlock(&lock_types_mtx);
+}
+
+#define IX_TO_BIT(IX) ((UWord)1 << ((IX) % BITS_PER_WORD))
+#define IX_TO_WORD(IX) ((IX) / BITS_PER_WORD)
+
+static dlc_thread_t *get_thr(void)
+{
+ dlc_thread_t *thr = (dlc_thread_t*) erts_tsd_get(dlc_thread_key);
+ int i;
+
+ if (!thr) {
+ thr = malloc(sizeof(dlc_thread_t));
+ for (i = 0; i < LOCK_TYPE_WORDS; i++) {
+ thr->locked_now[i] = 0;
+ thr->locked_before[i] = 0;
+ }
+ thr->n_locked = 0;
+ erts_tsd_set(dlc_thread_key, thr);
+ }
+ return thr;
+}
+
+static ERTS_INLINE int is_bit_set(unsigned ix, const UWord* words)
+{
+ DLC_ASSERT(ix < MAX_LOCK_TYPES);
+ return (words[IX_TO_WORD(ix)] & IX_TO_BIT(ix)) != (UWord)0;
+}
+
+static ERTS_INLINE int is_any_bit_set(const UWord* words)
+{
+ UWord bor = 0;
+ int i=0;
+ for (i = 0; i < LOCK_TYPE_WORDS; i++)
+ bor |= words[i];
+ return bor != (UWord)0;
+}
+
+static ERTS_INLINE void set_bit(unsigned ix, UWord* words)
+{
+ DLC_ASSERT(ix < MAX_LOCK_TYPES);
+ words[IX_TO_WORD(ix)] |= IX_TO_BIT(ix);
+}
+
+static ERTS_INLINE void clr_bit(unsigned ix, UWord* words)
+{
+ DLC_ASSERT(ix < MAX_LOCK_TYPES);
+ words[IX_TO_WORD(ix)] &= ~IX_TO_BIT(ix);
+}
+
+int erts_dlc_lock(erts_dlc_t* dlc)
+{
+ dlc_thread_t *thr = get_thr();
+
+ if (thr->n_locked) {
+ int i;
+
+ DLC_ASSERT(is_any_bit_set(thr->locked_now));
+
+ /*
+ * Check if we introduce new lock dependencies
+ */
+ for (i=0; i < LOCK_TYPE_WORDS; i++) {
+ UWord before = erts_atomic_read_nob(&locked_before[dlc->ix][i]);
+ UWord new_before = (thr->locked_before[i] & ~before);
+
+ if (new_before) {
+ if (!check_lock_order(thr, dlc)) {
+ DLC_ASSERT(DLC_IS_UNIT_TEST());
+ return 0;
+ }
+ erts_atomic_read_bor_mb(&locked_before[dlc->ix][i],
+ new_before);
+ /* check again to detect racing deadlock */
+ if (!check_lock_order(thr, dlc)) {
+ DLC_ASSERT(DLC_IS_UNIT_TEST());
+ /* can't continue test as 'locked_before' is inconsistent */
+ abort();
+ }
+ }
+ }
+
+ if (is_bit_set(dlc->ix, thr->locked_now)) {
+ /*
+ * Lock of this type already held.
+ * Must be other instance of last locked lock
+ */
+ DLC_ASSERT(is_bit_set(dlc->ix, thr->locked_before));
+ i = thr->n_locked-1;
+ while (dlc->ix != thr->lock_order[i].ix) {
+ DLC_ASSERT(thr->lock_order[i].trylock);
+ i--;
+ DLC_ASSERT(i >= 0);
+ }
+ thr->lock_order[i].cnt++;
+ thr->lock_order[i].trylock = 0;
+ return 1;
+ }
+ }
+ else {
+ DLC_ASSERT(!is_any_bit_set(thr->locked_now));
+ DLC_ASSERT(!is_any_bit_set(thr->locked_before));
+ }
+ set_bit(dlc->ix, thr->locked_now);
+ set_bit(dlc->ix, thr->locked_before);
+ thr->lock_order[thr->n_locked].ix = dlc->ix;
+ thr->lock_order[thr->n_locked].cnt = 1;
+ thr->lock_order[thr->n_locked].trylock = 0;
+ thr->n_locked++;
+ return 1;
+}
+
+static ERTS_INLINE int get_lock_order(dlc_thread_t* thr,
+ erts_dlc_t* dlc)
+{
+ int i;
+ DLC_ASSERT(is_bit_set(dlc->ix, thr->locked_before));
+ for (i = 0; ; i++) {
+ DLC_ASSERT(i < thr->n_locked);
+ if (dlc->ix == thr->lock_order[i].ix)
+ return i;
+ }
+}
+
+void erts_dlc_trylock(erts_dlc_t* dlc, int locked)
+{
+ dlc_thread_t *thr = get_thr();
+
+ if (!locked) {
+ /* We have no way to detect trylock of self-locked instance (yet)
+ * so nothing to do here. */
+ return;
+ }
+
+ if (is_bit_set(dlc->ix, thr->locked_now)) {
+ int i = get_lock_order(thr, dlc);
+ DLC_ASSERT(thr->lock_order[i].cnt > 0);
+ thr->lock_order[i].cnt++;
+ /* keep .trylock as is */
+ }
+ else {
+ set_bit(dlc->ix, thr->locked_now);
+
+ if (!is_bit_set(dlc->ix, thr->locked_before)) {
+ set_bit(dlc->ix, thr->locked_before);
+ thr->lock_order[thr->n_locked].ix = dlc->ix;
+ thr->lock_order[thr->n_locked].cnt = 1;
+ thr->lock_order[thr->n_locked].trylock = 1;
+ thr->n_locked++;
+ }
+ else {
+ int i = get_lock_order(thr, dlc);
+ DLC_ASSERT(thr->lock_order[i].cnt == 0);
+ thr->lock_order[i].cnt = 1;
+ thr->lock_order[i].trylock = 1;
+ }
+ }
+}
+
+void erts_dlc_unlock(erts_dlc_t* dlc)
+{
+ dlc_thread_t *thr = (dlc_thread_t*) erts_tsd_get(dlc_thread_key);
+ int i;
+
+ ERTS_ASSERT(thr);
+ ERTS_ASSERT(is_bit_set(dlc->ix, thr->locked_now));
+ DLC_ASSERT(is_bit_set(dlc->ix, thr->locked_before));
+ DLC_ASSERT(thr->n_locked > 0);
+
+ i = get_lock_order(thr, dlc);
+
+ DLC_ASSERT(thr->lock_order[i].cnt > 0);
+ thr->lock_order[i].cnt--;
+ if (thr->lock_order[i].cnt > 0)
+ return; /* still locked by other instance */
+
+ clr_bit(dlc->ix, thr->locked_now);
+
+ /*
+ * Now clear and forget all our unlocked locks (including this one)
+ * THAT was not locked *before* any of our still held locked locks.
+ */
+ for (i = thr->n_locked-1; i >= 0; i--) {
+ if (thr->lock_order[i].cnt) {
+ DLC_ASSERT(is_bit_set(thr->lock_order[i].ix, thr->locked_now));
+ if (!thr->lock_order[i].trylock) {
+ /* A locked lock, must remember it and all locked before it. */
+ break;
+ }
+ }
+ else { /* forget this unlocked lock */
+ int j;
+
+ DLC_ASSERT(!is_bit_set(thr->lock_order[i].ix, thr->locked_now));
+ DLC_ASSERT(is_bit_set(thr->lock_order[i].ix, thr->locked_before));
+ clr_bit(thr->lock_order[i].ix, thr->locked_before);
+ thr->n_locked--;
+
+ /* and compact all trylocks that we may have skipped over */
+ for (j = i; j < thr->n_locked; j++) {
+ DLC_ASSERT(thr->lock_order[j+1].trylock);
+ thr->lock_order[j] = thr->lock_order[j+1];
+ }
+ }
+ }
+}
+
+static int check_lock_order(dlc_thread_t *thr, erts_dlc_t* dlc)
+{
+ const UWord lock_bit = IX_TO_BIT(dlc->ix % 64);
+ const unsigned lock_word = IX_TO_WORD(dlc->ix);
+ int i, error = 0;
+
+ for (i = 0; i < thr->n_locked; i++) {
+ const unsigned ix = thr->lock_order[i].ix;
+
+ if (ix != dlc->ix &&
+ lock_bit & erts_atomic_read_nob(&locked_before[ix][lock_word])) {
+ if (!error) {
+ error = 1;
+ erts_fprintf(stderr, "###### DYNAMIC LOCK ORDER VIOLATION ######\n");
+ erts_fprintf(stderr, "# Trying to lock '%s'\n", lock_types[dlc->ix].name);
+ }
+ erts_fprintf(stderr, "# while '%s' is held\n",
+ lock_types[thr->lock_order[i].ix].name);
+ }
+ }
+ if (error) {
+ if (DLC_IS_UNIT_TEST())
+ return 0;
+ abort();
+ }
+ return 1;
+}
+
+#ifdef DLC_UNIT_TEST
+
+static void dlc_clear_order(void)
+{
+ int i, j, n = erts_atomic_read_nob(&n_lock_types);
+
+ for (i = 0; i < n; i++) {
+ for (j = 0; j < LOCK_TYPE_WORDS; j++)
+ erts_atomic_set_nob(&locked_before[i][j], 0);
+ }
+}
+
+static void dlc_unit_test(void)
+{
+ erts_aint_t save_n_lock_types = erts_atomic_read_nob(&n_lock_types);
+ dlc_thread_t* thr = get_thr();
+ dlc_thread_t save_thr = *thr;
+ erts_dlc_t A,B,C,D,E,F;
+
+ ERTS_ASSERT(save_n_lock_types <= 1); /* no need to save existing order */
+
+ is_dlc_unit_test = 1;
+ erts_dlc_create_lock(&A, "A");
+ erts_dlc_create_lock(&B, "B");
+ erts_dlc_create_lock(&C, "C");
+ erts_dlc_create_lock(&D, "D");
+ erts_dlc_create_lock(&E, "E");
+ erts_dlc_create_lock(&F, "F");
+
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ ERTS_ASSERT(erts_dlc_lock(&C));
+ ERTS_ASSERT(!erts_dlc_lock(&A));
+
+ erts_dlc_unlock(&A);
+ ERTS_ASSERT(!erts_dlc_lock(&A));
+ erts_dlc_unlock(&C);
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ ERTS_ASSERT(erts_dlc_lock(&B));
+ ERTS_ASSERT(erts_dlc_lock(&C));
+ erts_dlc_unlock(&A);
+ erts_dlc_unlock(&B);
+ erts_dlc_unlock(&C);
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ ERTS_ASSERT(erts_dlc_lock(&C));
+ ERTS_ASSERT(!erts_dlc_lock(&B));
+ erts_dlc_unlock(&A);
+ erts_dlc_unlock(&C);
+
+ dlc_clear_order();
+
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ ERTS_ASSERT(erts_dlc_lock(&B));
+ erts_dlc_unlock(&A);
+ ERTS_ASSERT(erts_dlc_lock(&C));
+ erts_dlc_unlock(&B);
+ ERTS_ASSERT(erts_dlc_lock(&D));
+ erts_dlc_unlock(&C);
+ ERTS_ASSERT(erts_dlc_lock(&E));
+ erts_dlc_unlock(&D);
+ ERTS_ASSERT(erts_dlc_lock(&F));
+ erts_dlc_unlock(&E);
+ erts_dlc_unlock(&F);
+ ERTS_ASSERT(erts_dlc_lock(&F));
+ ERTS_ASSERT(!erts_dlc_lock(&A));
+ erts_dlc_unlock(&F);
+
+ dlc_clear_order();
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ erts_dlc_trylock(&B, 1);
+ erts_dlc_unlock(&A);
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ erts_dlc_unlock(&A);
+ erts_dlc_unlock(&B);
+
+ dlc_clear_order();
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ ERTS_ASSERT(erts_dlc_lock(&B));
+ ERTS_ASSERT(erts_dlc_lock(&C));
+ erts_dlc_trylock(&D, 1);
+ erts_dlc_trylock(&E, 1);
+ ERTS_ASSERT(erts_dlc_lock(&F));
+ erts_dlc_unlock(&C);
+ erts_dlc_unlock(&F);
+ ERTS_ASSERT(erts_dlc_lock(&B));
+ erts_dlc_unlock(&B);
+ ERTS_ASSERT(!erts_dlc_lock(&A));
+ erts_dlc_unlock(&B);
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ erts_dlc_unlock(&A);
+ erts_dlc_unlock(&A);
+ erts_dlc_unlock(&D);
+ erts_dlc_unlock(&E);
+
+ dlc_clear_order();
+ ERTS_ASSERT(erts_dlc_lock(&A));
+ erts_dlc_trylock(&B, 1);
+ erts_dlc_trylock(&C, 1);
+ ERTS_ASSERT(erts_dlc_lock(&B));
+ erts_dlc_unlock(&B);
+ ERTS_ASSERT(!erts_dlc_lock(&C));
+
+ /* Restore */
+ is_dlc_unit_test = 0;
+ dlc_clear_order();
+ erts_atomic_set_nob(&n_lock_types, save_n_lock_types);
+ *thr = save_thr;
+}
+#endif /* DLC_UNIT_TEST */
+
+#endif /* ERTS_DYN_LOCK_CHECK */
+
+
+
diff --git a/erts/emulator/beam/erl_dyn_lock_check.h b/erts/emulator/beam/erl_dyn_lock_check.h
new file mode 100644
index 0000000000..0ff8e4cafa
--- /dev/null
+++ b/erts/emulator/beam/erl_dyn_lock_check.h
@@ -0,0 +1,61 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2001-2017. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/* Description: A dynamic lock order checker.
+ * A global locking order is recorded during runtime
+ * and continuously checked against itself.
+ *
+ * Author: Sverker Eriksson
+ */
+
+#ifndef ERL_DYN_LOCK_CHECK_H__
+#define ERL_DYN_LOCK_CHECK_H__
+
+#ifdef ERTS_ENABLE_LOCK_CHECK
+/*
+ * ERTS_DYN_LOCK_CHECK enables dynamic lock checker
+ * on NIF and driver mutexes and rwlocks.
+ */
+# define ERTS_DYN_LOCK_CHECK
+#endif
+
+#ifdef ERTS_DYN_LOCK_CHECK
+
+/*
+ * ERTS_DYN_LOCK_CHECK_INTERNAL will also enable dynamic lock checker
+ * on ERTS internal mutexes and rwlocks.
+ */
+/*#define ERTS_DYN_LOCK_CHECK_INTERNAL*/
+
+
+/* The struct to put in each lock instances */
+typedef struct {
+ unsigned ix;
+} erts_dlc_t;
+
+void erts_dlc_create_lock(erts_dlc_t* dlc, const char* name);
+int erts_dlc_lock(erts_dlc_t* dlc);
+void erts_dlc_trylock(erts_dlc_t* dlc, int locked);
+void erts_dlc_unlock(erts_dlc_t* dlc);
+void erts_dlc_init(void);
+
+#endif /* ERTS_DYN_LOCK_CHECK */
+
+#endif /* !ERL_DYN_LOCK_CHECK_H__ */
diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c
index 547e4064a2..5f0352f5c0 100644
--- a/erts/emulator/beam/erl_init.c
+++ b/erts/emulator/beam/erl_init.c
@@ -694,7 +694,7 @@ void erts_usage(void)
erts_fprintf(stderr, "-SDPcpu p1:p2 specify dirty CPU schedulers (p1) and dirty CPU schedulers\n");
erts_fprintf(stderr, " online (p2) as percentages of logical processors configured\n");
erts_fprintf(stderr, " and logical processors available, respectively\n");
- erts_fprintf(stderr, "-SDio n set number of dirty I/O schedulers, valid range is [0-%d]\n",
+ erts_fprintf(stderr, "-SDio n set number of dirty I/O schedulers, valid range is [1-%d]\n",
ERTS_MAX_NO_OF_DIRTY_IO_SCHEDULERS);
erts_fprintf(stderr, "-t size set the maximum number of atoms the emulator can handle\n");
erts_fprintf(stderr, " valid range is [%d-%d]\n",
@@ -1054,7 +1054,7 @@ early_init(int *argc, char **argv) /*
} else if (sys_strncmp(type, "io", 2) == 0) {
arg = get_arg(argv[i]+5, argv[i+1], &i);
dirty_io_scheds = atoi(arg);
- if (dirty_io_scheds < 0 ||
+ if (dirty_io_scheds < 1 ||
dirty_io_scheds > ERTS_MAX_NO_OF_DIRTY_IO_SCHEDULERS) {
erts_fprintf(stderr,
"bad number of dirty I/O schedulers %s\n",
diff --git a/erts/emulator/beam/erl_lock_check.c b/erts/emulator/beam/erl_lock_check.c
index ba61f721b4..b391c05643 100644
--- a/erts/emulator/beam/erl_lock_check.c
+++ b/erts/emulator/beam/erl_lock_check.c
@@ -147,6 +147,7 @@ static erts_lc_lock_order_t erts_lock_order[] = {
{ "mtrace_op", NULL },
{ "instr_x", NULL },
{ "instr", NULL },
+ { "dyn_lock_check", NULL },
{ "alcu_allocator", "index" },
{ "mseg", NULL },
{ "get_time", NULL },
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c
index 1fbe362330..27959ba2bb 100644
--- a/erts/emulator/beam/erl_nif.c
+++ b/erts/emulator/beam/erl_nif.c
@@ -2209,6 +2209,10 @@ static ErlNifResourceType* find_resource_type(Eterm module, Eterm name)
#define in_area(ptr,start,nbytes) \
((UWord)((char*)(ptr) - (char*)(start)) < (nbytes))
+static ERTS_INLINE int rt_have_callbacks(ErlNifResourceType* rt)
+{
+ return rt->dtor != NULL;
+}
static void close_lib(struct erl_module_nif* lib)
{
@@ -2231,7 +2235,7 @@ static void steal_resource_type(ErlNifResourceType* type)
{
struct erl_module_nif* lib = type->owner;
- if (type->dtor != NULL
+ if (rt_have_callbacks(type)
&& erts_refc_dectest(&lib->rt_dtor_cnt, 0) == 0
&& lib->mod == NULL) {
/* last type with destructor gone, close orphan lib */
@@ -2244,6 +2248,11 @@ static void steal_resource_type(ErlNifResourceType* type)
}
}
+static void resource_dtor_nop(ErlNifEnv* env, void* obj)
+{
+ /* do nothing */
+}
+
/* The opened_rt_list is used by enif_open_resource_type()
* in order to rollback "creates" and "take-overs" in case the load fails.
*/
@@ -2306,6 +2315,12 @@ ErlNifResourceType* open_resource_type(ErlNifEnv* env,
sys_memzero(&ort->new_callbacks, sizeof(ErlNifResourceTypeInit));
ASSERT(sizeof_init > 0 && sizeof_init <= sizeof(ErlNifResourceTypeInit));
sys_memcpy(&ort->new_callbacks, init, sizeof_init);
+ if (!ort->new_callbacks.dtor && (ort->new_callbacks.down ||
+ ort->new_callbacks.stop)) {
+ /* Set dummy dtor for fast rt_have_callbacks()
+ * This case should be rare anyway */
+ ort->new_callbacks.dtor = resource_dtor_nop;
+ }
ort->next = opened_rt_list;
opened_rt_list = ort;
}
@@ -2362,7 +2377,7 @@ static void commit_opened_resource_types(struct erl_module_nif* lib)
type->stop = ort->new_callbacks.stop;
type->down = ort->new_callbacks.down;
- if (type->dtor != NULL) {
+ if (rt_have_callbacks(type)) {
erts_refc_inc(&lib->rt_dtor_cnt, 1);
}
erts_refc_inc(&lib->rt_cnt, 1);
@@ -4169,6 +4184,7 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
/* Block system (is this the right place to do it?) */
erts_proc_unlock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
+ erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
/* Find calling module */
ASSERT(BIF_P->current != NULL);
@@ -4276,17 +4292,12 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
ret = load_nif_error(BIF_P,bad_lib,"Function not found %T:%s/%u",
mod_atom, f->name, f->arity);
}
- else if (f->flags) {
- /*
- * If the flags field is non-zero and this emulator was
- * built with dirty scheduler support, check that the flags
- * value is legal. But if this emulator was built without
- * dirty scheduler support, treat a non-zero flags field as
- * a load error.
- */
- if (f->flags != ERL_NIF_DIRTY_JOB_IO_BOUND && f->flags != ERL_NIF_DIRTY_JOB_CPU_BOUND)
- ret = load_nif_error(BIF_P, bad_lib, "Illegal flags field value %d for NIF %T:%s/%u",
- f->flags, mod_atom, f->name, f->arity);
+ else if (f->flags != 0 &&
+ f->flags != ERL_NIF_DIRTY_JOB_IO_BOUND &&
+ f->flags != ERL_NIF_DIRTY_JOB_CPU_BOUND) {
+ ret = load_nif_error(BIF_P, bad_lib,
+ "Illegal flags field value %d for NIF %T:%s/%u",
+ f->flags, mod_atom, f->name, f->arity);
}
else if (erts_codeinfo_to_code(ci_pp[1]) - erts_codeinfo_to_code(ci_pp[0])
< BEAM_NIF_MIN_FUNC_SZ)
@@ -4383,7 +4394,6 @@ BIF_RETTYPE load_nif_2(BIF_ALIST_2)
}
erts_thr_progress_unblock();
- erts_proc_lock(BIF_P, ERTS_PROC_LOCK_MAIN);
erts_release_code_write_permission();
erts_free(ERTS_ALC_T_TMP, lib_name);
@@ -4413,7 +4423,7 @@ erts_unload_nif(struct erl_module_nif* lib)
rt->next = NULL;
rt->prev = NULL;
if (erts_refc_dectest(&rt->refc, 0) == 0) {
- if (rt->dtor != NULL) {
+ if (rt_have_callbacks(rt)) {
erts_refc_dec(&lib->rt_dtor_cnt, 0);
}
erts_refc_dec(&lib->rt_cnt, 0);
diff --git a/erts/emulator/beam/erl_node_tables.c b/erts/emulator/beam/erl_node_tables.c
index 0564aec846..51e6a4dc40 100644
--- a/erts/emulator/beam/erl_node_tables.c
+++ b/erts/emulator/beam/erl_node_tables.c
@@ -1270,7 +1270,9 @@ erts_get_node_and_dist_references(struct process *proc)
erts_proc_unlock(proc, ERTS_PROC_LOCK_MAIN);
erts_thr_progress_block();
- /* No need to lock any thing since we are alone... */
+ erts_proc_lock(proc, ERTS_PROC_LOCK_MAIN);
+ /* No need to lock any thing else since we are alone...
+ ... except dirty stuff... (?) */
if (references_atoms_need_init) {
INIT_AM(heap);
@@ -1325,7 +1327,6 @@ erts_get_node_and_dist_references(struct process *proc)
clear_system();
erts_thr_progress_unblock();
- erts_proc_lock(proc, ERTS_PROC_LOCK_MAIN);
return res;
}
diff --git a/erts/emulator/beam/erl_proc_sig_queue.c b/erts/emulator/beam/erl_proc_sig_queue.c
index 2347527e28..f8d82a8f98 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.c
+++ b/erts/emulator/beam/erl_proc_sig_queue.c
@@ -560,8 +560,7 @@ erts_make_dirty_proc_handled(Eterm pid,
ErtsMessage *mp;
Process *sig_handler;
- ASSERT(state & (ERTS_PSFLG_DIRTY_RUNNING |
- ERTS_PSFLG_DIRTY_RUNNING_SYS));
+ ASSERT(state & ERTS_PSFLG_DIRTY_RUNNING);
if (prio < 0)
prio = (int) ERTS_PSFLGS_GET_USR_PRIO(state);
@@ -765,10 +764,13 @@ maybe_elevate_sig_handling_prio(Process *c_p, Eterm other)
if (res) {
/* ensure handled if dirty executing... */
state = erts_atomic32_read_nob(&rp->state);
- if (state & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
+ /*
+ * We ignore ERTS_PSFLG_DIRTY_RUNNING_SYS. For
+ * more info see erts_execute_dirty_system_task()
+ * in erl_process.c.
+ */
+ if (state & ERTS_PSFLG_DIRTY_RUNNING)
erts_make_dirty_proc_handled(other, state, my_prio);
- }
}
}
}
@@ -4565,8 +4567,12 @@ erts_internal_dirty_process_handle_signals_1(BIF_ALIST_1)
BIF_RET(am_noproc);
state = erts_atomic32_read_nob(&rp->state);
- dirty = (state & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS));
+ dirty = (state & ERTS_PSFLG_DIRTY_RUNNING);
+ /*
+ * Ignore ERTS_PSFLG_DIRTY_RUNNING_SYS (see
+ * comment in erts_execute_dirty_system_task()
+ * in erl_process.c).
+ */
if (!dirty)
BIF_RET(am_normal);
@@ -4574,8 +4580,7 @@ erts_internal_dirty_process_handle_signals_1(BIF_ALIST_1)
state = erts_atomic32_read_mb(&rp->state);
noproc = (state & ERTS_PSFLG_FREE);
- dirty = (state & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS));
+ dirty = (state & ERTS_PSFLG_DIRTY_RUNNING);
if (busy) {
if (noproc)
diff --git a/erts/emulator/beam/erl_proc_sig_queue.h b/erts/emulator/beam/erl_proc_sig_queue.h
index 2b055e73bc..2789179b34 100644
--- a/erts/emulator/beam/erl_proc_sig_queue.h
+++ b/erts/emulator/beam/erl_proc_sig_queue.h
@@ -1115,8 +1115,12 @@ erts_proc_notify_new_sig(Process* rp, erts_aint32_t state,
state = erts_proc_sys_schedule(rp, state, enable_flag);
}
- if (state & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
+ if (state & ERTS_PSFLG_DIRTY_RUNNING) {
+ /*
+ * We ignore ERTS_PSFLG_DIRTY_RUNNING_SYS. For
+ * more info see erts_execute_dirty_system_task()
+ * in erl_process.c.
+ */
erts_make_dirty_proc_handled(rp->common.id, state, -1);
}
}
diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c
index 4c91c60220..e9ed4a7407 100644
--- a/erts/emulator/beam/erl_process.c
+++ b/erts/emulator/beam/erl_process.c
@@ -7462,11 +7462,16 @@ msb_scheduler_type_switch(ErtsSchedType sched_type,
}
static ERTS_INLINE void
-suspend_normal_scheduler_sleep(ErtsSchedulerData *esdp)
+suspend_scheduler_sleep(ErtsSchedulerData *esdp,
+ int normal_sched,
+ ErtsMonotonicTime initial_time,
+ ErtsMonotonicTime timeout_time)
{
ErtsSchedulerSleepInfo *ssi = esdp->ssi;
erts_aint32_t flgs = sched_spin_suspended(ssi,
ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT);
+ ASSERT(!normal_sched || esdp->type == ERTS_SCHED_NORMAL);
+ ASSERT(esdp->type != ERTS_SCHED_NORMAL || normal_sched);
if (flgs == (ERTS_SSI_FLG_SLEEPING
| ERTS_SSI_FLG_WAITING
| ERTS_SSI_FLG_SUSPENDED)) {
@@ -7475,21 +7480,34 @@ suspend_normal_scheduler_sleep(ErtsSchedulerData *esdp)
| ERTS_SSI_FLG_TSE_SLEEPING
| ERTS_SSI_FLG_WAITING
| ERTS_SSI_FLG_SUSPENDED)) {
- int res;
+ if (!normal_sched) {
+ while (1) {
+ int res = erts_tse_wait(ssi->event);
+ if (res != EINTR)
+ break;
+ }
+ }
+ else {
+ ErtsMonotonicTime current_time = initial_time;
+ while (1) {
+ int res;
+ Sint64 timeout;
- do {
- res = erts_tse_wait(ssi->event);
- } while (res == EINTR);
+ timeout = ERTS_MONOTONIC_TO_NSEC(timeout_time
+ - current_time
+ - 1) + 1;
+ res = erts_tse_twait(ssi->event, timeout);
+ if (res != EINTR)
+ break;
+ current_time = erts_get_monotonic_time(esdp);
+ if (current_time >= timeout_time)
+ break;
+ }
+ }
}
}
}
-static ERTS_INLINE void
-suspend_dirty_scheduler_sleep(ErtsSchedulerData *esdp)
-{
- suspend_normal_scheduler_sleep(esdp);
-}
-
static void
suspend_scheduler(ErtsSchedulerData *esdp)
{
@@ -7590,18 +7608,31 @@ suspend_scheduler(ErtsSchedulerData *esdp)
for (i = 0; msb[i]; i++) {
erts_aint32_t clr_flg = 0;
- if (msb[i] == &schdlr_sspnd.nmsb
- && schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
- ERTS_SCHED_NORMAL) == 1) {
- clr_flg = ERTS_SCHDLR_SSPND_CHNG_NMSB;
+ if (!msb[i]->ongoing)
+ continue;
+
+ if (msb[i] == &schdlr_sspnd.nmsb) {
+ if (schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
+ ERTS_SCHED_NORMAL) == 1) {
+ clr_flg = ERTS_SCHDLR_SSPND_CHNG_NMSB;
+ }
}
- else if (schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
- ERTS_SCHED_NORMAL) == 1
- && schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
- ERTS_SCHED_DIRTY_CPU) == 0
- && schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
- ERTS_SCHED_DIRTY_IO) == 0) {
- clr_flg = ERTS_SCHDLR_SSPND_CHNG_MSB;
+ else {
+ ASSERT(msb[i] == &schdlr_sspnd.msb);
+ if (schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
+ ERTS_SCHED_NORMAL) == 1
+ && schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
+ ERTS_SCHED_DIRTY_CPU) == 0
+ && schdlr_sspnd_get_nscheds(&schdlr_sspnd.active,
+ ERTS_SCHED_DIRTY_IO) == 0) {
+
+ clr_flg = ERTS_SCHDLR_SSPND_CHNG_MSB;
+
+ /* Begin switching between scheduler types executing... */
+ ERTS_RUNQ_FLGS_SET_NOB(ERTS_RUNQ_IX(0), ERTS_RUNQ_FLG_MSB_EXEC);
+ erts_atomic32_read_bor_nob(&ERTS_RUNQ_IX(0)->scheduler->ssi->flags,
+ ERTS_SSI_FLG_MSB_EXEC);
+ }
}
if (clr_flg) {
@@ -7684,7 +7715,7 @@ suspend_scheduler(ErtsSchedulerData *esdp)
while (1) {
if (sched_type != ERTS_SCHED_NORMAL)
- suspend_dirty_scheduler_sleep(esdp);
+ suspend_scheduler_sleep(esdp, 0, 0, 0);
else
{
ErtsMonotonicTime current_time, timeout_time;
@@ -7729,7 +7760,7 @@ suspend_scheduler(ErtsSchedulerData *esdp)
sched_wall_time_change(esdp, 0);
}
erts_thr_progress_prepare_wait(erts_thr_prgr_data(NULL));
- suspend_normal_scheduler_sleep(esdp);
+ suspend_scheduler_sleep(esdp, !0, current_time, timeout_time);
erts_thr_progress_finalize_wait(erts_thr_prgr_data(NULL));
current_time = erts_get_monotonic_time(esdp);
}
@@ -8235,9 +8266,6 @@ erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int normal
}
if (!normal) {
- ERTS_RUNQ_FLGS_SET_NOB(ERTS_RUNQ_IX(0), ERTS_RUNQ_FLG_MSB_EXEC);
- erts_atomic32_read_bor_nob(&ERTS_RUNQ_IX(0)->scheduler->ssi->flags,
- ERTS_SSI_FLG_MSB_EXEC);
for (ix = 0; ix < erts_no_dirty_cpu_schedulers; ix++)
dcpu_sched_ix_suspend_wake(ix);
for (ix = 0; ix < erts_no_dirty_io_schedulers; ix++)
@@ -9596,6 +9624,24 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
ASSERT(p); /* Wrong qmask in rq->flags? */
+#ifdef DEBUG
+ switch (((erts_aint32_t) 1) << ERTS_PSFLGS_GET_PRQ_PRIO(state)) {
+ case MAX_BIT:
+ ASSERT(qbit == MAX_BIT);
+ break;
+ case HIGH_BIT:
+ ASSERT(qbit == HIGH_BIT);
+ break;
+ case NORMAL_BIT:
+ case LOW_BIT:
+ ASSERT(qbit == NORMAL_BIT || qbit == LOW_BIT);
+ break;
+ default:
+ ASSERT(0);
+ break;
+ }
+#endif
+
if (is_normal_sched) {
psflg_running = ERTS_PSFLG_RUNNING;
psflg_running_sys = ERTS_PSFLG_RUNNING_SYS;
@@ -9606,6 +9652,7 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
psflg_running = ERTS_PSFLG_DIRTY_RUNNING;
psflg_running_sys = ERTS_PSFLG_DIRTY_RUNNING_SYS;
psflg_band_mask = ~((erts_aint32_t) 0);
+ qbit = ((erts_aint32_t) 1) << ERTS_PSFLGS_GET_PRQ_PRIO(state);
}
if (!(state & ERTS_PSFLG_PROXY))
@@ -9758,25 +9805,33 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
}
}
else {
- if (!(state & ERTS_PSFLGS_DIRTY_WORK)) {
- /* Dirty work completed... */
- goto sunlock_sched_out_proc;
+ /* On dirty scheduler */
+ if (!(state & ERTS_PSFLGS_DIRTY_WORK)
+ | !!(state & (ERTS_PSFLG_SYS_TASKS
+ | ERTS_PSFLG_EXITING
+ | ERTS_PSFLG_DIRTY_ACTIVE_SYS))) {
+
+ if (!(state & ERTS_PSFLGS_DIRTY_WORK)) {
+ /* Dirty work completed... */
+ goto sunlock_sched_out_proc;
+ }
+ if (state & (ERTS_PSFLG_SYS_TASKS
+ | ERTS_PSFLG_EXITING)) {
+ /*
+ * IMPORTANT! We need to take care of
+ * scheduled check-process-code requests
+ * before continuing with dirty execution!
+ */
+ /* Migrate to normal scheduler... */
+ goto sunlock_sched_out_proc;
+ }
+ if ((state & ERTS_PSFLG_DIRTY_ACTIVE_SYS)
+ && rq == ERTS_DIRTY_IO_RUNQ) {
+ /* Migrate to dirty cpu scheduler... */
+ goto sunlock_sched_out_proc;
+ }
+
}
- if (state & (ERTS_PSFLG_ACTIVE_SYS
- | ERTS_PSFLG_EXITING)) {
- /*
- * IMPORTANT! We need to take care of
- * scheduled check-process-code requests
- * before continuing with dirty execution!
- */
- /* Migrate to normal scheduler... */
- goto sunlock_sched_out_proc;
- }
- if ((state & ERTS_PSFLG_DIRTY_ACTIVE_SYS)
- && rq == ERTS_DIRTY_IO_RUNQ) {
- /* Migrate to dirty cpu scheduler... */
- goto sunlock_sched_out_proc;
- }
ASSERT(rq == ERTS_DIRTY_CPU_RUNQ
? (state & (ERTS_PSFLG_DIRTY_CPU_PROC
@@ -9790,7 +9845,17 @@ Process *erts_schedule(ErtsSchedulerData *esdp, Process *p, int calls)
if (IS_TRACED(p))
trace_schedule_in(p, state);
- if (is_normal_sched) {
+ if (!is_normal_sched) {
+ /* On dirty scheduler */
+ if (!!(state & ERTS_PSFLG_DIRTY_RUNNING)
+ & !!(state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q))) {
+ /* Ensure signals are handled while executing dirty... */
+ int prio = ERTS_PSFLGS_GET_ACT_PRIO(state);
+ erts_make_dirty_proc_handled(p->common.id, state, prio);
+ }
+ }
+ else {
+ /* On normal scheduler */
if (state & ERTS_PSFLG_RUNNING_SYS) {
if (state & (ERTS_PSFLG_SIG_Q|ERTS_PSFLG_SIG_IN_Q)) {
int local_only = (!!(p->sig_qs.flags & FS_LOCAL_SIGS_ONLY)
@@ -10086,10 +10151,14 @@ fetch_sys_task(Process *c_p, erts_aint32_t state, int *qmaskp, int *priop)
qmask = c_p->sys_task_qs->qmask;
- if ((state & (ERTS_PSFLG_ACTIVE
+ if ((state & (ERTS_PSFLGS_DIRTY_WORK
+ | ERTS_PSFLG_ACTIVE
| ERTS_PSFLG_EXITING
| ERTS_PSFLG_SUSPENDED)) == ERTS_PSFLG_ACTIVE) {
- /* No sys tasks if we got exclusively higher prio user work to do */
+ /*
+ * No sys tasks if we got exclusively higher prio user work
+ * to do; ignoring dirty work...
+ */
st = NULL;
switch (ERTS_PSFLGS_GET_USR_PRIO(state)) {
case PRIORITY_MAX:
@@ -10484,6 +10553,34 @@ erts_execute_dirty_system_task(Process *c_p)
Eterm cla_res = THE_NON_VALUE;
ErtsProcSysTask *stasks;
+ ASSERT(erts_atomic32_read_nob(&c_p->state)
+ & ERTS_PSFLG_DIRTY_RUNNING_SYS);
+ /*
+ * Currently all dirty system tasks are handled while holding
+ * the main lock. The process is during this in the state
+ * ERTS_PSFLG_DIRTY_RUNNING_SYS. The dirty signal handlers
+ * (erts/preloaded/src/erts_dirty_process_signal_handler.erl)
+ * cannot execute any signal handling on behalf of a process
+ * executing dirty unless they will be able to acquire the
+ * main lock. If they try to, they will just end up in a
+ * busy wait until the lock has been released.
+ *
+ * We now therefore do not schedule any handling on dirty
+ * signal handlers while a process is in the state
+ * ERTS_PSFLG_DIRTY_RUNNING_SYS. We instead leave the work
+ * scheduled on the process an let it detect it itself
+ * when it leaves the ERTS_PSFLG_DIRTY_RUNNING_SYS state.
+ * See erts_proc_notify_new_sig() in erl_proc_sig_queue.h,
+ * request_system_task() (check_process_code) in
+ * erl_process.c, and maybe_elevate_sig_handling_prio()
+ * in erl_proc_sig_queue.c for scheduling points.
+ *
+ * If there are dirty system tasks introduced that execute
+ * without the main lock held, we most likely want to trigger
+ * handling of signals via dirty signal handlers for these
+ * states.
+ */
+
/*
* If multiple operations, perform them in the following
* order (in order to avoid unnecessary GC):
@@ -10579,8 +10676,7 @@ dispatch_system_task(Process *c_p, erts_aint_t fail_state,
switch (st->type) {
case ERTS_PSTT_CPC:
rp = erts_dirty_process_signal_handler;
- ASSERT(fail_state & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS));
+ ASSERT(fail_state & ERTS_PSFLG_DIRTY_RUNNING);
if (c_p == rp) {
ERTS_BIF_PREP_RET(ret, am_dirty_execution);
return ret;
@@ -10726,9 +10822,12 @@ request_system_task(Process *c_p, Eterm requester, Eterm target,
* If the process should start executing dirty
* code it is important that this task is
* aborted. Therefore this strict fail state...
- */
- fail_state |= (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS);
+ *
+ * We ignore ERTS_PSFLG_DIRTY_RUNNING_SYS. For
+ * more info see erts_execute_dirty_system_task()
+ * in erl_process.c.
+ */
+ fail_state |= ERTS_PSFLG_DIRTY_RUNNING;
break;
case am_copy_literals:
@@ -10751,8 +10850,7 @@ request_system_task(Process *c_p, Eterm requester, Eterm target,
noproc:
failure = noproc_res;
}
- else if (fail_state & (ERTS_PSFLG_DIRTY_RUNNING
- | ERTS_PSFLG_DIRTY_RUNNING_SYS)) {
+ else if (fail_state & ERTS_PSFLG_DIRTY_RUNNING) {
ret = dispatch_system_task(c_p, fail_state, st,
target, priority, operation);
goto cleanup_return;
@@ -13510,8 +13608,7 @@ erts_dbg_check_halloc_lock(Process *p)
esdp = erts_proc_sched_data(p);
if (esdp && p == esdp->match_pseudo_process)
return 1;
- if (erts_thr_progress_is_blocking())
- return 1;
+ /* erts_thr_progress_is_blocking() is not enough as dirty NIFs may run */
return 0;
}
#endif
diff --git a/erts/emulator/beam/erl_sys_driver.h b/erts/emulator/beam/erl_sys_driver.h
index d46e88cb05..8f1963fbd4 100644
--- a/erts/emulator/beam/erl_sys_driver.h
+++ b/erts/emulator/beam/erl_sys_driver.h
@@ -33,10 +33,39 @@
typedef long ErlDrvEvent; /* An event to be selected on. */
-/* typedef struct _SysDriverOpts SysDriverOpts; defined in sys.h */
+typedef struct _SysDriverOpts SysDriverOpts;
#include "erl_driver.h"
+/*
+ * This structure contains options to all built in drivers.
+ * None of the drivers use all of the fields.
+ */
+
+struct _SysDriverOpts {
+ Uint ifd; /* Input file descriptor (fd driver). */
+ Uint ofd; /* Outputfile descriptor (fd driver). */
+ int packet_bytes; /* Number of bytes in packet header. */
+ int read_write; /* Read and write bits. */
+ int use_stdio; /* Use standard I/O: TRUE or FALSE. */
+ int redir_stderr; /* Redirect stderr to stdout: TRUE/FALSE. */
+ int hide_window; /* Hide this windows (Windows). */
+ int exit_status; /* Report exit status of subprocess. */
+ int overlapped_io; /* Only has effect on windows NT et al */
+ erts_osenv_t envir; /* Environment of the port process */
+ char **argv; /* Argument vector in Unix'ish format. */
+ char *wd; /* Working directory. */
+ unsigned spawn_type; /* Bitfield of ERTS_SPAWN_DRIVER |
+ ERTS_SPAWN_EXTERNAL | both*/
+ int parallelism; /* Optimize for parallelism */
+ ErlDrvSizeT high_watermark;
+ ErlDrvSizeT low_watermark;
+ ErlDrvSizeT high_msgq_watermark;
+ ErlDrvSizeT low_msgq_watermark;
+ char port_watermarks_set;
+ char msgq_watermarks_set;
+};
+
#endif
diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h
index e81f76d25b..c5c7b626c0 100644
--- a/erts/emulator/beam/erl_threads.h
+++ b/erts/emulator/beam/erl_threads.h
@@ -249,6 +249,7 @@
#include "erl_lock_check.h"
#include "erl_lock_count.h"
+#include "erl_dyn_lock_check.h"
#if defined(__GLIBC__) && (__GLIBC__ << 16) + __GLIBC_MINOR__ < (2 << 16) + 5
/*
@@ -295,6 +296,9 @@ typedef struct {
#ifdef DEBUG
erts_lock_flags_t flags;
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_t dlc;
+#endif
} erts_mtx_t;
typedef ethr_cond erts_cnd_t;
@@ -310,6 +314,9 @@ typedef struct {
#ifdef DEBUG
erts_lock_flags_t flags;
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_t dlc;
+#endif
} erts_rwmtx_t;
#define ERTS_MTX_OPT_DEFAULT_INITER ETHR_MUTEX_OPT_DEFAULT_INITER
@@ -1619,6 +1626,9 @@ erts_mtx_init(erts_mtx_t *mtx, char *name, Eterm extra, erts_lock_flags_t flags)
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_init_ref_x(&mtx->lcnt, name, extra, flags);
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_create_lock(&mtx->dlc, name);
+#endif
}
ERTS_GLB_INLINE void
@@ -1630,6 +1640,9 @@ erts_mtx_init_locked(erts_mtx_t *mtx, char *name, Eterm extra, erts_lock_flags_t
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_trylock(1, &mtx->lc);
#endif
+ #ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_trylock(&mtx->dlc, 1);
+ #endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_trylock(&mtx->lcnt, 1);
#endif
@@ -1686,11 +1699,13 @@ erts_mtx_trylock(erts_mtx_t *mtx)
erts_lc_trylock(res == 0, &mtx->lc);
#endif
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_trylock(&mtx->dlc, res == 0);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_trylock(&mtx->lcnt, res);
#endif
return res;
-
}
ERTS_GLB_INLINE void
@@ -1707,6 +1722,9 @@ erts_mtx_lock(erts_mtx_t *mtx)
erts_lc_lock(&mtx->lc);
#endif
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_lock(&mtx->dlc);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock(&mtx->lcnt);
#endif
@@ -1722,6 +1740,9 @@ erts_mtx_unlock(erts_mtx_t *mtx)
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock(&mtx->lc);
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_unlock(&mtx->dlc);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock(&mtx->lcnt);
#endif
@@ -1847,6 +1868,9 @@ erts_rwmtx_init_opt(erts_rwmtx_t *rwmtx, erts_rwmtx_opt_t *opt,
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_init_lock_x(&rwmtx->lc, name, flags, extra);
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_create_lock(&rwmtx->dlc, name);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_init_ref_x(&rwmtx->lcnt, name, extra, flags);
#endif
@@ -1909,6 +1933,9 @@ erts_rwmtx_tryrlock(erts_rwmtx_t *rwmtx)
erts_lc_trylock_flg(res == 0, &rwmtx->lc, ERTS_LOCK_OPTIONS_READ);
#endif
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_trylock(&rwmtx->dlc, res == 0);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_trylock_opt(&rwmtx->lcnt, res, ERTS_LOCK_OPTIONS_READ);
#endif
@@ -1930,6 +1957,9 @@ erts_rwmtx_rlock(erts_rwmtx_t *rwmtx)
erts_lc_lock_flg(&rwmtx->lc, ERTS_LOCK_OPTIONS_READ);
#endif
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_lock(&rwmtx->dlc);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_opt(&rwmtx->lcnt, ERTS_LOCK_OPTIONS_READ);
#endif
@@ -1945,6 +1975,9 @@ erts_rwmtx_runlock(erts_rwmtx_t *rwmtx)
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock_flg(&rwmtx->lc, ERTS_LOCK_OPTIONS_READ);
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_unlock(&rwmtx->dlc);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock_opt(&rwmtx->lcnt, ERTS_LOCK_OPTIONS_READ);
#endif
@@ -1976,6 +2009,9 @@ erts_rwmtx_tryrwlock(erts_rwmtx_t *rwmtx)
erts_lc_trylock_flg(res == 0, &rwmtx->lc, ERTS_LOCK_OPTIONS_RDWR);
#endif
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_trylock(&rwmtx->dlc, res == 0);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_trylock_opt(&rwmtx->lcnt, res, ERTS_LOCK_OPTIONS_RDWR);
#endif
@@ -1997,6 +2033,9 @@ erts_rwmtx_rwlock(erts_rwmtx_t *rwmtx)
erts_lc_lock_flg(&rwmtx->lc, ERTS_LOCK_OPTIONS_RDWR);
#endif
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_lock(&rwmtx->dlc);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_lock_opt(&rwmtx->lcnt, ERTS_LOCK_OPTIONS_RDWR);
#endif
@@ -2012,6 +2051,9 @@ erts_rwmtx_rwunlock(erts_rwmtx_t *rwmtx)
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_unlock_flg(&rwmtx->lc, ERTS_LOCK_OPTIONS_RDWR);
#endif
+#ifdef ERTS_DYN_LOCK_CHECK_INTERNAL
+ erts_dlc_unlock(&rwmtx->dlc);
+#endif
#ifdef ERTS_ENABLE_LOCK_COUNT
erts_lcnt_unlock_opt(&rwmtx->lcnt, ERTS_LOCK_OPTIONS_RDWR);
#endif
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index 20a155e1d8..78f7a146f2 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -605,6 +605,19 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
ERTS_OPEN_DRIVER_RET(NULL, -3, BADARG);
}
+ if (opts->port_watermarks_set && driver != &spawn_driver
+ && driver != &fd_driver && driver != &vanilla_driver) {
+ erts_rwmtx_runlock(&erts_driver_list_lock);
+ ERTS_OPEN_DRIVER_RET(NULL, -3, BADARG);
+ }
+
+ if (opts->msgq_watermarks_set
+ && (driver->flags & ERL_DRV_FLAG_NO_BUSY_MSGQ)
+ && opts->high_msgq_watermark != ERL_DRV_BUSY_MSGQ_DISABLED) {
+ erts_rwmtx_runlock(&erts_driver_list_lock);
+ ERTS_OPEN_DRIVER_RET(NULL, -3, BADARG);
+ }
+
driver_lock = driver->lock;
if (driver->handle != NULL) {
@@ -644,6 +657,11 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */
1));
}
+ if (opts->msgq_watermarks_set)
+ erl_drv_busy_msgq_limits(ERTS_Port2ErlDrvPort(port),
+ &opts->low_msgq_watermark,
+ &opts->high_msgq_watermark);
+
error_number = error_type = 0;
if (driver->start) {
ERTS_MSACC_PUSH_STATE_M();
diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h
index c534891f30..0d85211be8 100644
--- a/erts/emulator/beam/sys.h
+++ b/erts/emulator/beam/sys.h
@@ -668,29 +668,6 @@ typedef Eterm ErtsTracer;
#include "erl_osenv.h"
-/*
- * This structure contains options to all built in drivers.
- * None of the drivers use all of the fields.
- */
-
-typedef struct _SysDriverOpts {
- Uint ifd; /* Input file descriptor (fd driver). */
- Uint ofd; /* Outputfile descriptor (fd driver). */
- int packet_bytes; /* Number of bytes in packet header. */
- int read_write; /* Read and write bits. */
- int use_stdio; /* Use standard I/O: TRUE or FALSE. */
- int redir_stderr; /* Redirect stderr to stdout: TRUE/FALSE. */
- int hide_window; /* Hide this windows (Windows). */
- int exit_status; /* Report exit status of subprocess. */
- int overlapped_io; /* Only has effect on windows NT et al */
- erts_osenv_t envir; /* Environment of the port process */
- char **argv; /* Argument vector in Unix'ish format. */
- char *wd; /* Working directory. */
- unsigned spawn_type; /* Bitfield of ERTS_SPAWN_DRIVER |
- ERTS_SPAWN_EXTERNAL | both*/
- int parallelism; /* Optimize for parallelism */
-} SysDriverOpts;
-
extern char *erts_default_arg0;
extern char os_type[];
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 66ff8d8450..2ef452fa01 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2019. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2020. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -12607,12 +12607,8 @@ static ErlDrvSSizeT packet_inet_ctl(ErlDrvData e, unsigned int cmd, char* buf,
return ctl_error(EALREADY, rbuf, rsize);
if (packet_inet_input(udesc, desc->event) == 0) {
- if (timeout == 0)
- async_error_am(desc, am_timeout);
- else {
- if (timeout != INET_INFINITY)
- driver_set_timer(desc->port, timeout);
- }
+ if (timeout != INET_INFINITY)
+ driver_set_timer(desc->port, timeout);
}
return ctl_reply(INET_REP_OK, tbuf, 2, rbuf, rsize);
}
diff --git a/erts/emulator/nifs/common/prim_net_nif.c b/erts/emulator/nifs/common/prim_net_nif.c
index c95b0d7f70..1fbd3e2366 100644
--- a/erts/emulator/nifs/common/prim_net_nif.c
+++ b/erts/emulator/nifs/common/prim_net_nif.c
@@ -1061,7 +1061,7 @@ ERL_NIF_TERM nif_getifaddrs(ErlNifEnv* env,
return result;
#else // HAVE_GETIFADDRS
- return esock_make_error(env, esock_atom_notsup);
+ return esock_make_error(env, esock_atom_enotsup);
#endif
}
diff --git a/erts/emulator/nifs/common/socket_int.h b/erts/emulator/nifs/common/socket_int.h
index e4a3d6157d..621d52af16 100644
--- a/erts/emulator/nifs/common/socket_int.h
+++ b/erts/emulator/nifs/common/socket_int.h
@@ -166,6 +166,7 @@ typedef unsigned int BOOLEAN_T;
GLOBAL_ATOM_DEF(drop_source_membership); \
GLOBAL_ATOM_DEF(dstopts); \
GLOBAL_ATOM_DEF(egp); \
+ GLOBAL_ATOM_DEF(enotsup); \
GLOBAL_ATOM_DEF(eor); \
GLOBAL_ATOM_DEF(error); \
GLOBAL_ATOM_DEF(errqueue); \
@@ -207,6 +208,7 @@ typedef unsigned int BOOLEAN_T;
GLOBAL_ATOM_DEF(keepcnt); \
GLOBAL_ATOM_DEF(keepidle); \
GLOBAL_ATOM_DEF(keepintvl); \
+ GLOBAL_ATOM_DEF(kernel); \
GLOBAL_ATOM_DEF(leave_group); \
GLOBAL_ATOM_DEF(level); \
GLOBAL_ATOM_DEF(linger); \
@@ -328,6 +330,7 @@ typedef unsigned int BOOLEAN_T;
GLOBAL_ATOM_DEF(unicast_hops); \
GLOBAL_ATOM_DEF(unknown); \
GLOBAL_ATOM_DEF(usec); \
+ GLOBAL_ATOM_DEF(user); \
GLOBAL_ATOM_DEF(user_timeout); \
GLOBAL_ATOM_DEF(use_ext_recvinfo); \
GLOBAL_ATOM_DEF(use_min_mtu); \
@@ -378,6 +381,7 @@ GLOBAL_ERROR_REASON_ATOM_DEFS
enif_make_tuple8((E), (E1), (E2), (E3), (E4), (E5), (E6), (E7), (E8))
#define MKTA(E, A, AL) enif_make_tuple_from_array((E), (A), (AL))
#define MKUI(E,UI) enif_make_uint((E), (UI))
+#define MKUI64(E,UI) enif_make_uint64((E), (UI))
#define MKUL(E,UL) enif_make_ulong((E), (UL))
#define MCREATE(N) enif_mutex_create((N))
@@ -414,6 +418,7 @@ GLOBAL_ERROR_REASON_ATOM_DEFS
#define GET_STR(E, L, B, SZ) \
enif_get_string((E), (L), (B), (SZ), ERL_NIF_LATIN1)
#define GET_UINT(E, TE, UIP) enif_get_uint((E), (TE), (UIP))
+#define GET_UINT64(E, TE, UIP) enif_get_uint64((E), (TE), (UIP))
#define GET_ULONG(E, TE, ULP) enif_get_long((E), (TE), (ULP))
#define GET_TUPLE(E, TE, TSZ, TA) enif_get_tuple((E), (TE), (TSZ), (TA))
#define GET_MAP_VAL(E, M, K, V) enif_get_map_value((E), (M), (K), (V))
diff --git a/erts/emulator/nifs/common/socket_nif.c b/erts/emulator/nifs/common/socket_nif.c
index 84b07252d8..fbda73d518 100644
--- a/erts/emulator/nifs/common/socket_nif.c
+++ b/erts/emulator/nifs/common/socket_nif.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2018-2019. All Rights Reserved.
+ * Copyright Ericsson AB 2018-2020. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -368,7 +368,7 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
#define ESOCK_GLOBAL_DEBUG_DEFAULT FALSE
#define ESOCK_DEBUG_DEFAULT FALSE
-/* Counters and stuff (Don't know where to sent this stuff anyway) */
+/* Counters and stuff (Don't know where to sen2 this stuff anyway) */
#define ESOCK_NIF_IOW_DEFAULT FALSE
@@ -487,6 +487,7 @@ static void (*esock_sctp_freepaddrs)(struct sockaddr *addrs) = NULL;
#define ESOCK_RECV_FLAG_LOW ESOCK_RECV_FLAG_CMSG_CLOEXEC
#define ESOCK_RECV_FLAG_HIGH ESOCK_RECV_FLAG_TRUNC
+#define ESOCK_RECV_BUFFER_COUNT_DEFAULT 0
#define ESOCK_RECV_BUFFER_SIZE_DEFAULT 8192
#define ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT 1024
#define ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT 1024
@@ -532,6 +533,7 @@ typedef union {
/*----------------------------------------------------------------------------
* Interface constants.
*
+ * This section must be "identical" to the corresponding socket.erl
*/
/* domain */
@@ -576,9 +578,11 @@ typedef union {
#define ESOCK_OPT_OTP_RCVCTRLBUF 6
#define ESOCK_OPT_OTP_SNDCTRLBUF 7
#define ESOCK_OPT_OTP_FD 8
+#define ESOCK_OPT_OTP_META 9
#define ESOCK_OPT_OTP_DOMAIN 0xFF01 // INTERNAL AND ONLY GET
#define ESOCK_OPT_OTP_TYPE 0xFF02 // INTERNAL AND ONLY GET
#define ESOCK_OPT_OTP_PROTOCOL 0xFF03 // INTERNAL AND ONLY GET
+#define ESOCK_OPT_OTP_DTP 0xFF04 // INTERNAL AND ONLY GET
#define ESOCK_OPT_SOCK_ACCEPTCONN 1
#define ESOCK_OPT_SOCK_BINDTODEVICE 3
@@ -702,7 +706,7 @@ typedef union {
/* Socket specific debug */
#define SSDBG( __D__ , proto ) ESOCK_DBG_PRINTF( (__D__)->dbg , proto )
-#define SOCK_CNT_INC( __E__, __D__, SF, ACNT, CNT, INC) \
+#define ESOCK_CNT_INC( __E__, __D__, SF, ACNT, CNT, INC) \
{ \
if (cnt_inc(CNT, INC) && (__D__)->iow) { \
esock_send_wrap_msg(__E__, __D__, SF, ACNT); \
@@ -827,6 +831,12 @@ typedef struct {
ERL_NIF_TERM ref; // The (unique) reference (ID) of the request
} ESockRequestor;
+typedef struct{
+ // Holding the socket level 'otp' option 'meta' term
+ ErlNifEnv* env;
+ ERL_NIF_TERM ref;
+} ESockMeta;
+
typedef struct esock_request_queue_element {
struct esock_request_queue_element* nextP;
ESockRequestor data;
@@ -837,6 +847,48 @@ typedef struct {
ESockRequestQueueElement* last;
} ESockRequestQueue;
+/*** The point of this is primarily testing ***/
+
+// #define ESOCK_COUNTER_SIZE 16
+// #define ESOCK_COUNTER_SIZE 24
+// #define ESOCK_COUNTER_SIZE 32
+// #define ESOCK_COUNTER_SIZE 48
+
+#if ESOCK_COUNTER_SIZE == 16
+
+typedef Uint16 ESockCounter;
+#define ESOCK_COUNTER_MAX 0xFFFF
+#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKUI((ENV), (CNT)))
+
+#elif ESOCK_COUNTER_SIZE == 24
+
+typedef Uint32 ESockCounter;
+#define ESOCK_COUNTER_MAX 0xFFFFFF
+#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKUI((ENV), (CNT)))
+
+#elif ESOCK_COUNTER_SIZE == 32
+
+typedef Uint32 ESockCounter;
+#define ESOCK_COUNTER_MAX 0xFFFFFFFF
+#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKUI((ENV), (CNT)))
+
+#elif ESOCK_COUNTER_SIZE == 48
+
+typedef Uint64 ESockCounter;
+#define ESOCK_COUNTER_MAX 0xFFFFFFFFFFFF
+#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKUI64((ENV), (CNT)))
+
+#elif ESOCK_COUNTER_SIZE == 64
+
+typedef Uint64 ESockCounter;
+#define ESOCK_COUNTER_MAX 0xFFFFFFFFFFFFFFFF
+#define MKCT(ENV, TAG, CNT) MKT2((ENV), (TAG), MKUI64((ENV), (CNT)))
+
+#else
+
+#error "Invalid counter size"
+
+#endif
typedef struct {
/*
@@ -874,11 +926,13 @@ typedef struct {
ESockRequestor* currentWriterP; // NULL or points to currentWriter
ESockRequestQueue writersQ;
BOOLEAN_T isWritable;
- Uint32 writePkgCnt;
- Uint32 writeByteCnt;
- Uint32 writeTries;
- Uint32 writeWaits;
- Uint32 writeFails;
+ ESockCounter writePkgCnt;
+ ESockCounter writePkgMax;
+ ESockCounter writePkgMaxCnt;
+ ESockCounter writeByteCnt;
+ ESockCounter writeTries;
+ ESockCounter writeWaits;
+ ESockCounter writeFails;
/* +++ Read stuff +++ */
ErlNifMutex* readMtx;
@@ -888,17 +942,23 @@ typedef struct {
BOOLEAN_T isReadable;
ErlNifBinary rbuffer; // DO WE NEED THIS
Uint32 readCapacity; // DO WE NEED THIS
- Uint32 readPkgCnt;
- Uint32 readByteCnt;
- Uint32 readTries;
- Uint32 readWaits;
- Uint32 readFails;
+ ESockCounter readPkgCnt;
+ ESockCounter readPkgMax;
+ ESockCounter readPkgMaxCnt;
+ ESockCounter readByteCnt;
+ ESockCounter readTries;
+ ESockCounter readWaits;
+ ESockCounter readFails;
/* +++ Accept stuff +++ */
ErlNifMutex* accMtx;
ESockRequestor currentAcceptor;
ESockRequestor* currentAcceptorP; // NULL or points to currentAcceptor
ESockRequestQueue acceptorsQ;
+ ESockCounter accSuccess;
+ ESockCounter accTries;
+ ESockCounter accWaits;
+ ESockCounter accFails;
/* +++ Config & Misc stuff +++ */
ErlNifMutex* cfgMtx;
@@ -914,6 +974,7 @@ typedef struct {
unsigned int rNumCnt; // recv: Current number of reads (so far)
size_t rCtrlSz; // Read control buffer size
size_t wCtrlSz; // Write control buffer size
+ ESockMeta meta; // Level 'otp' option 'meta' term
BOOLEAN_T iow; // Inform On (counter) Wrap
BOOLEAN_T dbg;
@@ -925,6 +986,9 @@ typedef struct {
ERL_NIF_TERM closeRef;
BOOLEAN_T closeLocal;
+ /* Lock order: closeMtx, readMtx, accMtx, writeMtx, cfgMtx
+ * unordered: cntMtx
+ */
} ESockDescriptor;
@@ -934,21 +998,34 @@ typedef struct {
/* These are for debugging, testing and the like */
// ERL_NIF_TERM version;
// ERL_NIF_TERM buildDate;
+
+ /* XXX Should be locked but too awkward and small gain */
BOOLEAN_T dbg;
+ /* Registry stuff */
+ ErlNifPid regPid; /* Constant - not locked */
+
+ /* XXX
+ * Should be locked but too awkward for no gain since it is not used yet
+ */
BOOLEAN_T iow; // Where do we send this? Subscription?
- ErlNifMutex* cntMtx;
- Uint32 numSockets;
- Uint32 numTypeStreams;
- Uint32 numTypeDGrams;
- Uint32 numTypeSeqPkgs;
- Uint32 numDomainInet;
- Uint32 numDomainInet6;
- Uint32 numDomainLocal;
- Uint32 numProtoIP;
- Uint32 numProtoTCP;
- Uint32 numProtoUDP;
- Uint32 numProtoSCTP;
+
+ ErlNifMutex* cntMtx; /* Locks the below */
+ /* Its extreme overkill to have these counters be 64-bit,
+ * but since the other counters are, its much simpler to
+ * let to let these be 64-bit also
+ */
+ ESockCounter numSockets;
+ ESockCounter numTypeStreams;
+ ESockCounter numTypeDGrams;
+ ESockCounter numTypeSeqPkgs;
+ ESockCounter numDomainInet;
+ ESockCounter numDomainInet6;
+ ESockCounter numDomainLocal;
+ ESockCounter numProtoIP;
+ ESockCounter numProtoTCP;
+ ESockCounter numProtoUDP;
+ ESockCounter numProtoSCTP;
} ESockData;
@@ -1121,6 +1198,7 @@ static ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env,
int save_errno);
static ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env,
ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
SOCKET accSock,
ErlNifPid caller,
ESockAddress* remote);
@@ -1154,6 +1232,7 @@ static ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env,
unsigned int nextState);
static BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
SOCKET accSock,
ErlNifPid pid,
ESockAddress* remote,
@@ -1182,7 +1261,7 @@ static ERL_NIF_TERM esock_recv(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sendRef,
ERL_NIF_TERM recvRef,
- int len,
+ size_t len,
int flags);
static ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
ESockDescriptor* descP,
@@ -1226,9 +1305,11 @@ static ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env,
* *** esock_setopt_otp_rcvbuf ***
* *** esock_setopt_otp_rcvctrlbuf ***
* *** esock_setopt_otp_sndctrlbuf ***
+ * *** esock_setopt_otp_meta ***
*/
#define ESOCK_SETOPT_OTP_FUNCS \
ESOCK_SETOPT_OTP_FUNC_DEF(debug); \
+ ESOCK_SETOPT_OTP_FUNC_DEF(meta); \
ESOCK_SETOPT_OTP_FUNC_DEF(iow); \
ESOCK_SETOPT_OTP_FUNC_DEF(ctrl_proc); \
ESOCK_SETOPT_OTP_FUNC_DEF(rcvbuf); \
@@ -1757,12 +1838,15 @@ static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env,
* *** esock_getopt_otp_rcvctrlbuf ***
* *** esock_getopt_otp_sndctrlbuf ***
* *** esock_getopt_otp_fd ***
+ * *** esock_getopt_otp_meta ***
* *** esock_getopt_otp_domain ***
* *** esock_getopt_otp_type ***
* *** esock_getopt_otp_protocol ***
+ * *** esock_getopt_otp_dtp ***
*/
#define ESOCK_GETOPT_OTP_FUNCS \
ESOCK_GETOPT_OTP_FUNC_DEF(debug); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(meta); \
ESOCK_GETOPT_OTP_FUNC_DEF(iow); \
ESOCK_GETOPT_OTP_FUNC_DEF(ctrl_proc); \
ESOCK_GETOPT_OTP_FUNC_DEF(rcvbuf); \
@@ -1771,7 +1855,8 @@ static ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env,
ESOCK_GETOPT_OTP_FUNC_DEF(fd); \
ESOCK_GETOPT_OTP_FUNC_DEF(domain); \
ESOCK_GETOPT_OTP_FUNC_DEF(type); \
- ESOCK_GETOPT_OTP_FUNC_DEF(protocol);
+ ESOCK_GETOPT_OTP_FUNC_DEF(protocol); \
+ ESOCK_GETOPT_OTP_FUNC_DEF(dtp);
#define ESOCK_GETOPT_OTP_FUNC_DEF(F) \
static ERL_NIF_TERM esock_getopt_otp_##F(ErlNifEnv* env, \
ESockDescriptor* descP)
@@ -2245,6 +2330,10 @@ static ERL_NIF_TERM send_check_fail(ErlNifEnv* env,
ESockDescriptor* descP,
int saveErrno,
ERL_NIF_TERM sockRef);
+static void send_error_waiting_writers(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM reason);
static ERL_NIF_TERM send_check_retry(ErlNifEnv* env,
ESockDescriptor* descP,
ssize_t written,
@@ -2266,29 +2355,29 @@ static void recv_error_current_reader(ErlNifEnv* env,
ERL_NIF_TERM reason);
static ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
- int toRead,
+ ssize_t read,
+ size_t toRead,
int saveErrno,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef);
static ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
- int toRead,
+ ssize_t read,
+ size_t toRead,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef);
static ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
- int toRead,
+ ssize_t read,
+ size_t toRead,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef);
static ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
+ ssize_t read,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef);
static ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
@@ -2298,25 +2387,25 @@ static ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
ErlNifBinary* buf2P,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef);
-static ERL_NIF_TERM recv_check_fail_closed(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM recvRef);
+static ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM recvRef);
static ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
- int toRead,
+ ssize_t read,
+ size_t toRead,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef);
static ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
+ ssize_t read,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef);
static ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
+ ssize_t read,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef);
@@ -2534,8 +2623,8 @@ static BOOLEAN_T change_network_namespace(char* netns, int* cns, int* err);
static BOOLEAN_T restore_network_namespace(int ns, SOCKET sock, int* err);
#endif
-static BOOLEAN_T cnt_inc(Uint32* cnt, Uint32 inc);
-static void cnt_dec(Uint32* cnt, Uint32 dec);
+static BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc);
+static void cnt_dec(ESockCounter* cnt, ESockCounter dec);
static void inc_socket(int domain, int type, int protocol);
static void dec_socket(int domain, int type, int protocol);
@@ -2599,6 +2688,8 @@ ESOCK_OPERATOR_FUNCS_DEFS
static BOOLEAN_T requestor_pop(ESockRequestQueue* q,
ESockRequestor* reqP);
+static void requestor_clear(ESockRequestor* reqP);
+
static BOOLEAN_T qsearch4pid(ErlNifEnv* env,
ESockRequestQueue* q,
ErlNifPid* pid);
@@ -2623,6 +2714,10 @@ static int esock_demonitor(const char* slogan,
static void esock_monitor_init(ESockMonitor* mon);
static ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env,
const ESockMonitor* monP);
+static void esock_release_current(const char* slogan,
+ ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESockRequestor* current);
#endif // if defined(__WIN32__)
@@ -2658,6 +2753,11 @@ static void esock_down_reader(ErlNifEnv* env,
ERL_NIF_TERM sockRef,
const ErlNifPid* pid);
+static void esock_send_reg_add_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef);
+static void esock_send_reg_del_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef);
+
static char* esock_send_wrap_msg(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
@@ -2676,6 +2776,13 @@ static char* esock_send_msg(ErlNifEnv* env,
ERL_NIF_TERM msg,
ErlNifEnv* msgEnv);
+static ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef);
+static ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef);
+static ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env,
+ ERL_NIF_TERM tag,
+ ERL_NIF_TERM sockRef);
static ERL_NIF_TERM mk_abort_msg(ErlNifEnv* env,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM opRef,
@@ -2811,6 +2918,7 @@ static char str_exsend[] = "exsend"; // failed send
GLOBAL_ATOM_DECL(drop_source_membership); \
GLOBAL_ATOM_DECL(dstopts); \
GLOBAL_ATOM_DECL(egp); \
+ GLOBAL_ATOM_DECL(enotsup); \
GLOBAL_ATOM_DECL(eor); \
GLOBAL_ATOM_DECL(error); \
GLOBAL_ATOM_DECL(errqueue); \
@@ -2852,6 +2960,7 @@ static char str_exsend[] = "exsend"; // failed send
GLOBAL_ATOM_DECL(keepcnt); \
GLOBAL_ATOM_DECL(keepidle); \
GLOBAL_ATOM_DECL(keepintvl); \
+ GLOBAL_ATOM_DECL(kernel); \
GLOBAL_ATOM_DECL(leave_group); \
GLOBAL_ATOM_DECL(level); \
GLOBAL_ATOM_DECL(linger); \
@@ -2972,6 +3081,7 @@ static char str_exsend[] = "exsend"; // failed send
GLOBAL_ATOM_DECL(unicast_hops); \
GLOBAL_ATOM_DECL(unknown); \
GLOBAL_ATOM_DECL(usec); \
+ GLOBAL_ATOM_DECL(user); \
GLOBAL_ATOM_DECL(user_timeout); \
GLOBAL_ATOM_DECL(use_ext_recvinfo); \
GLOBAL_ATOM_DECL(use_min_mtu); \
@@ -2993,7 +3103,12 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
/* *** Local atoms *** */
#define LOCAL_ATOMS \
+ LOCAL_ATOM_DECL(acc_success); \
+ LOCAL_ATOM_DECL(acc_fails); \
+ LOCAL_ATOM_DECL(acc_tries); \
+ LOCAL_ATOM_DECL(acc_waits); \
LOCAL_ATOM_DECL(adaptation_layer); \
+ LOCAL_ATOM_DECL(add); \
LOCAL_ATOM_DECL(addr_unreach); \
LOCAL_ATOM_DECL(address); \
LOCAL_ATOM_DECL(adm_prohibited); \
@@ -3009,13 +3124,13 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(counter_wrap); \
LOCAL_ATOM_DECL(counters); \
LOCAL_ATOM_DECL(data_in); \
+ LOCAL_ATOM_DECL(del); \
LOCAL_ATOM_DECL(dest_unreach); \
LOCAL_ATOM_DECL(do); \
LOCAL_ATOM_DECL(dont); \
LOCAL_ATOM_DECL(exclude); \
LOCAL_ATOM_DECL(false); \
LOCAL_ATOM_DECL(frag_needed); \
- LOCAL_ATOM_DECL(global_counters); \
LOCAL_ATOM_DECL(host_unknown); \
LOCAL_ATOM_DECL(host_unreach); \
LOCAL_ATOM_DECL(in4_sockaddr); \
@@ -3041,6 +3156,7 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(not_neighbour); \
LOCAL_ATOM_DECL(null); \
LOCAL_ATOM_DECL(num_acceptors); \
+ LOCAL_ATOM_DECL(num_cnt_bits); \
LOCAL_ATOM_DECL(num_dinet); \
LOCAL_ATOM_DECL(num_dinet6); \
LOCAL_ATOM_DECL(num_dlocal); \
@@ -3069,6 +3185,7 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(read_byte); \
LOCAL_ATOM_DECL(read_fails); \
LOCAL_ATOM_DECL(read_pkg); \
+ LOCAL_ATOM_DECL(read_pkg_max); \
LOCAL_ATOM_DECL(read_tries); \
LOCAL_ATOM_DECL(read_waits); \
LOCAL_ATOM_DECL(reject_route); \
@@ -3089,12 +3206,14 @@ ERL_NIF_TERM esock_atom_socket_tag; // This has a "special" name ('$socket')
LOCAL_ATOM_DECL(write_byte); \
LOCAL_ATOM_DECL(write_fails); \
LOCAL_ATOM_DECL(write_pkg); \
+ LOCAL_ATOM_DECL(write_pkg_max); \
LOCAL_ATOM_DECL(write_tries); \
LOCAL_ATOM_DECL(write_waits); \
LOCAL_ATOM_DECL(zerocopy);
/* Local error reason atoms */
#define LOCAL_ERROR_REASON_ATOMS \
+ LOCAL_ATOM_DECL(econnreset); \
LOCAL_ATOM_DECL(eisconn); \
LOCAL_ATOM_DECL(enotclosing); \
LOCAL_ATOM_DECL(enotconn); \
@@ -3194,7 +3313,6 @@ static ESOCK_INLINE ErlNifEnv* esock_alloc_env(const char* slogan)
* Description:
* This is currently just a placeholder...
*/
-#define MKCT(E, T, C) MKT2((E), (T), MKUI((E), (C)))
static
ERL_NIF_TERM nif_info(ErlNifEnv* env,
@@ -3237,40 +3355,60 @@ ERL_NIF_TERM nif_info(ErlNifEnv* env,
/*
* This function return a property list containing "global" info.
+ *
+ * Note that we also include something in the counter list that is not
+ * actually a counter, the num_cnt_bits. This is the "size" of each counter,
+ * in number of bits: 16 | 24 | 32 | 48 | 64.
*/
#if !defined(__WIN32__)
static
ERL_NIF_TERM esock_global_info(ErlNifEnv* env)
{
- ERL_NIF_TERM numSockets = MKCT(env, atom_num_sockets, data.numSockets);
- ERL_NIF_TERM numTypeDGrams = MKCT(env, atom_num_tdgrams, data.numTypeDGrams);
- ERL_NIF_TERM numTypeStreams = MKCT(env, atom_num_tstreams, data.numTypeStreams);
- ERL_NIF_TERM numTypeSeqPkgs = MKCT(env, atom_num_tseqpkgs, data.numTypeSeqPkgs);
- ERL_NIF_TERM numDomLocal = MKCT(env, atom_num_dlocal, data.numDomainLocal);
- ERL_NIF_TERM numDomInet = MKCT(env, atom_num_dinet, data.numDomainInet);
- ERL_NIF_TERM numDomInet6 = MKCT(env, atom_num_dinet6, data.numDomainInet6);
- ERL_NIF_TERM numProtoIP = MKCT(env, atom_num_pip, data.numProtoIP);
- ERL_NIF_TERM numProtoTCP = MKCT(env, atom_num_ptcp, data.numProtoTCP);
- ERL_NIF_TERM numProtoUDP = MKCT(env, atom_num_pudp, data.numProtoUDP);
- ERL_NIF_TERM numProtoSCTP = MKCT(env, atom_num_psctp, data.numProtoSCTP);
- ERL_NIF_TERM gcnt[] = {numSockets,
- numTypeDGrams, numTypeStreams, numTypeSeqPkgs,
- numDomLocal, numDomInet, numDomInet6,
- numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP};
- unsigned int lenGCnt = sizeof(gcnt) / sizeof(ERL_NIF_TERM);
- ERL_NIF_TERM lgcnt = MKLA(env, gcnt, lenGCnt);
- ERL_NIF_TERM keys[] = {esock_atom_debug, atom_iow, atom_global_counters};
- ERL_NIF_TERM vals[] = {BOOL2ATOM(data.dbg), BOOL2ATOM(data.iow), lgcnt};
- ERL_NIF_TERM info;
- unsigned int numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM);
- unsigned int numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
+ ERL_NIF_TERM
+ numBits, numSockets, numTypeDGrams, numTypeStreams,
+ numTypeSeqPkgs, numDomLocal, numDomInet, numDomInet6,
+ numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP;
- ESOCK_ASSERT( (numKeys == numVals) );
+ MLOCK(data.cntMtx);
+ numBits = MKCT(env, atom_num_cnt_bits, ESOCK_COUNTER_SIZE);
+ numSockets = MKCT(env, atom_num_sockets, data.numSockets);
+ numTypeDGrams = MKCT(env, atom_num_tdgrams, data.numTypeDGrams);
+ numTypeStreams = MKCT(env, atom_num_tstreams, data.numTypeStreams);
+ numTypeSeqPkgs = MKCT(env, atom_num_tseqpkgs, data.numTypeSeqPkgs);
+ numDomLocal = MKCT(env, atom_num_dlocal, data.numDomainLocal);
+ numDomInet = MKCT(env, atom_num_dinet, data.numDomainInet);
+ numDomInet6 = MKCT(env, atom_num_dinet6, data.numDomainInet6);
+ numProtoIP = MKCT(env, atom_num_pip, data.numProtoIP);
+ numProtoTCP = MKCT(env, atom_num_ptcp, data.numProtoTCP);
+ numProtoUDP = MKCT(env, atom_num_pudp, data.numProtoUDP);
+ numProtoSCTP = MKCT(env, atom_num_psctp, data.numProtoSCTP);
+ MUNLOCK(data.cntMtx);
- if (!MKMA(env, keys, vals, numKeys, &info))
- return enif_make_badarg(env);
+ {
+ ERL_NIF_TERM gcnt[] =
+ {numBits,
+ numSockets,
+ numTypeDGrams, numTypeStreams, numTypeSeqPkgs,
+ numDomLocal, numDomInet, numDomInet6,
+ numProtoIP, numProtoTCP, numProtoUDP, numProtoSCTP};
+ unsigned int lenGCnt =
+ sizeof(gcnt) / sizeof(ERL_NIF_TERM);
+ ERL_NIF_TERM
+ lgcnt = MKLA(env, gcnt, lenGCnt),
+ keys[] = {esock_atom_debug, atom_iow, atom_counters},
+ vals[] = {BOOL2ATOM(data.dbg), BOOL2ATOM(data.iow), lgcnt},
+ info;
+ unsigned int
+ numKeys = sizeof(keys) / sizeof(ERL_NIF_TERM),
+ numVals = sizeof(vals) / sizeof(ERL_NIF_TERM);
- return info;
+ ESOCK_ASSERT( (numKeys == numVals) );
+
+ if (!MKMA(env, keys, vals, numKeys, &info))
+ return enif_make_badarg(env);
+
+ return info;
+ }
}
@@ -3280,7 +3418,7 @@ ERL_NIF_TERM esock_global_info(ErlNifEnv* env)
* domain: The domain of the socket
* type: The type of the socket
* protocol: The protocol of the socket
- * (ctrl: Controlling process of the socket)
+ * ctrl: Controlling process of the socket)
* (readable: Is the socket readable)
* (writable: Is the socket writable)
* (connected: Is the socket connected)
@@ -3297,7 +3435,7 @@ ERL_NIF_TERM esock_socket_info(ErlNifEnv* env,
ERL_NIF_TERM domain = esock_socket_info_domain(env, descP);
ERL_NIF_TERM type = esock_socket_info_type(env, descP);
ERL_NIF_TERM protocol = esock_socket_info_protocol(env, descP);
- // ERL_NIF_TERM ctrlPid = MKPID(env, &descP->ctrlPid);
+ ERL_NIF_TERM ctrlPid = MKPID(env, &descP->ctrlPid);
ERL_NIF_TERM readable = BOOL2ATOM(descP->isReadable);
ERL_NIF_TERM writable = BOOL2ATOM(descP->isWritable);
// ERL_NIF_TERM connected = BOOL2ATOM(descP->isConnected);
@@ -3308,6 +3446,7 @@ ERL_NIF_TERM esock_socket_info(ErlNifEnv* env,
ERL_NIF_TERM keys[] = {esock_atom_domain,
esock_atom_type,
esock_atom_protocol,
+ esock_atom_ctrl,
atom_readable,
atom_writable,
atom_counters,
@@ -3317,6 +3456,7 @@ ERL_NIF_TERM esock_socket_info(ErlNifEnv* env,
ERL_NIF_TERM vals[] = {domain,
type,
protocol,
+ ctrlPid,
readable,
writable,
counters,
@@ -3409,24 +3549,32 @@ ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env,
{
ERL_NIF_TERM info;
- MLOCK(descP->writeMtx);
MLOCK(descP->readMtx);
+ MLOCK(descP->writeMtx);
{
ERL_NIF_TERM readByteCnt = MKCT(env, atom_read_byte, descP->readByteCnt);
ERL_NIF_TERM readFails = MKCT(env, atom_read_fails, descP->readFails);
ERL_NIF_TERM readPkgCnt = MKCT(env, atom_read_pkg, descP->readPkgCnt);
+ ERL_NIF_TERM readPkgMax = MKCT(env, atom_read_pkg_max, descP->readPkgMax);
ERL_NIF_TERM readTries = MKCT(env, atom_read_tries, descP->readTries);
ERL_NIF_TERM readWaits = MKCT(env, atom_read_waits, descP->readWaits);
ERL_NIF_TERM writeByteCnt = MKCT(env, atom_write_byte, descP->writeByteCnt);
ERL_NIF_TERM writeFails = MKCT(env, atom_write_fails, descP->writeFails);
ERL_NIF_TERM writePkgCnt = MKCT(env, atom_write_pkg, descP->writePkgCnt);
+ ERL_NIF_TERM writePkgMax = MKCT(env, atom_write_pkg_max, descP->writePkgMax);
ERL_NIF_TERM writeTries = MKCT(env, atom_write_tries, descP->writeTries);
ERL_NIF_TERM writeWaits = MKCT(env, atom_write_waits, descP->writeWaits);
- ERL_NIF_TERM acnt[] = {readByteCnt, readFails, readPkgCnt,
+
+ ERL_NIF_TERM accSuccess = MKCT(env, atom_acc_success, descP->accSuccess);
+ ERL_NIF_TERM accFails = MKCT(env, atom_acc_fails, descP->accFails);
+ ERL_NIF_TERM accTries = MKCT(env, atom_acc_tries, descP->accTries);
+ ERL_NIF_TERM accWaits = MKCT(env, atom_acc_waits, descP->accWaits);
+ ERL_NIF_TERM acnt[] = {readByteCnt, readFails, readPkgCnt, readPkgMax,
readTries, readWaits,
- writeByteCnt, writeFails, writePkgCnt,
- writeTries, writeWaits};
+ writeByteCnt, writeFails, writePkgCnt, writePkgMax,
+ writeTries, writeWaits,
+ accSuccess, accFails, accTries, accWaits};
unsigned int lenACnt = sizeof(acnt) / sizeof(ERL_NIF_TERM);
info = MKLA(env, acnt, lenACnt);
@@ -3438,8 +3586,8 @@ ERL_NIF_TERM esock_socket_info_counters(ErlNifEnv* env,
}
- MUNLOCK(descP->readMtx);
MUNLOCK(descP->writeMtx);
+ MUNLOCK(descP->readMtx);
SSDBG( descP, ("SOCKET", "esock_socket_info_counters -> done with"
"\r\n info: %T"
@@ -5334,6 +5482,9 @@ ERL_NIF_TERM esock_open(ErlNifEnv* env,
inc_socket(domain, type, protocol);
+ /* And finally update the registry */
+ esock_send_reg_add_msg(env, res);
+
return esock_make_ok2(env, res);
}
@@ -6146,7 +6297,8 @@ ERL_NIF_TERM esock_accept_listening(ErlNifEnv* env,
SSDBG( descP, ("SOCKET", "esock_accept_listening -> success\r\n") );
- res = esock_accept_listening_accept(env, descP, accSock, caller, &remote);
+ res = esock_accept_listening_accept(env, descP,
+ sockRef, accSock, caller, &remote);
}
@@ -6180,6 +6332,8 @@ ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env,
SSDBG( descP,
("SOCKET", "esock_accept_listening_error -> would block\r\n") );
+ ESOCK_CNT_INC(env, descP, sockRef, atom_acc_tries, &descP->accTries, 1);
+
descP->currentAcceptor.pid = caller;
if (MONP("esock_accept_listening -> current acceptor",
env, descP,
@@ -6201,6 +6355,9 @@ ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
"esock_accept_listening -> errno: %d\r\n", save_errno) );
+
+ ESOCK_CNT_INC(env, descP, sockRef, atom_acc_fails, &descP->accFails, 1);
+
res = esock_make_error_errno(env, save_errno);
}
@@ -6215,13 +6372,14 @@ ERL_NIF_TERM esock_accept_listening_error(ErlNifEnv* env,
static
ERL_NIF_TERM esock_accept_listening_accept(ErlNifEnv* env,
ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
SOCKET accSock,
ErlNifPid caller,
ESockAddress* remote)
{
ERL_NIF_TERM res;
- esock_accept_accepted(env, descP, accSock, caller, remote, &res);
+ esock_accept_accepted(env, descP, sockRef, accSock, caller, remote, &res);
return res;
}
@@ -6342,16 +6500,9 @@ ERL_NIF_TERM esock_accept_accepting_current_accept(ErlNifEnv* env,
{
ERL_NIF_TERM res;
- if (esock_accept_accepted(env, descP, accSock,
+ if (esock_accept_accepted(env, descP, sockRef, accSock,
descP->currentAcceptor.pid, remote, &res)) {
- /* Clean out the old cobweb's before trying to invite a new spider */
-
- esock_free_env("esock_accept_accepting_current_accept - "
- "current-accept-env",
- descP->currentAcceptor.env);
- descP->currentAcceptor.env = NULL;
-
if (!activate_next_acceptor(env, descP, sockRef)) {
SSDBG( descP,
@@ -6362,13 +6513,6 @@ ERL_NIF_TERM esock_accept_accepting_current_accept(ErlNifEnv* env,
descP->state = ESOCK_STATE_LISTENING;
descP->currentAcceptorP = NULL;
- /* Do we really need this?
- * The activate_next_acceptor (actually the requestor_pop) function
- * initiates these values if there are no waiting acceptor...
- */
- descP->currentAcceptor.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentAcceptor.pid);
- MON_INIT(&descP->currentAcceptor.mon);
}
}
@@ -6390,10 +6534,8 @@ ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env,
ERL_NIF_TERM opRef,
int save_errno)
{
- ESockRequestor req;
ERL_NIF_TERM res, reason;
- req.env = NULL;
if (save_errno == ERRNO_BLOCK) {
/*
@@ -6405,16 +6547,25 @@ ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env,
"esock_accept_accepting_current_error -> "
"would block: try again\r\n") );
+ ESOCK_CNT_INC(env, descP, sockRef, atom_acc_waits, &descP->accWaits, 1);
+
res = esock_accept_busy_retry(env, descP, sockRef, opRef,
&descP->currentAcceptor.pid,
/* No state change */
descP->state);
} else {
+ ESockRequestor req;
+
+ ESOCK_CNT_INC(env, descP, sockRef, atom_acc_fails, &descP->accFails, 1);
+
+ esock_release_current("esock_accept_accepting_current_error",
+ env, descP, descP->currentAcceptorP);
reason = MKA(env, erl_errno_id(save_errno));
res = esock_make_error(env, reason);
+ req.env = NULL;
while (acceptor_pop(env, descP, &req)) {
SSDBG( descP,
("SOCKET",
@@ -6426,7 +6577,7 @@ ERL_NIF_TERM esock_accept_accepting_current_error(ErlNifEnv* env,
DEMONP("esock_accept_accepting_current_error -> pop'ed writer",
env, descP, &req.mon);
}
-
+ descP->currentAcceptorP = NULL;
}
return res;
@@ -6475,6 +6626,21 @@ ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env,
if ((sres = esock_select_read(env, descP->sock, descP, pid,
sockRef, accRef)) < 0) {
+
+ DEMONP("esock_accept_busy_retry - select failed",
+ env, descP, &descP->currentAcceptor.mon);
+ /* It is very unlikely that a next acceptor will be able
+ * to do anything succesful, but we will clean the queue
+ */
+ if (!activate_next_acceptor(env, descP, sockRef)) {
+ SSDBG( descP,
+ ("SOCKET",
+ "esock_accept_busy_retry -> no more acceptors\r\n") );
+
+ descP->state = ESOCK_STATE_LISTENING;
+ descP->currentAcceptorP = NULL;
+ }
+
reason = MKT2(env, esock_atom_select_failed, MKI(env, sres));
res = esock_make_error(env, reason);
} else {
@@ -6494,6 +6660,7 @@ ERL_NIF_TERM esock_accept_busy_retry(ErlNifEnv* env,
static
BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
SOCKET accSock,
ErlNifPid pid,
ESockAddress* remote,
@@ -6508,6 +6675,8 @@ BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
* We got one
*/
+ ESOCK_CNT_INC(env, descP, sockRef, atom_acc_success, &descP->accSuccess, 1);
+
if ((accEvent = sock_create_event(accSock)) == INVALID_EVENT) {
save_errno = sock_errno();
while ((sock_close(accSock) == INVALID_SOCKET) &&
@@ -6530,6 +6699,8 @@ BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
accDescP->rNumCnt = 0;
accDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size
accDescP->wCtrlSz = descP->wCtrlSz; // Inherit buffer size
+ accDescP->iow = descP->iow; // Inherit iow
+ accDescP->dbg = descP->dbg; // Inherit debug flag
accRef = enif_make_resource(env, accDescP);
enif_release_resource(accDescP);
@@ -6552,6 +6723,9 @@ BOOLEAN_T esock_accept_accepted(ErlNifEnv* env,
accDescP->isReadable = TRUE;
accDescP->isWritable = TRUE;
+ /* And finally update the registry */
+ esock_send_reg_add_msg(env, accRef);
+
*result = esock_make_ok2(env, accRef);
return TRUE;
@@ -6596,12 +6770,14 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env,
if ((argc != 4) ||
!GET_BIN(env, argv[2], &sndData) ||
!GET_UINT(env, argv[3], &eflags)) {
+ SGDBG( ("SOCKET", "nif_send -> argv decode failed\r\n") );
return enif_make_badarg(env);
}
sockRef = argv[0]; // We need this in case we send in case we send abort
sendRef = argv[1];
if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
+ SSDBG( descP, ("SOCKET", "nif_send -> get resource failed\r\n") );
return enif_make_badarg(env);
}
@@ -6613,8 +6789,10 @@ ERL_NIF_TERM nif_send(ErlNifEnv* env,
"\r\n eFlags: 0x%lX"
"\r\n", descP->sock, sockRef, sendRef, sndData.size, eflags) );
- if (!esendflags2sendflags(eflags, &flags))
+ if (!esendflags2sendflags(eflags, &flags)) {
+ SSDBG( descP, ("SOCKET", "nif_send -> sendflags decode failed\r\n") );
return esock_make_error(env, esock_atom_einval);
+ }
SSDBG( descP, ("SOCKET", "nif_send -> flags: 0x%lX\r\n", flags) );
@@ -6659,18 +6837,22 @@ ERL_NIF_TERM esock_send(ErlNifEnv* env,
ssize_t written;
ERL_NIF_TERM writerCheck;
- if (!descP->isWritable)
- return enif_make_badarg(env);
+ if (!descP->isWritable) {
+ SSDBG( descP, ("SOCKET", "esock_send -> return not writable\r\n") );
+ return esock_make_error(env, atom_closed);
+ }
- /* Check if there is already a current writer and if its us */
- if (!send_check_writer(env, descP, sendRef, &writerCheck))
+ /* Ensure that we either have no current writer or that we are it */
+ if (!send_check_writer(env, descP, sendRef, &writerCheck)) {
+ SSDBG( descP, ("SOCKET", "esock_send -> writer check failed: "
+ "\r\n %T\r\n", writerCheck) );
return writerCheck;
+ }
/* We ignore the wrap for the moment.
* Maybe we should issue a wrap-message to controlling process...
*/
- // cnt_inc(&descP->writeTries, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
written = sock_send(descP->sock, sndDataP->data, sndDataP->size, flags);
if (IS_SOCKET_ERROR(written))
@@ -6727,6 +6909,7 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
if ((argc != 5) ||
!GET_BIN(env, argv[2], &sndData) ||
!GET_UINT(env, argv[4], &eflags)) {
+ SGDBG( ("SOCKET", "nif_sendto -> argv decode failed\r\n") );
return enif_make_badarg(env);
}
sockRef = argv[0]; // We need this in case we send abort (to the caller)
@@ -6734,6 +6917,7 @@ ERL_NIF_TERM nif_sendto(ErlNifEnv* env,
eSockAddr = argv[3];
if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
+ SSDBG( descP, ("SOCKET", "nif_sendto -> get resource failed\r\n") );
return enif_make_badarg(env);
}
@@ -6792,18 +6976,22 @@ ERL_NIF_TERM esock_sendto(ErlNifEnv* env,
ssize_t written;
ERL_NIF_TERM writerCheck;
- if (!descP->isWritable)
- return enif_make_badarg(env);
+ if (!descP->isWritable) {
+ SSDBG( descP, ("SOCKET", "esock_sendto -> return not writable\r\n") );
+ return esock_make_error(env, atom_closed);
+ }
- /* Check if there is already a current writer and if its us */
- if (!send_check_writer(env, descP, sendRef, &writerCheck))
+ /* Ensure that we either have no current writer or we are it */
+ if (!send_check_writer(env, descP, sendRef, &writerCheck)) {
+ SSDBG( descP, ("SOCKET", "esock_sendto -> writer check failed: "
+ "\r\n %T\r\n", writerCheck) );
return writerCheck;
+ }
/* We ignore the wrap for the moment.
* Maybe we should issue a wrap-message to controlling process...
*/
- // cnt_inc(&descP->writeTries, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
if (toAddrP != NULL) {
written = sock_sendto(descP->sock,
@@ -6859,6 +7047,7 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env,
if ((argc != 4) ||
!IS_MAP(env, argv[2]) ||
!GET_UINT(env, argv[3], &eflags)) {
+ SGDBG( ("SOCKET", "nif_sendmsg -> argv decode failed\r\n") );
return enif_make_badarg(env);
}
sockRef = argv[0]; // We need this in case we send abort (to the caller)
@@ -6866,6 +7055,7 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env,
eMsgHdr = argv[2];
if (!ESOCK_GET_RESOURCE(env, sockRef, (void**) &descP)) {
+ SSDBG( descP, ("SOCKET", "nif_sendmsg -> get resource failed\r\n") );
return enif_make_badarg(env);
}
@@ -6877,8 +7067,10 @@ ERL_NIF_TERM nif_sendmsg(ErlNifEnv* env,
"\r\n",
descP->sock, argv[0], sendRef, eflags) );
- if (!esendflags2sendflags(eflags, &flags))
+ if (!esendflags2sendflags(eflags, &flags)) {
+ SSDBG( descP, ("SOCKET", "nif_sendmsg -> sendflags decode failed\r\n") );
return esock_make_error(env, esock_atom_einval);
+ }
MLOCK(descP->writeMtx);
@@ -6920,19 +7112,15 @@ ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env,
char* xres;
if (!descP->isWritable) {
-
SSDBG( descP, ("SOCKET", "esock_sendmsg -> not writable\r\n") );
-
- return enif_make_badarg(env);
+ return esock_make_error(env, atom_closed);
}
- /* Check if there is already a current writer and if its us */
+ /* Ensure that we either have no current writer or we are it */
if (!send_check_writer(env, descP, sendRef, &writerCheck)) {
-
- SSDBG( descP,
- ("SOCKET", "esock_sendmsg -> writer check failed: "
- "\r\n %T\r\n", writerCheck) );
-
+ SSDBG( descP,
+ ("SOCKET", "esock_sendmsg -> writer check failed: "
+ "\r\n %T\r\n", writerCheck) );
return writerCheck;
}
@@ -7044,8 +7232,7 @@ ERL_NIF_TERM esock_sendmsg(ErlNifEnv* env,
/* We ignore the wrap for the moment.
* Maybe we should issue a wrap-message to controlling process...
*/
- // cnt_inc(&descP->writeTries, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_write_tries, &descP->writeTries, 1);
/* And now, finally, try to send the message */
written = sock_sendmsg(descP->sock, &msgHdr, flags);
@@ -7164,16 +7351,20 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env,
#else
ESockDescriptor* descP;
ERL_NIF_TERM sockRef, recvRef;
- int len;
+ ErlNifUInt64 elen;
unsigned int eflags;
+ ssize_t len; /* ssize_t due to the return type of recv() */
int flags;
ERL_NIF_TERM res;
if ((argc != 4) ||
- !GET_INT(env, argv[2], &len) ||
+ !GET_UINT64(env, argv[2], &elen) ||
!GET_UINT(env, argv[3], &eflags)) {
return enif_make_badarg(env);
}
+ len = (ssize_t) elen;
+ if (elen != (ErlNifUInt64)len) return enif_make_badarg(env);
+
sockRef = argv[0]; // We need this in case we send abort (to the caller)
recvRef = argv[1];
@@ -7184,7 +7375,8 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env,
if (!erecvflags2recvflags(eflags, &flags))
return esock_make_error(env, esock_atom_einval);
- SSDBG( descP, ("SOCKET", "nif_recv -> flags: 0x%lX\r\n", flags) );
+ SSDBG( descP, ("SOCKET", "nif_recv -> flags: 0x%lX\r\n",
+ (unsigned)flags) );
MLOCK(descP->readMtx);
@@ -7196,10 +7388,12 @@ ERL_NIF_TERM nif_recv(ErlNifEnv* env,
* is done!
*/
- res = esock_recv(env, descP, sockRef, recvRef, len, flags);
+ res = esock_recv(env, descP, sockRef, recvRef, (size_t)len, flags);
MUNLOCK(descP->readMtx);
+ SSDBG( descP, ("SOCKET", "nif_recv -> done: %T\r\n", res) );
+
return res;
#endif // if defined(__WIN32__)
@@ -7217,24 +7411,26 @@ ERL_NIF_TERM esock_recv(ErlNifEnv* env,
ESockDescriptor* descP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef,
- int len,
+ size_t len,
int flags)
{
ssize_t read;
ErlNifBinary buf;
ERL_NIF_TERM readerCheck;
int save_errno;
- int bufSz = (len ? len : descP->rBufSz);
+ size_t bufSz = (len ? len : descP->rBufSz);
SSDBG( descP, ("SOCKET", "esock_recv -> entry with"
- "\r\n len: %d (%d:%d)"
+ "\r\n len: %lu (%d:lu)"
"\r\n flags: %d"
- "\r\n", len, descP->rNumCnt, bufSz, flags) );
+ "\r\n",
+ (unsigned long)len, descP->rNumCnt, (unsigned long)bufSz,
+ flags) );
if (!descP->isReadable)
- return enif_make_badarg(env);
+ return esock_make_error(env, atom_closed);
- /* Check if there is already a current reader and if its us */
+ /* Ensure that we either have no current reader or that we are it */
if (!recv_check_reader(env, descP, recvRef, &readerCheck))
return readerCheck;
@@ -7245,11 +7441,11 @@ ERL_NIF_TERM esock_recv(ErlNifEnv* env,
if (!ALLOC_BIN(bufSz, &buf))
return esock_make_error(env, atom_exalloc);
- // cnt_inc(&descP->readTries, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
// If it fails (read = -1), we need errno...
- SSDBG( descP, ("SOCKET", "esock_recv -> try read (%d)\r\n", buf.size) );
+ SSDBG( descP, ("SOCKET", "esock_recv -> try read (%lu)\r\n",
+ (unsigned long)buf.size) );
read = sock_recv(descP->sock, buf.data, buf.size, flags);
if (IS_SOCKET_ERROR(read)) {
save_errno = sock_errno();
@@ -7258,7 +7454,8 @@ ERL_NIF_TERM esock_recv(ErlNifEnv* env,
}
SSDBG( descP, ("SOCKET",
- "esock_recv -> read: %d (%d)\r\n", read, save_errno) );
+ "esock_recv -> read: %ld (%d)\r\n",
+ (long)read, save_errno) );
return recv_check_result(env, descP,
read, len,
@@ -7396,9 +7593,9 @@ ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
"\r\n", len, bufSz, flags) );
if (!descP->isReadable)
- return enif_make_badarg(env);
+ return esock_make_error(env, atom_closed);
- /* Check if there is already a current reader and if its us */
+ /* Ensure that we either have no current reader or that we are it */
if (!recv_check_reader(env, descP, recvRef, &readerCheck))
return readerCheck;
@@ -7409,8 +7606,7 @@ ERL_NIF_TERM esock_recvfrom(ErlNifEnv* env,
if (!ALLOC_BIN(bufSz, &buf))
return esock_make_error(env, atom_exalloc);
- // cnt_inc(&descP->readTries, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
addrLen = sizeof(fromAddr);
sys_memzero((char*) &fromAddr, addrLen);
@@ -7572,9 +7768,9 @@ ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env,
"\r\n", bufSz, bufLen, ctrlSz, ctrlLen, flags) );
if (!descP->isReadable)
- return enif_make_badarg(env);
+ return esock_make_error(env, atom_closed);
- /* Check if there is already a current reader and if its us */
+ /* Ensure that we either have no current reader or that we are it */
if (!recv_check_reader(env, descP, recvRef, &readerCheck))
return readerCheck;
@@ -7597,8 +7793,7 @@ ERL_NIF_TERM esock_recvmsg(ErlNifEnv* env,
if (!ALLOC_BIN(ctrlSz, &ctrl))
return esock_make_error(env, atom_exalloc);
- // cnt_inc(&descP->readTries, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_tries, &descP->readTries, 1);
addrLen = sizeof(addr);
sys_memzero((char*) &addr, addrLen);
@@ -7652,6 +7847,9 @@ ERL_NIF_TERM nif_close(ErlNifEnv* env,
return enif_raise_exception(env, MKA(env, "notsup"));
#else
ESockDescriptor* descP;
+ ERL_NIF_TERM res;
+
+ SGDBG( ("SOCKET", "nif_close -> entry with argc: %d\r\n", argc) );
if ((argc != 1) ||
!ESOCK_GET_RESOURCE(env, argv[0], (void**) &descP)) {
@@ -7661,7 +7859,15 @@ ERL_NIF_TERM nif_close(ErlNifEnv* env,
if (IS_CLOSED(descP) || IS_CLOSING(descP))
return esock_make_error(env, atom_closed);
- return esock_close(env, descP);
+ MLOCK(descP->closeMtx);
+
+ res = esock_close(env, descP);
+
+ MUNLOCK(descP->closeMtx);
+
+ SSDBG( descP, ("SOCKET", "nif_close -> res: %T\r\n", res) );
+
+ return res;
#endif // if defined(__WIN32__)
}
@@ -7682,8 +7888,6 @@ ERL_NIF_TERM esock_close(ErlNifEnv* env,
descP->currentReaderP,
descP->currentAcceptorP) );
- MLOCK(descP->closeMtx);
-
doClose = esock_close_check(env, descP, &reason);
if (doClose) {
@@ -7692,8 +7896,6 @@ ERL_NIF_TERM esock_close(ErlNifEnv* env,
reply = esock_make_error(env, reason);
}
- MUNLOCK(descP->closeMtx);
-
SSDBG( descP,
("SOCKET", "esock_close -> [%d] done when: "
"\r\n state: 0x%lX"
@@ -7962,13 +8164,14 @@ ERL_NIF_TERM nif_shutdown(ErlNifEnv* env,
return enif_make_badarg(env);
}
- if (IS_CLOSED(descP) || IS_CLOSING(descP))
+ if (IS_CLOSED(descP))
return esock_make_error(env, atom_closed);
if (!ehow2how(ehow, &how))
return enif_make_badarg(env);
return esock_shutdown(env, descP, how);
+
#endif // if defined(__WIN32__)
}
@@ -8167,6 +8370,10 @@ ERL_NIF_TERM esock_setopt_otp(ErlNifEnv* env,
result = esock_setopt_otp_sndctrlbuf(env, descP, eVal);
break;
+ case ESOCK_OPT_OTP_META:
+ result = esock_setopt_otp_meta(env, descP, eVal);
+ break;
+
default:
result = esock_make_error(env, esock_atom_einval);
break;
@@ -8365,6 +8572,32 @@ ERL_NIF_TERM esock_setopt_otp_sndctrlbuf(ErlNifEnv* env,
}
+/* esock_setopt_otp_meta - Handle the OTP (level) meta options
+ */
+static
+ERL_NIF_TERM esock_setopt_otp_meta(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM eVal)
+{
+ ErlNifPid caller;
+
+ if (enif_self(env, &caller) == NULL)
+ return esock_make_error(env, atom_exself);
+
+ if (COMPARE_PIDS(&descP->ctrlPid, &caller) != 0) {
+ SSDBG( descP, ("SOCKET",
+ "esock_setopt_otp_meta -> not owner (%T)\r\n",
+ descP->ctrlPid) );
+ return esock_make_error(env, esock_atom_not_owner);
+ }
+
+ enif_clear_env(descP->meta.env);
+ descP->meta.ref = CP_TERM(descP->meta.env, eVal);
+
+ return esock_atom_ok;
+}
+
+
/* The option has *not* been encoded. Instead it has been provided
* in "native mode" (option is provided as is and value as a binary).
@@ -11727,7 +11960,7 @@ ERL_NIF_TERM nif_getopt(ErlNifEnv* env,
eIsEncoded = argv[1];
eOpt = argv[3]; // Is "normally" an int, but if raw mode: {Int, ValueSz}
- if (IS_CLOSED(descP) || IS_CLOSING(descP))
+ if (IS_CLOSED(descP))
return esock_make_error(env, atom_closed);
SSDBG( descP,
@@ -11846,6 +12079,10 @@ ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env,
result = esock_getopt_otp_fd(env, descP);
break;
+ case ESOCK_OPT_OTP_META:
+ result = esock_getopt_otp_meta(env, descP);
+ break;
+
/* *** INTERNAL *** */
case ESOCK_OPT_OTP_DOMAIN:
result = esock_getopt_otp_domain(env, descP);
@@ -11859,6 +12096,10 @@ ERL_NIF_TERM esock_getopt_otp(ErlNifEnv* env,
result = esock_getopt_otp_protocol(env, descP);
break;
+ case ESOCK_OPT_OTP_DTP:
+ result = esock_getopt_otp_dtp(env, descP);
+ break;
+
default:
result = esock_make_error(env, esock_atom_einval);
break;
@@ -11964,128 +12205,187 @@ ERL_NIF_TERM esock_getopt_otp_fd(ErlNifEnv* env,
}
-/* esock_getopt_otp_domain - Handle the OTP (level) domain option
+/* esock_getopt_otp_meta - Handle the OTP (level) meta option
*/
static
-ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM esock_getopt_otp_meta(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- ERL_NIF_TERM result, reason;
- int val = descP->domain;
+ ERL_NIF_TERM eVal = CP_TERM(env, descP->meta.ref);
- switch (val) {
+ return esock_make_ok2(env, eVal);
+}
+
+
+static
+ERL_NIF_TERM getopt_otp_domain(ErlNifEnv* env, int domain)
+{
+ ERL_NIF_TERM result;
+
+ switch (domain) {
case AF_INET:
- result = esock_make_ok2(env, esock_atom_inet);
+ result = esock_atom_inet;
break;
#if defined(HAVE_IN6) && defined(AF_INET6)
case AF_INET6:
- result = esock_make_ok2(env, esock_atom_inet6);
+ result = esock_atom_inet6;
break;
#endif
#if defined(HAVE_SYS_UN_H)
case AF_UNIX:
- result = esock_make_ok2(env, esock_atom_local);
+ result = esock_atom_local;
break;
#endif
default:
- reason = MKT2(env, esock_atom_unknown, MKI(env, val));
- result = esock_make_error(env, reason);
+ result = MKI(env, domain);
break;
}
return result;
}
+/*
+ * esock_getopt_otp_domain - Handle the OTP (level) domain option
+ */
+static
+ERL_NIF_TERM esock_getopt_otp_domain(ErlNifEnv* env,
+ ESockDescriptor* descP)
+{
+ ERL_NIF_TERM domain, result;
+
+ domain = getopt_otp_domain(env, descP->domain);
+ result = esock_make_ok2(env, domain);
+
+ return result;
+}
-/* esock_getopt_otp_type - Handle the OTP (level) type options.
- */
static
-ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM getopt_otp_type(ErlNifEnv* env, int type)
{
- ERL_NIF_TERM result, reason;
- int val = descP->type;
+ ERL_NIF_TERM result;
- switch (val) {
+ switch (type) {
case SOCK_STREAM:
- result = esock_make_ok2(env, esock_atom_stream);
+ result = esock_atom_stream;
break;
case SOCK_DGRAM:
- result = esock_make_ok2(env, esock_atom_dgram);
+ result = esock_atom_dgram;
break;
#ifdef HAVE_SCTP
case SOCK_SEQPACKET:
- result = esock_make_ok2(env, esock_atom_seqpacket);
+ result = esock_atom_seqpacket;
break;
#endif
case SOCK_RAW:
- result = esock_make_ok2(env, esock_atom_raw);
+ result = esock_atom_raw;
break;
case SOCK_RDM:
- result = esock_make_ok2(env, esock_atom_rdm);
+ result = esock_atom_rdm;
break;
default:
- reason = MKT2(env, esock_atom_unknown, MKI(env, val));
- result = esock_make_error(env, reason);
+ result = MKI(env, type);
break;
}
return result;
}
+/*
+ * esock_getopt_otp_type - Handle the OTP (level) type options.
+ */
+static
+ERL_NIF_TERM esock_getopt_otp_type(ErlNifEnv* env,
+ ESockDescriptor* descP)
+{
+ ERL_NIF_TERM type, result;
+
+ type = getopt_otp_type(env, descP->type);
+ result = esock_make_ok2(env, type);
+
+ return result;
+}
-/* esock_getopt_otp_protocol - Handle the OTP (level) protocol options.
- */
static
-ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env,
- ESockDescriptor* descP)
+ERL_NIF_TERM getopt_otp_protocol(ErlNifEnv* env,
+ ESockDescriptor* descP)
{
- ERL_NIF_TERM result, reason;
+ ERL_NIF_TERM result;
int val = descP->protocol;
- switch (val) {
- case IPPROTO_IP:
+ switch (val) {
+ case IPPROTO_IP:
#if defined(AF_LOCAL)
- if (descP->domain == AF_LOCAL) {
- result = esock_make_ok2(env, esock_atom_default);
- } else {
- result = esock_make_ok2(env, esock_atom_ip);
- }
+ if (descP->domain == AF_LOCAL) {
+ result = esock_atom_default;
+ } else {
+ result = esock_atom_ip;
+ }
#else
- result = esock_make_ok2(env, esock_atom_ip);
+ result = esock_atom_ip;
#endif
- break;
+ break;
- case IPPROTO_TCP:
- result = esock_make_ok2(env, esock_atom_tcp);
- break;
+ case IPPROTO_TCP:
+ result = esock_atom_tcp;
+ break;
- case IPPROTO_UDP:
- result = esock_make_ok2(env, esock_atom_udp);
- break;
+ case IPPROTO_UDP:
+ result = esock_atom_udp;
+ break;
#if defined(HAVE_SCTP)
- case IPPROTO_SCTP:
- result = esock_make_ok2(env, esock_atom_sctp);
- break;
+ case IPPROTO_SCTP:
+ result = esock_atom_sctp;
+ break;
#endif
- default:
- reason = MKT2(env, esock_atom_unknown, MKI(env, val));
- result = esock_make_error(env, reason);
- break;
+ default:
+ result = MKI(env, val);
+ break;
}
return result;
}
+/*
+ * esock_getopt_otp_protocol - Handle the OTP (level) protocol options.
+ */
+static
+ERL_NIF_TERM esock_getopt_otp_protocol(ErlNifEnv* env,
+ ESockDescriptor* descP)
+{
+ ERL_NIF_TERM protocol, result;
+ protocol = getopt_otp_protocol(env, descP);
+ result = esock_make_ok2(env, protocol);
+
+ return result;
+}
+
+
+/*
+ * esock_getopt_otp_dtp - Handle the OTP (level) type options.
+ */
+static
+ERL_NIF_TERM esock_getopt_otp_dtp(ErlNifEnv* env,
+ ESockDescriptor* descP)
+{
+ ERL_NIF_TERM domain, type, protocol, dtp, result;
+
+ domain = getopt_otp_domain(env, descP->domain);
+ type = getopt_otp_type(env, descP->type);
+ protocol = getopt_otp_protocol(env, descP);
+ dtp = MKT3(env, domain, type, protocol);
+ result = esock_make_ok2(env, dtp);
+
+ return result;
+}
/* The option has *not* been encoded. Instead it has been provided
@@ -14882,12 +15182,6 @@ ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env,
SSDBG( descP, ("SOCKET",
"esock_cancel_accept_current -> cancel res: %T\r\n", res) );
- /* Clean out the old cobweb's before trying to invite a new spider */
-
- esock_free_env("esock_cancel_accept_current - current-accept-env",
- descP->currentAcceptor.env);
- descP->currentAcceptor.env = NULL;
-
if (!activate_next_acceptor(env, descP, sockRef)) {
SSDBG( descP,
@@ -14897,13 +15191,6 @@ ERL_NIF_TERM esock_cancel_accept_current(ErlNifEnv* env,
descP->state = ESOCK_STATE_LISTENING;
descP->currentAcceptorP = NULL;
- /* Do we really need this?
- * The activate_next_acceptor (actually the requestor_pop) function
- * initiates these values if there are no waiting acceptor...
- */
- descP->currentAcceptor.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentAcceptor.pid);
- MON_INIT(&descP->currentAcceptor.mon);
}
SSDBG( descP, ("SOCKET", "esock_cancel_accept_current -> done with result:"
@@ -15007,10 +15294,8 @@ ERL_NIF_TERM esock_cancel_send_current(ErlNifEnv* env,
if (!activate_next_writer(env, descP, sockRef)) {
SSDBG( descP,
("SOCKET", "esock_cancel_send_current -> no more writers\r\n") );
- descP->currentWriterP = NULL;
- descP->currentWriter.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentWriter.pid);
- esock_monitor_init(&descP->currentWriter.mon);
+
+ descP->currentWriterP = NULL;
}
SSDBG( descP, ("SOCKET", "esock_cancel_send_current -> done with result:"
@@ -15113,10 +15398,8 @@ ERL_NIF_TERM esock_cancel_recv_current(ErlNifEnv* env,
if (!activate_next_reader(env, descP, sockRef)) {
SSDBG( descP,
("SOCKET", "esock_cancel_recv_current -> no more readers\r\n") );
- descP->currentReaderP = NULL;
- descP->currentReader.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentReader.pid);
- esock_monitor_init(&descP->currentReader.mon);
+
+ descP->currentReaderP = NULL;
}
SSDBG( descP, ("SOCKET", "esock_cancel_recv_current -> done with result:"
@@ -15181,14 +15464,19 @@ ERL_NIF_TERM esock_cancel_mode_select(ErlNifEnv* env,
int smode,
int rmode)
{
+ /* Assumes cancelling only one mode */
+
int selectRes = esock_select_cancel(env, descP->sock, smode, descP);
- if (selectRes & rmode) {
- /* Was cancelled */
- return esock_atom_ok;
- } else if (selectRes > 0) {
- /* Has already sent the message */
- return esock_make_error(env, esock_atom_select_sent);
+ if (selectRes >= 0) {
+ /* Success */
+ if ((selectRes & rmode) != 0) {
+ /* Was cancelled */
+ return esock_atom_ok;
+ } else {
+ /* Has already sent the message */
+ return esock_make_error(env, esock_atom_select_sent);
+ }
} else {
/* Stopped? */
SSDBG( descP, ("SOCKET",
@@ -15226,6 +15514,8 @@ BOOLEAN_T send_check_writer(ErlNifEnv* env,
if (enif_self(env, &caller) == NULL) {
*checkResult = esock_make_error(env, atom_exself);
+ SSDBG( descP, ("SOCKET",
+ "send_check_writer -> exself\r\n") );
return FALSE;
}
@@ -15239,12 +15529,12 @@ BOOLEAN_T send_check_writer(ErlNifEnv* env,
if (!writer_search4pid(env, descP, &caller))
*checkResult = writer_push(env, descP, caller, ref);
else
- *checkResult = esock_make_error(env, esock_atom_eagain);
+ *checkResult = esock_make_error(env, atom_exbusy);
SSDBG( descP,
("SOCKET",
"send_check_writer -> queue (push) result: %T\r\n",
- checkResult) );
+ *checkResult) );
return FALSE;
@@ -15344,35 +15634,32 @@ ERL_NIF_TERM send_check_ok(ErlNifEnv* env,
ssize_t dataSize,
ERL_NIF_TERM sockRef)
{
- // cnt_inc(&descP->writePkgCnt, 1);
- SOCK_CNT_INC(env, descP, sockRef,
- atom_write_pkg, &descP->writePkgCnt, 1);
- // cnt_inc(&descP->writeByteCnt, written);
- SOCK_CNT_INC(env, descP, sockRef,
- atom_write_byte, &descP->writeByteCnt, written);
-
- if (descP->currentWriterP != NULL) {
- DEMONP("send_check_ok -> current writer",
- env, descP, &descP->currentWriter.mon);
- esock_free_env("send_check_ok", descP->currentWriter.env);
- descP->currentWriter.env = NULL;
- }
+ ESOCK_CNT_INC(env, descP, sockRef,
+ atom_write_pkg, &descP->writePkgCnt, 1);
+ ESOCK_CNT_INC(env, descP, sockRef,
+ atom_write_byte, &descP->writeByteCnt, written);
+ descP->writePkgMaxCnt += written;
+ if (descP->writePkgMaxCnt > descP->writePkgMax)
+ descP->writePkgMax = descP->writePkgMaxCnt;
+ descP->writePkgMaxCnt = 0;
SSDBG( descP,
("SOCKET", "send_check_ok -> "
"everything written (%d,%d) - done\r\n", dataSize, written) );
+ if (descP->currentWriterP != NULL) {
+ DEMONP("send_check_ok -> current writer",
+ env, descP, &descP->currentWriter.mon);
+ }
/*
* Ok, this write is done maybe activate the next (if any)
*/
-
if (!activate_next_writer(env, descP, sockRef)) {
- descP->currentWriterP = NULL;
- ESOCK_ASSERT(!descP->currentWriter.env);
- descP->currentWriter.env = NULL;
- descP->currentWriter.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentWriter.pid);
- esock_monitor_init(&descP->currentWriter.mon);
+
+ SSDBG( descP,
+ ("SOCKET", "send_check_ok -> no more writers\r\n") );
+
+ descP->currentWriterP = NULL;
}
return esock_atom_ok;
@@ -15391,12 +15678,9 @@ ERL_NIF_TERM send_check_fail(ErlNifEnv* env,
int saveErrno,
ERL_NIF_TERM sockRef)
{
- ESockRequestor req;
- ERL_NIF_TERM reason;
+ ERL_NIF_TERM reason;
- req.env = NULL;
- // cnt_inc(&descP->writeFails, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_write_fails, &descP->writeFails, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_write_fails, &descP->writeFails, 1);
SSDBG( descP, ("SOCKET", "send_check_fail -> error: %d\r\n", saveErrno) );
@@ -15411,24 +15695,44 @@ ERL_NIF_TERM send_check_fail(ErlNifEnv* env,
if (descP->currentWriterP != NULL) {
- DEMONP("send_check_fail -> current writer",
- env, descP, &descP->currentWriter.mon);
+ esock_release_current("send_check_fail",
+ env, descP, descP->currentWriterP);
- while (writer_pop(env, descP, &req)) {
- SSDBG( descP,
- ("SOCKET", "send_check_fail -> abort %T\r\n", req.pid) );
- esock_send_abort_msg(env, sockRef, req.ref, req.env,
- reason, &req.pid);
- req.env = NULL;
- DEMONP("send_check_fail -> pop'ed writer",
- env, descP, &req.mon);
- }
+ send_error_waiting_writers(env, descP, sockRef, reason);
+
+ descP->currentWriterP = NULL;
}
}
-
return esock_make_error(env, reason);
}
+/* *** send_error_current_writer ***
+ *
+ * Process all waiting writers when a fatal error has occured.
+ * All waiting writers will be "aborted", that is a
+ * nif_abort message will be sent (with ref and reason).
+ */
+static
+void send_error_waiting_writers(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM reason)
+{
+ ESockRequestor req;
+
+ req.env = NULL; /* read by writer_pop before free */
+ while (writer_pop(env, descP, &req)) {
+ SSDBG( descP,
+ ("SOCKET", "send_error_current_writer -> abort %T\r\n",
+ req.pid) );
+ esock_send_abort_msg(env, sockRef, req.ref, req.env,
+ reason, &req.pid);
+ req.env = NULL;
+ DEMONP("send_error_waiting_writers -> pop'ed writer",
+ env, descP, &req.mon);
+ }
+}
+
/* *** send_check_retry ***
@@ -15463,15 +15767,17 @@ ERL_NIF_TERM send_check_retry(ErlNifEnv* env,
enif_set_pid_undefined(&descP->currentWriter.pid);
return esock_make_error(env, atom_exmon);
} else {
- ESOCK_ASSERT(!descP->currentWriter.env);
+ ESOCK_ASSERT(descP->currentWriter.env == NULL);
descP->currentWriter.env = esock_alloc_env("current-writer");
- descP->currentWriter.ref = CP_TERM(descP->currentWriter.env, sendRef);
+ descP->currentWriter.ref =
+ CP_TERM(descP->currentWriter.env, sendRef);
descP->currentWriterP = &descP->currentWriter;
}
+ } else {
+ descP->currentWriter.ref = CP_TERM(descP->currentWriter.env, sendRef);
}
- // cnt_inc(&descP->writeWaits, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_write_waits, &descP->writeWaits, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_write_waits, &descP->writeWaits, 1);
sres = esock_select_write(env, descP->sock, descP, NULL, sockRef, sendRef);
@@ -15479,10 +15785,17 @@ ERL_NIF_TERM send_check_retry(ErlNifEnv* env,
/* Partial *write* success */
+ descP->writePkgMaxCnt += written;
+
if (sres < 0) {
/* Returned: {error, Reason}
* Reason: {select_failed, sres, written}
*/
+
+ if (descP->writePkgMaxCnt > descP->writePkgMax)
+ descP->writePkgMax = descP->writePkgMaxCnt;
+ descP->writePkgMaxCnt = 0;
+
res = esock_make_error(env,
MKT3(env,
esock_atom_select_failed,
@@ -15537,8 +15850,6 @@ BOOLEAN_T recv_check_reader(ErlNifEnv* env,
}
if (COMPARE_PIDS(&descP->currentReader.pid, &caller) != 0) {
- ERL_NIF_TERM tmp;
-
/* Not the "current reader", so (maybe) push onto queue */
SSDBG( descP,
@@ -15546,15 +15857,14 @@ BOOLEAN_T recv_check_reader(ErlNifEnv* env,
"recv_check_reader -> not (current) reader\r\n") );
if (!reader_search4pid(env, descP, &caller))
- tmp = reader_push(env, descP, caller, ref);
+ *checkResult = reader_push(env, descP, caller, ref);
else
- tmp = esock_make_error(env, esock_atom_eagain);
+ *checkResult = esock_make_error(env, atom_exbusy);
SSDBG( descP,
("SOCKET",
- "recv_check_reader -> queue (push) result: %T\r\n", tmp) );
-
- *checkResult = tmp;
+ "recv_check_reader -> queue (push) result: %T\r\n",
+ *checkResult) );
return FALSE;
@@ -15637,20 +15947,13 @@ ERL_NIF_TERM recv_update_current_reader(ErlNifEnv* env,
DEMONP("recv_update_current_reader",
env, descP, &descP->currentReader.mon);
- esock_free_env("recv_update_current_reader - current-read-env",
- descP->currentReader.env);
- descP->currentReader.env = NULL;
-
if (!activate_next_reader(env, descP, sockRef)) {
SSDBG( descP,
("SOCKET",
"recv_update_current_reader -> no more readers\r\n") );
- descP->currentReaderP = NULL;
- descP->currentReader.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentReader.pid);
- esock_monitor_init(&descP->currentReader.mon);
+ descP->currentReaderP = NULL;
}
}
@@ -15665,7 +15968,7 @@ ERL_NIF_TERM recv_update_current_reader(ErlNifEnv* env,
* Process the current reader and any waiting readers
* when a read (fatal) error has occured.
* All waiting readers will be "aborted", that is a
- * nif_abort message will be sent (with reaf and reason).
+ * nif_abort message will be sent (with ref and reason).
*/
static
void recv_error_current_reader(ErlNifEnv* env,
@@ -15673,14 +15976,13 @@ void recv_error_current_reader(ErlNifEnv* env,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM reason)
{
- ESockRequestor req;
-
- req.env = NULL;
if (descP->currentReaderP != NULL) {
+ ESockRequestor req;
- DEMONP("recv_error_current_reader -> current reader",
- env, descP, &descP->currentReader.mon);
+ esock_release_current("recv_error_current_reader",
+ env, descP, descP->currentReaderP);
+ req.env = NULL; /* read by reader_pop before free */
while (reader_pop(env, descP, &req)) {
SSDBG( descP,
("SOCKET", "recv_error_current_reader -> abort %T\r\n",
@@ -15691,6 +15993,8 @@ void recv_error_current_reader(ErlNifEnv* env,
DEMONP("recv_error_current_reader -> pop'ed reader",
env, descP, &req.mon);
}
+
+ descP->currentReaderP = NULL;
}
}
@@ -15703,8 +16007,8 @@ void recv_error_current_reader(ErlNifEnv* env,
static
ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
- int toRead,
+ ssize_t read,
+ size_t toRead,
int saveErrno,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
@@ -15714,11 +16018,12 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
SSDBG( descP,
("SOCKET", "recv_check_result -> entry with"
- "\r\n read: %d"
- "\r\n toRead: %d"
+ "\r\n read: %ld"
+ "\r\n toRead: %lu"
"\r\n saveErrno: %d"
"\r\n recvRef: %T"
- "\r\n", read, toRead, saveErrno, recvRef) );
+ "\r\n",
+ (long)read, (unsigned long)toRead, saveErrno, recvRef) );
/* <KOLLA>
@@ -15730,10 +16035,10 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
*/
if ((read == 0) && (descP->type == SOCK_STREAM)) {
-
- res = esock_make_error(env, atom_closed);
+ ERL_NIF_TERM reason = atom_closed;
+ res = esock_make_error(env, reason);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
/*
* When a stream socket peer has performed an orderly shutdown,
@@ -15744,7 +16049,7 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
* We must also notify any waiting readers!
*/
- recv_error_current_reader(env, descP, sockRef, res);
+ recv_error_current_reader(env, descP, sockRef, reason);
FREE_BIN(bufP);
@@ -15752,7 +16057,7 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
/* There is a special case: If the provided 'to read' value is
* zero (0) (only for type =/= stream).
- * That means that we reads as much as we can, using the default
+ * That means that we read as much as we can, using the default
* read buffer size.
*/
@@ -15762,8 +16067,8 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "recv_check_result -> [%d] filled the buffer\r\n",
- toRead) );
+ "recv_check_result -> [%lu] filled the buffer\r\n",
+ (unsigned long)toRead) );
res = recv_check_full(env, descP, read, toRead, bufP,
sockRef, recvRef);
@@ -15781,9 +16086,10 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "recv_check_result -> [%d] "
- "did not fill the buffer (%d of %d)\r\n",
- toRead, read, bufP->size) );
+ "recv_check_result -> [%lu] "
+ "did not fill the buffer (%ld of %lu)\r\n",
+ (unsigned long)toRead,
+ (long)read, (unsigned long)bufP->size) );
res = recv_check_partial(env, descP, read, toRead, bufP,
sockRef, recvRef);
@@ -15807,8 +16113,8 @@ ERL_NIF_TERM recv_check_result(ErlNifEnv* env,
static
ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
- int toRead,
+ ssize_t read,
+ size_t toRead,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef)
@@ -15832,10 +16138,10 @@ ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
SSDBG( descP,
("SOCKET", "recv_check_full -> shall we continue reading"
- "\r\n read: %d"
- "\r\n rNum: %d"
- "\r\n rNumCnt: %d"
- "\r\n", read, descP->rNum, descP->rNumCnt) );
+ "\r\n read: %ld"
+ "\r\n rNum: %u"
+ "\r\n rNumCnt: %u"
+ "\r\n", (unsigned long)read, descP->rNum, descP->rNumCnt) );
res = recv_check_full_maybe_done(env, descP, read, toRead, bufP,
sockRef, recvRef);
@@ -15846,8 +16152,9 @@ ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "recv_check_full -> [%d] "
- "we got exactly what we could fit\r\n", toRead) );
+ "recv_check_full -> [%lu] "
+ "we got exactly what we could fit\r\n",
+ (unsigned long)toRead) );
res = recv_check_full_done(env, descP, read, bufP, sockRef);
@@ -15873,42 +16180,47 @@ ERL_NIF_TERM recv_check_full(ErlNifEnv* env,
static
ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
- int toRead,
+ ssize_t read,
+ size_t toRead,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef)
{
char* xres;
- // cnt_inc(&descP->readByteCnt, read);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
-
- if (descP->rNum > 0) {
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
+ descP->readPkgMaxCnt += read;
- descP->rNumCnt++;
- if (descP->rNumCnt >= descP->rNum) {
+ descP->rNumCnt++;
+ if (descP->rNumCnt >= descP->rNum) {
- descP->rNumCnt = 0;
+ descP->rNumCnt = 0;
- // cnt_inc(&descP->readPkgCnt, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ ESOCK_CNT_INC(env, descP, sockRef,
+ atom_read_pkg, &descP->readPkgCnt, 1);
+ if (descP->readPkgMaxCnt > descP->readPkgMax)
+ descP->readPkgMax = descP->readPkgMaxCnt;
+ descP->readPkgMaxCnt = 0;
- recv_update_current_reader(env, descP, sockRef);
+ recv_update_current_reader(env, descP, sockRef);
- /* This transfers "ownership" of the *allocated* binary to an
- * erlang term (no need for an explicit free).
- */
+ /* This transfers "ownership" of the *allocated* binary to an
+ * erlang term (no need for an explicit free).
+ */
- return esock_make_ok3(env, atom_true, MKBIN(env, bufP));
+ return esock_make_ok3(env, atom_true, MKBIN(env, bufP));
- }
}
/* Yes, we *do* need to continue reading */
if ((xres = recv_init_current_reader(env, descP, recvRef)) != NULL) {
descP->rNumCnt = 0;
+
+ if (descP->readPkgMaxCnt > descP->readPkgMax)
+ descP->readPkgMax = descP->readPkgMaxCnt;
+ descP->readPkgMaxCnt = 0;
+
FREE_BIN(bufP);
return esock_make_error_str(env, xres);
}
@@ -15919,8 +16231,8 @@ ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "recv_check_full_maybe_done -> [%d] "
- "we are done for now - read more\r\n", toRead) );
+ "recv_check_full_maybe_done -> [%lu] "
+ "we are done for now - read more\r\n", (unsigned long)toRead) );
return esock_make_ok3(env, atom_false, MKBIN(env, bufP));
}
@@ -15934,16 +16246,20 @@ ERL_NIF_TERM recv_check_full_maybe_done(ErlNifEnv* env,
static
ERL_NIF_TERM recv_check_full_done(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
+ ssize_t read,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef)
{
ERL_NIF_TERM data;
- // cnt_inc(&descP->readPkgCnt, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
- // cnt_inc(&descP->readByteCnt, read);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ &descP->readByteCnt, read);
+
+ descP->readPkgMaxCnt += read;
+ if (descP->readPkgMaxCnt > descP->readPkgMax)
+ descP->readPkgMax = descP->readPkgMaxCnt;
+ descP->readPkgMaxCnt = 0;
recv_update_current_reader(env, descP, sockRef);
@@ -15978,13 +16294,13 @@ ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
/* +++ Oups - closed +++ */
- SSDBG( descP, ("SOCKET", "recv_check_fail -> closed\r\n") );
+ SSDBG( descP, ("SOCKET", "recv_check_fail econnreset -> closed\r\n") );
// This is a bit overkill (to count here), but just in case...
- // cnt_inc(&descP->readFails, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails,
+ &descP->readFails, 1);
- res = recv_check_fail_closed(env, descP, sockRef, recvRef);
+ res = recv_check_fail_econnreset(env, descP, sockRef, recvRef);
} else if ((saveErrno == ERRNO_BLOCK) ||
(saveErrno == EAGAIN)) {
@@ -15998,8 +16314,8 @@ ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
SSDBG( descP, ("SOCKET", "recv_check_fail -> errno: %d\r\n",
saveErrno) );
- // cnt_inc(&descP->readFails, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails,
+ &descP->readFails, 1);
res = recv_check_fail_gen(env, descP, saveErrno, sockRef);
}
@@ -16009,19 +16325,19 @@ ERL_NIF_TERM recv_check_fail(ErlNifEnv* env,
-/* *** recv_check_fail_closed ***
+/* *** recv_check_fail_econnreset ***
*
* We detected that the socket was closed wile reading.
* Inform current and waiting readers.
*/
static
-ERL_NIF_TERM recv_check_fail_closed(ErlNifEnv* env,
- ESockDescriptor* descP,
- ERL_NIF_TERM sockRef,
- ERL_NIF_TERM recvRef)
+ERL_NIF_TERM recv_check_fail_econnreset(ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ERL_NIF_TERM sockRef,
+ ERL_NIF_TERM recvRef)
{
- ERL_NIF_TERM res = esock_make_error(env, atom_closed);
- int sres;
+ ERL_NIF_TERM reason = atom_econnreset;
+ ERL_NIF_TERM res = esock_make_error(env, atom_econnreset);
/* <KOLLA>
*
@@ -16038,16 +16354,18 @@ ERL_NIF_TERM recv_check_fail_closed(ErlNifEnv* env,
* </KOLLA>
*/
+ recv_error_current_reader(env, descP, sockRef, reason);
+
+ MUNLOCK(descP->readMtx);
+
+ MLOCK(descP->closeMtx);
+ MLOCK(descP->readMtx);
+
+ descP->isReadable = FALSE;
descP->closeLocal = FALSE;
descP->state = ESOCK_STATE_CLOSING;
- recv_error_current_reader(env, descP, sockRef, res);
-
- if ((sres = esock_select_stop(env, descP->sock, descP)) < 0) {
- esock_warning_msg("Failed stop select (closed) "
- "for current reader (%T): %d\r\n",
- recvRef, sres);
- }
+ MUNLOCK(descP->closeMtx);
return res;
}
@@ -16100,11 +16418,11 @@ ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env,
int saveErrno,
ERL_NIF_TERM sockRef)
{
- ERL_NIF_TERM res = esock_make_error_errno(env, saveErrno);
+ ERL_NIF_TERM reason = MKA(env, erl_errno_id(saveErrno));
- recv_error_current_reader(env, descP, sockRef, res);
+ recv_error_current_reader(env, descP, sockRef, reason);
- return res;
+ return esock_make_error(env, reason);
}
@@ -16116,8 +16434,8 @@ ERL_NIF_TERM recv_check_fail_gen(ErlNifEnv* env,
static
ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
- int toRead,
+ ssize_t read,
+ size_t toRead,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef)
@@ -16133,14 +16451,16 @@ ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "recv_check_partial -> [%d] split buffer\r\n", toRead) );
+ "recv_check_partial -> [%lu] split buffer\r\n",
+ (unsigned long)toRead) );
res = recv_check_partial_done(env, descP, read, bufP, sockRef);
} else {
- SSDBG( descP, ("SOCKET", "recv_check_partial -> [%d] "
- "only part of message - expect more\r\n", toRead) );
+ SSDBG( descP, ("SOCKET", "recv_check_partial -> [%lu] "
+ "only part of message - expect more\r\n",
+ (unsigned long)toRead) );
res = recv_check_partial_part(env, descP, read, bufP, sockRef, recvRef);
}
@@ -16157,17 +16477,21 @@ ERL_NIF_TERM recv_check_partial(ErlNifEnv* env,
static
ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
+ ssize_t read,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef)
{
ERL_NIF_TERM data;
descP->rNumCnt = 0;
- // cnt_inc(&descP->readPkgCnt, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
- // cnt_inc(&descP->readByteCnt, read);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ &descP->readByteCnt, read);
+
+ descP->readPkgMaxCnt += read;
+ if (descP->readPkgMaxCnt > descP->readPkgMax)
+ descP->readPkgMax = descP->readPkgMaxCnt;
+ descP->readPkgMaxCnt = 0;
recv_update_current_reader(env, descP, sockRef);
@@ -16178,7 +16502,8 @@ ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env,
data = MKSBIN(env, data, 0, read);
SSDBG( descP,
- ("SOCKET", "recv_check_partial_done -> [%d] done\r\n", read) );
+ ("SOCKET", "recv_check_partial_done -> [%ld] done\r\n",
+ (long)read) );
return esock_make_ok3(env, atom_true, data);
}
@@ -16193,7 +16518,7 @@ ERL_NIF_TERM recv_check_partial_done(ErlNifEnv* env,
static
ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env,
ESockDescriptor* descP,
- int read,
+ ssize_t read,
ErlNifBinary* bufP,
ERL_NIF_TERM sockRef,
ERL_NIF_TERM recvRef)
@@ -16210,8 +16535,8 @@ ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env,
data = MKBIN(env, bufP);
data = MKSBIN(env, data, 0, read);
- // cnt_inc(&descP->readByteCnt, read);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_byte, &descP->readByteCnt, read);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ &descP->readByteCnt, read);
/* SELECT for more data */
@@ -16241,7 +16566,7 @@ ERL_NIF_TERM recv_check_partial_part(ErlNifEnv* env,
/* The recvfrom function delivers one (1) message. If our buffer
- * is to small, the message will be truncated. So, regardless
+ * is too small, the message will be truncated. So, regardless
* if we filled the buffer or not, we have got what we are going
* to get regarding this message.
*/
@@ -16298,11 +16623,10 @@ ERL_NIF_TERM recvfrom_check_result(ErlNifEnv* env,
data = MKSBIN(env, data, 0, read);
}
- // cnt_inc(&descP->readPkgCnt, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
- // cnt_inc(&descP->readByteCnt, read);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
- &descP->readByteCnt, read);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg,
+ &descP->readPkgCnt, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ &descP->readByteCnt, read);
recv_update_current_reader(env, descP, sockRef);
@@ -16361,7 +16685,7 @@ ERL_NIF_TERM recvmsg_check_result(ErlNifEnv* env,
* *We* do never actually try to read 0 bytes from a stream socket!
*/
- SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
FREE_BIN(dataBufP); FREE_BIN(ctrlBufP);
@@ -16442,9 +16766,9 @@ ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env,
* For now, we increment all three...
*/
- SOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_fails, &descP->readFails, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
&descP->readByteCnt, read);
recv_update_current_reader(env, descP, sockRef);
@@ -16458,8 +16782,8 @@ ERL_NIF_TERM recvmsg_check_msg(ErlNifEnv* env,
SSDBG( descP,
("SOCKET", "recvmsg_check_result -> (msghdr) encode ok\r\n") );
- SOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
- SOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_pkg, &descP->readPkgCnt, 1);
+ ESOCK_CNT_INC(env, descP, sockRef, atom_read_byte,
&descP->readByteCnt, read);
recv_update_current_reader(env, descP, sockRef);
@@ -18653,64 +18977,66 @@ ESockDescriptor* alloc_descriptor(SOCKET sock, HANDLE event)
enif_set_pid_undefined(&descP->connPid);
MON_INIT(&descP->connMon);
- sprintf(buf, "esock[w,%d]", sock);
+ sprintf(buf, "esock.w[%d]", sock);
descP->writeMtx = MCREATE(buf);
- enif_set_pid_undefined(&descP->currentWriter.pid);
- MON_INIT(&descP->currentWriter.mon);
- descP->currentWriter.env = NULL;
- descP->currentWriter.ref = esock_atom_undefined;
+ requestor_clear(&descP->currentWriter);
descP->currentWriterP = NULL; // currentWriter not used
descP->writersQ.first = NULL;
descP->writersQ.last = NULL;
descP->isWritable = FALSE; // TRUE;
descP->writePkgCnt = 0;
+ descP->writePkgMax = 0;
+ descP->writePkgMaxCnt = 0;
descP->writeByteCnt = 0;
descP->writeTries = 0;
descP->writeWaits = 0;
descP->writeFails = 0;
- sprintf(buf, "esock[r,%d]", sock);
+ sprintf(buf, "esock.r[%d]", sock);
descP->readMtx = MCREATE(buf);
- enif_set_pid_undefined(&descP->currentReader.pid);
- MON_INIT(&descP->currentReader.mon);
- descP->currentReader.env = NULL;
- descP->currentReader.ref = esock_atom_undefined;
+ requestor_clear(&descP->currentReader);
descP->currentReaderP = NULL; // currentReader not used
descP->readersQ.first = NULL;
descP->readersQ.last = NULL;
descP->isReadable = FALSE; // TRUE;
descP->readPkgCnt = 0;
+ descP->readPkgMax = 0;
+ descP->readPkgMaxCnt = 0;
descP->readByteCnt = 0;
descP->readTries = 0;
descP->readWaits = 0;
descP->readFails = 0;
- sprintf(buf, "esock[acc,%d]", sock);
+ sprintf(buf, "esock.acc[%d]", sock);
descP->accMtx = MCREATE(buf);
- enif_set_pid_undefined(&descP->currentAcceptor.pid);
- MON_INIT(&descP->currentAcceptor.mon);
- descP->currentAcceptor.env = NULL;
- descP->currentAcceptor.ref = esock_atom_undefined;
+ requestor_clear(&descP->currentAcceptor);
descP->currentAcceptorP = NULL; // currentAcceptor not used
descP->acceptorsQ.first = NULL;
descP->acceptorsQ.last = NULL;
+ descP->accSuccess = 0;
+ descP->accFails = 0;
+ descP->accTries = 0;
+ descP->accWaits = 0;
- sprintf(buf, "esock[close,%d]", sock);
+ sprintf(buf, "esock.close[%d]", sock);
descP->closeMtx = MCREATE(buf);
descP->closeEnv = NULL;
descP->closeRef = esock_atom_undefined;
enif_set_pid_undefined(&descP->closerPid);
MON_INIT(&descP->closerMon);
- sprintf(buf, "esock[cfg,%d]", sock);
+ sprintf(buf, "esock.cfg[%d]", sock);
descP->cfgMtx = MCREATE(buf);
descP->rBufSz = ESOCK_RECV_BUFFER_SIZE_DEFAULT;
- descP->rNum = 0;
+ descP->rNum = ESOCK_RECV_BUFFER_COUNT_DEFAULT;
descP->rNumCnt = 0;
descP->rCtrlSz = ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT;
descP->wCtrlSz = ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT;
descP->iow = FALSE;
descP->dbg = ESOCK_DEBUG_DEFAULT;
+ descP->meta.env = esock_alloc_env("alloc_descriptor - "
+ "meta-env");
+ descP->meta.ref = esock_atom_undefined;
descP->sock = sock;
descP->event = event;
@@ -19319,6 +19645,55 @@ size_t my_strnlen(const char *s, size_t maxlen)
#endif
+
+
+/* ===========================================================================
+ *
+ * Socket Registry message functions
+ *
+ * ===========================================================================
+ */
+
+/* Send a (socket) add message to the socket registry process.
+ * We know that this process *is* alive since the VM would
+ * terminate otherwise, so there is no need to test if
+ * the sending fails.
+ */
+static
+void esock_send_reg_add_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef)
+{
+ ERL_NIF_TERM msg = mk_reg_add_msg(env, sockRef);
+
+ esock_send_msg(env, &data.regPid, msg, NULL);
+}
+
+
+
+/* Send a (socket) del message to the socket registry process.
+ * We know that this process *is* alive since the VM would
+ * terminate otherwise, so there is no need to test if
+ * the sending fails.
+ */
+static
+void esock_send_reg_del_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef)
+{
+ ERL_NIF_TERM msg = mk_reg_del_msg(env, sockRef);
+
+ esock_send_msg(env, &data.regPid, msg, NULL);
+}
+
+
+
+
+/* ===========================================================================
+ *
+ * Socket user message functions
+ *
+ * ===========================================================================
+ */
+
/* Send an counter wrap message to the controlling process:
* A message in the form:
*
@@ -19354,6 +19729,7 @@ char* esock_send_close_msg(ErlNifEnv* env,
{
ERL_NIF_TERM sockRef, msg;
ErlNifEnv* menv;
+ char* result;
if (descP->closeEnv != NULL) {
sockRef = enif_make_resource(descP->closeEnv, descP);
@@ -19365,7 +19741,9 @@ char* esock_send_close_msg(ErlNifEnv* env,
menv = NULL; // This has the effect that the message will be copied
}
- return esock_send_msg(env, pid, msg, menv);
+ result = esock_send_msg(env, pid, msg, menv);
+ descP->closeEnv = NULL;
+ return result;
}
@@ -19414,6 +19792,55 @@ char* esock_send_msg(ErlNifEnv* env,
+/* *** mk_reg_add_msg ***
+ *
+ * Construct a socket add message for the socket registry.
+ *
+ * {'$socket', add, Socket}
+ *
+ */
+static
+ERL_NIF_TERM mk_reg_add_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef)
+{
+ return mk_reg_msg(env, atom_add, sockRef);
+}
+
+
+/* *** mk_reg_del_msg ***
+ *
+ * Construct a socket del message for the socket registry.
+ *
+ * {'$socket', del, Socket}
+ *
+ */
+static
+ERL_NIF_TERM mk_reg_del_msg(ErlNifEnv* env,
+ ERL_NIF_TERM sockRef)
+{
+ return mk_reg_msg(env, atom_del, sockRef);
+}
+
+
+/* *** mk_reg_msg ***
+ *
+ * Construct a general message for the socket registry.
+ * Tag is (at this time) either the atom 'add' or the atom 'del'.
+ *
+ * {'$socket', Tag, Socket}
+ *
+ */
+static
+ERL_NIF_TERM mk_reg_msg(ErlNifEnv* env,
+ ERL_NIF_TERM tag,
+ ERL_NIF_TERM sockRef)
+{
+ ERL_NIF_TERM socket = mk_socket(env, sockRef);
+
+ return MKT3(env, esock_atom_socket_tag, tag, socket);
+}
+
+
/* *** mk_abort_msg ***
*
* Create the abort message, which has the following form:
@@ -19577,6 +20004,14 @@ int esock_select_write(ErlNifEnv* env,
}
+/* *** esock_select_stop ***
+ *
+ * WARNING: enif_select may call esock_stop directly
+ * in which case deadlock is avoided by esock_stop that checks
+ * if it got a direct call and then does not lock closeMtx.
+ *
+ * So closeMtx is supposed to be locked when this function is called.
+ */
static
int esock_select_stop(ErlNifEnv* env,
ErlNifEvent event,
@@ -19848,15 +20283,19 @@ BOOLEAN_T requestor_pop(ESockRequestQueue* q,
return TRUE;
} else {
/* Queue was empty */
- enif_set_pid_undefined(&reqP->pid);
- MON_INIT(&reqP->mon);
- reqP->env = NULL;
- reqP->ref = esock_atom_undefined; // Just in case
+ requestor_clear(reqP);
return FALSE;
}
}
+static void requestor_clear(ESockRequestor* reqP) {
+ enif_set_pid_undefined(&reqP->pid);
+ MON_INIT(&reqP->mon);
+ reqP->env = NULL;
+ reqP->ref = esock_atom_undefined;
+}
+
static
BOOLEAN_T qsearch4pid(ErlNifEnv* env,
@@ -19975,11 +20414,11 @@ BOOLEAN_T qunqueue(ErlNifEnv* env,
#if !defined(__WIN32__)
static
-BOOLEAN_T cnt_inc(Uint32* cnt, Uint32 inc)
+BOOLEAN_T cnt_inc(ESockCounter* cnt, ESockCounter inc)
{
- BOOLEAN_T wrap;
- Uint32 max = 0xFFFFFFFF;
- Uint32 current = *cnt;
+ BOOLEAN_T wrap;
+ ESockCounter max = ESOCK_COUNTER_MAX;
+ ESockCounter current = *cnt;
if ((max - inc) >= current) {
*cnt += inc;
@@ -19994,9 +20433,9 @@ BOOLEAN_T cnt_inc(Uint32* cnt, Uint32 inc)
static
-void cnt_dec(Uint32* cnt, Uint32 dec)
+void cnt_dec(ESockCounter* cnt, ESockCounter dec)
{
- Uint32 current = *cnt;
+ ESockCounter current = *cnt;
if (dec > current)
*cnt = 0; // The counter cannot be < 0 so this is the best we can do...
@@ -20059,7 +20498,7 @@ int esock_demonitor(const char* slogan,
res = enif_demonitor_process(env, descP, &monP->mon);
if (res == 0) {
- esock_monitor_init(monP);
+ MON_INIT(monP);
} else {
SSDBG( descP,
("SOCKET", "[%d][%T] %s: demonitor failed: %d\r\n",
@@ -20088,6 +20527,17 @@ ERL_NIF_TERM esock_make_monitor_term(ErlNifEnv* env, const ESockMonitor* monP)
+static
+void esock_release_current(const char* slogan,
+ ErlNifEnv* env,
+ ESockDescriptor* descP,
+ ESockRequestor* current)
+{
+ DEMONP(slogan, env, descP, &current->mon);
+ esock_free_env(slogan, current->env);
+ requestor_clear(current);
+}
+
#endif // if !defined(__WIN32__)
@@ -20119,12 +20569,12 @@ void esock_dtor(ErlNifEnv* env, void* obj)
#if !defined(__WIN32__)
ESockDescriptor* descP = (ESockDescriptor*) obj;
- SGDBG( ("SOCKET", "dtor -> try destroy write mutex\r\n") );
- MDESTROY(descP->writeMtx); descP->writeMtx = NULL;
-
SGDBG( ("SOCKET", "dtor -> try destroy read mutex\r\n") );
MDESTROY(descP->readMtx); descP->readMtx = NULL;
+ SGDBG( ("SOCKET", "dtor -> try destroy write mutex\r\n") );
+ MDESTROY(descP->writeMtx); descP->writeMtx = NULL;
+
SGDBG( ("SOCKET", "dtor -> try destroy accept mutex\r\n") );
MDESTROY(descP->accMtx); descP->accMtx = NULL;
@@ -20194,32 +20644,38 @@ void esock_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
((is_direct_call) ? "called" : "scheduled"), descP->sock, fd) );
/* +++ Lock it down +++ */
-
- MLOCK(descP->writeMtx);
+
+ /* If we are called with a direct call; we already have closeMtx
+ */
+ if (!is_direct_call) MLOCK(descP->closeMtx);
MLOCK(descP->readMtx);
MLOCK(descP->accMtx);
+ MLOCK(descP->writeMtx);
MLOCK(descP->cfgMtx);
- if (!is_direct_call) MLOCK(descP->closeMtx);
SSDBG( descP, ("SOCKET", "esock_stop -> "
"[%d, %T] all mutex(s) locked when counters:"
"\r\n writePkgCnt: %u"
+ "\r\n writePkgMax: %u"
"\r\n writeByteCnt: %u"
"\r\n writeTries: %u"
"\r\n writeWaits: %u"
"\r\n writeFails: %u"
"\r\n readPkgCnt: %u"
+ "\r\n readPkgMax: %u"
"\r\n readByteCnt: %u"
"\r\n readTries: %u"
"\r\n readWaits: %u"
"\r\n",
descP->sock, descP->ctrlPid,
descP->writePkgCnt,
+ descP->writePkgMax,
descP->writeByteCnt,
descP->writeTries,
descP->writeWaits,
descP->writeFails,
descP->readPkgCnt,
+ descP->readPkgMax,
descP->readByteCnt,
descP->readTries,
descP->readWaits) );
@@ -20347,15 +20803,22 @@ void esock_stop(ErlNifEnv* env, void* obj, int fd, int is_direct_call)
}
}
}
-
+
+ if (descP->meta.env != NULL) {
+ esock_free_env("esock_stop - meta-env", descP->meta.env);
+ descP->meta.env = NULL;
+ }
SSDBG( descP, ("SOCKET", "esock_stop -> unlock all mutex(s)\r\n") );
- if (!is_direct_call) MUNLOCK(descP->closeMtx);
MUNLOCK(descP->cfgMtx);
+ MUNLOCK(descP->writeMtx);
MUNLOCK(descP->accMtx);
MUNLOCK(descP->readMtx);
- MUNLOCK(descP->writeMtx);
+ if (!is_direct_call) MUNLOCK(descP->closeMtx);
+
+ /* And finally update the registry */
+ esock_send_reg_del_msg(env, sockRef);
SSDBG( descP,
("SOCKET", "esock_stop -> done (%d, %d)\r\n", descP->sock, fd) );
@@ -20382,7 +20845,8 @@ void esock_stop_handle_current(ErlNifEnv* env,
DEMONP("esock_stop_handle_current", env, descP, &reqP->mon);
- if (COMPARE_PIDS(&descP->closerPid, &reqP->pid) != 0) {
+ if ((! enif_is_pid_undefined(&descP->closerPid)) &&
+ (COMPARE_PIDS(&descP->closerPid, &reqP->pid) != 0)) {
SSDBG( descP, ("SOCKET", "esock_stop_handle_current -> "
"send abort message to current %s %T\r\n",
@@ -20391,9 +20855,10 @@ void esock_stop_handle_current(ErlNifEnv* env,
if (esock_send_abort_msg(env, sockRef, reqP->ref, reqP->env,
atom_closed, &reqP->pid) != NULL) {
- esock_warning_msg("Failed sending abort (%T) message to "
+ esock_warning_msg("esock_stop_handle_current: "
+ "Failed sending abort (closed) message to "
"current %s %T\r\n",
- reqP->ref, role, reqP->pid);
+ role, reqP->pid);
}
reqP->env = NULL;
}
@@ -20434,8 +20899,9 @@ void inform_waiting_procs(ErlNifEnv* env,
SSDBG( descP,
("SOCKET",
- "inform_waiting_procs -> abort request %T (from %T)\r\n",
- currentP->data.ref, currentP->data.pid) );
+ "inform_waiting_procs -> "
+ "send abort message to waiting %s %T\r\n",
+ role, currentP->data.pid) );
if (esock_send_abort_msg(env,
sockRef,
@@ -20444,9 +20910,10 @@ void inform_waiting_procs(ErlNifEnv* env,
reason,
&currentP->data.pid) != NULL) {
- esock_warning_msg("Failed sending abort (%T) message to "
+ esock_warning_msg("inform_waiting_procs: "
+ "Failed sending abort (%T) message to "
"current %s %T\r\n",
- currentP->data.ref,
+ reason,
role,
currentP->data.pid);
@@ -20500,6 +20967,8 @@ void esock_down(ErlNifEnv* env,
* we leave it to the stop callback function.
*/
+ MLOCK(descP->closeMtx);
+
SSDBG( descP,
("SOCKET", "esock_down -> controlling process exit\r\n") );
@@ -20592,6 +21061,8 @@ void esock_down(ErlNifEnv* env,
MON2T(env, mon));
}
+ MUNLOCK(descP->closeMtx);
+
} else if (COMPARE_PIDS(&descP->connPid, pid) == 0) {
/* The connPid is only set during the connection.
@@ -20615,19 +21086,19 @@ void esock_down(ErlNifEnv* env,
sockRef = enif_make_resource(env, descP);
+ MLOCK(descP->readMtx);
MLOCK(descP->accMtx);
+ MLOCK(descP->writeMtx);
+
+ if (descP->currentReaderP != NULL)
+ esock_down_reader(env, descP, sockRef, pid);
if (descP->currentAcceptorP != NULL)
esock_down_acceptor(env, descP, sockRef, pid);
- MUNLOCK(descP->accMtx);
-
- MLOCK(descP->writeMtx);
if (descP->currentWriterP != NULL)
esock_down_writer(env, descP, sockRef, pid);
- MUNLOCK(descP->writeMtx);
- MLOCK(descP->readMtx);
- if (descP->currentReaderP != NULL)
- esock_down_reader(env, descP, sockRef, pid);
+ MUNLOCK(descP->writeMtx);
+ MUNLOCK(descP->accMtx);
MUNLOCK(descP->readMtx);
}
@@ -20663,12 +21134,8 @@ void esock_down_acceptor(ErlNifEnv* env,
SSDBG( descP,
("SOCKET", "esock_down_acceptor -> no more writers\r\n") );
- descP->state = ESOCK_STATE_LISTENING;
-
- descP->currentAcceptorP = NULL;
- descP->currentAcceptor.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentAcceptor.pid);
- esock_monitor_init(&descP->currentAcceptor.mon);
+ descP->state = ESOCK_STATE_LISTENING;
+ descP->currentAcceptorP = NULL;
}
} else {
@@ -20704,12 +21171,11 @@ void esock_down_writer(ErlNifEnv* env,
"current writer - try activate next\r\n") );
if (!activate_next_writer(env, descP, sockRef)) {
+
SSDBG( descP, ("SOCKET",
"esock_down_writer -> no active writer\r\n") );
+
descP->currentWriterP = NULL;
- descP->currentWriter.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentWriter.pid);
- esock_monitor_init(&descP->currentWriter.mon);
}
} else {
@@ -20745,13 +21211,12 @@ void esock_down_reader(ErlNifEnv* env,
"current reader - try activate next\r\n") );
if (!activate_next_reader(env, descP, sockRef)) {
+
SSDBG( descP,
("SOCKET",
"esock_down_reader -> no more readers\r\n") );
+
descP->currentReaderP = NULL;
- descP->currentReader.ref = esock_atom_undefined;
- enif_set_pid_undefined(&descP->currentReader.pid);
- esock_monitor_init(&descP->currentReader.mon);
}
} else {
@@ -20860,8 +21325,11 @@ int on_load(ErlNifEnv* env, void** priv_data, ERL_NIF_TERM load_info)
data.dbg = extract_debug(env, load_info);
data.iow = extract_iow(env, load_info);
+ esock_extract_pid_from_map(env, load_info,
+ MKA(env, "registry"), &data.regPid);
+
/* +++ Global Counters +++ */
- data.cntMtx = MCREATE("esock[gcnt]");
+ data.cntMtx = MCREATE("esock.gcnt");
data.numSockets = 0;
data.numTypeDGrams = 0;
data.numTypeStreams = 0;
diff --git a/erts/emulator/nifs/common/socket_util.c b/erts/emulator/nifs/common/socket_util.c
index b64e055c3e..a30c2e36ae 100644
--- a/erts/emulator/nifs/common/socket_util.c
+++ b/erts/emulator/nifs/common/socket_util.c
@@ -39,6 +39,13 @@
#include "config.h"
#endif
+#if defined(HAVE_SCTP_H)
+#include <netinet/sctp.h>
+#ifndef HAVE_SCTP
+# define HAVE_SCTP
+#endif
+#endif
+
#ifdef HAVE_SOCKLEN_T
# define SOCKLEN_T socklen_t
#else
@@ -99,7 +106,10 @@ static char* make_sockaddr_ll(ErlNifEnv* env,
ERL_NIF_TERM addr,
ERL_NIF_TERM* sa);
#endif
-
+static BOOLEAN_T esock_extract_from_map(ErlNifEnv* env,
+ ERL_NIF_TERM map,
+ ERL_NIF_TERM key,
+ ERL_NIF_TERM* val);
/* +++ esock_encode_iov +++
*
@@ -1082,50 +1092,43 @@ char* esock_decode_timeval(ErlNifEnv* env,
if (!GET_MAP_VAL(env, eTime, esock_atom_usec, &eUSec))
return ESOCK_STR_EINVAL;
- /* On some platforms (e.g. OpenBSD) this is a 'long long' and on others
- * (e.g. Linux) its a long.
- * As long as they are both 64 bits, its easy (use our own signed 64-bit int
- * and then cast). But if they are either not 64 bit, or they are of different size
- * then we make it easy on ourselves and use long and then cast to whatever
- * type sec is.
+ /* Use the appropriate variable type and nif function
+ * to decode the value from Erlang into the struct timeval fields
*/
-#if (SIZEOF_LONG_LONG == SIZEOF_LONG) && (SIZEOF_LONG == 8)
- {
+ { /* time_t tv_sec; */
+#if (SIZEOF_TIME_T == 8)
ErlNifSInt64 sec;
if (!GET_INT64(env, eSec, &sec))
return ESOCK_STR_EINVAL;
- timeP->tv_sec = (typeof(timeP->tv_sec)) sec;
- }
-#else
- {
+#elif (SIZEOF_TIME_T == SIZEOF_INT)
+ int sec;
+ if (!GET_INT(env, eSec, &sec))
+ return ESOCK_STR_EINVAL;
+#else /* long or other e.g undefined */
long sec;
if (!GET_LONG(env, eSec, &sec))
return ESOCK_STR_EINVAL;
- timeP->tv_sec = (typeof(timeP->tv_sec)) sec;
- }
#endif
+ timeP->tv_sec = sec;
+ }
- #if (SIZEOF_INT == 4)
- {
+ { /* suseconds_t tv_usec; */
+#if (SIZEOF_SUSECONDS_T == 8)
+ ErlNifSInt64 usec;
+ if (!GET_INT64(env, eSec, &usec))
+ return ESOCK_STR_EINVAL;
+#elif (SIZEOF_SUSECONDS_T == SIZEOF_INT)
int usec;
- if (!GET_INT(env, eUSec, &usec))
+ if (!GET_INT(env, eSec, &usec))
return ESOCK_STR_EINVAL;
- timeP->tv_usec = (typeof(timeP->tv_usec)) usec;
- }
-#elif (SIZEOF_LONG == 4)
- {
+#else /* long or other e.g undefined */
long usec;
- if (!GET_LONG(env, eUSec, &usec))
+ if (!GET_LONG(env, eSec, &usec))
return ESOCK_STR_EINVAL;
- timeP->tv_usec = (typeof(timeP->tv_usec)) usec;
+#endif
+ timeP->tv_usec = usec;
}
-#else
- /* Ok, we give up... */
- if (!GET_LONG(env, eUSec, &timeP->tv_usec))
- return ESOCK_STR_EINVAL;
-#endif
-
return NULL;
}
@@ -1635,7 +1638,7 @@ BOOLEAN_T esock_decode_string(ErlNifEnv* env,
/* *** esock_extract_bool_from_map ***
*
* Extract an boolean item from a map.
- *
+ * This function returns the retreived or the provided default value.
*/
extern
BOOLEAN_T esock_extract_bool_from_map(ErlNifEnv* env,
@@ -1645,7 +1648,7 @@ BOOLEAN_T esock_extract_bool_from_map(ErlNifEnv* env,
{
ERL_NIF_TERM val;
- if (!GET_MAP_VAL(env, map, key, &val))
+ if (!esock_extract_from_map(env, map, key, &val))
return def;
if (!IS_ATOM(env, val))
@@ -1659,6 +1662,59 @@ BOOLEAN_T esock_extract_bool_from_map(ErlNifEnv* env,
+/* *** esock_extract_pid_from_map ***
+ *
+ * Extract a pid item from a map.
+ * Returns TRUE on success and FALSE on failure (and then
+ * the pid value will be set to 'undefined').
+ *
+ */
+extern
+BOOLEAN_T esock_extract_pid_from_map(ErlNifEnv* env,
+ ERL_NIF_TERM map,
+ ERL_NIF_TERM key,
+ ErlNifPid* pid)
+{
+ BOOLEAN_T res;
+ ERL_NIF_TERM val;
+
+ if (!esock_extract_from_map(env, map, key, &val)) {
+ enif_set_pid_undefined(pid);
+ res = FALSE;
+ } else {
+ if (enif_get_local_pid(env, val, pid)) {
+ res = TRUE;
+ } else {
+ enif_set_pid_undefined(pid);
+ res = FALSE;
+ }
+ }
+
+ return res;
+}
+
+
+
+/* *** esock_extract_from_map ***
+ *
+ * Extract a value from a map.
+ * Returns true on success and false on failure.
+ *
+ */
+static
+BOOLEAN_T esock_extract_from_map(ErlNifEnv* env,
+ ERL_NIF_TERM map,
+ ERL_NIF_TERM key,
+ ERL_NIF_TERM* val)
+{
+ if (!GET_MAP_VAL(env, map, key, val))
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+
/* *** esock_decode_bool ***
*
* Decode a boolean value.
diff --git a/erts/emulator/nifs/common/socket_util.h b/erts/emulator/nifs/common/socket_util.h
index 7600b5e521..398fb40a5a 100644
--- a/erts/emulator/nifs/common/socket_util.h
+++ b/erts/emulator/nifs/common/socket_util.h
@@ -200,6 +200,11 @@ BOOLEAN_T esock_extract_bool_from_map(ErlNifEnv* env,
ERL_NIF_TERM key,
BOOLEAN_T def);
extern
+BOOLEAN_T esock_extract_pid_from_map(ErlNifEnv* env,
+ ERL_NIF_TERM map,
+ ERL_NIF_TERM key,
+ ErlNifPid* pid);
+extern
BOOLEAN_T esock_decode_bool(ERL_NIF_TERM val);
extern
ERL_NIF_TERM esock_encode_bool(BOOLEAN_T val);
diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c
index 1b125056f5..941d64f5cd 100644
--- a/erts/emulator/sys/common/erl_poll.c
+++ b/erts/emulator/sys/common/erl_poll.c
@@ -2346,7 +2346,7 @@ uint32_t epoll_events(int kp_fd, int fd)
char s[256];
FILE *f;
unsigned int pos, flags, mnt_id;
- int line = 0;
+ int hdr_lines, line = 1;
sprintf(fname,"/proc/%d/fdinfo/%d",getpid(), kp_fd);
f = fopen(fname,"r");
if (!f) {
@@ -2354,13 +2354,14 @@ uint32_t epoll_events(int kp_fd, int fd)
ASSERT(0);
return 0;
}
- if (fscanf(f,"pos:\t%x\nflags:\t%x", &pos, &flags) != 2) {
+ hdr_lines = fscanf(f,"pos:\t%x\nflags:\t%x\nmnt_id:\t%x\n",
+ &pos, &flags, &mnt_id);
+ if (hdr_lines < 2) {
fprintf(stderr,"failed to parse file %s, errno = %d\n", fname, errno);
ASSERT(0);
return 0;
}
- if (fscanf(f,"\nmnt_id:\t%x\n", &mnt_id));
- line += 3;
+ line += hdr_lines;
while (fgets(s, sizeof(s) / sizeof(*s), f)) {
/* tfd: 10 events: 40000019 data: 180000000a */
int ev_fd;
@@ -2414,7 +2415,7 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps,
char s[256];
FILE *f;
unsigned int pos, flags, mnt_id;
- int line = 0;
+ int hdr_lines, line = 1;
sprintf(fname,"/proc/%d/fdinfo/%d",getpid(), ps->kp_fd);
for (fd = 0; fd < len; fd++)
ev[fd] = ERTS_POLL_EV_NONE;
@@ -2423,14 +2424,15 @@ ERTS_POLL_EXPORT(erts_poll_get_selected_events)(ErtsPollSet *ps,
fprintf(stderr,"failed to open file %s, errno = %d\n", fname, errno);
return;
}
- if (fscanf(f,"pos:\t%x\nflags:\t%x", &pos, &flags) != 2) {
+ hdr_lines = fscanf(f,"pos:\t%x\nflags:\t%x\nmnt_id:\t%x\n",
+ &pos, &flags, &mnt_id);
+ if (hdr_lines < 2) {
fprintf(stderr,"failed to parse file %s, errno = %d\n", fname, errno);
ASSERT(0);
fclose(f);
return;
}
- if (fscanf(f,"\nmnt_id:\t%x\n", &mnt_id));
- line += 3;
+ line += hdr_lines;
while (fgets(s, sizeof(s) / sizeof(*s), f)) {
/* tfd: 10 events: 40000019 data: 180000000a */
int fd;
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index 4823e549ea..6475a70fbf 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -75,6 +75,7 @@
#include "erl_check_io.h"
#include "erl_cpu_topology.h"
#include "erl_osenv.h"
+#include "erl_dyn_lock_check.h"
extern int driver_interrupt(int, int);
extern void do_break(void);
@@ -276,7 +277,9 @@ erts_sys_pre_init(void)
#ifdef ERTS_ENABLE_LOCK_CHECK
erts_lc_init();
#endif
-
+#ifdef ERTS_DYN_LOCK_CHECK
+ erts_dlc_init();
+#endif
erts_init_sys_time_sup();
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 92020c6f35..6883519dc3 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -87,7 +87,7 @@ static Eterm forker_port;
/* Used by the fd driver iff the fd could not be set to non-blocking */
typedef struct ErtsSysBlocking_ {
ErlDrvPDL pdl;
- int res;
+ ErlDrvSSizeT res;
int err;
unsigned int pkey;
} ErtsSysBlocking;
@@ -112,6 +112,9 @@ typedef struct driver_data {
int status;
int terminating;
ErtsSysBlocking *blocking;
+ int busy;
+ ErlDrvSizeT high_watermark;
+ ErlDrvSizeT low_watermark;
} ErtsSysDriverData;
#define DIR_SEPARATOR_CHAR '/'
@@ -169,7 +172,7 @@ typedef struct driver_data {
void
erl_sys_late_init(void)
{
- SysDriverOpts opts;
+ SysDriverOpts opts = {0};
Port *port;
sys_signal(SIGPIPE, SIG_IGN); /* Ignore - we'll handle the write failure */
@@ -371,7 +374,8 @@ create_driver_data(ErlDrvPort port_num,
int read_write,
int exit_status,
int pid,
- int is_blocking)
+ int is_blocking,
+ SysDriverOpts* opts)
{
Port *prt;
ErtsSysDriverData *driver_data;
@@ -430,6 +434,10 @@ create_driver_data(ErlDrvPort port_num,
driver_data->ofd = NULL;
}
+ driver_data->busy = 0;
+ driver_data->high_watermark = opts->high_watermark;
+ driver_data->low_watermark = opts->low_watermark;
+
return driver_data;
}
@@ -719,7 +727,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
dd = create_driver_data(port_num, ifd[0], ofd[1], opts->packet_bytes,
DO_WRITE | DO_READ, opts->exit_status,
- 0, 0);
+ 0, 0, opts);
{
/* send ofd[0] + ifd[1] + stderrfd to forker port */
@@ -999,7 +1007,7 @@ static ErlDrvData fd_start(ErlDrvPort port_num, char* name,
return (ErlDrvData)create_driver_data(port_num, opts->ifd, opts->ofd,
opts->packet_bytes,
opts->read_write, 0, -1,
- !non_blocking);
+ !non_blocking, opts);
}
static void clear_fd_data(ErtsSysFdData *fdd)
@@ -1075,7 +1083,8 @@ static ErlDrvData vanilla_start(ErlDrvPort port_num, char* name,
res = (ErlDrvData)(long)create_driver_data(port_num, fd, fd,
opts->packet_bytes,
- opts->read_write, 0, -1, 0);
+ opts->read_write, 0, -1, 0,
+ opts);
return res;
}
@@ -1108,10 +1117,10 @@ static void outputv(ErlDrvData e, ErlIOVec* ev)
int pb = dd->packet_bytes;
int ofd = dd->ofd ? dd->ofd->fd : -1;
ssize_t n;
- ErlDrvSizeT sz;
char lb[4];
char* lbp;
ErlDrvSizeT len = ev->size;
+ ErlDrvSizeT qsz;
/* (len > ((unsigned long)-1 >> (4-pb)*8)) */
/* if (pb >= 0 && (len & (((ErlDrvSizeT)1 << (pb*8))) - 1) != len) {*/
@@ -1130,14 +1139,20 @@ static void outputv(ErlDrvData e, ErlIOVec* ev)
if (dd->blocking)
driver_pdl_lock(dd->blocking->pdl);
- if ((sz = driver_sizeq(ix)) > 0) {
- driver_enqv(ix, ev, 0);
-
+ qsz = driver_sizeq(ix);
+ if (qsz) {
+ if (qsz == (ErlDrvSizeT) -1) {
+ if (dd->blocking)
+ driver_pdl_unlock(dd->blocking->pdl);
+ driver_failure_posix(ix, EINVAL);
+ return;
+ }
+ driver_enqv(ix, ev, 0);
+ qsz += ev->size;
+ if (!dd->busy && qsz >= dd->high_watermark)
+ set_busy_port(ix, (dd->busy = !0));
if (dd->blocking)
driver_pdl_unlock(dd->blocking->pdl);
-
- if (sz + ev->size >= (1 << 13))
- set_busy_port(ix, 1);
}
else if (!dd->blocking) {
/* We try to write directly if the fd in non-blocking */
@@ -1154,11 +1169,17 @@ static void outputv(ErlDrvData e, ErlIOVec* ev)
n = 0;
}
driver_enqv(ix, ev, n); /* n is the skip value */
+ qsz = ev->size - n;
+ if (!dd->busy && qsz >= dd->high_watermark)
+ set_busy_port(ix, (dd->busy = !0));
driver_select(ix, ofd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
}
else {
if (ev->size != 0) {
driver_enqv(ix, ev, 0);
+ qsz = ev->size;
+ if (!dd->busy && qsz >= dd->high_watermark)
+ set_busy_port(ix, (dd->busy = !0));
driver_pdl_unlock(dd->blocking->pdl);
driver_async(ix, &dd->blocking->pkey,
fd_async, dd, NULL);
@@ -1166,6 +1187,7 @@ static void outputv(ErlDrvData e, ErlIOVec* ev)
driver_pdl_unlock(dd->blocking->pdl);
}
}
+
/* return 0;*/
}
@@ -1177,7 +1199,7 @@ static void output(ErlDrvData e, char* buf, ErlDrvSizeT len)
int pb = dd->packet_bytes;
int ofd = dd->ofd ? dd->ofd->fd : -1;
ssize_t n;
- ErlDrvSizeT sz;
+ ErlDrvSizeT qsz;
char lb[4];
char* lbp;
struct iovec iv[2];
@@ -1192,11 +1214,15 @@ static void output(ErlDrvData e, char* buf, ErlDrvSizeT len)
put_int32(len, lb);
lbp = lb + (4-pb);
- if ((sz = driver_sizeq(ix)) > 0) {
+ qsz = driver_sizeq(ix);
+ if (qsz) {
+ if (qsz == (ErlDrvSizeT) -1) {
+ driver_failure_posix(ix, EINVAL);
+ return;
+ }
driver_enq(ix, lbp, pb);
driver_enq(ix, buf, len);
- if (sz + len + pb >= (1 << 13))
- set_busy_port(ix, 1);
+ qsz += len + pb;
}
else {
iv[0].iov_base = lbp;
@@ -1213,6 +1239,7 @@ static void output(ErlDrvData e, char* buf, ErlDrvSizeT len)
}
n = 0;
}
+ qsz = pb + len - n;
if (n < pb) {
driver_enq(ix, lbp+n, pb-n);
driver_enq(ix, buf, len);
@@ -1223,6 +1250,10 @@ static void output(ErlDrvData e, char* buf, ErlDrvSizeT len)
}
driver_select(ix, ofd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
}
+
+ if (!dd->busy && qsz >= dd->high_watermark)
+ set_busy_port(ix, (dd->busy = !0));
+
return; /* 0; */
}
@@ -1479,6 +1510,8 @@ static void ready_output(ErlDrvData e, ErlDrvEvent ready_fd)
int vsize;
if ((iv = (struct iovec*) driver_peekq(ix, &vsize)) == NULL) {
+ if (dd->busy)
+ set_busy_port(ix, (dd->busy = 0));
driver_select(ix, ready_fd, ERL_DRV_WRITE, 0);
if (dd->pid > 0 && dd->ofd->fd < 0) {
/* The port was opened with 'in' option, which means we
@@ -1494,8 +1527,13 @@ static void ready_output(ErlDrvData e, ErlDrvEvent ready_fd)
}
vsize = vsize > MAX_VSIZE ? MAX_VSIZE : vsize;
if ((n = writev(ready_fd, iv, vsize)) > 0) {
- if (driver_deq(ix, n) == 0)
- set_busy_port(ix, 0);
+ ErlDrvSizeT qsz = driver_deq(ix, n);
+ if (qsz == (ErlDrvSizeT) -1) {
+ driver_failure_posix(ix, EINVAL);
+ return;
+ }
+ if (dd->busy && qsz < dd->low_watermark)
+ set_busy_port(ix, (dd->busy = 0));
}
else if (n < 0) {
if (errno == ERRNO_BLOCK || errno == EINTR)
@@ -1519,7 +1557,7 @@ static void stop_select(ErlDrvEvent fd, void* _)
static void
fd_async(void *async_data)
{
- int res;
+ ErlDrvSSizeT res;
ErtsSysDriverData *dd = (ErtsSysDriverData *)async_data;
SysIOVec *iov0;
SysIOVec *iov;
@@ -1544,7 +1582,6 @@ fd_async(void *async_data)
} while (res < 0 && errno == EINTR);
if (res < 0)
err = errno;
- err = errno;
erts_free(ERTS_ALC_T_SYS_WRITE_BUF, iov);
}
@@ -1560,10 +1597,18 @@ void fd_ready_async(ErlDrvData drv_data,
ASSERT(dd->blocking);
if (dd->blocking->res > 0) {
+ ErlDrvSizeT qsz;
driver_pdl_lock(dd->blocking->pdl);
- if (driver_deq(port_num, dd->blocking->res) == 0) {
+ qsz = driver_deq(port_num, dd->blocking->res);
+ if (qsz == (ErlDrvSizeT) -1) {
driver_pdl_unlock(dd->blocking->pdl);
- set_busy_port(port_num, 0);
+ driver_failure_posix(port_num, EINVAL);
+ return;
+ }
+ if (dd->busy && qsz < dd->low_watermark)
+ set_busy_port(port_num, (dd->busy = 0));
+ driver_pdl_unlock(dd->blocking->pdl);
+ if (qsz == 0) {
if (dd->terminating) {
/* The port is has been ordered to terminate
from either fd_flush or port_inp_failure */
@@ -1576,14 +1621,12 @@ void fd_ready_async(ErlDrvData drv_data,
return; /* -1; */
}
} else {
- driver_pdl_unlock(dd->blocking->pdl);
/* still data left to write in queue */
driver_async(port_num, &dd->blocking->pkey, fd_async, dd, NULL);
return /* 0; */;
}
} else if (dd->blocking->res < 0) {
if (dd->blocking->err == ERRNO_BLOCK) {
- set_busy_port(port_num, 1);
/* still data left to write in queue */
driver_async(port_num, &dd->blocking->pkey, fd_async, dd, NULL);
} else
diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c
index b95aadc9b2..53411a4cc2 100644
--- a/erts/emulator/sys/win32/sys.c
+++ b/erts/emulator/sys/win32/sys.c
@@ -507,6 +507,9 @@ struct driver_data {
AsyncIo out; /* Control block for overlapped writing. */
int report_exit; /* Do report exit status for the port */
erts_atomic32_t refc; /* References to this struct */
+ ErlDrvSizeT high_watermark; /* Q size when to go to busy port state */
+ ErlDrvSizeT low_watermark; /* Q size when to leave busy port state */
+ int busy;
};
/* Driver interfaces */
@@ -740,13 +743,8 @@ release_driver_data(DriverData* dp)
}
ASSERT(dp->inBufSize == 0);
- if (dp->outbuf != NULL) {
- ASSERT(erts_atomic_read_nob(&sys_misc_mem_sz) >= dp->outBufSize);
- erts_atomic_add_nob(&sys_misc_mem_sz, -1*dp->outBufSize);
- DRV_BUF_FREE(dp->outbuf);
- dp->outBufSize = 0;
- dp->outbuf = NULL;
- }
+ /* outbuf is released when queue is released */
+ ASSERT(!dp->outbuf);
ASSERT(dp->outBufSize == 0);
if (dp->port_pid != INVALID_HANDLE_VALUE) {
@@ -866,13 +864,18 @@ threaded_handle_closer(LPVOID param)
*/
static ErlDrvData
-set_driver_data(DriverData* dp, HANDLE ifd, HANDLE ofd, int read_write, int report_exit)
+set_driver_data(DriverData* dp, HANDLE ifd, HANDLE ofd, int read_write, int report_exit,
+ SysDriverOpts* opts)
{
int result;
dp->in.fd = ifd;
dp->out.fd = ofd;
dp->report_exit = report_exit;
+ dp->high_watermark = opts->high_watermark;
+ dp->low_watermark = opts->low_watermark;
+
+ dp->busy = 0;
if (read_write & DO_READ) {
result = driver_select(dp->port_num, (ErlDrvEvent)dp->in.ov.hEvent,
@@ -1322,7 +1325,7 @@ spawn_start(ErlDrvPort port_num, char* utf8_name, SysDriverOpts* opts)
}
#endif
retval = set_driver_data(dp, hFromChild, hToChild, opts->read_write,
- opts->exit_status);
+ opts->exit_status, opts);
if (retval != ERL_DRV_ERROR_GENERAL && retval != ERL_DRV_ERROR_ERRNO) {
/* We assume that this cannot generate a negative number */
erl_drv_set_os_pid(port_num, pid);
@@ -2200,7 +2203,8 @@ fd_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
} else if (in == 2 && out == 2) {
save_22_port = dp;
}
- return set_driver_data(dp, (HANDLE) opts->ifd, (HANDLE) opts->ofd, opts->read_write, 0);
+ return set_driver_data(dp, (HANDLE) opts->ifd, (HANDLE) opts->ofd, opts->read_write,
+ 0, opts);
}
}
@@ -2268,7 +2272,8 @@ vanilla_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts)
}
if (ofd == INVALID_HANDLE_VALUE)
return ERL_DRV_ERROR_GENERAL;
- return set_driver_data(dp, ifd, ofd, opts->read_write,0);
+ return set_driver_data(dp, ifd, ofd, opts->read_write,
+ 0, opts);
}
static void
@@ -2433,6 +2438,8 @@ output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
DriverData* dp = (DriverData *) drv_data;
int pb; /* The header size for this port. */
char* current;
+ ErlDrvSizeT qsz, sz;
+ ErlDrvBinary *bin;
pb = dp->packet_bytes;
@@ -2452,24 +2459,19 @@ output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
* Allocate memory for both the message and the header.
*/
- ASSERT(dp->outbuf == NULL);
- ASSERT(dp->outBufSize == 0);
-
- ASSERT(!dp->outbuf);
- dp->outbuf = DRV_BUF_ALLOC(pb+len);
- if (!dp->outbuf) {
- driver_failure_posix(dp->port_num, ENOMEM);
- return ; /* -1; */
+ sz = pb+len;
+ bin = driver_alloc_binary(sz);
+ if (!bin) {
+ driver_failure_posix(dp->port_num, ENOMEM);
+ return ; /* -1; */
}
- dp->outBufSize = pb+len;
- erts_atomic_add_nob(&sys_misc_mem_sz, dp->outBufSize);
-
/*
* Store header bytes (if any).
*/
- current = dp->outbuf;
+ current = bin->orig_bytes;
+
switch (pb) {
case 4:
*current++ = (len >> 24) & 255;
@@ -2486,18 +2488,34 @@ output(ErlDrvData drv_data, char* buf, ErlDrvSizeT len)
if (len)
memcpy(current, buf, len);
-
- if (!async_write_file(&dp->out, dp->outbuf, pb+len)) {
- set_busy_port(dp->port_num, 1);
- } else {
- dp->out.ov.Offset += pb+len; /* For vanilla driver. */
- /* XXX OffsetHigh should be changed too. */
- ASSERT(erts_atomic_read_nob(&sys_misc_mem_sz) >= dp->outBufSize);
- erts_atomic_add_nob(&sys_misc_mem_sz, -1*dp->outBufSize);
- DRV_BUF_FREE(dp->outbuf);
- dp->outBufSize = 0;
- dp->outbuf = NULL;
+
+ qsz = driver_sizeq(dp->port_num);
+
+ if (qsz > 0) {
+ driver_enq_bin(dp->port_num, bin, 0, sz);
+ qsz += pb+len;
}
+ else {
+ ASSERT(!dp->outbuf);
+ dp->outbuf = bin->orig_bytes;
+ dp->outBufSize = sz;
+ if (!async_write_file(&dp->out, dp->outbuf, sz)) {
+ driver_enq_bin(dp->port_num, bin, 0, sz);
+ qsz = sz;
+ } else {
+ dp->out.ov.Offset += pb+len; /* For vanilla driver. */
+ /* XXX OffsetHigh should be changed too. */
+ dp->outBufSize = 0;
+ dp->outbuf = NULL;
+ }
+ }
+
+ if (!dp->busy && qsz >= dp->high_watermark)
+ set_busy_port(dp->port_num, (dp->busy = !0));
+
+ /* Binary either handled or buffered */
+ driver_free_binary(bin);
+
/*return 0;*/
}
@@ -2693,20 +2711,19 @@ ready_output(ErlDrvData drv_data, ErlDrvEvent ready_event)
DWORD bytesWritten;
DriverData *dp = (DriverData *) drv_data;
int error;
+ ErlDrvSizeT qsz;
if(dp->out.thread == (HANDLE) -1) {
dp->out.async_io_active = 0;
}
DEBUGF(("ready_output(%p, 0x%x)\n", drv_data, ready_event));
- set_busy_port(dp->port_num, 0);
- if (!(dp->outbuf)) {
+ if (!dp->outbuf) {
/* Happens because event sometimes get signalled during a successful
write... */
return;
}
- ASSERT(erts_atomic_read_nob(&sys_misc_mem_sz) >= dp->outBufSize);
- erts_atomic_add_nob(&sys_misc_mem_sz, -1*dp->outBufSize);
- DRV_BUF_FREE(dp->outbuf);
+
+ qsz = driver_deq(dp->port_num, dp->outBufSize);
dp->outBufSize = 0;
dp->outbuf = NULL;
#ifdef HARD_POLL_DEBUG
@@ -2717,15 +2734,32 @@ ready_output(ErlDrvData drv_data, ErlDrvEvent ready_event)
poll_debug_write_done(dp->out.ov.hEvent,bytesWritten);
#endif
- if (error == NO_ERROR) {
- dp->out.ov.Offset += bytesWritten; /* For vanilla driver. */
- return ; /* 0; */
+ if (error != NO_ERROR) {
+ (void) driver_select(dp->port_num, ready_event, ERL_DRV_WRITE, 0);
+ _dosmaperr(error);
+ driver_failure_posix(dp->port_num, errno);
+ return;
}
-
- (void) driver_select(dp->port_num, ready_event, ERL_DRV_WRITE, 0);
- _dosmaperr(error);
- driver_failure_posix(dp->port_num, errno);
- /* return 0; */
+
+ dp->out.ov.Offset += bytesWritten; /* For vanilla driver. */
+
+ while (qsz > 0) {
+ int vsize;
+ SysIOVec *iov = driver_peekq(dp->port_num, &vsize);
+ ASSERT(iov->iov_base && iov->iov_len);
+ dp->outbuf = iov->iov_base;
+ dp->outBufSize = iov->iov_len;
+ if (!async_write_file(&dp->out, dp->outbuf, dp->outBufSize))
+ break;
+ dp->out.ov.Offset += dp->outBufSize; /* For vanilla driver. */
+ /* XXX OffsetHigh should be changed too. */
+ qsz = driver_deq(dp->port_num, dp->outBufSize);
+ dp->outbuf = NULL;
+ dp->outBufSize = 0;
+ }
+
+ if (dp->busy && qsz < dp->low_watermark)
+ set_busy_port(dp->port_num, (dp->busy = 0));
}
static void stop_select(ErlDrvEvent e, void* _)
diff --git a/erts/emulator/test/dirty_nif_SUITE.erl b/erts/emulator/test/dirty_nif_SUITE.erl
index 6f5ec161a3..8e5e2ded6e 100644
--- a/erts/emulator/test/dirty_nif_SUITE.erl
+++ b/erts/emulator/test/dirty_nif_SUITE.erl
@@ -226,18 +226,21 @@ dirty_call_while_terminated(Config) when is_list(Config) ->
element(2,
process_info(self(),
binary))),
- receive after 2000 -> ok end,
receive
Msg ->
ct:fail({unexpected_message, Msg})
after
- 0 ->
+ 1000 ->
ok
end,
- {value, {BinAddr, 4711, 1}} = lists:keysearch(4711, 2,
- element(2,
- process_info(self(),
- binary))),
+ ok = wait_until(fun() ->
+ {value, {BinAddr, 4711, 1}} ==
+ lists:keysearch(4711, 2,
+ element(2,
+ process_info(self(),
+ binary)))
+ end,
+ 10000),
process_flag(trap_exit, OT),
try
blipp:blupp(Bin)
@@ -714,6 +717,39 @@ nif_whereis_proxy(Ref) ->
ok
end.
+wait_until(Fun, infinity) ->
+ wait_until_aux(Fun, infinity);
+wait_until(Fun, MaxTime) ->
+ End = erlang:monotonic_time(millisecond) + MaxTime,
+ wait_until_aux(Fun, End).
+
+wait_until_aux(Fun, End) ->
+ case Fun() of
+ true ->
+ ok;
+ _ ->
+ if End == infinity ->
+ receive after 100 -> ok end,
+ wait_until_aux(Fun, infinity);
+ true ->
+ Now = erlang:monotonic_time(millisecond),
+ case End =< Now of
+ true ->
+ timeout;
+ _ ->
+ Wait = case End - Now of
+ Short when End - Now < 100 ->
+ Short;
+ _ ->
+ 100
+ end,
+ receive after Wait -> ok end,
+ wait_until_aux(Fun, End)
+ end
+ end
+ end.
+
+
%% The NIFs:
lib_loaded() -> false.
call_dirty_nif(_,_,_) -> ?nif_stub.
diff --git a/erts/emulator/test/esock_misc/esock_iow_client.erl b/erts/emulator/test/esock_misc/esock_iow_client.erl
new file mode 100644
index 0000000000..3e48a8f300
--- /dev/null
+++ b/erts/emulator/test/esock_misc/esock_iow_client.erl
@@ -0,0 +1,94 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% ---------------------------------------------------------------------
+%%
+%% Writes small messages to a socket, until counters wrap!
+%%
+%% ---------------------------------------------------------------------
+
+-module(esock_iow_client).
+
+-export([start/1]).
+
+-define(LIB, esock_iow_lib).
+-define(LIMIT, 100000).
+
+-define(MSG, <<"abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz"
+ "abcdefghijklmnopqrstuvxyz">>).
+
+
+%% ---------------------------------------------------------------------
+
+start(ServerPort) ->
+ Domain = inet,
+ ?LIB:iprint("open"),
+ {ok, S} = socket:open(Domain, stream, tcp),
+ ?LIB:iprint("iow"),
+ ok = socket:setopt(S, otp, iow, true),
+ ?LIB:iprint("bind"),
+ LocalSA = #{family => Domain,
+ addr => {147,214,93,147}},
+ {ok, _} = socket:bind(S, LocalSA),
+ ?LIB:iprint("connect (to ~w)", [ServerPort]),
+ ServerSA = LocalSA#{port => ServerPort},
+ ok = socket:connect(S, ServerSA),
+ ?LIB:iprint("connected - now await begin"),
+ case socket:recv(S, 0, infinity) of
+ {ok, <<"begin">>} ->
+ ?LIB:iprint("begin"),
+ loop(S, 0);
+ {error, Reason} ->
+ ?LIB:eprint("failed receive begin: ~p", [Reason])
+ end.
+
+loop(S, N) ->
+ ok = socket:send(S, ?MSG),
+ NextN = receive
+ {'$socket', S, counter_wrap, Cnt} ->
+ ?LIB:iprint("Counter ~w wrapped", [Cnt]),
+ N + 1;
+ Any ->
+ ?LIB:iprint("Received: ~n ~p~n", [Any]),
+ N + 1
+ after 1 ->
+ if (N < ?LIMIT) ->
+ N+1;
+ true ->
+ ?LIB:iprint("Counters:"
+ "~s", [?LIB:format_counters(cnts(S))]),
+ 0
+ end
+ end,
+ loop(S, NextN).
+
+
+cnts(S) ->
+ #{counters := Cnts} = socket:info(S),
+ Cnts.
+
diff --git a/erts/emulator/test/esock_misc/esock_iow_lib.erl b/erts/emulator/test/esock_misc/esock_iow_lib.erl
new file mode 100644
index 0000000000..6fc1365dca
--- /dev/null
+++ b/erts/emulator/test/esock_misc/esock_iow_lib.erl
@@ -0,0 +1,123 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(esock_iow_lib).
+
+-export([
+ format_counters/1, format_counters/2, format_counters/3,
+ iprint/1, iprint/2,
+ eprint/1, eprint/2,
+ f/2,
+ fts/0, fts/1
+ ]).
+
+
+%% ---------------------------------------------------------------------
+
+format_counters(Counters) ->
+ format_counters(traffic, Counters).
+
+format_counters(Type, Counters) when (Type =:= listen) orelse (Type =:= traffic) ->
+ format_counters(" ", Type, Counters).
+
+format_counters(Prefix, traffic, Counters) ->
+ ReadByte = proplists:get_value(read_byte, Counters, -1),
+ ReadFails = proplists:get_value(read_fails, Counters, -1),
+ ReadPkg = proplists:get_value(read_pkg, Counters, -1),
+ ReadPkgMax = proplists:get_value(read_pkg_max, Counters, -1),
+ ReadTries = proplists:get_value(read_tries, Counters, -1),
+ ReadWaits = proplists:get_value(read_waits, Counters, -1),
+ WriteByte = proplists:get_value(write_byte, Counters, -1),
+ WriteFails = proplists:get_value(write_fails, Counters, -1),
+ WritePkg = proplists:get_value(write_pkg, Counters, -1),
+ WritePkgMax = proplists:get_value(write_pkg_max, Counters, -1),
+ WriteTries = proplists:get_value(write_tries, Counters, -1),
+ WriteWaits = proplists:get_value(write_waits, Counters, -1),
+ f("~n~sNumber Of Read Bytes: ~p"
+ "~n~sNumber Of Read Fails: ~p"
+ "~n~sNumber Of Read Packages: ~p"
+ "~n~sNumber Of Read Tries: ~p"
+ "~n~sNumber Of Read Waits: ~p"
+ "~n~sMax Read Package Size: ~p"
+ "~n~sNumber Of Write Bytes: ~p"
+ "~n~sNumber Of Write Fails: ~p"
+ "~n~sNumber Of Write Packages: ~p"
+ "~n~sNumber Of Write Tries: ~p"
+ "~n~sNumber Of Write Waits: ~p"
+ "~n~sMax Write Package Size: ~p",
+ [Prefix, ReadByte,
+ Prefix, ReadFails,
+ Prefix, ReadPkg,
+ Prefix, ReadTries,
+ Prefix, ReadWaits,
+ Prefix, ReadPkgMax,
+ Prefix, WriteByte,
+ Prefix, WriteFails,
+ Prefix, WritePkg,
+ Prefix, WriteTries,
+ Prefix, WriteWaits,
+ Prefix, WritePkgMax]);
+
+format_counters(Prefix, listen, Counters) ->
+ AccSuccess = proplists:get_value(acc_success, Counters, -1),
+ AccFails = proplists:get_value(acc_fails, Counters, -1),
+ AccTries = proplists:get_value(acc_tries, Counters, -1),
+ AccWaits = proplists:get_value(acc_waits, Counters, -1),
+ f("~n~sNumber Of Successful Accepts: ~p"
+ "~n~sNumber Of Failed Accepts: ~p"
+ "~n~sNumber Of Accept Attempts: ~p"
+ "~n~sNumber Of Accept Waits: ~p",
+ [Prefix, AccSuccess,
+ Prefix, AccFails,
+ Prefix, AccTries,
+ Prefix, AccWaits]).
+
+%% ---------------------------------------------------------------------
+
+iprint(F) ->
+ iprint(F, []).
+
+iprint(F, A) ->
+ print("INFO", F, A).
+
+eprint(F) ->
+ iprint(F, []).
+
+eprint(F, A) ->
+ print("ERROR", F, A).
+
+print(Pre, F, A) ->
+ io:format("*** ~s *** ~s ~n" ++ F ++ "~n~n", [Pre, fts() | A]).
+
+
+f(F, A) ->
+ lists:flatten(io_lib:format(F, A)).
+
+
+ts() ->
+ os:timestamp().
+
+fts() ->
+ fts(ts()).
+
+fts({_N1, _N2, N3} = TS) ->
+ {_Date, Time} = calendar:now_to_local_time(TS),
+ {Hour,Min,Sec} = Time,
+ f("~.2.0w:~.2.0w:~.2.0w.4~w", [Hour, Min, Sec, round(N3/1000)]).
diff --git a/erts/emulator/test/esock_misc/esock_iow_server.erl b/erts/emulator/test/esock_misc/esock_iow_server.erl
new file mode 100644
index 0000000000..4b364a6ca6
--- /dev/null
+++ b/erts/emulator/test/esock_misc/esock_iow_server.erl
@@ -0,0 +1,83 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% ---------------------------------------------------------------------
+%%
+%% Reads small messages to a socket, until counters wrap!
+%%
+%% ---------------------------------------------------------------------
+
+-module(esock_iow_server).
+
+-export([start/0]).
+
+-define(LIB, esock_iow_lib).
+-define(LIMIT, 100000).
+
+
+%% ---------------------------------------------------------------------
+
+start() ->
+ Domain = inet,
+ ?LIB:iprint("open"),
+ {ok, LSock} = socket:open(Domain, stream, tcp),
+ ?LIB:iprint("iow"),
+ ok = socket:setopt(LSock, otp, iow, true),
+ ?LIB:iprint("bind"),
+ LocalSA = #{family => Domain,
+ addr => {147,214,93,147}},
+ {ok, LPort} = socket:bind(LSock, LocalSA),
+ ?LIB:iprint("listen port: ~p", [LPort]),
+ ?LIB:iprint("make listen socket"),
+ ok = socket:listen(LSock),
+ ?LIB:iprint("accept"),
+ {ok, CSock} = socket:accept(LSock),
+ ok = socket:send(CSock, <<"begin">>),
+ loop(CSock, 0).
+
+loop(S, N) ->
+ case socket:recv(S) of
+ {ok, _} when (N < ?LIMIT) ->
+ flush(S),
+ loop(S, N+1);
+ {ok, _} ->
+ ?LIB:iprint("Counters:"
+ "~s", [?LIB:format_counters(cnts(S))]),
+ flush(S),
+ loop(S, 0);
+ {error, Reason} ->
+ ?LIB:eprint("failed receive: ~p", [Reason])
+ end.
+
+
+cnts(S) ->
+ #{counters := Cnts} = socket:info(S),
+ Cnts.
+
+flush(S) ->
+ receive
+ {'$socket', S, counter_wrap, Cnt} ->
+ ?LIB:iprint("Counter ~w wrapped", [Cnt]);
+ Any ->
+ ?LIB:iprint("Received: ~n ~p~n", [Any])
+ after 0 ->
+ ok
+ end.
+
diff --git a/erts/emulator/test/list_bif_SUITE.erl b/erts/emulator/test/list_bif_SUITE.erl
index f95251943d..4ddcd0f60b 100644
--- a/erts/emulator/test/list_bif_SUITE.erl
+++ b/erts/emulator/test/list_bif_SUITE.erl
@@ -23,6 +23,7 @@
-export([all/0, suite/0]).
-export([hd_test/1,tl_test/1,t_length/1,t_list_to_pid/1,
+ t_list_to_ref/1, t_list_to_ext_pidportref/1,
t_list_to_port/1,t_list_to_float/1,t_list_to_integer/1]).
@@ -33,6 +34,7 @@ suite() ->
all() ->
[hd_test, tl_test, t_length, t_list_to_pid, t_list_to_port,
+ t_list_to_ref, t_list_to_ext_pidportref,
t_list_to_float, t_list_to_integer].
%% Tests list_to_integer and string:to_integer
@@ -126,6 +128,61 @@ t_list_to_port(Config) when is_list(Config) ->
end,
ok.
+t_list_to_ref(Config) when is_list(Config) ->
+ Ref = make_ref(),
+ RefStr = ref_to_list(Ref),
+ Ref = list_to_ref(RefStr),
+ case catch list_to_ref(id("Incorrect list")) of
+ {'EXIT', {badarg, _}} ->
+ ok;
+ Res ->
+ ct:fail("list_to_ref/1 with incorrect arg succeeded.~n"
+ "Result: ~p", [Res])
+ end,
+ ok.
+
+%% Test list_to_pid/port/ref for external pids/ports/refs.
+t_list_to_ext_pidportref(Config) when is_list(Config) ->
+ {ok, Node} = slave:start(net_adm:localhost(), t_list_to_ext_pidportref),
+ Pid = rpc:call(Node, erlang, self, []),
+ Port = hd(rpc:call(Node, erlang, ports, [])),
+ Ref = rpc:call(Node, erlang, make_ref, []),
+
+ PidStr = pid_to_list(Pid),
+ PortStr = port_to_list(Port),
+ RefStr = ref_to_list(Ref),
+
+ Pid2 = list_to_pid(PidStr),
+ Port2 = list_to_port(PortStr),
+ Ref2 = list_to_ref(RefStr),
+
+ %% The local roundtrips of externals does not work
+ %% as 'creation' is missing in the string formats and we don't know
+ %% the 'creation' of the connected node.
+ false = (Pid =:= Pid2),
+ false = (Port =:= Port2),
+ false = (Ref =:= Ref2),
+
+ %% Local roundtrip kind of "works" for '==' since OTP-22.0 (bf7c722bd3b)
+ %% Operator '==' treats 0-creations as wildcards
+ %% which breaks term transitivity (A==B and B==C => B==C).
+ true = (Pid == Pid2),
+ true = (Port == Port2),
+ true = (Ref == Ref2),
+
+ %% It works when sent back to node with matching name, as 0-creations
+ %% will be converted to the local node creation.
+ true = rpc:call(Node, erlang, '=:=', [Pid, Pid2]),
+ true = rpc:call(Node, erlang, '==', [Pid, Pid2]),
+ true = rpc:call(Node, erlang, '=:=', [Port, Port2]),
+ true = rpc:call(Node, erlang, '==', [Port, Port2]),
+ true = rpc:call(Node, erlang, '=:=', [Ref, Ref2]),
+ true = rpc:call(Node, erlang, '==', [Ref, Ref2]),
+
+ slave:stop(Node),
+ ok.
+
+
%% Test list_to_float/1 with correct and incorrect arguments.
t_list_to_float(Config) when is_list(Config) ->
diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl
index b824daea67..6a8f7607cd 100644
--- a/erts/emulator/test/nif_SUITE.erl
+++ b/erts/emulator/test/nif_SUITE.erl
@@ -38,6 +38,7 @@
monitor_process_b/1,
monitor_process_c/1,
monitor_process_d/1,
+ monitor_process_purge/1,
demonitor_process/1,
monitor_frenzy/1,
hipe/1,
@@ -67,6 +68,7 @@
nif_whereis_threaded/1, nif_whereis_proxy/1,
nif_ioq/1,
pid/1,
+ id/1,
nif_term_type/1
]).
@@ -76,6 +78,9 @@
-define(is_resource, is_reference).
+-define(RT_CREATE,1).
+-define(RT_TAKEOVER,2).
+
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
@@ -125,6 +130,7 @@ groups() ->
monitor_process_b,
monitor_process_c,
monitor_process_d,
+ monitor_process_purge,
demonitor_process]}].
api_groups() -> [api_latest, api_2_4, api_2_0].
@@ -823,6 +829,57 @@ monitor_process_d(Config) ->
ok.
+%% OTP-16399: Test fire resource monitor after the NIF module been purged.
+monitor_process_purge(Config) ->
+ Data = proplists:get_value(data_dir, Config),
+ File = filename:join(Data, "nif_mod"),
+ {ok,nif_mod,NifModBin} = compile:file(File, [binary,return_errors]),
+
+ monitor_process_purge_do(Config, NifModBin, resource_dtor_A),
+ erlang:garbage_collect(),
+ receive after 10 -> ok end,
+ [{{resource_dtor_A_v1,_},1,4,104},
+ {unload,1,5,105}] = nif_mod_call_history(),
+
+ %% This used to crash VM as only resources with destructor
+ %% prevented NIF lib from being unloaded.
+ monitor_process_purge_do(Config, NifModBin, null),
+ erlang:garbage_collect(),
+ receive after 10 -> ok end,
+ [{unload,1,4,104}] = nif_mod_call_history(),
+ ok.
+
+monitor_process_purge_do(Config, NifModBin, Dtor) ->
+ io:format("Test with destructor = ~p\n", [Dtor]),
+
+ {module,nif_mod} = erlang:load_module(nif_mod,NifModBin),
+
+ ok = nif_mod:load_nif_lib(Config, 1, [{resource_type, 0, ?RT_CREATE,
+ "monitor_process_purge", Dtor,
+ ?RT_CREATE, resource_down_D}
+ ]),
+ hold_nif_mod_priv_data(nif_mod:get_priv_data_ptr()),
+ [{load,1,1,101},
+ {get_priv_data_ptr,1,2,102}] = nif_mod_call_history(),
+
+ {Pid,MRef} = spawn_opt(fun() ->
+ receive
+ return -> ok
+ end
+ end,
+ [link, monitor]),
+ RBin = <<"blahblah">>,
+ R = nif_mod:make_new_resource(0, RBin),
+ 0 = nif_mod:monitor_process(0, R, Pid),
+ true = erlang:delete_module(nif_mod),
+ true = erlang:purge_module(nif_mod),
+ Pid ! return,
+ [{'DOWN', MRef, process, Pid, normal}] = flush(),
+ [{{resource_down_D_v1,RBin},1,3,103}] = nif_mod_call_history(),
+ keep_alive(R),
+ ok.
+
+
%% Test basic demonitoring
demonitor_process(Config) ->
ensure_lib_loaded(Config),
@@ -1414,10 +1471,6 @@ resource_binary_do() ->
ResInfo = get_resource(binary_resource_type,ResBin2),
ResInfo.
-
--define(RT_CREATE,1).
--define(RT_TAKEOVER,2).
-
%% Test resource takeover by module upgrade
resource_takeover(Config) when is_list(Config) ->
TmpMem = tmpmem(),
@@ -3458,6 +3511,7 @@ last_resource_dtor_call() ->
last_resource_dtor_call_nif().
id(I) -> I.
+keep_alive(Term) -> ?MODULE:id(Term).
%% The NIFs:
lib_version() -> undefined.
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.c b/erts/emulator/test/nif_SUITE_data/nif_mod.c
index 885b8ebaf8..d8c1ca2a2e 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.c
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.c
@@ -23,6 +23,10 @@
#include "nif_mod.h"
+#if ERL_NIF_MAJOR_VERSION*100 + ERL_NIF_MINOR_VERSION >= 215
+# define HAVE_ENIF_MONITOR_PROCESS
+#endif
+
#define CHECK(X) ((void)((X) || (check_abort(__LINE__),1)))
#ifdef __GNUC__
static void check_abort(unsigned line) __attribute__((noreturn));
@@ -42,6 +46,7 @@ static ERL_NIF_TERM am_null;
static ERL_NIF_TERM am_resource_type;
static ERL_NIF_TERM am_resource_dtor_A;
static ERL_NIF_TERM am_resource_dtor_B;
+static ERL_NIF_TERM am_resource_down_D;
static ERL_NIF_TERM am_return;
static NifModPrivData* priv_data(ErlNifEnv* env)
@@ -56,6 +61,7 @@ static void init(ErlNifEnv* env)
am_resource_type = enif_make_atom(env, "resource_type");
am_resource_dtor_A = enif_make_atom(env, "resource_dtor_A");
am_resource_dtor_B = enif_make_atom(env, "resource_dtor_B");
+ am_resource_down_D = enif_make_atom(env, "resource_down_D");
am_return = enif_make_atom(env, "return");
}
@@ -107,8 +113,26 @@ static void resource_dtor_B(ErlNifEnv* env, void* a)
enif_sizeof_resource(a));
}
-/* {resource_type, Ix|null, ErlNifResourceFlags in, "TypeName", dtor(A|B|null), ErlNifResourceFlags out}*/
-static void open_resource_type(ErlNifEnv* env, const ERL_NIF_TERM* arr)
+#ifdef HAVE_ENIF_MONITOR_PROCESS
+static void resource_down_D(ErlNifEnv* env, void* a, ErlNifPid* pid, ErlNifMonitor* mon)
+{
+ const char down_name[] = "resource_down_D_v" STRINGIFY(NIF_LIB_VER);
+
+ add_call_with_arg(env, priv_data(env), down_name, (const char*)a,
+ enif_sizeof_resource(a));
+}
+#endif
+
+
+/* {resource_type,
+ Ix|null,
+ ErlNifResourceFlags in,
+ "TypeName",
+ dtor(A|B|null),
+ ErlNifResourceFlags out
+ [, down(D|null)]}
+*/
+static void open_resource_type(ErlNifEnv* env, int arity, const ERL_NIF_TERM* arr)
{
NifModPrivData* data = priv_data(env);
char rt_name[30];
@@ -132,10 +156,27 @@ static void open_resource_type(ErlNifEnv* env, const ERL_NIF_TERM* arr)
CHECK(enif_is_identical(arr[4], am_resource_dtor_B));
dtor = resource_dtor_B;
}
-
- got_ptr = enif_open_resource_type(env, NULL, rt_name, dtor,
- flags.e, &got_res.e);
-
+#ifdef HAVE_ENIF_MONITOR_PROCESS
+ if (arity == 7) {
+ ErlNifResourceTypeInit init;
+ init.dtor = dtor;
+ init.stop = NULL;
+ if (enif_is_identical(arr[6], am_null)) {
+ init.down = NULL;
+ }
+ else {
+ CHECK(enif_is_identical(arr[6], am_resource_down_D));
+ init.down = resource_down_D;
+ }
+ got_ptr = enif_open_resource_type_x(env, rt_name, &init,
+ flags.e, &got_res.e);
+ }
+ else
+#endif
+ {
+ got_ptr = enif_open_resource_type(env, NULL, rt_name, dtor,
+ flags.e, &got_res.e);
+ }
if (enif_get_uint(env, arr[1], &ix) && ix < RT_MAX && got_ptr != NULL) {
data->rt_arr[ix] = got_ptr;
}
@@ -163,7 +204,8 @@ static void do_load_info(ErlNifEnv* env, ERL_NIF_TERM load_info, int* retvalp)
CHECK(enif_get_tuple(env, head, &arity, &arr));
switch (arity) {
case 6:
- open_resource_type(env, arr);
+ case 7:
+ open_resource_type(env, arity, arr);
break;
case 2:
CHECK(arr[0] == am_return);
@@ -290,6 +332,25 @@ static ERL_NIF_TERM get_resource(ErlNifEnv* env, int argc, const ERL_NIF_TERM ar
return enif_make_binary(env, &obin);
}
+#ifdef HAVE_ENIF_MONITOR_PROCESS
+static ERL_NIF_TERM monitor_process(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
+{
+ NifModPrivData* data = priv_data(env);
+ ErlNifPid pid;
+ unsigned ix;
+ void* obj;
+ int ret;
+
+ if (!enif_get_uint(env, argv[0], &ix) || ix >= RT_MAX
+ || !enif_get_resource(env, argv[1], data->rt_arr[ix], &obj)
+ || !enif_get_local_pid(env, argv[2], &pid)) {
+ return enif_make_badarg(env);
+ }
+ ret = enif_monitor_process(env, obj, &pid, NULL);
+ return enif_make_int(env, ret);
+}
+#endif
+
static ErlNifFunc nif_funcs[] =
{
{"lib_version", 0, lib_version},
@@ -297,6 +358,9 @@ static ErlNifFunc nif_funcs[] =
{"get_priv_data_ptr", 0, get_priv_data_ptr},
{"make_new_resource", 2, make_new_resource},
{"get_resource", 2, get_resource}
+#ifdef HAVE_ENIF_MONITOR_PROCESS
+ ,{"monitor_process", 3, monitor_process}
+#endif
};
#if NIF_LIB_VER != 3
diff --git a/erts/emulator/test/nif_SUITE_data/nif_mod.erl b/erts/emulator/test/nif_SUITE_data/nif_mod.erl
index 8019cfcf82..f3b9dcfaf3 100644
--- a/erts/emulator/test/nif_SUITE_data/nif_mod.erl
+++ b/erts/emulator/test/nif_SUITE_data/nif_mod.erl
@@ -23,7 +23,8 @@
-include_lib("common_test/include/ct.hrl").
-export([load_nif_lib/2, load_nif_lib/3, start/0, lib_version/0,
- get_priv_data_ptr/0, make_new_resource/2, get_resource/2]).
+ get_priv_data_ptr/0, make_new_resource/2, get_resource/2,
+ monitor_process/3]).
-export([loop/0, upgrade/1]).
@@ -89,6 +90,7 @@ nif_api_version() -> %NIF
get_priv_data_ptr() -> ?nif_stub.
make_new_resource(_,_) -> ?nif_stub.
get_resource(_,_) -> ?nif_stub.
+monitor_process(_,_,_) -> ?nif_stub.
nif_stub_error(Line) ->
exit({nif_not_loaded,module,?MODULE,line,Line}).
diff --git a/erts/emulator/test/port_bif_SUITE.erl b/erts/emulator/test/port_bif_SUITE.erl
index e1e1ec9fb9..333c5bce04 100644
--- a/erts/emulator/test/port_bif_SUITE.erl
+++ b/erts/emulator/test/port_bif_SUITE.erl
@@ -26,7 +26,7 @@
command_e_1/1, command_e_2/1, command_e_3/1, command_e_4/1,
port_info1/1, port_info2/1,
port_info_os_pid/1, port_info_race/1,
- connect/1, control/1, echo_to_busy/1]).
+ connect/1, control/1, echo_to_busy/1, busy_options/1]).
-export([do_command_e_1/1, do_command_e_2/1, do_command_e_4/1]).
@@ -38,7 +38,7 @@ suite() ->
all() ->
[command, {group, port_info}, connect, control,
- echo_to_busy].
+ echo_to_busy, busy_options].
groups() ->
[{command_e, [],
@@ -475,3 +475,171 @@ sub_bin(Bin) when is_binary(Bin) ->
B.
id(I) -> I.
+
+busy_options(Config) when is_list(Config) ->
+ SleepTime = 2000,
+ SleepTimeX = SleepTime + 100,
+ MinVal = 1,
+ MaxVal = (1 bsl (8*erlang:system_info(wordsize))) - 2,
+ DataDir = proplists:get_value(data_dir, Config),
+ Sleep = filename:join(DataDir, "sleeper") ++ " " ++ integer_to_list(SleepTime),
+ Data = "hej hopp! hej hopp! hej hopp! hej hopp! hej hopp! hej hopp! hej hopp! hej hopp! hej hopp! hej hopp!",
+
+ process_flag(trap_exit, true),
+ Tester = self(),
+ HejLoop = fun (Prt, _F, 1000) ->
+ Prt;
+ (Prt, F, N) ->
+ Prt ! {Tester, {command, Data}},
+ F(Prt, F, N+1)
+ end,
+
+ io:format("Test1...~n", []),
+ Start1 = erlang:monotonic_time(millisecond),
+ Prt1 = open_port({spawn, Sleep},
+ [{busy_limits_port, {MinVal, MinVal}},
+ {busy_limits_msgq, {MinVal, MinVal}}]),
+ T1 = spawn_link(fun () ->
+ HejLoop(Prt1, HejLoop, 0)
+ end),
+ true = wait_until(fun () ->
+ {status, suspended} == process_info(T1, status)
+ end,
+ SleepTimeX),
+ unlink(T1),
+ exit(T1, kill),
+ io:format("Test1 done: ~p ms~n", [erlang:monotonic_time(millisecond)-Start1]),
+
+ io:format("Test2...~n", []),
+ Start2 = erlang:monotonic_time(millisecond),
+ Prt2 = open_port({spawn, Sleep},
+ [{busy_limits_port, {50, 100}},
+ {busy_limits_msgq, {50, 100}}]),
+ T2 = spawn_link(fun () ->
+ HejLoop(Prt2, HejLoop, 0)
+ end),
+ true = wait_until(fun () ->
+ {status, suspended} == process_info(T2, status)
+ end,
+ SleepTimeX),
+ unlink(T2),
+ exit(T2, kill),
+ io:format("Test2 done: ~p ms~n", [erlang:monotonic_time(millisecond)-Start2]),
+
+ io:format("Test3...~n", []),
+ Start3 = erlang:monotonic_time(millisecond),
+
+ Prt3 = open_port({spawn, Sleep},
+ [{busy_limits_port, {MaxVal,MaxVal}},
+ {busy_limits_msgq, {MaxVal,MaxVal}}]),
+ T3 = spawn_link(fun () ->
+ HejLoop(Prt3, HejLoop, 0)
+ end),
+ false = wait_until(fun () ->
+ {status, suspended} == process_info(T3, status)
+ end,
+ SleepTimeX),
+ unlink(T3),
+ exit(T3, kill),
+ io:format("Test3 done: ~p ms~n", [erlang:monotonic_time(millisecond)-Start3]),
+
+ io:format("Test4...~n", []),
+ Start4 = erlang:monotonic_time(millisecond),
+
+ Prt4 = open_port({spawn, Sleep},
+ [{busy_limits_port, disabled},
+ {busy_limits_msgq, disabled}]),
+ T4 = spawn_link(fun () ->
+ HejLoop(Prt4, HejLoop, 0)
+ end),
+ false = wait_until(fun () ->
+ {status, suspended} == process_info(T4, status)
+ end,
+ SleepTimeX),
+ unlink(T4),
+ exit(T4, kill),
+ io:format("Test4 done: ~p ms~n", [erlang:monotonic_time(millisecond)-Start4]),
+
+ try
+ open_port({spawn, Sleep},
+ [{busy_limits_port, {MinVal-1,MinVal-1}}])
+ catch
+ error:badarg -> ok
+ end,
+
+ try
+ open_port({spawn, Sleep},
+ [{busy_limits_msgq, {MinVal-1,MinVal-1}}])
+ catch
+ error:badarg -> ok
+ end,
+
+ try
+ open_port({spawn, Sleep},
+ [{busy_limits_port, {MaxVal+1,MaxVal+1}}])
+ catch
+ error:badarg -> ok
+ end,
+
+ try
+ open_port({spawn, Sleep},
+ [{busy_limits_msgq, {MaxVal+1,MaxVal+1}}])
+ catch
+ error:badarg -> ok
+ end,
+
+ load_control_drv(Config),
+
+ CtrlPort = open_port({spawn, "control_drv"},
+ [{busy_limits_msgq, {50,100}}]),
+ unlink(CtrlPort),
+ exit(CtrlPort, kill),
+
+ try
+ open_port({spawn, "control_drv"},
+ [{busy_limits_port, {50,100}}])
+ catch
+ error:badarg -> ok
+ end,
+
+ receive {'EXIT', Prt1, _} -> ok end,
+ receive {'EXIT', Prt2, _} -> ok end,
+ receive {'EXIT', Prt3, _} -> ok end,
+ receive {'EXIT', Prt4, _} -> ok end,
+
+ ok.
+
+wait_until(Fun, infinity) ->
+ wait_until_aux(Fun, infinity);
+wait_until(Fun, MaxTime) ->
+ End = erlang:monotonic_time(millisecond) + MaxTime,
+ wait_until_aux(Fun, End).
+
+wait_until_aux(Fun, End) ->
+ case catch Fun() of
+ true ->
+ true;
+ _ ->
+ if End == infinity ->
+ receive after 100 -> ok end,
+ wait_until_aux(Fun, infinity);
+ true ->
+ Now = erlang:monotonic_time(millisecond),
+ case End =< Now of
+ true ->
+ false;
+ _ ->
+ Wait = case End - Now of
+ Short when End - Now < 100 ->
+ Short;
+ _ ->
+ 100
+ end,
+ receive after Wait -> ok end,
+ wait_until_aux(Fun, End)
+ end
+ end
+ end.
+
+
+
diff --git a/erts/emulator/test/port_bif_SUITE_data/Makefile.src b/erts/emulator/test/port_bif_SUITE_data/Makefile.src
index 1a2d348ecb..85ecf14eac 100644
--- a/erts/emulator/test/port_bif_SUITE_data/Makefile.src
+++ b/erts/emulator/test/port_bif_SUITE_data/Makefile.src
@@ -3,7 +3,7 @@ LD = @LD@
CFLAGS = @CFLAGS@ -I@erl_include@ @DEFS@
CROSSLDFLAGS = @CROSSLDFLAGS@
-all: control_drv@dll@ port_test@exe@
+all: control_drv@dll@ port_test@exe@ sleeper@exe@
port_test@exe@: port_test@obj@
$(LD) $(CROSSLDFLAGS) -o port_test port_test@obj@ @LIBS@
@@ -11,4 +11,10 @@ port_test@exe@: port_test@obj@
port_test@obj@: port_test.c
$(CC) -c -o port_test@obj@ $(CFLAGS) port_test.c
+sleeper@exe@: sleeper@obj@
+ $(LD) $(CROSSLDFLAGS) -o sleeper sleeper@obj@ @LIBS@
+
+sleeper@obj@: sleeper.c
+ $(CC) -c -o sleeper@obj@ $(CFLAGS) sleeper.c
+
@SHLIB_RULES@
diff --git a/erts/emulator/test/port_bif_SUITE_data/sleeper.c b/erts/emulator/test/port_bif_SUITE_data/sleeper.c
new file mode 100644
index 0000000000..bd662f51a4
--- /dev/null
+++ b/erts/emulator/test/port_bif_SUITE_data/sleeper.c
@@ -0,0 +1,66 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2020. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#ifndef __WIN32__
+# include <unistd.h>
+# include <sys/time.h>
+#else
+# include "windows.h"
+# include "winbase.h"
+#endif
+#include <sys/types.h>
+
+int
+main(int argc, char *argv[])
+{
+ long int ms;
+ char *endp;
+
+ if (argc != 2) {
+ fprintf(stderr, "Invalid argument count: %d\n", argc);
+ exit(1);
+ }
+
+ errno = 0;
+ ms = strtol(argv[1], &endp, 10);
+ if (errno || argv[1] == endp || *endp != '\0' || ms < 0) {
+ if (errno == 0)
+ errno = EINVAL;
+ perror("Invalid timeout value");
+ exit(1);
+ }
+
+#ifdef __WIN32__
+ Sleep(ms);
+#else
+ {
+ struct timeval t;
+ t.tv_sec = ms/1000;
+ t.tv_usec = (ms % 1000) * 1000;
+
+ select(0, NULL, NULL, NULL, &t);
+ }
+#endif
+
+ return 0;
+}
diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl
index 13dde12e69..0e1c15e160 100644
--- a/erts/emulator/test/process_SUITE.erl
+++ b/erts/emulator/test/process_SUITE.erl
@@ -62,7 +62,8 @@
system_task_on_suspended/1,
system_task_failed_enqueue/1,
gc_request_when_gc_disabled/1,
- gc_request_blast_when_gc_disabled/1]).
+ gc_request_blast_when_gc_disabled/1,
+ otp_16436/1]).
-export([prio_server/2, prio_client/2, init/1, handle_event/2]).
-export([init_per_testcase/2, end_per_testcase/2]).
@@ -110,7 +111,8 @@ groups() ->
{system_task, [],
[no_priority_inversion, no_priority_inversion2,
system_task_blast, system_task_on_suspended, system_task_failed_enqueue,
- gc_request_when_gc_disabled, gc_request_blast_when_gc_disabled]}].
+ gc_request_when_gc_disabled, gc_request_blast_when_gc_disabled,
+ otp_16436]}].
init_per_suite(Config) ->
A0 = case application:start(sasl) of
@@ -2868,6 +2870,15 @@ gc_request_blast_when_gc_disabled(Config) when is_list(Config) ->
receive {'DOWN', M, process, P, _Reason} -> ok end,
ok.
+otp_16436(Config) when is_list(Config) ->
+ P = spawn_opt(fun () ->
+ erts_debug:dirty_io(wait, 1000)
+ end,
+ [{priority,high},link]),
+ erlang:check_process_code(P, non_existing),
+ unlink(P),
+ exit(P, kill),
+ ok.
%% Internal functions
diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl
index f61949c75b..59cf66d277 100644
--- a/erts/emulator/test/scheduler_SUITE.erl
+++ b/erts/emulator/test/scheduler_SUITE.erl
@@ -58,7 +58,8 @@
scheduler_suspend/1,
dirty_scheduler_threads/1,
poll_threads/1,
- reader_groups/1]).
+ reader_groups/1,
+ otp_16446/1]).
suite() ->
[{ct_hooks,[ts_install_cth]},
@@ -74,7 +75,8 @@ all() ->
scheduler_suspend_basic, scheduler_suspend,
dirty_scheduler_threads,
poll_threads,
- reader_groups].
+ reader_groups,
+ otp_16446].
groups() ->
[{scheduler_bind, [],
@@ -1794,6 +1796,77 @@ reader_groups_map(CPUT, Groups) ->
erlang:system_flag(cpu_topology, Old),
lists:sort(Res).
+otp_16446(Config) when is_list(Config) ->
+ ct:timetrap({minutes, 1}),
+
+ process_flag(priority, high),
+
+ DIO = erlang:system_info(dirty_io_schedulers),
+ NoPrioProcs = 10*DIO,
+ io:format("DIO = ~p~nNoPrioProcs = ~p~n", [DIO, NoPrioProcs]),
+
+ DirtyLoop = fun Loop(P, N) ->
+ erts_debug:dirty_io(wait,1),
+ receive {get, From} -> From ! {P, N}
+ after 0 -> Loop(P,N+1)
+ end
+ end,
+
+ Spawn = fun SpawnLoop(_Prio, 0, Acc) ->
+ Acc;
+ SpawnLoop(Prio, N, Acc) ->
+ Pid = spawn_opt(fun () -> DirtyLoop(Prio, 0) end,
+ [link, {priority, Prio}]),
+ SpawnLoop(Prio, N-1, [Pid|Acc])
+ end,
+
+ Ns = Spawn(normal, NoPrioProcs, []),
+ Ls = Spawn(low, NoPrioProcs, []),
+
+ receive after 10000 -> ok end,
+
+ RequestInfo = fun (P) -> P ! {get, self()} end,
+ lists:foreach(RequestInfo, Ns),
+ lists:foreach(RequestInfo, Ls),
+
+ Collect = fun CollectFun(0, LLs, NLs) ->
+ {LLs, NLs};
+ CollectFun(N, LLs, NLs) ->
+ receive
+ {low, Calls} ->
+ CollectFun(N-1, LLs+Calls, NLs);
+ {normal, Calls} ->
+ CollectFun(N-1, LLs, NLs+Calls)
+ end
+ end,
+
+ {LLs, NLs} = Collect(2*NoPrioProcs, 0, 0),
+
+ %% expected ratio 0.125, but this is not especially exact...
+ Ratio = LLs / NLs,
+
+ io:format("LLs = ~p~nNLs = ~p~nRatio = ~p~n", [LLs, NLs, Ratio]),
+
+ true = Ratio > 0.05,
+ true = Ratio < 0.5,
+
+ WaitUntilDead = fun (P) ->
+ case is_process_alive(P) of
+ false ->
+ ok;
+ true ->
+ unlink(P),
+ exit(P, kill),
+ false = is_process_alive(P)
+ end
+ end,
+
+ lists:foreach(WaitUntilDead, Ns),
+ lists:foreach(WaitUntilDead, Ls),
+ Comment = "low/normal ratio: " ++ erlang:float_to_list(Ratio,[{decimals,4}]),
+ erlang:display(Comment),
+ {comment, Comment}.
+
%%
%% Utils
%%
diff --git a/erts/emulator/test/signal_SUITE.erl b/erts/emulator/test/signal_SUITE.erl
index 4e6baa9e0e..0bfe7539b4 100644
--- a/erts/emulator/test/signal_SUITE.erl
+++ b/erts/emulator/test/signal_SUITE.erl
@@ -34,7 +34,8 @@
-export([init_per_testcase/2, end_per_testcase/2]).
% Test cases
--export([xm_sig_order/1]).
+-export([xm_sig_order/1,
+ kill2killed/1]).
init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) ->
[{testcase, Func}|Config].
@@ -53,7 +54,8 @@ suite() ->
{timetrap, {minutes, 2}}].
all() ->
- [xm_sig_order].
+ [xm_sig_order,
+ kill2killed].
%% Test that exit signals and messages are received in correct order
@@ -89,6 +91,68 @@ xm_sig_order_proc() ->
end,
xm_sig_order_proc().
+kill2killed(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ kill2killed_test(node()),
+ {ok, Node} = start_node(Config),
+ kill2killed_test(Node),
+ stop_node(Node),
+ ok.
+
+kill2killed_test(Node) ->
+ if Node == node() ->
+ io:format("Testing against local node", []);
+ true ->
+ io:format("Testing against remote node ~p", [Node])
+ end,
+ check_exit(Node, other_exit2, 1),
+ check_exit(Node, other_exit2, 2),
+ check_exit(Node, other_exit2, 9),
+ check_exit(Node, other_exit2, 10),
+ check_exit(Node, exit2, 1),
+ check_exit(Node, exit2, 2),
+ check_exit(Node, exit2, 9),
+ check_exit(Node, exit2, 10),
+ check_exit(Node, exit1, 1),
+ check_exit(Node, exit1, 2),
+ check_exit(Node, exit1, 9),
+ check_exit(Node, exit1, 10),
+ ok.
+
+check_exit(Node, Type, N) ->
+ io:format("Testing ~p length ~p~n", [Type, N]),
+ P = spawn_link_line(Node, node(), Type, N, self()),
+ if Type == other_exit2 ->
+ receive
+ {end_of_line, EOL} ->
+ exit(EOL, kill)
+ end;
+ true -> ok
+ end,
+ receive
+ {'EXIT', P, Reason} ->
+ if Type == exit1 ->
+ kill = Reason;
+ true ->
+ killed = Reason
+ end
+ end.
+
+spawn_link_line(_NodeA, _NodeB, other_exit2, 0, Tester) ->
+ Tester ! {end_of_line, self()},
+ receive after infinity -> ok end;
+spawn_link_line(_NodeA, _NodeB, exit1, 0, _Tester) ->
+ exit(kill);
+spawn_link_line(_NodeA, _NodeB, exit2, 0, _Tester) ->
+ exit(self(), kill);
+spawn_link_line(NodeA, NodeB, Type, N, Tester) ->
+ spawn_link(NodeA,
+ fun () ->
+ spawn_link_line(NodeB, NodeA, Type, N-1, Tester),
+ receive after infinity -> ok end
+ end).
+
+
%%
%% -- Internal utils --------------------------------------------------------
%%
diff --git a/erts/emulator/test/socket_SUITE.erl b/erts/emulator/test/socket_SUITE.erl
index 44a338a68f..a263ac87bc 100644
--- a/erts/emulator/test/socket_SUITE.erl
+++ b/erts/emulator/test/socket_SUITE.erl
@@ -130,6 +130,7 @@
%% *** API Options ***
api_opt_simple_otp_options/1,
+ api_opt_simple_otp_meta_option/1,
api_opt_simple_otp_rcvbuf_option/1,
api_opt_simple_otp_controlling_process/1,
api_opt_sock_acceptconn_udp/1,
@@ -203,6 +204,9 @@
api_to_recvmsg_tcp4/1,
api_to_recvmsg_tcp6/1,
+ %% Socket Registry
+ reg_s_single_open_and_close_and_count/1,
+
%% *** Socket Closure ***
sc_cpe_socket_cleanup_tcp4/1,
sc_cpe_socket_cleanup_tcp6/1,
@@ -695,6 +699,7 @@ groups() ->
{api_options_udp, [], api_options_udp_cases()},
%% {api_options_sctp, [], api_options_sctp_cases()},
{api_op_with_timeout, [], api_op_with_timeout_cases()},
+ {reg, [], reg_simple_cases()},
{socket_close, [], socket_close_cases()},
{sc_ctrl_proc_exit, [], sc_cp_exit_cases()},
{sc_local_close, [], sc_lc_cases()},
@@ -856,6 +861,7 @@ api_options_cases() ->
api_options_otp_cases() ->
[
api_opt_simple_otp_options,
+ api_opt_simple_otp_meta_option,
api_opt_simple_otp_rcvbuf_option,
api_opt_simple_otp_controlling_process
].
@@ -999,6 +1005,13 @@ api_op_with_timeout_cases() ->
api_to_recvmsg_tcp6
].
+%% Socket Registry "simple" test cases
+reg_simple_cases() ->
+ [
+ reg_s_single_open_and_close_and_count
+ ].
+
+
%% These cases tests what happens when the socket is closed/shutdown,
%% locally or remotely.
socket_close_cases() ->
@@ -2221,6 +2234,25 @@ analyze_and_print_freebsd_host_info(Version) ->
+init_per_group(GroupName, Config)
+ when (GroupName =:= sc_remote_close) orelse
+ (GroupName =:= sc_remote_shutdown) orelse
+ (GroupName =:= traffic) ->
+ io:format("init_per_group(~w) -> entry with"
+ "~n Config: ~p"
+ "~n", [GroupName, Config]),
+ %% Maybe we should skip the entire suite for this platform,
+ %% but for now we just skip these groups, which seem to
+ %% have problems (slave node start).
+ %% As stated elsewhere, its not really Fedora 16, but
+ %% the *really* slow VM that is the issue.
+ try is_old_fedora16() of
+ ok ->
+ Config
+ catch
+ throw:{skip, _} = SKIP ->
+ SKIP
+ end;
init_per_group(ttest = _GroupName, Config) ->
io:format("init_per_group(~w) -> entry with"
"~n Config: ~p"
@@ -8825,6 +8857,181 @@ api_opt_simple_otp_options() ->
i("await udp evaluator"),
ok = ?SEV_AWAIT_FINISH([Tester2]).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Perform some simple getopt and setopt otp meta option
+api_opt_simple_otp_meta_option(suite) ->
+ [];
+api_opt_simple_otp_meta_option(doc) ->
+ [];
+api_opt_simple_otp_meta_option(_Config) when is_list(_Config) ->
+ ?TT(?SECS(5)),
+ tc_try(api_opt_simple_otp_meta_option,
+ fun() -> api_opt_simple_otp_meta_option() end).
+
+api_opt_simple_otp_meta_option() ->
+ Get = fun(S) ->
+ socket:getopt(S, otp, meta)
+ end,
+ Set = fun(S, Val) ->
+ socket:setopt(S, otp, meta, Val)
+ end,
+
+ MainSeq =
+ [
+ #{desc => "monitor helper",
+ cmd => fun(#{helper := Pid}) ->
+ _ = erlang:monitor(process, Pid),
+ ok
+ end},
+
+ #{desc => "create socket",
+ cmd => fun(#{domain := Domain,
+ type := Type,
+ protocol := Protocol} = State) ->
+ Sock = sock_open(Domain, Type, Protocol),
+ {ok, State#{sock => Sock}}
+ end},
+
+ #{desc => "get default",
+ cmd => fun(#{sock := Sock}) ->
+ case Get(Sock) of
+ {ok, undefined} ->
+ ok;
+ {ok, Invalid} ->
+ {error, {invalid, Invalid}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "set value",
+ cmd => fun(#{sock := Sock} = State) ->
+ Value = make_ref(),
+ case Set(Sock, Value) of
+ ok ->
+ {ok, State#{value => Value}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "get value",
+ cmd => fun(#{sock := Sock, value := Value}) ->
+ case Get(Sock) of
+ {ok, Value} ->
+ ok;
+ {ok, Invalid} ->
+ {error, {invalid, Invalid}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "set complex value",
+ cmd => fun(#{sock := Sock} = State) ->
+ Value =
+ #{a => 1,
+ b => {2, 3},
+ c => make_ref(),
+ d => self(),
+ e => State},
+ case Set(Sock, Value) of
+ ok ->
+ {ok, State#{value := Value}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "get complex value",
+ cmd => fun(#{sock := Sock, value := Value}) ->
+ case Get(Sock) of
+ {ok, Value} ->
+ ok;
+ {ok, Invalid} ->
+ {error, {invalid, Invalid}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "start helper",
+ cmd => fun(#{helper := Pid, sock := Sock, value := Value}) ->
+ ?SEV_ANNOUNCE_START(Pid, {Sock, Value}),
+ ok
+ end},
+
+ #{desc => "wait for helper ready",
+ cmd => fun(#{helper := Pid}) ->
+ ?SEV_AWAIT_READY(Pid, helper, test)
+ end},
+
+ #{desc => "socket close",
+ cmd => fun(#{sock := Sock}) ->
+ socket:close(Sock)
+ end},
+
+ ?SEV_FINISH_NORMAL],
+
+ HelperSeq =
+ [#{desc => "await start",
+ cmd => fun (State) ->
+ {Main, {Sock, Value}} = ?SEV_AWAIT_START(),
+ {ok, State#{main => Main,
+ sock => Sock,
+ value => Value}}
+ end},
+ #{desc => "monitor main",
+ cmd => fun(#{main := Main}) ->
+ _ = erlang:monitor(process, Main),
+ ok
+ end}
+
+ #{desc => "get value",
+ cmd => fun(#{sock := Sock, value := Value}) ->
+ case Get(Sock) of
+ {ok, Value} ->
+ ok;
+ {ok, Invalid} ->
+ {error, {invalid, Invalid}};
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "set and fail",
+ cmd => fun(#{sock := Sock}) ->
+ Value = self(),
+ case Set(Sock, Value) of
+ ok ->
+ {error, only_owner_may_set};
+ {error, not_owner} ->
+ ok;
+ {error, _} = ERROR ->
+ ERROR
+ end
+ end},
+
+ #{desc => "announce ready (test)",
+ cmd => fun(#{main := Main}) ->
+ ?SEV_ANNOUNCE_READY(Main, test),
+ ok
+ end},
+
+ ?SEV_FINISH_NORMAL],
+
+
+ i("start tcp helper evaluator"),
+ Helper = ?SEV_START("tcp-helper", HelperSeq, #{}),
+
+ i("start tcp main evaluator"),
+ MainState = #{domain => inet, type => stream, protocol => tcp,
+ helper => Helper#ev.pid},
+ Main = ?SEV_START("tcp-main", MainSeq, MainState),
+
+ i("await tcp evaluators"),
+ ok = ?SEV_AWAIT_FINISH([Helper, Main]).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -15638,6 +15845,16 @@ api_opt_sock_timestamp_tcp(InitState) ->
ERROR
end
end},
+ %% Linux pecularity observed here...
+ %% Detected on Kernel 4.15.0-72 x96_64.
+ %% The option set to enable receiving timestamps just above
+ %% has failed to be effective down in "await recv reply 2
+ %% (from server, w timestamp)" below, unless we put the
+ %% sleep between setting the option and informing
+ %% the writer that it shall write to the other socket end.
+ %% A sleep 1 ms improves a lot but does not remove
+ %% problem completely. Believe it or not.
+ ?SEV_SLEEP(100),
#{desc => "announce ready (timestamp on)",
cmd => fun(#{tester := Tester}) ->
?SEV_ANNOUNCE_READY(Tester, timestamp_on),
@@ -15658,7 +15875,7 @@ api_opt_sock_timestamp_tcp(InitState) ->
ok
end},
#{desc => "await recv reply 2 (from server, w timestamp)",
- cmd => fun(#{sock := Sock, recv := Recv}) ->
+ cmd => fun(#{sock := Sock, recv := Recv, get := Get}) ->
case Recv(Sock) of
{ok, {[#{level := socket,
type := timestamp,
@@ -15668,6 +15885,8 @@ api_opt_sock_timestamp_tcp(InitState) ->
"~n ~p", [TS]),
ok;
{ok, {BadCMsgHdrs, ?BASIC_REP}} ->
+ ?SEV_EPRINT("Current timestamp value:"
+ " ~p", [Get(Sock)]),
{error, {unexpected_reply_cmsghdrs,
BadCMsgHdrs}};
{ok, {[#{level := socket,
@@ -15824,7 +16043,7 @@ api_opt_sock_timestamp_tcp(InitState) ->
?SEV_ANNOUNCE_CONTINUE(Server, accept),
ok
end},
- ?SEV_SLEEP(?SECS(1)),
+%%% ?SEV_SLEEP(?SECS(1)),
#{desc => "order client to continue (with connect)",
cmd => fun(#{client := Client} = _State) ->
?SEV_ANNOUNCE_CONTINUE(Client, connect),
@@ -15999,8 +16218,6 @@ api_opt_sock_timestamp_tcp(InitState) ->
ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
-
-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Tests that the add_mambership and drop_membership ip options work.
@@ -22902,6 +23119,319 @@ api_to_recvmsg_tcp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% %%
+%% REGISTRY %%
+%% %%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% We create a bunch of different sockets and ensure that the registry
+%% has the correct info.
+
+reg_s_single_open_and_close_and_count(suite) ->
+ [];
+reg_s_single_open_and_close_and_count(doc) ->
+ [];
+reg_s_single_open_and_close_and_count(_Config) when is_list(_Config) ->
+ ?TT(?SECS(10)),
+ tc_try(reg_s_single_open_and_close_and_count,
+ fun() ->
+ ok = reg_s_single_open_and_close_and_count()
+ end).
+
+
+reg_s_single_open_and_close_and_count() ->
+ SupportsIPV6 =
+ case (catch has_support_ipv6()) of
+ ok ->
+ true;
+ _ ->
+ false
+ end,
+ SupportsLOCAL =
+ case (catch has_support_unix_domain_socket()) of
+ ok ->
+ true;
+ _ ->
+ false
+ end,
+ SupportsSCTP =
+ case (catch has_support_sctp()) of
+ ok ->
+ true;
+ _ ->
+ false
+ end,
+ InitSockInfos =
+ [
+ {inet, stream, tcp},
+ {inet, dgram, udp}
+ ] ++
+ case SupportsIPV6 of
+ true ->
+ [
+ {inet6, stream, tcp},
+ {inet6, dgram, udp}
+ ];
+ false ->
+ []
+ end ++
+ case SupportsLOCAL of
+ true ->
+ [
+ {local, stream, default},
+ {local, dgram, default}
+ ];
+ false ->
+ []
+ end ++
+ [
+ {inet, stream, tcp},
+ {inet, dgram, udp}
+ ] ++
+ case SupportsSCTP of
+ true ->
+ [
+ {inet, seqpacket, sctp},
+ {inet, seqpacket, sctp}
+ ];
+ false ->
+ []
+ end ++
+ [
+ {inet, stream, tcp},
+ {inet, dgram, udp}
+ ] ++
+ case SupportsSCTP andalso SupportsIPV6 of
+ true ->
+ [
+ {inet6, seqpacket, sctp},
+ {inet6, seqpacket, sctp}
+ ];
+ false ->
+ []
+ end,
+
+ i("open sockets"),
+ Socks =
+ [fun({Domain, Type, Proto}) ->
+ i("open socket: ~w, ~w, ~w", [Domain, Type, Proto]),
+ {ok, Sock} = socket:open(Domain, Type, Proto),
+ Sock
+ end(InitSockInfo) || InitSockInfo <- InitSockInfos],
+
+ ?SLEEP(1000),
+
+
+ %% **** Total Number Of Sockets ****
+
+ NumSocks1 = length(Socks),
+ NumberOf1 = socket:number_of(),
+
+ i("verify (total) number of sockets(1): ~w, ~w", [NumSocks1, NumberOf1]),
+ case (NumSocks1 =:= NumberOf1) of
+ true ->
+ ok;
+ false ->
+ exit({wrong_number_of_sockets1, NumSocks1, NumberOf1})
+ end,
+
+
+ %% **** Number Of IPv4 TCP Sockets ****
+
+ %% inet, stream, tcp
+ SiNumTCP = reg_si_num(InitSockInfos, inet, stream, tcp),
+ SrNumTCP = reg_sr_num(inet, stream, tcp),
+
+ i("verify number of IPv4 TCP sockets: ~w, ~w", [SiNumTCP, SrNumTCP]),
+ case (SiNumTCP =:= SrNumTCP) of
+ true ->
+ ok;
+ false ->
+ exit({wrong_number_of_ipv4_tcp_sockets, SiNumTCP, SrNumTCP})
+ end,
+
+
+ %% **** Number Of IPv4 UDP Sockets ****
+
+ %% inet, dgram, udp
+ SiNumUDP = reg_si_num(InitSockInfos, inet, dgram, udp),
+ SrNumUDP = reg_sr_num(inet, dgram, udp),
+
+ i("verify number of IPv4 UDP sockets: ~w, ~w", [SiNumUDP, SrNumUDP]),
+ case (SiNumUDP =:= SrNumUDP) of
+ true ->
+ ok;
+ false ->
+ exit({wrong_number_of_ipv4_udp_sockets, SiNumUDP, SrNumUDP})
+ end,
+
+
+ %% **** Number Of IPv4 SCTP Sockets ****
+
+ %% inet, seqpacket, sctp
+ SiNumSCTP = reg_si_num(InitSockInfos, inet, seqpacket, sctp),
+ SrNumSCTP = reg_sr_num(inet, seqpacket, sctp),
+
+ i("verify number of IPv4 SCTP sockets: ~w, ~w", [SiNumSCTP, SrNumSCTP]),
+ case (SiNumSCTP =:= SrNumSCTP) of
+ true ->
+ ok;
+ false ->
+ exit({wrong_number_of_sctp_sockets, SiNumSCTP, SrNumSCTP})
+ end,
+
+
+ %% **** Number Of IPv4 Sockets ****
+
+ %% inet
+ SiNumINET = reg_si_num(InitSockInfos, inet),
+ SrNumINET = reg_sr_num(inet),
+
+ i("verify number of IPv4 sockets: ~w, ~w", [SiNumINET, SrNumINET]),
+ case (SiNumINET =:= SrNumINET) of
+ true ->
+ ok;
+ false ->
+ exit({wrong_number_of_ipv4_sockets, SiNumINET, SrNumINET})
+ end,
+
+
+ %% **** Number Of IPv6 Sockets ****
+
+ %% inet6
+ SiNumINET6 = reg_si_num(InitSockInfos, inet6),
+ SrNumINET6 = reg_sr_num(inet6),
+
+ i("verify number of IPv6 sockets: ~w, ~w", [SiNumINET6, SrNumINET6]),
+ case (SiNumINET6 =:= SrNumINET6) of
+ true ->
+ ok;
+ false ->
+ exit({wrong_number_of_ipv6_sockets, SiNumINET6, SrNumINET6})
+ end,
+
+
+ %% **** Number Of Unix Domain Sockets Sockets ****
+
+ %% local
+ SiNumLOCAL = reg_si_num(InitSockInfos, local),
+ SrNumLOCAL = reg_sr_num(local),
+
+ i("verify number of Unix Domain Sockets sockets: ~w, ~w",
+ [SiNumLOCAL, SrNumLOCAL]),
+ case (SiNumLOCAL =:= SrNumLOCAL) of
+ true ->
+ ok;
+ false ->
+ exit({wrong_number_of_local_sockets, SiNumLOCAL, SrNumLOCAL})
+ end,
+
+
+ %% **** Close *all* Sockets then verify Number Of Sockets ****
+
+ i("close sockets"),
+ lists:foreach(fun(S) ->
+ i("close socket"),
+ ok = socket:close(S)
+ end, Socks),
+
+ ?SLEEP(1000),
+
+ NumSocks2 = 0,
+ NumberOf2 = socket:number_of(),
+
+ i("verify number of sockets(2): ~w, ~w", [NumSocks2, NumberOf2]),
+ case (NumSocks2 =:= NumberOf2) of
+ true ->
+ ok;
+ false ->
+ exit({wrong_number_of_sockets2, NumSocks2, NumberOf2})
+ end,
+
+ ok.
+
+
+reg_si_num(SocksInfo, Domain)
+ when ((Domain =:= inet) orelse (Domain =:= inet6) orelse (Domain =:= local)) ->
+ reg_si_num(SocksInfo, Domain, undefined, undefined);
+reg_si_num(SocksInfo, Type)
+ when ((Type =:= stream) orelse (Type =:= dgram) orelse (Type =:= seqpacket)) ->
+ reg_si_num(SocksInfo, undefined, Type, undefined);
+reg_si_num(SocksInfo, Proto)
+ when ((Proto =:= sctp) orelse (Proto =:= tcp) orelse (Proto =:= udp)) ->
+ reg_si_num(SocksInfo, undefined, undefined, Proto).
+
+reg_si_num(SocksInfo, Domain, undefined, undefined) ->
+ F = fun({D, _T, _P}) when (D =:= Domain) -> true;
+ (_) -> false
+ end,
+ reg_si_num2(F, SocksInfo);
+reg_si_num(SocksInfo, undefined, Type, undefined) ->
+ F = fun({_D, T, _P}) when (T =:= Type) -> true;
+ (_) -> false
+ end,
+ reg_si_num2(F, SocksInfo);
+reg_si_num(SocksInfo, undefined, undefined, Proto) ->
+ F = fun({_D, _T, P}) when (P =:= Proto) -> true;
+ (_) -> false
+ end,
+ reg_si_num2(F, SocksInfo);
+reg_si_num(SocksInfo, Domain, Type, Proto) ->
+ F = fun({D, T, P}) when (D =:= Domain) andalso
+ (T =:= Type) andalso
+ (P =:= Proto) ->
+ true;
+ (_) ->
+ false
+ end,
+ reg_si_num2(F, SocksInfo).
+
+reg_si_num2(F, SocksInfo) ->
+ length(lists:filter(F, SocksInfo)).
+
+
+reg_sr_num(Domain)
+ when ((Domain =:= inet) orelse (Domain =:= inet6)) ->
+ length(socket:which_sockets(Domain));
+reg_sr_num(Domain)
+ when (Domain =:= local) ->
+ reg_sr_num(Domain, undefined, undefined);
+reg_sr_num(Type)
+ when ((Type =:= stream) orelse (Type =:= dgram) orelse (Type =:= seqpacket)) ->
+ length(socket:which_sockets(Type));
+reg_sr_num(Proto)
+ when ((Proto =:= sctp) orelse (Proto =:= tcp) orelse (Proto =:= udp)) ->
+ length(socket:which_sockets(Proto)).
+
+reg_sr_num(Domain, undefined, undefined) ->
+ F = fun(#{domain := D}) when (D =:= Domain) ->
+ true;
+ (_X) ->
+ false
+ end,
+ reg_sr_num2(F);
+reg_sr_num(Domain, Type, Proto) ->
+ F = fun(#{domain := D,
+ type := T,
+ protocol := P}) when (D =:= Domain) andalso
+ (T =:= Type) andalso
+ (P =:= Proto) ->
+ true;
+ (_X) ->
+ %% i("reg_sr_num -> not counting: "
+ %% "~n ~p", [_X]),
+ false
+ end,
+ reg_sr_num2(F).
+
+reg_sr_num2(F) ->
+ length(socket:which_sockets(F)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% %%
%% SOCKET CLOSURE %%
%% %%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -23916,7 +24446,9 @@ sc_lc_recvfrom_response_udpL(_Config) when is_list(_Config) ->
tc_try(sc_lc_recvfrom_response_udpL,
fun() -> has_support_unix_domain_socket() end,
fun() ->
- Recv = fun(Sock, To) -> socket:recvfrom(Sock, [], To) end,
+ Recv = fun(Sock, To) ->
+ socket:recvfrom(Sock, [], To)
+ end,
InitState = #{domain => local,
protocol => default,
recv => Recv},
@@ -23950,8 +24482,20 @@ sc_lc_receive_response_udp(InitState) ->
#{desc => "open socket",
cmd => fun(#{domain := Domain, protocol := Proto} = State) ->
Sock = sock_open(Domain, dgram, Proto),
- SA = sock_sockname(Sock),
- {ok, State#{sock => Sock, sa => SA}}
+ %% SA = sock_sockname(Sock),
+ case socket:sockname(Sock) of
+ {ok, SA} ->
+ {ok, State#{sock => Sock, sa => SA}};
+ {error, eafnosupport = Reason} ->
+ ?SEV_IPRINT("Failed get socket name: "
+ "~n ~p", [Reason]),
+ (catch socket:close(Sock)),
+ {skip, Reason};
+ {error, Reason} = ERROR ->
+ ?SEV_EPRINT("Failed get socket name: "
+ "~n ~p", [Reason]),
+ ERROR
+ end
end},
#{desc => "bind socket",
cmd => fun(#{sock := Sock, local_sa := LSA}) ->
@@ -27177,6 +27721,23 @@ traffic_send_and_recv_tcp(InitState) ->
cmd => fun(#{lsock := LSock}) ->
socket:listen(LSock)
end},
+ #{desc => "initial (listen socket) counter validation (=zero)",
+ cmd => fun(#{lsock := LSock} = _State) ->
+ try socket:info(LSock) of
+ #{counters := Counters} ->
+ ?SEV_IPRINT("Validate initial listen socket counters: "
+ "~s", [format_counters(listen,
+ Counters)]),
+ traffic_sar_counters_validation(Counters)
+ catch
+ C:E:S ->
+ ?SEV_EPRINT("Failed get socket info: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ {error, {socket_info_failed, {C, E, S}}}
+ end
+ end},
#{desc => "announce ready (init)",
cmd => fun(#{domain := local,
tester := Tester,
@@ -27197,8 +27758,22 @@ traffic_send_and_recv_tcp(InitState) ->
#{desc => "accept",
cmd => fun(#{lsock := LSock} = State) ->
case socket:accept(LSock) of
- {ok, Sock} ->
- {ok, State#{csock => Sock}};
+ {ok, CSock} ->
+ #{counters := LCnts} = socket:info(LSock),
+ ?SEV_IPRINT("Validate listen counters: "
+ "~s", [format_counters(listen,
+ LCnts)]),
+ traffic_sar_counters_validation(
+ LCnts,
+ [{acc_success, 1},
+ {acc_fails, 0},
+ {acc_tries, 1},
+ {acc_waits, 0}]),
+ #{counters := CCnts} = socket:info(CSock),
+ ?SEV_IPRINT("Validate initial accept counters: "
+ "~s", [format_counters(CCnts)]),
+ traffic_sar_counters_validation(CCnts),
+ {ok, State#{csock => CSock}};
{error, _} = ERROR ->
ERROR
end
@@ -27208,7 +27783,7 @@ traffic_send_and_recv_tcp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("Validate initial counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(Counters)
catch
C:E:S ->
@@ -27248,12 +27823,13 @@ traffic_send_and_recv_tcp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, Pkg},
- {read_byte, Byte},
- {read_tries, any}])
+ [{read_pkg, Pkg},
+ {read_byte, Byte},
+ {read_tries, any},
+ {read_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -27295,15 +27871,17 @@ traffic_send_and_recv_tcp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -27346,15 +27924,17 @@ traffic_send_and_recv_tcp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -27398,15 +27978,17 @@ traffic_send_and_recv_tcp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -27555,12 +28137,13 @@ traffic_send_and_recv_tcp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{write_pkg, SPkg},
- {write_byte, SByte},
- {write_tries, any}])
+ [{write_pkg, SPkg},
+ {write_byte, SByte},
+ {write_tries, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -27593,23 +28176,25 @@ traffic_send_and_recv_tcp(InitState) ->
end
end},
#{desc => "validate (recv 1)",
- cmd => fun(#{sock := Sock,
- read_pkg := RPkg,
- read_byte := RByte,
+ cmd => fun(#{sock := Sock,
+ read_pkg := RPkg,
+ read_byte := RByte,
write_pkg := SPkg,
write_byte := SByte} = _State) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -27653,15 +28238,17 @@ traffic_send_and_recv_tcp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -27704,15 +28291,17 @@ traffic_send_and_recv_tcp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -27960,34 +28549,153 @@ traffic_send_and_recv_tcp(InitState) ->
ok = ?SEV_AWAIT_FINISH([Server, Client, Tester]).
+format_counters(Counters) ->
+ format_counters(traffic, Counters).
+
+format_counters(Type, Counters) when (Type =:= listen) orelse (Type =:= traffic) ->
+ format_counters(" ", Type, Counters).
+
+format_counters(Prefix, traffic, Counters) ->
+ ReadByte = proplists:get_value(read_byte, Counters, -1),
+ ReadFails = proplists:get_value(read_fails, Counters, -1),
+ ReadPkg = proplists:get_value(read_pkg, Counters, -1),
+ ReadPkgMax = proplists:get_value(read_pkg_max, Counters, -1),
+ ReadTries = proplists:get_value(read_tries, Counters, -1),
+ ReadWaits = proplists:get_value(read_waits, Counters, -1),
+ WriteByte = proplists:get_value(write_byte, Counters, -1),
+ WriteFails = proplists:get_value(write_fails, Counters, -1),
+ WritePkg = proplists:get_value(write_pkg, Counters, -1),
+ WritePkgMax = proplists:get_value(write_pkg_max, Counters, -1),
+ WriteTries = proplists:get_value(write_tries, Counters, -1),
+ WriteWaits = proplists:get_value(write_waits, Counters, -1),
+ f("~n~sNumber Of Read Bytes: ~p"
+ "~n~sNumber Of Read Fails: ~p"
+ "~n~sNumber Of Read Packages: ~p"
+ "~n~sNumber Of Read Tries: ~p"
+ "~n~sNumber Of Read Waits: ~p"
+ "~n~sMax Read Package Size: ~p"
+ "~n~sNumber Of Write Bytes: ~p"
+ "~n~sNumber Of Write Fails: ~p"
+ "~n~sNumber Of Write Packages: ~p"
+ "~n~sNumber Of Write Tries: ~p"
+ "~n~sNumber Of Write Waits: ~p"
+ "~n~sMax Write Package Size: ~p",
+ [Prefix, ReadByte,
+ Prefix, ReadFails,
+ Prefix, ReadPkg,
+ Prefix, ReadTries,
+ Prefix, ReadWaits,
+ Prefix, ReadPkgMax,
+ Prefix, WriteByte,
+ Prefix, WriteFails,
+ Prefix, WritePkg,
+ Prefix, WriteTries,
+ Prefix, WriteWaits,
+ Prefix, WritePkgMax]);
+
+format_counters(Prefix, listen, Counters) ->
+ AccSuccess = proplists:get_value(acc_success, Counters, -1),
+ AccFails = proplists:get_value(acc_fails, Counters, -1),
+ AccTries = proplists:get_value(acc_tries, Counters, -1),
+ AccWaits = proplists:get_value(acc_waits, Counters, -1),
+ f("~n~sNumber Of Successful Accepts: ~p"
+ "~n~sNumber Of Failed Accepts: ~p"
+ "~n~sNumber Of Accept Attempts: ~p"
+ "~n~sNumber Of Accept Waits: ~p",
+ [Prefix, AccSuccess,
+ Prefix, AccFails,
+ Prefix, AccTries,
+ Prefix, AccWaits]).
+
+all_counters() ->
+ [
+ read_byte,
+ read_fails,
+ read_pkg,
+ read_pkg_max,
+ read_tries,
+ read_waits,
+ write_byte,
+ write_fails,
+ write_pkg,
+ write_pkg_max,
+ write_tries,
+ write_waits,
+ acc_success,
+ acc_fails,
+ acc_tries,
+ acc_waits
+ ].
+
+zero_counters() ->
+ [{Cnt, 0} || Cnt <- all_counters()].
+
+any_counters() ->
+ [{Cnt, any} || Cnt <- all_counters()].
+
+
+%% This function ensures that we have a list of "validate counters"
+%% that have an entry for each existing counter.
+
+ensure_counters(Counters) ->
+ ensure_counters(any_counters(), Counters, []).
+
+ensure_counters([], [], Acc) ->
+ lists:reverse(Acc);
+ensure_counters([{Cnt, Val}|DefCounters], Counters, Acc) ->
+ case lists:keysearch(Cnt, 1, Counters) of
+ {value, {Cnt, _} = T} ->
+ Counters2 = lists:keydelete(Cnt, 1, Counters),
+ ensure_counters(DefCounters, Counters2, [T|Acc]);
+ false ->
+ ensure_counters(DefCounters, Counters, [{Cnt, Val}|Acc])
+ end.
traffic_sar_counters_validation(Counters) ->
- traffic_sar_counters_validation(Counters, []).
+ traffic_sar_counters_validation2(Counters, zero_counters()).
-traffic_sar_counters_validation(Counters, []) ->
+traffic_sar_counters_validation(Counters, ValidateCounters) ->
+ traffic_sar_counters_validation2(Counters, ensure_counters(ValidateCounters)).
+
+traffic_sar_counters_validation2(Counters, []) ->
+ %% ?SEV_IPRINT("traffic_sar_counters_validation2 -> Remaining Counters: "
+ %% "~n ~p", [Counters]),
(catch lists:foreach(
fun({_Cnt, 0}) -> ok;
- ({Cnt, Val}) -> throw({error, {invalid_counter, Cnt, Val}})
+ ({Cnt, Val}) ->
+ throw({error, {invalid_counter, Cnt, Val}})
end,
Counters));
-traffic_sar_counters_validation(Counters, [{Cnt, Val}|ValidateCounters]) ->
+traffic_sar_counters_validation2(Counters, [{Cnt, Val}|ValidateCounters]) ->
+ %% ?SEV_IPRINT("traffic_sar_counters_validation2 -> try validate ~w when"
+ %% "~n Counters: ~p"
+ %% "~n ValidateCounters: ~p", [Cnt, Counters, ValidateCounters]),
case lists:keysearch(Cnt, 1, Counters) of
{value, {Cnt, Val}} ->
+ %% ?SEV_IPRINT("traffic_sar_counters_validation2 -> ~w validated", [Cnt]),
Counters2 = lists:keydelete(Cnt, 1, Counters),
- traffic_sar_counters_validation(Counters2, ValidateCounters);
+ traffic_sar_counters_validation2(Counters2, ValidateCounters);
{value, {Cnt, _Val}} when (Val =:= any) ->
+ %% ?SEV_IPRINT("traffic_sar_counters_validation2 -> "
+ %% "~w validated (any) when"
+ %% "~n Counters: ~p", [Cnt, Counters]),
Counters2 = lists:keydelete(Cnt, 1, Counters),
- traffic_sar_counters_validation(Counters2, ValidateCounters);
+ traffic_sar_counters_validation2(Counters2, ValidateCounters);
{value, {Cnt, InvVal}} ->
+ ?SEV_EPRINT("traffic_sar_counters_validation2 -> ~w validation failed: "
+ "~n Expected Value: ~p"
+ "~n Actual Value: ~p", [Cnt, Val, InvVal]),
{error, {invalid_counter, Cnt, InvVal, Val}};
false ->
+ ?SEV_EPRINT("traffic_sar_counters_validation2 -> "
+ "~w validation failed: Unknown", [Cnt]),
{error, {unknown_counter, Cnt, Counters}}
end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% This test case is intended to (simply) test that the counters
+%% This test case is intended to (simply) test the counters
%% for both read and write.
%% So that its easy to extend, we use fun's for read and write.
%% We use UDP on IPv4.
@@ -28013,7 +28721,7 @@ traffic_sendto_and_recvfrom_counters_udp4(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% This test case is intended to (simply) test that the counters
+%% This test case is intended to (simply) test the counters
%% for both read and write.
%% So that its easy to extend, we use fun's for read and write.
%% We use UDP on IPv6.
@@ -28040,7 +28748,7 @@ traffic_sendto_and_recvfrom_counters_udp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% This test case is intended to (simply) test that the counters
+%% This test case is intended to (simply) test the counters
%% for both read and write.
%% So that its easy to extend, we use fun's for read and write.
%% We use default (UDP) on local.
@@ -28067,7 +28775,7 @@ traffic_sendto_and_recvfrom_counters_udpL(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% This test case is intended to (simply) test that the counters
+%% This test case is intended to (simply) test the counters
%% for both read and write.
%% So that its easy to extend, we use fun's for read and write.
%% We use UDP on IPv4.
@@ -28101,7 +28809,7 @@ traffic_sendmsg_and_recvmsg_counters_udp4(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% This test case is intended to (simply) test that the counters
+%% This test case is intended to (simply) test the counters
%% for both read and write.
%% So that its easy to extend, we use fun's for read and write.
%% We use UDP on IPv6.
@@ -28136,7 +28844,7 @@ traffic_sendmsg_and_recvmsg_counters_udp6(_Config) when is_list(_Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%% This test case is intended to (simply) test that the counters
+%% This test case is intended to (simply) test the counters
%% for both read and write.
%% So that its easy to extend, we use fun's for read and write.
%% We use default (UDP) on local.
@@ -28226,7 +28934,7 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("Validate initial counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(Counters)
catch
C:E:S ->
@@ -28274,7 +28982,7 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
[{read_pkg, Pkg},
@@ -28322,7 +29030,7 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
[{read_pkg, RPkg},
@@ -28374,7 +29082,7 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
[{read_pkg, RPkg},
@@ -28427,7 +29135,7 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
[{read_pkg, RPkg},
@@ -28536,7 +29244,7 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("Validate initial counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(Counters)
catch
C:E:S ->
@@ -28579,12 +29287,13 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{write_pkg, SPkg},
- {write_byte, SByte},
- {write_tries, any}])
+ [{write_pkg, SPkg},
+ {write_byte, SByte},
+ {write_tries, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -28637,15 +29346,17 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -28690,15 +29401,17 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -28755,15 +29468,17 @@ traffic_send_and_recv_udp(InitState) ->
try socket:info(Sock) of
#{counters := Counters} ->
?SEV_IPRINT("validate counters: "
- "~n ~p", [Counters]),
+ "~s", [format_counters(Counters)]),
traffic_sar_counters_validation(
Counters,
- [{read_pkg, RPkg},
- {read_byte, RByte},
- {write_pkg, SPkg},
- {write_byte, SByte},
- {read_tries, any},
- {write_tries, any}])
+ [{read_pkg, RPkg},
+ {read_byte, RByte},
+ {write_pkg, SPkg},
+ {write_byte, SByte},
+ {read_tries, any},
+ {write_tries, any},
+ {read_pkg_max, any},
+ {write_pkg_max, any}])
catch
C:E:S ->
?SEV_EPRINT("Failed get socket info: "
@@ -31478,7 +32193,7 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
client := Client} = State) ->
case ?SEV_AWAIT_READY(Client, client, send,
[{server, Server}]) of
- {ok, {_, _, _, _} = Result} ->
+ {ok, {_, _, _, _, _} = Result} ->
?SEV_IPRINT("client result: "
"~n ~p", [Result]),
{ok, State#{client_result => Result}};
@@ -31514,7 +32229,7 @@ traffic_ping_pong_send_and_receive_tcp2(InitState) ->
client_result := CRes,
num := Num} = State) ->
{SSent, SReceived, SStart, SStop} = SRes,
- {CSent, CReceived, CStart, CStop} = CRes,
+ {CSent, CReceived, _, CStart, CStop} = CRes,
STime = tdiff(SStart, SStop),
CTime = tdiff(CStart, CStop),
%% Note that the sizes we are counting is only
@@ -31768,9 +32483,10 @@ tpp_tcp_client_msg_exchange_loop(Sock, _Send, _Recv, _Msg,
Num, Num, Sent, Received,
Start) ->
Stop = ?LIB:timestamp(),
+ Info = socket:info(Sock),
case socket:close(Sock) of
ok ->
- {Sent, Received, Start, Stop};
+ {Sent, Received, Info, Start, Stop};
{error, Reason} ->
exit({failed_closing, Reason})
end;
diff --git a/erts/emulator/test/socket_test_lib.erl b/erts/emulator/test/socket_test_lib.erl
index 39cbf0c79f..f05796cbcf 100644
--- a/erts/emulator/test/socket_test_lib.erl
+++ b/erts/emulator/test/socket_test_lib.erl
@@ -194,49 +194,34 @@ which_local_host_info(Domain) ->
which_local_host_info(_Domain, []) ->
{error, no_address};
-which_local_host_info(Domain, [{"lo" ++ _, _}|IFL]) ->
- which_local_host_info(Domain, IFL);
which_local_host_info(Domain, [{"docker" ++ _, _}|IFL]) ->
which_local_host_info(Domain, IFL);
which_local_host_info(Domain, [{"br-" ++ _, _}|IFL]) ->
which_local_host_info(Domain, IFL);
which_local_host_info(Domain, [{Name, IFO}|IFL]) ->
- try which_local_host_info2(Domain, IFO) of
- Info ->
- {ok, Info#{name => Name}}
- catch
- throw:_:_ ->
+ case if_is_running_and_not_loopback(IFO) of
+ true ->
+ try which_local_host_info2(Domain, IFO) of
+ Info ->
+ {ok, Info#{name => Name}}
+ catch
+ throw:_:_ ->
+ which_local_host_info(Domain, IFL)
+ end;
+ false ->
which_local_host_info(Domain, IFL)
end;
which_local_host_info(Domain, [_|IFL]) ->
which_local_host_info(Domain, IFL).
-%% which_local_host_info2(Domain, IFO) ->
-%% case lists:keysearch(flags, 1, IFO) of
-%% {value, {flags, Flags}} ->
-%% which_local_host_info2(Domain, IFO, Flags);
-%% false ->
-%% {error, no_flags}
-%% end.
-
-
-%% which_local_host_info2(_Domain, [], _Flags) ->
-%% {error, no_address};
-%% which_local_host_info2(inet = _Domain, [{addr, Addr}|_IFO], Flags)
-%% when (size(Addr) =:= 4) andalso (element(1, Addr) =/= 127) ->
-%% {ok, {Flags, Addr}};
-%% which_local_host_info2(inet6 = _Domain, [{addr, Addr}|_IFO], Flags)
-%% when (size(Addr) =:= 8) andalso
-%% (element(1, Addr) =/= 0) andalso
-%% (element(1, Addr) =/= 16#fe80) ->
-%% {ok, {Flags, Addr}};
-%% which_local_host_info2(Domain, [_|IFO], Flags) ->
-%% which_local_host_info2(Domain, IFO, Flags).
-
-%% foo(Info, inet = Domain, IFO) ->
-%% foo(Info, Domain, IFO, [flags, addr, netmask, broadaddr, hwaddr]);
-%% foo(Info, inet6 = Domain, IFO) ->
-%% foo(Info, Domain, IFO, [flags, addr, netmask, hwaddr]).
+if_is_running_and_not_loopback(If) ->
+ lists:keymember(flags, 1, If) andalso
+ begin
+ {value, {flags, Flags}} = lists:keysearch(flags, 1, If),
+ (not lists:member(loopback, Flags)) andalso
+ lists:member(running, Flags)
+ end.
+
which_local_host_info2(inet = _Domain, IFO) ->
Addr = which_local_host_info3(addr, IFO,
diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl
index 15fe13c8c0..cdfc4f2882 100644
--- a/erts/emulator/test/timer_bif_SUITE.erl
+++ b/erts/emulator/test/timer_bif_SUITE.erl
@@ -30,7 +30,8 @@
cleanup/1, evil_timers/1, registered_process/1, same_time_yielding/1,
same_time_yielding_with_cancel/1, same_time_yielding_with_cancel_other/1,
% same_time_yielding_with_cancel_other_accessor/1,
- auto_cancel_yielding/1]).
+ auto_cancel_yielding/1,
+ suspended_scheduler_timeout/1]).
-include_lib("common_test/include/ct.hrl").
@@ -68,7 +69,8 @@ all() ->
same_time_yielding, same_time_yielding_with_cancel,
same_time_yielding_with_cancel_other,
% same_time_yielding_with_cancel_other_accessor,
- auto_cancel_yielding].
+ auto_cancel_yielding,
+ suspended_scheduler_timeout].
%% Basic start_timer/3 functionality
@@ -630,6 +632,31 @@ auto_cancel_yielding(Config) when is_list(Config) ->
Mem = mem(),
ok.
+suspended_scheduler_timeout(Config) when is_list(Config) ->
+ Ref = make_ref(),
+ SchdlrsOnln = erlang:system_info(schedulers_online),
+ lists:foreach(fun (Sched) ->
+ process_flag(scheduler, Sched),
+ erlang:send_after(1000, self(), {Ref, Sched})
+ end,
+ lists:seq(1, SchdlrsOnln)),
+ process_flag(scheduler, 0),
+ erlang:system_flag(schedulers_online, 1),
+ try
+ lists:foreach(fun (Sched) ->
+ receive
+ {Ref, Sched} ->
+ ok
+ after 2000 ->
+ ct:fail({missing_timeout, Sched})
+ end
+ end,
+ lists:seq(1, SchdlrsOnln))
+ after
+ erlang:system_flag(schedulers_online, SchdlrsOnln)
+ end,
+ ok.
+
process_is_cleaned_up(P) when is_pid(P) ->
undefined == erts_debug:get_internal_state({process_status, P}).
diff --git a/erts/preloaded/ebin/atomics.beam b/erts/preloaded/ebin/atomics.beam
index 610264de8f..aa246f8808 100644
--- a/erts/preloaded/ebin/atomics.beam
+++ b/erts/preloaded/ebin/atomics.beam
Binary files differ
diff --git a/erts/preloaded/ebin/counters.beam b/erts/preloaded/ebin/counters.beam
index df4a3dce2d..1fb85276f9 100644
--- a/erts/preloaded/ebin/counters.beam
+++ b/erts/preloaded/ebin/counters.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_init.beam b/erts/preloaded/ebin/erl_init.beam
index 511f38624d..04559ff767 100644
--- a/erts/preloaded/ebin/erl_init.beam
+++ b/erts/preloaded/ebin/erl_init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam
index 7723e420fe..b8adf71297 100644
--- a/erts/preloaded/ebin/erl_prim_loader.beam
+++ b/erts/preloaded/ebin/erl_prim_loader.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erl_tracer.beam b/erts/preloaded/ebin/erl_tracer.beam
index 18a06a7446..4430489710 100644
--- a/erts/preloaded/ebin/erl_tracer.beam
+++ b/erts/preloaded/ebin/erl_tracer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam
index d995c7bf49..b744d97a41 100644
--- a/erts/preloaded/ebin/erlang.beam
+++ b/erts/preloaded/ebin/erlang.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_code_purger.beam b/erts/preloaded/ebin/erts_code_purger.beam
index 16b1930635..a94b37854e 100644
--- a/erts/preloaded/ebin/erts_code_purger.beam
+++ b/erts/preloaded/ebin/erts_code_purger.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
index b67b682a6d..dd92fb9582 100644
--- a/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
+++ b/erts/preloaded/ebin/erts_dirty_process_signal_handler.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam
index b648a1c223..d52ae9a2dc 100644
--- a/erts/preloaded/ebin/erts_internal.beam
+++ b/erts/preloaded/ebin/erts_internal.beam
Binary files differ
diff --git a/erts/preloaded/ebin/erts_literal_area_collector.beam b/erts/preloaded/ebin/erts_literal_area_collector.beam
index 72d347f401..44103e5d56 100644
--- a/erts/preloaded/ebin/erts_literal_area_collector.beam
+++ b/erts/preloaded/ebin/erts_literal_area_collector.beam
Binary files differ
diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam
index be3036d4f2..06074d1717 100644
--- a/erts/preloaded/ebin/init.beam
+++ b/erts/preloaded/ebin/init.beam
Binary files differ
diff --git a/erts/preloaded/ebin/persistent_term.beam b/erts/preloaded/ebin/persistent_term.beam
index bb889f181e..dc4a1aceb5 100644
--- a/erts/preloaded/ebin/persistent_term.beam
+++ b/erts/preloaded/ebin/persistent_term.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_buffer.beam b/erts/preloaded/ebin/prim_buffer.beam
index e7c8adf589..a54a956fac 100644
--- a/erts/preloaded/ebin/prim_buffer.beam
+++ b/erts/preloaded/ebin/prim_buffer.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam
index 6b3e0220cc..7b39f3e5ba 100644
--- a/erts/preloaded/ebin/prim_eval.beam
+++ b/erts/preloaded/ebin/prim_eval.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam
index d4cb52e5a8..d0ef080a30 100644
--- a/erts/preloaded/ebin/prim_file.beam
+++ b/erts/preloaded/ebin/prim_file.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index 2293728375..197ff59503 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_net.beam b/erts/preloaded/ebin/prim_net.beam
index 02dea609fa..76d4f0fc69 100644
--- a/erts/preloaded/ebin/prim_net.beam
+++ b/erts/preloaded/ebin/prim_net.beam
Binary files differ
diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam
index bcdd836d5b..75413bb065 100644
--- a/erts/preloaded/ebin/prim_zip.beam
+++ b/erts/preloaded/ebin/prim_zip.beam
Binary files differ
diff --git a/erts/preloaded/ebin/socket.beam b/erts/preloaded/ebin/socket.beam
index 3d01d19a67..1a5f34f3ee 100644
--- a/erts/preloaded/ebin/socket.beam
+++ b/erts/preloaded/ebin/socket.beam
Binary files differ
diff --git a/erts/preloaded/ebin/socket_registry.beam b/erts/preloaded/ebin/socket_registry.beam
new file mode 100644
index 0000000000..a5eb2c190f
--- /dev/null
+++ b/erts/preloaded/ebin/socket_registry.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index 16bc893d41..14558a7424 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile
index 38b85915cc..d2153f23e1 100644
--- a/erts/preloaded/src/Makefile
+++ b/erts/preloaded/src/Makefile
@@ -35,6 +35,7 @@ include $(ERL_TOP)/lib/kernel/vsn.mk
ifeq ($(USE_ESOCK), yes)
PRE_LOADED_ERL_ESOCK_MODULES = \
+ socket_registry \
socket \
prim_net
else
@@ -81,7 +82,7 @@ APP_FILE= erts.app
APP_SRC= $(APP_FILE).src
APP_TARGET= $(STATIC_EBIN)/$(APP_FILE)
ifeq ($(USE_ESOCK), yes)
-APP_ESOCK_MODS= prim_net, socket
+APP_ESOCK_MODS= prim_net, socket, socket_registry
else
APP_ESOCK_MODS=
endif
diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl
index 1605c20f2c..658a138694 100644
--- a/erts/preloaded/src/erl_prim_loader.erl
+++ b/erts/preloaded/src/erl_prim_loader.erl
@@ -300,12 +300,18 @@ check_file_result(Func, Target, {error,Reason}) ->
%% This is equal to calling logger:error/2 which
%% we don't want to do from code_server during system boot.
%% We don't want to call logger:timestamp() either.
- logger ! {log,error,#{label=>{?MODULE,file_error},report=>Report},
- #{pid=>self(),
- gl=>group_leader(),
- time=>os:system_time(microsecond),
- error_logger=>#{tag=>error_report,
- type=>std_error}}},
+ _ = try
+ logger ! {log,error,#{label=>{?MODULE,file_error},report=>Report},
+ #{pid=>self(),
+ gl=>group_leader(),
+ time=>os:system_time(microsecond),
+ error_logger=>#{tag=>error_report,
+ type=>std_error}}}
+ catch _:_ ->
+ %% If logger has not been started yet we just display it
+ erlang:display({?MODULE,file_error}),
+ erlang:display(Report)
+ end,
error
end;
check_file_result(_, _, Other) ->
diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl
index 5df74b9668..82d0aa91f8 100644
--- a/erts/preloaded/src/erlang.erl
+++ b/erts/preloaded/src/erlang.erl
@@ -2205,7 +2205,9 @@ nodes(_Arg) ->
| binary
| eof
| {parallelism, Boolean :: boolean()}
- | hide.
+ | hide
+ | {busy_limits_port, {non_neg_integer(), non_neg_integer()} | disabled}
+ | {busy_limits_msgq, {non_neg_integer(), non_neg_integer()} | disabled}.
open_port(PortName, PortSettings) ->
case case erts_internal:open_port(PortName, PortSettings) of
Ref when erlang:is_reference(Ref) -> receive {Ref, Res} -> Res end;
diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl
index bbe9a9affa..0dd65d3e27 100644
--- a/erts/preloaded/src/erts_internal.erl
+++ b/erts/preloaded/src/erts_internal.erl
@@ -103,6 +103,8 @@
-export([ets_lookup_binary_info/2, ets_super_user/1, ets_info_binary/1,
ets_raw_first/1, ets_raw_next/2]).
+-export([get_internal_state_blocked/1]).
+
%%
%% Await result of send to port
%%
@@ -816,3 +818,15 @@ ets_info_binary_iter(Tab, Key, Acc) ->
[_|_] = BIL -> BIL ++ Acc
end,
ets_info_binary_iter(Tab, erts_internal:ets_raw_next(Tab, Key), NewAcc).
+
+-spec get_internal_state_blocked(Arg :: term()) -> term().
+
+get_internal_state_blocked(Arg) ->
+ erlang:system_flag(multi_scheduling, block),
+ Result = try
+ erts_debug:get_internal_state({Arg,
+ blocked})
+ after
+ erlang:system_flag(multi_scheduling, unblock)
+ end,
+ Result.
diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl
index 1aa5d85c64..f241be8569 100644
--- a/erts/preloaded/src/prim_file.erl
+++ b/erts/preloaded/src/prim_file.erl
@@ -575,11 +575,11 @@ list_dir_convert([RawName | Rest], SkipInvalid, Result) ->
%% This is equal to calling logger:warning/3 which
%% we don't want to do from code_server during system boot.
%% We don't want to call logger:timestamp() either.
- logger ! {log,warning,"Non-unicode filename ~p ignored\n", [RawName],
- #{pid=>self(),
- gl=>group_leader(),
- time=>os:system_time(microsecond),
- error_logger=>#{tag=>warning_msg}}},
+ catch logger ! {log,warning,"Non-unicode filename ~p ignored\n", [RawName],
+ #{pid=>self(),
+ gl=>group_leader(),
+ time=>os:system_time(microsecond),
+ error_logger=>#{tag=>warning_msg}}},
list_dir_convert(Rest, SkipInvalid, Result);
{error, _} ->
{error, {no_translation, RawName}}
diff --git a/erts/preloaded/src/socket.erl b/erts/preloaded/src/socket.erl
index 5984b5bda9..eb1bcdce66 100644
--- a/erts/preloaded/src/socket.erl
+++ b/erts/preloaded/src/socket.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2018-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2018-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,9 @@
-export([
on_load/0, on_load/1,
+ number_of/0,
+ which_sockets/0, which_sockets/1,
+
ensure_sockaddr/1,
debug/1,
@@ -148,6 +151,9 @@
]).
+-define(REGISTRY, socket_registry).
+
+
%% The command type has the general form:
%% #{
%% command := atom(),
@@ -161,13 +167,21 @@
%% -type command() :: debug_command().
-type socket_counters() :: [{socket_counter(), non_neg_integer()}].
--type socket_counter() :: read_byte | read_fails | read_pkg | read_tries |
- read_waits | write_byte | write_fails | write_pkg |
- write_tries | write_waits.
--type socket_info() :: #{counters := socket_counters(),
+-type socket_counter() :: read_byte | read_fails | read_pkg | read_pkg_max |
+ read_tries | read_waits |
+ write_byte | write_fails | write_pkg | write_pkg_max |
+ write_tries | write_waits |
+ acc_success | acc_fails | acc_tries | acc_waits.
+-type socket_info() :: #{domain := domain(),
+ type := type(),
+ protocol := protocol(),
+ ctrl := pid(),
+ counters := socket_counters(),
num_readers := non_neg_integer(),
num_writers := non_neg_integer(),
- num_acceptors := non_neg_integer()}.
+ num_acceptors := non_neg_integer(),
+ writable := boolean(),
+ readable := boolean()}.
-type uint8() :: 0..16#FF.
-type uint16() :: 0..16#FFFF.
@@ -693,244 +707,246 @@
%% This is used in messages sent from the nif-code to erlang processes:
%%
-%% {?SOCKET_TAG, Socket :: socket(), Tag :: atom(), Info :: term()}
-%%
--define(SOCKET_TAG, '$socket').
-
--define(SOCKET_DOMAIN_LOCAL, 1).
--define(SOCKET_DOMAIN_UNIX, ?SOCKET_DOMAIN_LOCAL).
--define(SOCKET_DOMAIN_INET, 2).
--define(SOCKET_DOMAIN_INET6, 3).
-
--define(SOCKET_TYPE_STREAM, 1).
--define(SOCKET_TYPE_DGRAM, 2).
--define(SOCKET_TYPE_RAW, 3).
-%% -define(SOCKET_TYPE_RDM, 4).
--define(SOCKET_TYPE_SEQPACKET, 5).
-
--define(SOCKET_PROTOCOL_DEFAULT, 0).
--define(SOCKET_PROTOCOL_IP, 1).
--define(SOCKET_PROTOCOL_TCP, 2).
--define(SOCKET_PROTOCOL_UDP, 3).
--define(SOCKET_PROTOCOL_SCTP, 4).
--define(SOCKET_PROTOCOL_ICMP, 5).
--define(SOCKET_PROTOCOL_IGMP, 6).
-
--define(SOCKET_LISTEN_BACKLOG_DEFAULT, 5).
-
--define(SOCKET_ACCEPT_TIMEOUT_DEFAULT, infinity).
-
--define(SOCKET_SEND_FLAG_CONFIRM, 0).
--define(SOCKET_SEND_FLAG_DONTROUTE, 1).
--define(SOCKET_SEND_FLAG_EOR, 2).
--define(SOCKET_SEND_FLAG_MORE, 3).
--define(SOCKET_SEND_FLAG_NOSIGNAL, 4).
--define(SOCKET_SEND_FLAG_OOB, 5).
-
--define(SOCKET_SEND_FLAGS_DEFAULT, []).
--define(SOCKET_SEND_TIMEOUT_DEFAULT, infinity).
--define(SOCKET_SENDTO_FLAGS_DEFAULT, []).
--define(SOCKET_SENDTO_TIMEOUT_DEFAULT, ?SOCKET_SEND_TIMEOUT_DEFAULT).
--define(SOCKET_SENDMSG_FLAGS_DEFAULT, []).
--define(SOCKET_SENDMSG_TIMEOUT_DEFAULT, ?SOCKET_SEND_TIMEOUT_DEFAULT).
-
--define(SOCKET_RECV_FLAG_CMSG_CLOEXEC, 0).
--define(SOCKET_RECV_FLAG_ERRQUEUE, 1).
--define(SOCKET_RECV_FLAG_OOB, 2).
--define(SOCKET_RECV_FLAG_PEEK, 3).
--define(SOCKET_RECV_FLAG_TRUNC, 4).
-
--define(SOCKET_RECV_FLAGS_DEFAULT, []).
--define(SOCKET_RECV_TIMEOUT_DEFAULT, infinity).
-
--define(SOCKET_OPT_LEVEL_OTP, 0).
--define(SOCKET_OPT_LEVEL_SOCKET, 1).
--define(SOCKET_OPT_LEVEL_IP, 2).
--define(SOCKET_OPT_LEVEL_IPV6, 3).
--define(SOCKET_OPT_LEVEL_TCP, 4).
--define(SOCKET_OPT_LEVEL_UDP, 5).
--define(SOCKET_OPT_LEVEL_SCTP, 6).
+%% {?ESOCK_TAG, Socket :: socket(), Tag :: atom(), Info :: term()}
+%%
+-define(ESOCK_TAG, '$socket').
+
+-define(ESOCK_DOMAIN_LOCAL, 1).
+-define(ESOCK_DOMAIN_UNIX, ?ESOCK_DOMAIN_LOCAL).
+-define(ESOCK_DOMAIN_INET, 2).
+-define(ESOCK_DOMAIN_INET6, 3).
+
+-define(ESOCK_TYPE_STREAM, 1).
+-define(ESOCK_TYPE_DGRAM, 2).
+-define(ESOCK_TYPE_RAW, 3).
+%% -define(ESOCK_TYPE_RDM, 4).
+-define(ESOCK_TYPE_SEQPACKET, 5).
+
+-define(ESOCK_PROTOCOL_DEFAULT, 0).
+-define(ESOCK_PROTOCOL_IP, 1).
+-define(ESOCK_PROTOCOL_TCP, 2).
+-define(ESOCK_PROTOCOL_UDP, 3).
+-define(ESOCK_PROTOCOL_SCTP, 4).
+-define(ESOCK_PROTOCOL_ICMP, 5).
+-define(ESOCK_PROTOCOL_IGMP, 6).
+
+-define(ESOCK_LISTEN_BACKLOG_DEFAULT, 5).
+
+-define(ESOCK_ACCEPT_TIMEOUT_DEFAULT, infinity).
+
+-define(ESOCK_SEND_FLAG_CONFIRM, 0).
+-define(ESOCK_SEND_FLAG_DONTROUTE, 1).
+-define(ESOCK_SEND_FLAG_EOR, 2).
+-define(ESOCK_SEND_FLAG_MORE, 3).
+-define(ESOCK_SEND_FLAG_NOSIGNAL, 4).
+-define(ESOCK_SEND_FLAG_OOB, 5).
+
+-define(ESOCK_SEND_FLAGS_DEFAULT, []).
+-define(ESOCK_SEND_TIMEOUT_DEFAULT, infinity).
+-define(ESOCK_SENDTO_FLAGS_DEFAULT, []).
+-define(ESOCK_SENDTO_TIMEOUT_DEFAULT, ?ESOCK_SEND_TIMEOUT_DEFAULT).
+-define(ESOCK_SENDMSG_FLAGS_DEFAULT, []).
+-define(ESOCK_SENDMSG_TIMEOUT_DEFAULT, ?ESOCK_SEND_TIMEOUT_DEFAULT).
+
+-define(ESOCK_RECV_FLAG_CMSG_CLOEXEC, 0).
+-define(ESOCK_RECV_FLAG_ERRQUEUE, 1).
+-define(ESOCK_RECV_FLAG_OOB, 2).
+-define(ESOCK_RECV_FLAG_PEEK, 3).
+-define(ESOCK_RECV_FLAG_TRUNC, 4).
+
+-define(ESOCK_RECV_FLAGS_DEFAULT, []).
+-define(ESOCK_RECV_TIMEOUT_DEFAULT, infinity).
+
+-define(ESOCK_OPT_LEVEL_OTP, 0).
+-define(ESOCK_OPT_LEVEL_SOCKET, 1).
+-define(ESOCK_OPT_LEVEL_IP, 2).
+-define(ESOCK_OPT_LEVEL_IPV6, 3).
+-define(ESOCK_OPT_LEVEL_TCP, 4).
+-define(ESOCK_OPT_LEVEL_UDP, 5).
+-define(ESOCK_OPT_LEVEL_SCTP, 6).
%% *** OTP (socket) options
--define(SOCKET_OPT_OTP_DEBUG, 1).
--define(SOCKET_OPT_OTP_IOW, 2).
--define(SOCKET_OPT_OTP_CTRL_PROC, 3).
--define(SOCKET_OPT_OTP_RCVBUF, 4).
-%%-define(SOCKET_OPT_OTP_SNDBUF, 5).
--define(SOCKET_OPT_OTP_RCVCTRLBUF, 6).
--define(SOCKET_OPT_OTP_SNDCTRLBUF, 7).
--define(SOCKET_OPT_OTP_FD, 8).
--define(SOCKET_OPT_OTP_DOMAIN, 16#FF01). % INTERNAL
--define(SOCKET_OPT_OTP_TYPE, 16#FF02). % INTERNAL
--define(SOCKET_OPT_OTP_PROTOCOL, 16#FF03). % INTERNAL
+-define(ESOCK_OPT_OTP_DEBUG, 1).
+-define(ESOCK_OPT_OTP_IOW, 2).
+-define(ESOCK_OPT_OTP_CTRL_PROC, 3).
+-define(ESOCK_OPT_OTP_RCVBUF, 4).
+%%-define(ESOCK_OPT_OTP_SNDBUF, 5).
+-define(ESOCK_OPT_OTP_RCVCTRLBUF, 6).
+-define(ESOCK_OPT_OTP_SNDCTRLBUF, 7).
+-define(ESOCK_OPT_OTP_FD, 8).
+-define(ESOCK_OPT_OTP_META, 9).
+-define(ESOCK_OPT_OTP_DOMAIN, 16#FF01). % INTERNAL
+-define(ESOCK_OPT_OTP_TYPE, 16#FF02). % INTERNAL
+-define(ESOCK_OPT_OTP_PROTOCOL, 16#FF03). % INTERNAL
+-define(ESOCK_OPT_OTP_DTP, 16#FF04). % INTERNAL
%% *** SOCKET (socket) options
--define(SOCKET_OPT_SOCK_ACCEPTCONN, 1).
-%% -define(SOCKET_OPT_SOCK_ACCEPTFILTER, 2). % FreeBSD
--define(SOCKET_OPT_SOCK_BINDTODEVICE, 3).
--define(SOCKET_OPT_SOCK_BROADCAST, 4).
-%% -define(SOCKET_OPT_SOCK_BUSY_POLL, 5).
--define(SOCKET_OPT_SOCK_DEBUG, 6).
--define(SOCKET_OPT_SOCK_DOMAIN, 7).
--define(SOCKET_OPT_SOCK_DONTROUTE, 8).
-%% -define(SOCKET_OPT_SOCK_ERROR, 9).
--define(SOCKET_OPT_SOCK_KEEPALIVE, 10).
--define(SOCKET_OPT_SOCK_LINGER, 11).
-%% -define(SOCKET_OPT_SOCK_MARK, 12).
--define(SOCKET_OPT_SOCK_OOBINLINE, 13).
--define(SOCKET_OPT_SOCK_PASSCRED, 14).
--define(SOCKET_OPT_SOCK_PEEK_OFF, 15).
-%% -define(SOCKET_OPT_SOCK_PEERCRED, 16).
--define(SOCKET_OPT_SOCK_PRIORITY, 17).
--define(SOCKET_OPT_SOCK_PROTOCOL, 18).
--define(SOCKET_OPT_SOCK_RCVBUF, 19).
-%% -define(SOCKET_OPT_SOCK_RCVBUFFORCE, 20).
--define(SOCKET_OPT_SOCK_RCVLOWAT, 21).
--define(SOCKET_OPT_SOCK_RCVTIMEO, 22).
--define(SOCKET_OPT_SOCK_REUSEADDR, 23).
--define(SOCKET_OPT_SOCK_REUSEPORT, 24).
-%% -define(SOCKET_OPT_SOCK_RXQ_OVFL, 25).
-%% -define(SOCKET_OPT_SOCK_SETFIB, 26). % FreeBSD
--define(SOCKET_OPT_SOCK_SNDBUF, 27).
-%% -define(SOCKET_OPT_SOCK_SNDBUFFORCE, 28).
--define(SOCKET_OPT_SOCK_SNDLOWAT, 29).
--define(SOCKET_OPT_SOCK_SNDTIMEO, 30).
--define(SOCKET_OPT_SOCK_TIMESTAMP, 31).
--define(SOCKET_OPT_SOCK_TYPE, 32).
+-define(ESOCK_OPT_SOCK_ACCEPTCONN, 1).
+%% -define(ESOCK_OPT_SOCK_ACCEPTFILTER, 2). % FreeBSD
+-define(ESOCK_OPT_SOCK_BINDTODEVICE, 3).
+-define(ESOCK_OPT_SOCK_BROADCAST, 4).
+%% -define(ESOCK_OPT_SOCK_BUSY_POLL, 5).
+-define(ESOCK_OPT_SOCK_DEBUG, 6).
+-define(ESOCK_OPT_SOCK_DOMAIN, 7).
+-define(ESOCK_OPT_SOCK_DONTROUTE, 8).
+%% -define(ESOCK_OPT_SOCK_ERROR, 9).
+-define(ESOCK_OPT_SOCK_KEEPALIVE, 10).
+-define(ESOCK_OPT_SOCK_LINGER, 11).
+%% -define(ESOCK_OPT_SOCK_MARK, 12).
+-define(ESOCK_OPT_SOCK_OOBINLINE, 13).
+-define(ESOCK_OPT_SOCK_PASSCRED, 14).
+-define(ESOCK_OPT_SOCK_PEEK_OFF, 15).
+%% -define(ESOCK_OPT_SOCK_PEERCRED, 16).
+-define(ESOCK_OPT_SOCK_PRIORITY, 17).
+-define(ESOCK_OPT_SOCK_PROTOCOL, 18).
+-define(ESOCK_OPT_SOCK_RCVBUF, 19).
+%% -define(ESOCK_OPT_SOCK_RCVBUFFORCE, 20).
+-define(ESOCK_OPT_SOCK_RCVLOWAT, 21).
+-define(ESOCK_OPT_SOCK_RCVTIMEO, 22).
+-define(ESOCK_OPT_SOCK_REUSEADDR, 23).
+-define(ESOCK_OPT_SOCK_REUSEPORT, 24).
+%% -define(ESOCK_OPT_SOCK_RXQ_OVFL, 25).
+%% -define(ESOCK_OPT_SOCK_SETFIB, 26). % FreeBSD
+-define(ESOCK_OPT_SOCK_SNDBUF, 27).
+%% -define(ESOCK_OPT_SOCK_SNDBUFFORCE, 28).
+-define(ESOCK_OPT_SOCK_SNDLOWAT, 29).
+-define(ESOCK_OPT_SOCK_SNDTIMEO, 30).
+-define(ESOCK_OPT_SOCK_TIMESTAMP, 31).
+-define(ESOCK_OPT_SOCK_TYPE, 32).
%% *** IP (socket) options
--define(SOCKET_OPT_IP_ADD_MEMBERSHIP, 1).
--define(SOCKET_OPT_IP_ADD_SOURCE_MEMBERSHIP, 2).
--define(SOCKET_OPT_IP_BLOCK_SOURCE, 3).
-%% -define(SOCKET_OPT_IP_DONTFRAG, 4). % FreeBSD
--define(SOCKET_OPT_IP_DROP_MEMBERSHIP, 5).
--define(SOCKET_OPT_IP_DROP_SOURCE_MEMBERSHIP, 6).
--define(SOCKET_OPT_IP_FREEBIND, 7).
--define(SOCKET_OPT_IP_HDRINCL, 8).
--define(SOCKET_OPT_IP_MINTTL, 9).
--define(SOCKET_OPT_IP_MSFILTER, 10).
--define(SOCKET_OPT_IP_MTU, 11).
--define(SOCKET_OPT_IP_MTU_DISCOVER, 12).
--define(SOCKET_OPT_IP_MULTICAST_ALL, 13).
--define(SOCKET_OPT_IP_MULTICAST_IF, 14).
--define(SOCKET_OPT_IP_MULTICAST_LOOP, 15).
--define(SOCKET_OPT_IP_MULTICAST_TTL, 16).
--define(SOCKET_OPT_IP_NODEFRAG, 17).
-%% -define(SOCKET_OPT_IP_OPTIONS, 18). % FreeBSD
--define(SOCKET_OPT_IP_PKTINFO, 19).
--define(SOCKET_OPT_IP_RECVDSTADDR, 20). % FreeBSD
--define(SOCKET_OPT_IP_RECVERR, 21).
--define(SOCKET_OPT_IP_RECVIF, 22).
--define(SOCKET_OPT_IP_RECVOPTS, 23).
--define(SOCKET_OPT_IP_RECVORIGDSTADDR, 24).
--define(SOCKET_OPT_IP_RECVTOS, 25).
--define(SOCKET_OPT_IP_RECVTTL, 26).
--define(SOCKET_OPT_IP_RETOPTS, 27).
--define(SOCKET_OPT_IP_ROUTER_ALERT, 28).
--define(SOCKET_OPT_IP_SENDSRCADDR, 29). % FreeBSD
--define(SOCKET_OPT_IP_TOS, 30).
--define(SOCKET_OPT_IP_TRANSPARENT, 31).
--define(SOCKET_OPT_IP_TTL, 32).
--define(SOCKET_OPT_IP_UNBLOCK_SOURCE, 33).
+-define(ESOCK_OPT_IP_ADD_MEMBERSHIP, 1).
+-define(ESOCK_OPT_IP_ADD_SOURCE_MEMBERSHIP, 2).
+-define(ESOCK_OPT_IP_BLOCK_SOURCE, 3).
+%% -define(ESOCK_OPT_IP_DONTFRAG, 4). % FreeBSD
+-define(ESOCK_OPT_IP_DROP_MEMBERSHIP, 5).
+-define(ESOCK_OPT_IP_DROP_SOURCE_MEMBERSHIP, 6).
+-define(ESOCK_OPT_IP_FREEBIND, 7).
+-define(ESOCK_OPT_IP_HDRINCL, 8).
+-define(ESOCK_OPT_IP_MINTTL, 9).
+-define(ESOCK_OPT_IP_MSFILTER, 10).
+-define(ESOCK_OPT_IP_MTU, 11).
+-define(ESOCK_OPT_IP_MTU_DISCOVER, 12).
+-define(ESOCK_OPT_IP_MULTICAST_ALL, 13).
+-define(ESOCK_OPT_IP_MULTICAST_IF, 14).
+-define(ESOCK_OPT_IP_MULTICAST_LOOP, 15).
+-define(ESOCK_OPT_IP_MULTICAST_TTL, 16).
+-define(ESOCK_OPT_IP_NODEFRAG, 17).
+%% -define(ESOCK_OPT_IP_OPTIONS, 18). % FreeBSD
+-define(ESOCK_OPT_IP_PKTINFO, 19).
+-define(ESOCK_OPT_IP_RECVDSTADDR, 20). % FreeBSD
+-define(ESOCK_OPT_IP_RECVERR, 21).
+-define(ESOCK_OPT_IP_RECVIF, 22).
+-define(ESOCK_OPT_IP_RECVOPTS, 23).
+-define(ESOCK_OPT_IP_RECVORIGDSTADDR, 24).
+-define(ESOCK_OPT_IP_RECVTOS, 25).
+-define(ESOCK_OPT_IP_RECVTTL, 26).
+-define(ESOCK_OPT_IP_RETOPTS, 27).
+-define(ESOCK_OPT_IP_ROUTER_ALERT, 28).
+-define(ESOCK_OPT_IP_SENDSRCADDR, 29). % FreeBSD
+-define(ESOCK_OPT_IP_TOS, 30).
+-define(ESOCK_OPT_IP_TRANSPARENT, 31).
+-define(ESOCK_OPT_IP_TTL, 32).
+-define(ESOCK_OPT_IP_UNBLOCK_SOURCE, 33).
%% *** IPv6 (socket) options
--define(SOCKET_OPT_IPV6_ADDRFORM, 1).
--define(SOCKET_OPT_IPV6_ADD_MEMBERSHIP, 2).
--define(SOCKET_OPT_IPV6_AUTHHDR, 3). % Obsolete?
-%% -define(SOCKET_OPT_IPV6_AUTH_LEVEL, 4). % FreeBSD
-%% -define(SOCKET_OPT_IPV6_CHECKSUM, 5). % FreeBSD
--define(SOCKET_OPT_IPV6_DROP_MEMBERSHIP, 6).
--define(SOCKET_OPT_IPV6_DSTOPTS, 7).
-%% -define(SOCKET_OPT_IPV6_ESP_NETWORK_LEVEL, 8). % FreeBSD
-%% -define(SOCKET_OPT_IPV6_ESP_TRANS_LEVEL, 9). % FreeBSD
-%% -define(SOCKET_OPT_IPV6_FAITH, 10). % FreeBSD
--define(SOCKET_OPT_IPV6_FLOWINFO, 11).
--define(SOCKET_OPT_IPV6_HOPLIMIT, 12).
--define(SOCKET_OPT_IPV6_HOPOPTS, 13).
-%% -define(SOCKET_OPT_IPV6_IPCOMP_LEVEL, 14). % FreeBSD
-%% -define(SOCKET_OPT_IPV6_JOIN_GROUP, 15). % FreeBSD
-%% -define(SOCKET_OPT_IPV6_LEAVE_GROUP, 16). % FreeBSD
--define(SOCKET_OPT_IPV6_MTU, 17).
--define(SOCKET_OPT_IPV6_MTU_DISCOVER, 18).
--define(SOCKET_OPT_IPV6_MULTICAST_HOPS, 19).
--define(SOCKET_OPT_IPV6_MULTICAST_IF, 20).
--define(SOCKET_OPT_IPV6_MULTICAST_LOOP, 21).
-%% -define(SOCKET_OPT_IPV6_PORTRANGE, 22). % FreeBSD
-%% -define(SOCKET_OPT_IPV6_PKTOPTIONS, 23). % FreeBSD
--define(SOCKET_OPT_IPV6_RECVERR, 24).
--define(SOCKET_OPT_IPV6_RECVHOPLIMIT, 25).
--define(SOCKET_OPT_IPV6_RECVPKTINFO, 26). % On FreeBSD: PKTINFO
--define(SOCKET_OPT_IPV6_RECVTCLASS, 27).
--define(SOCKET_OPT_IPV6_ROUTER_ALERT, 28).
--define(SOCKET_OPT_IPV6_RTHDR, 29).
--define(SOCKET_OPT_IPV6_TCLASS, 30). % FreeBSD
--define(SOCKET_OPT_IPV6_UNICAST_HOPS, 31).
-%% -define(SOCKET_OPT_IPV6_USE_MIN_MTU, 32). % FreeBSD
--define(SOCKET_OPT_IPV6_V6ONLY, 33).
+-define(ESOCK_OPT_IPV6_ADDRFORM, 1).
+-define(ESOCK_OPT_IPV6_ADD_MEMBERSHIP, 2).
+-define(ESOCK_OPT_IPV6_AUTHHDR, 3). % Obsolete?
+%% -define(ESOCK_OPT_IPV6_AUTH_LEVEL, 4). % FreeBSD
+%% -define(ESOCK_OPT_IPV6_CHECKSUM, 5). % FreeBSD
+-define(ESOCK_OPT_IPV6_DROP_MEMBERSHIP, 6).
+-define(ESOCK_OPT_IPV6_DSTOPTS, 7).
+%% -define(ESOCK_OPT_IPV6_ESP_NETWORK_LEVEL, 8). % FreeBSD
+%% -define(ESOCK_OPT_IPV6_ESP_TRANS_LEVEL, 9). % FreeBSD
+%% -define(ESOCK_OPT_IPV6_FAITH, 10). % FreeBSD
+-define(ESOCK_OPT_IPV6_FLOWINFO, 11).
+-define(ESOCK_OPT_IPV6_HOPLIMIT, 12).
+-define(ESOCK_OPT_IPV6_HOPOPTS, 13).
+%% -define(ESOCK_OPT_IPV6_IPCOMP_LEVEL, 14). % FreeBSD
+%% -define(ESOCK_OPT_IPV6_JOIN_GROUP, 15). % FreeBSD
+%% -define(ESOCK_OPT_IPV6_LEAVE_GROUP, 16). % FreeBSD
+-define(ESOCK_OPT_IPV6_MTU, 17).
+-define(ESOCK_OPT_IPV6_MTU_DISCOVER, 18).
+-define(ESOCK_OPT_IPV6_MULTICAST_HOPS, 19).
+-define(ESOCK_OPT_IPV6_MULTICAST_IF, 20).
+-define(ESOCK_OPT_IPV6_MULTICAST_LOOP, 21).
+%% -define(ESOCK_OPT_IPV6_PORTRANGE, 22). % FreeBSD
+%% -define(ESOCK_OPT_IPV6_PKTOPTIONS, 23). % FreeBSD
+-define(ESOCK_OPT_IPV6_RECVERR, 24).
+-define(ESOCK_OPT_IPV6_RECVHOPLIMIT, 25).
+-define(ESOCK_OPT_IPV6_RECVPKTINFO, 26). % On FreeBSD: PKTINFO
+-define(ESOCK_OPT_IPV6_RECVTCLASS, 27).
+-define(ESOCK_OPT_IPV6_ROUTER_ALERT, 28).
+-define(ESOCK_OPT_IPV6_RTHDR, 29).
+-define(ESOCK_OPT_IPV6_TCLASS, 30). % FreeBSD
+-define(ESOCK_OPT_IPV6_UNICAST_HOPS, 31).
+%% -define(ESOCK_OPT_IPV6_USE_MIN_MTU, 32). % FreeBSD
+-define(ESOCK_OPT_IPV6_V6ONLY, 33).
%% *** TCP (socket) options
--define(SOCKET_OPT_TCP_CONGESTION, 1).
--define(SOCKET_OPT_TCP_CORK, 2).
-%% -define(SOCKET_OPT_TCP_INFO, 3).
-%% -define(SOCKET_OPT_TCP_KEEPCNT, 4).
-%% -define(SOCKET_OPT_TCP_KEEPIDLE, 5).
-%% -define(SOCKET_OPT_TCP_KEEPINTVL, 6).
--define(SOCKET_OPT_TCP_MAXSEG, 7).
-%% -define(SOCKET_OPT_TCP_MD5SIG, 8).
--define(SOCKET_OPT_TCP_NODELAY, 9).
-%% -define(SOCKET_OPT_TCP_NOOPT, 10).
-%% -define(SOCKET_OPT_TCP_NOPUSH, 11).
-%% -define(SOCKET_OPT_TCP_SYNCNT, 12).
-%% -define(SOCKET_OPT_TCP_USER_TIMEOUT, 13).
+-define(ESOCK_OPT_TCP_CONGESTION, 1).
+-define(ESOCK_OPT_TCP_CORK, 2).
+%% -define(ESOCK_OPT_TCP_INFO, 3).
+%% -define(ESOCK_OPT_TCP_KEEPCNT, 4).
+%% -define(ESOCK_OPT_TCP_KEEPIDLE, 5).
+%% -define(ESOCK_OPT_TCP_KEEPINTVL, 6).
+-define(ESOCK_OPT_TCP_MAXSEG, 7).
+%% -define(ESOCK_OPT_TCP_MD5SIG, 8).
+-define(ESOCK_OPT_TCP_NODELAY, 9).
+%% -define(ESOCK_OPT_TCP_NOOPT, 10).
+%% -define(ESOCK_OPT_TCP_NOPUSH, 11).
+%% -define(ESOCK_OPT_TCP_SYNCNT, 12).
+%% -define(ESOCK_OPT_TCP_USER_TIMEOUT, 13).
%% *** UDP (socket) options
--define(SOCKET_OPT_UDP_CORK, 1).
+-define(ESOCK_OPT_UDP_CORK, 1).
%% *** SCTP (socket) options
-%% -define(SOCKET_OPT_SCTP_ADAPTION_LAYER, 1).
--define(SOCKET_OPT_SCTP_ASSOCINFO, 2).
-%% -define(SOCKET_OPT_SCTP_AUTH_ACTIVE_KEY, 3).
-%% -define(SOCKET_OPT_SCTP_AUTH_ASCONF, 4).
-%% -define(SOCKET_OPT_SCTP_AUTH_CHUNK, 5).
-%% -define(SOCKET_OPT_SCTP_AUTH_KEY, 6).
-%% -define(SOCKET_OPT_SCTP_AUTH_DELETE_KEY, 7).
--define(SOCKET_OPT_SCTP_AUTOCLOSE, 8).
-%% -define(SOCKET_OPT_SCTP_CONTEXT, 9).
-%% -define(SOCKET_OPT_SCTP_DEFAULT_SEND_PARAMS, 10).
-%% -define(SOCKET_OPT_SCTP_DELAYED_ACK_TIME, 11).
--define(SOCKET_OPT_SCTP_DISABLE_FRAGMENTS, 12).
-%% -define(SOCKET_OPT_SCTP_HMAC_IDENT, 13).
--define(SOCKET_OPT_SCTP_EVENTS, 14).
-%% -define(SOCKET_OPT_SCTP_EXPLICIT_EOR, 15).
-%% -define(SOCKET_OPT_SCTP_FRAGMENT_INTERLEAVE, 16).
-%% -define(SOCKET_OPT_SCTP_GET_PEER_ADDR_INFO, 17).
--define(SOCKET_OPT_SCTP_INITMSG, 18).
-%% -define(SOCKET_OPT_SCTP_I_WANT_MAPPED_V4_ADDR, 19).
-%% -define(SOCKET_OPT_SCTP_LOCAL_AUTH_CHUNKS, 20).
--define(SOCKET_OPT_SCTP_MAXSEG, 21).
-%% -define(SOCKET_OPT_SCTP_MAXBURST, 22).
--define(SOCKET_OPT_SCTP_NODELAY, 23).
-%% -define(SOCKET_OPT_SCTP_PARTIAL_DELIVERY_POINT, 24).
-%% -define(SOCKET_OPT_SCTP_PEER_ADDR_PARAMS, 25).
-%% -define(SOCKET_OPT_SCTP_PEER_AUTH_CHUNKS, 26).
-%% -define(SOCKET_OPT_SCTP_PRIMARY_ADDR, 27).
-%% -define(SOCKET_OPT_SCTP_RESET_STREAMS, 28).
--define(SOCKET_OPT_SCTP_RTOINFO, 29).
-%% -define(SOCKET_OPT_SCTP_SET_PEER_PRIMARY_ADDR, 30).
-%% -define(SOCKET_OPT_SCTP_STATUS, 31).
-%% -define(SOCKET_OPT_SCTP_USE_EXT_RECVINFO, 32).
-
--define(SOCKET_SHUTDOWN_HOW_READ, 0).
--define(SOCKET_SHUTDOWN_HOW_WRITE, 1).
--define(SOCKET_SHUTDOWN_HOW_READ_WRITE, 2).
-
-
--define(SOCKET_SUPPORTS_OPTIONS, 16#0001).
--define(SOCKET_SUPPORTS_SCTP, 16#0002).
--define(SOCKET_SUPPORTS_IPV6, 16#0003).
--define(SOCKET_SUPPORTS_LOCAL, 16#0004).
--define(SOCKET_SUPPORTS_SEND_FLAGS, 16#0005).
--define(SOCKET_SUPPORTS_RECV_FLAGS, 16#0006).
+%% -define(ESOCK_OPT_SCTP_ADAPTION_LAYER, 1).
+-define(ESOCK_OPT_SCTP_ASSOCINFO, 2).
+%% -define(ESOCK_OPT_SCTP_AUTH_ACTIVE_KEY, 3).
+%% -define(ESOCK_OPT_SCTP_AUTH_ASCONF, 4).
+%% -define(ESOCK_OPT_SCTP_AUTH_CHUNK, 5).
+%% -define(ESOCK_OPT_SCTP_AUTH_KEY, 6).
+%% -define(ESOCK_OPT_SCTP_AUTH_DELETE_KEY, 7).
+-define(ESOCK_OPT_SCTP_AUTOCLOSE, 8).
+%% -define(ESOCK_OPT_SCTP_CONTEXT, 9).
+%% -define(ESOCK_OPT_SCTP_DEFAULT_SEND_PARAMS, 10).
+%% -define(ESOCK_OPT_SCTP_DELAYED_ACK_TIME, 11).
+-define(ESOCK_OPT_SCTP_DISABLE_FRAGMENTS, 12).
+%% -define(ESOCK_OPT_SCTP_HMAC_IDENT, 13).
+-define(ESOCK_OPT_SCTP_EVENTS, 14).
+%% -define(ESOCK_OPT_SCTP_EXPLICIT_EOR, 15).
+%% -define(ESOCK_OPT_SCTP_FRAGMENT_INTERLEAVE, 16).
+%% -define(ESOCK_OPT_SCTP_GET_PEER_ADDR_INFO, 17).
+-define(ESOCK_OPT_SCTP_INITMSG, 18).
+%% -define(ESOCK_OPT_SCTP_I_WANT_MAPPED_V4_ADDR, 19).
+%% -define(ESOCK_OPT_SCTP_LOCAL_AUTH_CHUNKS, 20).
+-define(ESOCK_OPT_SCTP_MAXSEG, 21).
+%% -define(ESOCK_OPT_SCTP_MAXBURST, 22).
+-define(ESOCK_OPT_SCTP_NODELAY, 23).
+%% -define(ESOCK_OPT_SCTP_PARTIAL_DELIVERY_POINT, 24).
+%% -define(ESOCK_OPT_SCTP_PEER_ADDR_PARAMS, 25).
+%% -define(ESOCK_OPT_SCTP_PEER_AUTH_CHUNKS, 26).
+%% -define(ESOCK_OPT_SCTP_PRIMARY_ADDR, 27).
+%% -define(ESOCK_OPT_SCTP_RESET_STREAMS, 28).
+-define(ESOCK_OPT_SCTP_RTOINFO, 29).
+%% -define(ESOCK_OPT_SCTP_SET_PEER_PRIMARY_ADDR, 30).
+%% -define(ESOCK_OPT_SCTP_STATUS, 31).
+%% -define(ESOCK_OPT_SCTP_USE_EXT_RECVINFO, 32).
+
+-define(ESOCK_SHUTDOWN_HOW_READ, 0).
+-define(ESOCK_SHUTDOWN_HOW_WRITE, 1).
+-define(ESOCK_SHUTDOWN_HOW_READ_WRITE, 2).
+
+
+-define(ESOCK_SUPPORTS_OPTIONS, 16#0001).
+-define(ESOCK_SUPPORTS_SCTP, 16#0002).
+-define(ESOCK_SUPPORTS_IPV6, 16#0003).
+-define(ESOCK_SUPPORTS_LOCAL, 16#0004).
+-define(ESOCK_SUPPORTS_SEND_FLAGS, 16#0005).
+-define(ESOCK_SUPPORTS_RECV_FLAGS, 16#0006).
%% ===========================================================================
@@ -949,7 +965,60 @@ on_load() ->
Extra :: map().
on_load(Extra) ->
- ok = erlang:load_nif(atom_to_list(?MODULE), Extra).
+ %% This is spawned as a system process to prevent init:restart/0 from
+ %% killing it.
+ Pid = erts_internal:spawn_system_process(?REGISTRY, start, []),
+ ok = erlang:load_nif(atom_to_list(?MODULE), Extra#{registry => Pid}).
+
+
+%% *** number_of ***
+%%
+%% Interface function to the socket registry
+%% returns the number of existing (and "alive") sockets.
+%%
+-spec number_of() -> non_neg_integer().
+
+number_of() ->
+ ?REGISTRY:number_of().
+
+
+%% *** which_sockets/0,1 ***
+%%
+%% Interface function to the socket registry
+%% Returns a list of all the sockets, accoring to the filter rule.
+%%
+-spec which_sockets() -> [socket()].
+
+which_sockets() ->
+ ?REGISTRY:which_sockets(fun(_) -> true end).
+
+-spec which_sockets(FilterRule) -> [socket()] when
+ FilterRule :: inet | inet6 |
+ stream | dgram | seqpacket |
+ sctp | tcp | udp |
+ pid() |
+ fun((socket_info()) -> boolean()).
+
+which_sockets(Domain)
+ when ((Domain =:= inet) orelse (Domain =:= inet6)) ->
+ ?REGISTRY:which_sockets(fun(#{domain := D}) when (D =:= Domain) -> true;
+ (_) -> false end);
+which_sockets(Type)
+ when ((Type =:= stream) orelse (Type =:= dgram) orelse (Type =:= seqpacket)) ->
+ ?REGISTRY:which_sockets(fun(#{type := T}) when (T =:= Type) -> true;
+ (_) -> false end);
+which_sockets(Proto)
+ when ((Proto =:= sctp) orelse (Proto =:= tcp) orelse (Proto =:= udp)) ->
+ ?REGISTRY:which_sockets(fun(#{protocol := P}) when (P =:= Proto) -> true;
+ (_) -> false end);
+which_sockets(CTRL)
+ when is_pid(CTRL) ->
+ ?REGISTRY:which_sockets(fun(#{ctrl := C}) when (C =:= CTRL) -> true;
+ (_) -> false end);
+which_sockets(Filter) when is_function(Filter, 1) ->
+ ?REGISTRY:which_sockets(Filter).
+
+
@@ -1036,7 +1105,7 @@ supports() ->
{recv_flags, supports(recv_flags)}].
--dialyzer({nowarn_function, supports/1}).
+-dialyzer({no_contracts, supports/1}).
-spec supports(options) -> supports_options();
(sctp) -> boolean();
(ipv6) -> boolean();
@@ -1047,21 +1116,21 @@ supports() ->
Key1 :: term().
supports(options) ->
- nif_supports(?SOCKET_SUPPORTS_OPTIONS);
+ nif_supports(?ESOCK_SUPPORTS_OPTIONS);
supports(sctp) ->
- nif_supports(?SOCKET_SUPPORTS_SCTP);
+ nif_supports(?ESOCK_SUPPORTS_SCTP);
supports(ipv6) ->
- nif_supports(?SOCKET_SUPPORTS_IPV6);
+ nif_supports(?ESOCK_SUPPORTS_IPV6);
supports(local) ->
- nif_supports(?SOCKET_SUPPORTS_LOCAL);
+ nif_supports(?ESOCK_SUPPORTS_LOCAL);
supports(send_flags) ->
- nif_supports(?SOCKET_SUPPORTS_SEND_FLAGS);
+ nif_supports(?ESOCK_SUPPORTS_SEND_FLAGS);
supports(recv_flags) ->
- nif_supports(?SOCKET_SUPPORTS_RECV_FLAGS);
+ nif_supports(?ESOCK_SUPPORTS_RECV_FLAGS);
supports(_Key1) ->
false.
--dialyzer({nowarn_function, supports/2}).
+-dialyzer({no_contracts, supports/2}).
-spec supports(options, socket) -> supports_options_socket();
(options, ip) -> supports_options_ip();
(options, ipv6) -> supports_options_ipv6();
@@ -1084,7 +1153,6 @@ supports(_Key1, _Level) ->
false.
--dialyzer({nowarn_function, supports/3}).
-spec supports(options, socket, Opt :: socket_option()) -> boolean();
(options, ip, Opt :: ip_socket_option()) -> boolean();
(options, ipv6, Opt :: ipv6_socket_option()) -> boolean();
@@ -1096,6 +1164,7 @@ supports(_Key1, _Level) ->
Key2 :: term(),
Key3 :: term().
+-dialyzer({no_contracts, supports/3}).
supports(options, Level, Opt) ->
case supports(options, Level) of
S when is_list(S) ->
@@ -1192,25 +1261,19 @@ open(Domain, Type, Protocol, Extra) when is_map(Extra) ->
try
begin
EDomain = enc_domain(Domain),
- EType = enc_type(Domain, Type),
- EProtocol = enc_protocol(Type, Protocol),
- case nif_open(EDomain, EType, EProtocol, Extra) of
- {ok, SockRef} ->
- Socket = #socket{ref = SockRef},
- {ok, Socket};
- {error, _} = ERROR ->
- ERROR
- end
+ EType = enc_type(Type),
+ EProtocol = enc_protocol(Protocol),
+ nif_open(EDomain, EType, EProtocol, Extra)
end
+ of
+ {ok, SockRef} ->
+ Socket = #socket{ref = SockRef},
+ {ok, Socket};
+ {error, _} = ERROR ->
+ ERROR
catch
- throw:T ->
- T;
- %% <WIN32-TEMPORARY>
- error:notsup:S ->
- erlang:raise(error, notsup, S);
- %% </WIN32-TEMPORARY>
- error:Reason ->
- {error, Reason}
+ throw:ERROR ->
+ ERROR
end.
@@ -1232,31 +1295,23 @@ bind(#socket{ref = SockRef}, Addr)
when ((Addr =:= any) orelse
(Addr =:= broadcast) orelse
(Addr =:= loopback)) ->
- try which_domain(SockRef) of
- inet ->
- nif_bind(SockRef, ?SOCKADDR_IN4_DEFAULT(Addr));
- inet6 when (Addr =:= any) orelse (Addr =:= loopback) ->
- nif_bind(SockRef, ?SOCKADDR_IN6_DEFAULT(Addr));
- _ ->
- einval()
+ try
+ case which_domain(SockRef) of
+ inet ->
+ nif_bind(SockRef, ?SOCKADDR_IN4_DEFAULT(Addr));
+ inet6 when (Addr =:= any) orelse (Addr =:= loopback) ->
+ nif_bind(SockRef, ?SOCKADDR_IN6_DEFAULT(Addr));
+ Domain ->
+ invalid_domain(Domain)
+ end
catch
- %% <WIN32-TEMPORARY>
- error:notsup:S ->
- erlang:raise(error, notsup, S);
- %% </WIN32-TEMPORARY>
throw:ERROR ->
ERROR
end;
bind(#socket{ref = SockRef} = _Socket, Addr) when is_map(Addr) ->
try
- begin
- nif_bind(SockRef, ensure_sockaddr(Addr))
- end
+ nif_bind(SockRef, ensure_sockaddr(Addr))
catch
- %% <WIN32-TEMPORARY>
- error:notsup:S ->
- erlang:raise(error, notsup, S);
- %% </WIN32-TEMPORARY>
throw:ERROR ->
ERROR
end.
@@ -1285,35 +1340,28 @@ bind(#socket{ref = SockRef}, Addrs, Action)
when is_list(Addrs) andalso ((Action =:= add) orelse (Action =:= remove)) ->
try
begin
- ensure_type(SockRef, seqpacket),
- ensure_proto(SockRef, sctp),
- validate_addrs(which_domain(SockRef), Addrs),
+ {Domain, Type, Proto} = which_dtp(SockRef),
+ ensure_domain(Domain, [inet, inet6]),
+ ensure_type(Type, seqpacket),
+ ensure_protocol(Proto, sctp),
+ validate_addrs(Domain, Addrs),
nif_bind(SockRef, Addrs, Action)
end
catch
- %% <WIN32-TEMPORARY>
- error:notsup:S ->
- erlang:raise(error, notsup, S);
- %% </WIN32-TEMPORARY>
throw:ERROR ->
ERROR
end.
-ensure_type(SockRef, Type) ->
- case which_type(SockRef) of
- Type ->
- ok;
- _InvalidType ->
- einval()
- end.
+ensure_domain(Domain, [Domain | _]) -> ok;
+ensure_domain(Domain, [_ | Domains]) -> ensure_domain(Domain, Domains);
+ensure_domain(Domain, []) -> invalid_domain(Domain).
+
+ensure_type(Type, Type) -> ok;
+ensure_type(Type, _) -> invalid_type(Type).
+
+ensure_protocol(Proto, Proto) -> ok;
+ensure_protocol(Proto, _) -> invalid_protocol(Proto).
-ensure_proto(SockRef, Proto) ->
- case which_protocol(SockRef) of
- Proto ->
- ok;
- _InvalidProto ->
- einval()
- end.
validate_addrs(inet = _Domain, Addrs) ->
validate_inet_addrs(Addrs);
@@ -1373,38 +1421,45 @@ connect(Socket, SockAddr) ->
%% <KOLLA>
%% Is it possible to connect with family = local for the (dest) sockaddr?
%% </KOLLA>
-connect(_Socket, _SockAddr, Timeout)
- when (is_integer(Timeout) andalso (Timeout =< 0)) ->
- {error, timeout};
-connect(#socket{ref = SockRef}, #{family := Fam} = SockAddr, Timeout)
- when ((Fam =:= inet) orelse (Fam =:= inet6) orelse (Fam =:= local)) andalso
- ((Timeout =:= nowait) orelse
- (Timeout =:= infinity) orelse is_integer(Timeout)) ->
- TS = timestamp(Timeout),
+connect(#socket{ref = SockRef}, SockAddr, Timeout) ->
+ try
+ do_connect(SockRef, ensure_sockaddr(SockAddr), deadline(Timeout))
+ catch
+ throw:ERROR ->
+ ERROR
+ end.
+
+
+do_connect(SockRef, SockAddr, Deadline) ->
case nif_connect(SockRef, ensure_sockaddr(SockAddr)) of
+
ok ->
%% Connected!
ok;
- {ok, Ref} when (Timeout =:= nowait) ->
+
+ {ok, Ref} when (Deadline =:= nowait) ->
%% Connecting, but the caller does not want to wait...
?SELECT(connect, Ref);
{ok, Ref} ->
%% Connecting...
- NewTimeout = next_timeout(TS, Timeout),
- receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, Ref} ->
- nif_finalize_connection(SockRef)
- after NewTimeout ->
+ Timeout = timeout(Deadline),
+ receive
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, Ref} ->
+ nif_finalize_connection(SockRef)
+ after Timeout ->
cancel(SockRef, connect, Ref),
- {error, timeout}
- end;
- {error, _} = ERROR ->
- ERROR
+ {error, timeout}
+ end;
+
+
+ {error, _} = ERROR ->
+ ERROR
end.
+
%% ===========================================================================
%%
%% listen - listen for connections on a socket
@@ -1415,7 +1470,7 @@ connect(#socket{ref = SockRef}, #{family := Fam} = SockAddr, Timeout)
Reason :: term().
listen(Socket) ->
- listen(Socket, ?SOCKET_LISTEN_BACKLOG_DEFAULT).
+ listen(Socket, ?ESOCK_LISTEN_BACKLOG_DEFAULT).
-spec listen(Socket, Backlog) -> ok | {error, Reason} when
Socket :: socket(),
@@ -1440,7 +1495,7 @@ listen(#socket{ref = SockRef}, Backlog)
Reason :: term().
accept(Socket) ->
- accept(Socket, ?SOCKET_ACCEPT_TIMEOUT_DEFAULT).
+ accept(Socket, ?ESOCK_ACCEPT_TIMEOUT_DEFAULT).
-spec accept(LSocket, nowait) ->
{ok, Socket} |
@@ -1456,45 +1511,44 @@ accept(Socket) ->
Socket :: socket(),
Reason :: term().
-%% Do we really need this optimization?
-accept(_, Timeout) when is_integer(Timeout) andalso (Timeout =< 0) ->
- {error, timeout};
-accept(#socket{ref = LSockRef}, Timeout)
- when is_integer(Timeout) orelse
- (Timeout =:= infinity) orelse
- (Timeout =:= nowait) ->
- do_accept(LSockRef, Timeout).
-
-do_accept(LSockRef, Timeout) ->
- TS = timestamp(Timeout),
+accept(#socket{ref = LSockRef}, Timeout) ->
+ try
+ do_accept(LSockRef, deadline(Timeout))
+ catch
+ throw:ERROR ->
+ ERROR
+ end.
+
+do_accept(LSockRef, Deadline) ->
AccRef = make_ref(),
case nif_accept(LSockRef, AccRef) of
+
{ok, SockRef} ->
Socket = #socket{ref = SockRef},
{ok, Socket};
- {error, eagain} when (Timeout =:= nowait) ->
+ {error, eagain} when (Deadline =:= nowait) ->
?SELECT(accept, AccRef);
-
{error, eagain} ->
%% Each call is non-blocking, but even then it takes
%% *some* time, so just to be sure, recalculate before
%% the receive.
- NewTimeout = next_timeout(TS, Timeout),
+ Timeout = timeout(Deadline),
receive
- {?SOCKET_TAG, #socket{ref = LSockRef}, select, AccRef} ->
- do_accept(LSockRef, next_timeout(TS, Timeout));
+ {?ESOCK_TAG, #socket{ref = LSockRef}, select, AccRef} ->
+ do_accept(LSockRef, Deadline);
- {?SOCKET_TAG, _Socket, abort, {AccRef, Reason}} ->
+ {?ESOCK_TAG, _Socket, abort, {AccRef, Reason}} ->
{error, Reason}
- after NewTimeout ->
+ after Timeout ->
cancel(LSockRef, accept, AccRef),
{error, timeout}
end;
+
{error, _} = ERROR ->
cancel(LSockRef, accept, AccRef), % Just to be on the safe side...
ERROR
@@ -1513,32 +1567,34 @@ do_accept(LSockRef, Timeout) ->
Reason :: term().
send(Socket, Data) ->
- send(Socket, Data, ?SOCKET_SEND_FLAGS_DEFAULT, ?SOCKET_SEND_TIMEOUT_DEFAULT).
+ send(Socket, Data, ?ESOCK_SEND_FLAGS_DEFAULT, ?ESOCK_SEND_TIMEOUT_DEFAULT).
-spec send(Socket, Data, Flags) -> ok | {error, Reason} when
Socket :: socket(),
Data :: iodata(),
Flags :: send_flags(),
- Reason :: term()
- ; (Socket, Data, Timeout :: nowait) -> ok |
- {select, SelectInfo} |
- {ok, {RestData, SelectInfo}} |
- {error, Reason} when
+ Reason :: term();
+ (Socket, Data, Timeout :: nowait) ->
+ ok |
+ {ok, {binary(), SelectInfo}} |
+ {select, SelectInfo} |
+ {ok, {RestData, SelectInfo}} |
+ {error, Reason} when
Socket :: socket(),
Data :: iodata(),
RestData :: binary(),
SelectInfo :: select_info(),
- Reason :: term()
- ; (Socket, Data, Timeout) -> ok | {error, Reason} when
+ Reason :: term();
+ (Socket, Data, Timeout) -> ok | {error, Reason} when
Socket :: socket(),
Data :: iodata(),
Timeout :: timeout(),
Reason :: term().
send(Socket, Data, Flags) when is_list(Flags) ->
- send(Socket, Data, Flags, ?SOCKET_SEND_TIMEOUT_DEFAULT);
+ send(Socket, Data, Flags, ?ESOCK_SEND_TIMEOUT_DEFAULT);
send(Socket, Data, Timeout) ->
- send(Socket, Data, ?SOCKET_SEND_FLAGS_DEFAULT, Timeout).
+ send(Socket, Data, ?ESOCK_SEND_FLAGS_DEFAULT, Timeout).
-spec send(Socket, Data, Flags, nowait) -> ok |
{select, SelectInfo} |
@@ -1561,75 +1617,95 @@ send(Socket, Data, Flags, Timeout) when is_list(Data) ->
Bin = erlang:list_to_binary(Data),
send(Socket, Bin, Flags, Timeout);
send(#socket{ref = SockRef}, Data, Flags, Timeout)
- when is_binary(Data) andalso
- is_list(Flags) andalso
- ((Timeout =:= nowait) orelse
- (Timeout =:= infinity) orelse
- (is_integer(Timeout) andalso (Timeout > 0))) ->
- EFlags = enc_send_flags(Flags),
- do_send(SockRef, Data, EFlags, Timeout).
-
-do_send(SockRef, Data, EFlags, Timeout) ->
- TS = timestamp(Timeout),
+ when is_binary(Data), is_list(Flags) ->
+ To = undefined,
+ try
+ begin
+ EFlags = enc_send_flags(Flags),
+ Deadline = deadline(Timeout),
+ send_common(SockRef, Data, To, EFlags, Deadline, send)
+ end
+ catch
+ throw:ERROR ->
+ ERROR
+ end.
+
+send_common(SockRef, Data, To, EFlags, Deadline, SendName) ->
+
SendRef = make_ref(),
- case nif_send(SockRef, SendRef, Data, EFlags) of
- ok ->
- ok;
+ case
+ case SendName of
+ send ->
+ nif_send(SockRef, SendRef, Data, EFlags);
+ sendto ->
+ nif_sendto(SockRef, SendRef, Data, To, EFlags)
+ end
+ of
- {ok, Written} when (Timeout =:= nowait) ->
- <<_:Written/binary, Rest/binary>> = Data,
+ ok -> ok;
+
+
+ {ok, Written} when (Deadline =:= nowait) ->
%% We are partially done, but the user don't want to wait (here)
%% for completion
- {ok, {Rest, ?SELECT_INFO(send, SendRef)}};
-
+ <<_:Written/binary, Rest/binary>> = Data,
+ {ok, {Rest, ?SELECT_INFO(SendName, SendRef)}};
{ok, Written} ->
- NewTimeout = next_timeout(TS, Timeout),
%% We are partially done, wait for continuation
+ Timeout = timeout(Deadline),
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef}
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, SendRef}
when (Written > 0) ->
<<_:Written/binary, Rest/binary>> = Data,
- do_send(SockRef, Rest, EFlags,
- next_timeout(TS, Timeout));
+ send_common(
+ SockRef, Rest, To, EFlags, Deadline, SendName);
- {?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef} ->
- do_send(SockRef, Data, EFlags,
- next_timeout(TS, Timeout));
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, SendRef} ->
+ send_common(
+ SockRef, Data, To, EFlags, Deadline, SendName);
- {?SOCKET_TAG, _Socket, abort, {SendRef, Reason}} ->
- {error, Reason}
+ {?ESOCK_TAG, _Socket, abort, {SendRef, Reason}} ->
+ {error, {Reason, size(Data)}}
- after NewTimeout ->
- cancel(SockRef, send, SendRef),
+ after Timeout ->
+ _ = cancel(SockRef, SendName, SendRef),
{error, {timeout, size(Data)}}
end;
- {error, eagain} when (Timeout =:= nowait) ->
- ?SELECT(send, SendRef);
+ {error, exbusy} = Error when Deadline =:= nowait -> Error;
+
+ {error, exbusy = Reason} ->
+ %% Internal error:
+ %% we called send, got eagain, and called send again
+ %% - without waiting for select message
+ erlang:error(Reason);
+
+ {error, eagain} when (Deadline =:= nowait) ->
+ ?SELECT(SendName, SendRef);
{error, eagain} ->
+ Timeout = timeout(Deadline),
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef} ->
- do_send(SockRef, Data, EFlags,
- next_timeout(TS, Timeout));
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, SendRef} ->
+ send_common(
+ SockRef, Data, To, EFlags, Deadline, SendName);
- {?SOCKET_TAG, _Socket, abort, {SendRef, Reason}} ->
- {error, Reason}
+ {?ESOCK_TAG, _Socket, abort, {SendRef, Reason}} ->
+ {error, {Reason, size(Data)}}
after Timeout ->
- cancel(SockRef, send, SendRef),
+ _ = cancel(SockRef, SendName, SendRef),
{error, {timeout, size(Data)}}
end;
- {error, _} = ERROR ->
- ERROR
- end.
-
+ {error, Reason} ->
+ {error, {Reason, size(Data)}}
+ end.
%% ---------------------------------------------------------------------------
@@ -1643,7 +1719,7 @@ do_send(SockRef, Data, EFlags, Timeout) ->
Reason :: term().
sendto(Socket, Data, Dest) ->
- sendto(Socket, Data, Dest, ?SOCKET_SENDTO_FLAGS_DEFAULT).
+ sendto(Socket, Data, Dest, ?ESOCK_SENDTO_FLAGS_DEFAULT).
-spec sendto(Socket, Data, Dest, Flags) -> ok | {error, Reason} when
Socket :: socket(),
@@ -1667,14 +1743,16 @@ sendto(Socket, Data, Dest) ->
Reason :: term().
sendto(Socket, Data, Dest, Flags) when is_list(Flags) ->
- sendto(Socket, Data, Dest, Flags, ?SOCKET_SENDTO_TIMEOUT_DEFAULT);
+ sendto(Socket, Data, Dest, Flags, ?ESOCK_SENDTO_TIMEOUT_DEFAULT);
sendto(Socket, Data, Dest, Timeout) ->
- sendto(Socket, Data, Dest, ?SOCKET_SENDTO_FLAGS_DEFAULT, Timeout).
+ sendto(Socket, Data, Dest, ?ESOCK_SENDTO_FLAGS_DEFAULT, Timeout).
--spec sendto(Socket, Data, Dest, Flags, nowait) -> ok |
- {select, SelectInfo} |
- {error, Reason} when
+-spec sendto(Socket, Data, Dest, Flags, nowait) ->
+ ok |
+ {ok, {binary(), SelectInfo}} |
+ {select, SelectInfo} |
+ {error, Reason} when
Socket :: socket(),
Data :: binary(),
Dest :: sockaddr(),
@@ -1692,75 +1770,21 @@ sendto(Socket, Data, Dest, Timeout) ->
sendto(Socket, Data, Dest, Flags, Timeout) when is_list(Data) ->
Bin = erlang:list_to_binary(Data),
sendto(Socket, Bin, Dest, Flags, Timeout);
-sendto(#socket{ref = SockRef}, Data, #{family := Fam} = Dest, Flags, Timeout)
- when is_binary(Data) andalso
- ((Fam =:= inet) orelse (Fam =:= inet6) orelse (Fam =:= local)) andalso
- is_list(Flags) andalso
- ((Timeout =:= nowait) orelse
- (Timeout =:= infinity) orelse
- (is_integer(Timeout) andalso (Timeout > 0))) ->
- EFlags = enc_send_flags(Flags),
- do_sendto(SockRef, Data, ensure_sockaddr(Dest), EFlags, Timeout).
-
-do_sendto(SockRef, Data, Dest, EFlags, Timeout) ->
- TS = timestamp(Timeout),
- SendRef = make_ref(),
- case nif_sendto(SockRef, SendRef, Data, Dest, EFlags) of
- ok ->
- %% We are done
- ok;
-
- {ok, Written} when (Timeout =:= nowait) ->
- <<_:Written/binary, Rest/binary>> = Data,
- {ok, {Rest, ?SELECT_INFO(sendto, SendRef)}};
-
-
- {ok, Written} ->
- %% We are partially done, wait for continuation
- receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef}
- when (Written > 0) ->
- <<_:Written/binary, Rest/binary>> = Data,
- do_sendto(SockRef, Rest, Dest, EFlags,
- next_timeout(TS, Timeout));
-
- {?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef} ->
- do_sendto(SockRef, Data, Dest, EFlags,
- next_timeout(TS, Timeout));
-
- {?SOCKET_TAG, _Socket, abort, {SendRef, Reason}} ->
- {error, Reason}
-
- after Timeout ->
- cancel(SockRef, sendto, SendRef),
- {error, timeout}
- end;
-
-
- {error, eagain} when (Timeout =:= nowait) ->
- ?SELECT(sendto, SendRef);
-
-
- {error, eagain} ->
- receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef} ->
- do_sendto(SockRef, Data, Dest, EFlags,
- next_timeout(TS, Timeout));
-
- {?SOCKET_TAG, _Socket, abort, {SendRef, Reason}} ->
- {error, Reason}
-
- after Timeout ->
- cancel(SockRef, sendto, SendRef),
- {error, timeout}
- end;
-
- {error, _} = ERROR ->
+sendto(#socket{ref = SockRef}, Data, Dest, Flags, Timeout)
+ when is_binary(Data), is_list(Flags) ->
+ try
+ begin
+ To = ensure_sockaddr(Dest),
+ EFlags = enc_send_flags(Flags),
+ Deadline = deadline(Timeout),
+ send_common(SockRef, Data, To, EFlags, Deadline, sendto)
+ end
+ catch
+ throw:ERROR ->
ERROR
end.
-
%% ---------------------------------------------------------------------------
%%
%% The only part of the msghdr() that *must* exist (a connected
@@ -1769,51 +1793,53 @@ do_sendto(SockRef, Data, Dest, EFlags, Timeout) ->
%% used when sending.
%%
--spec sendmsg(Socket, MsgHdr) -> ok | {error, Reason} when
+-spec sendmsg(Socket, MsgHdr) ->
+ ok |
+ {ok, Remaining} |
+ {error, Reason} when
Socket :: socket(),
MsgHdr :: msghdr(),
+ Remaining :: erlang:iovec(),
Reason :: term().
sendmsg(Socket, MsgHdr) ->
sendmsg(Socket, MsgHdr,
- ?SOCKET_SENDMSG_FLAGS_DEFAULT, ?SOCKET_SENDMSG_TIMEOUT_DEFAULT).
+ ?ESOCK_SENDMSG_FLAGS_DEFAULT, ?ESOCK_SENDMSG_TIMEOUT_DEFAULT).
-spec sendmsg(Socket, MsgHdr, Flags) -> ok | {error, Reason} when
Socket :: socket(),
MsgHdr :: msghdr(),
Flags :: send_flags(),
- Reason :: term()
- ; (Socket, MsgHdr, Timeout :: nowait) -> ok |
- {select, SelectInfo} |
- {error, Reason} when
+ Reason :: term();
+ (Socket, MsgHdr, Timeout :: nowait) ->
+ ok |
+ {ok, Remaining} |
+ {error, Reason} when
Socket :: socket(),
MsgHdr :: msghdr(),
- SelectInfo :: select_info(),
- Reason :: term()
- ; (Socket, MsgHdr, Timeout) -> ok | {error, Reason} when
+ Remaining :: erlang:iovec(),
+ Reason :: term();
+ (Socket, MsgHdr, Timeout) -> ok | {error, Reason} when
Socket :: socket(),
MsgHdr :: msghdr(),
Timeout :: timeout(),
Reason :: term().
sendmsg(Socket, MsgHdr, Flags) when is_list(Flags) ->
- sendmsg(Socket, MsgHdr, Flags, ?SOCKET_SENDMSG_TIMEOUT_DEFAULT);
-sendmsg(Socket, MsgHdr, Timeout)
- when is_integer(Timeout) orelse (Timeout =:= infinity) ->
- sendmsg(Socket, MsgHdr, ?SOCKET_SENDMSG_FLAGS_DEFAULT, Timeout).
+ sendmsg(Socket, MsgHdr, Flags, ?ESOCK_SENDMSG_TIMEOUT_DEFAULT);
+sendmsg(Socket, MsgHdr, Timeout) ->
+ sendmsg(Socket, MsgHdr, ?ESOCK_SENDMSG_FLAGS_DEFAULT, Timeout).
-spec sendmsg(Socket, MsgHdr, Flags, nowait) ->
ok |
{ok, Remaining} |
- {select, SelectInfo} |
{error, Reason} when
Socket :: socket(),
MsgHdr :: msghdr(),
Flags :: send_flags(),
Remaining :: erlang:iovec(),
- SelectInfo :: select_info(),
Reason :: term()
; (Socket, MsgHdr, Flags, Timeout) ->
ok |
@@ -1827,25 +1853,24 @@ sendmsg(Socket, MsgHdr, Timeout)
Reason :: term().
sendmsg(#socket{ref = SockRef}, #{iov := IOV} = MsgHdr, Flags, Timeout)
- when is_list(IOV) andalso
- is_list(Flags) andalso
- ((Timeout =:= nowait) orelse
- (Timeout =:= infinity) orelse
- (is_integer(Timeout) andalso (Timeout > 0))) ->
- try ensure_msghdr(MsgHdr) of
- M ->
+ when is_list(IOV), is_list(Flags) ->
+ try
+ begin
+ M = ensure_msghdr(MsgHdr),
EFlags = enc_send_flags(Flags),
- do_sendmsg(SockRef, M, EFlags, Timeout)
+ Deadline = deadline(Timeout),
+ do_sendmsg(SockRef, M, EFlags, Deadline)
+ end
catch
- throw:T ->
- T;
- error:Reason ->
- {error, Reason}
+ throw:ERROR ->
+ ERROR
end.
-do_sendmsg(SockRef, MsgHdr, EFlags, Timeout) ->
- TS = timestamp(Timeout),
+
+do_sendmsg(SockRef, MsgHdr, EFlags, Deadline) ->
+
SendRef = make_ref(),
+
case nif_sendmsg(SockRef, SendRef, MsgHdr, EFlags) of
ok ->
%% We are done
@@ -1857,28 +1882,39 @@ do_sendmsg(SockRef, MsgHdr, EFlags, Timeout) ->
%% be able to handle a message being split. Leave it to
%% the caller to figure out (call again with the rest).
%%
- %% We should really not need to cancel, since this is
- %% accepted for sendmsg!
+ %% We need to cancel this partial write.
%%
- cancel(SockRef, sendmsg, SendRef),
+ _ = cancel(SockRef, sendmsg, SendRef),
{ok, do_sendmsg_rest(maps:get(iov, MsgHdr), Written)};
- {error, eagain} when (Timeout =:= nowait) ->
+ {error, exbusy} = Error when Deadline =:= nowait -> Error;
+
+ {error, exbusy = Reason} ->
+ %% Internal error:
+ %% we called send, got eagain, and called send again
+ %% - without waiting for select message
+ erlang:error(Reason);
+
+
+ {error, eagain} when (Deadline =:= nowait) ->
?SELECT(sendmsg, SendRef);
-
{error, eagain} ->
+ Timeout = timeout(Deadline),
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, SendRef} ->
- do_sendmsg(SockRef, MsgHdr, EFlags,
- next_timeout(TS, Timeout))
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, SendRef} ->
+ do_sendmsg(SockRef, MsgHdr, EFlags, Deadline);
+
+ {?ESOCK_TAG, _Socket, abort, {SendRef, Reason}} ->
+ {error, Reason}
after Timeout ->
- cancel(SockRef, sendmsg, SendRef),
+ _ = cancel(SockRef, sendmsg, SendRef),
{error, timeout}
end;
+
{error, _} = ERROR ->
ERROR
end.
@@ -1902,7 +1938,6 @@ ensure_msghdr(_) ->
-
%% ===========================================================================
%%
%% recv, recvfrom, recvmsg - receive a message from a socket
@@ -1942,8 +1977,8 @@ recv(Socket) ->
recv(Socket, Length) ->
recv(Socket, Length,
- ?SOCKET_RECV_FLAGS_DEFAULT,
- ?SOCKET_RECV_TIMEOUT_DEFAULT).
+ ?ESOCK_RECV_FLAGS_DEFAULT,
+ ?ESOCK_RECV_TIMEOUT_DEFAULT).
-spec recv(Socket, Length, Flags) -> {ok, Data} |
{error, Reason} when
@@ -1970,9 +2005,9 @@ recv(Socket, Length) ->
Reason :: term().
recv(Socket, Length, Flags) when is_list(Flags) ->
- recv(Socket, Length, Flags, ?SOCKET_RECV_TIMEOUT_DEFAULT);
+ recv(Socket, Length, Flags, ?ESOCK_RECV_TIMEOUT_DEFAULT);
recv(Socket, Length, Timeout) ->
- recv(Socket, Length, ?SOCKET_RECV_FLAGS_DEFAULT, Timeout).
+ recv(Socket, Length, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
-spec recv(Socket, Length, Flags, nowait) -> {ok, Data} |
{select, SelectInfo} |
@@ -1994,154 +2029,134 @@ recv(Socket, Length, Timeout) ->
Reason :: term().
recv(#socket{ref = SockRef}, Length, Flags, Timeout)
- when (is_integer(Length) andalso (Length >= 0)) andalso
- is_list(Flags) andalso
- (is_integer(Timeout) orelse
- (Timeout =:= infinity) orelse
- (Timeout =:= nowait)) ->
- EFlags = enc_recv_flags(Flags),
- do_recv(SockRef, undefined, Length, EFlags, <<>>, Timeout).
-
-%% We need to pass the "old recv ref" around because of the special case
-%% with Length = 0. This case makes it neccessary to have a timeout function
-%% clause since we may never wait for anything (no receive select), and so the
-%% the only timeout check will be the function clause.
-%% Note that the Timeout value of 'nowait' has a special meaning. It means
+ when is_integer(Length), Length >= 0, is_list(Flags) ->
+ try
+ EFlags = enc_recv_flags(Flags),
+ Deadline = deadline(Timeout),
+ do_recv(SockRef, Length, EFlags, Deadline, <<>>)
+ catch
+ throw:ERROR ->
+ ERROR
+ end.
+
+%% We will only recurse with Length == 0 if Length is 0,
+%% so Length == 0 means to return all available data also when recursing
+%%
+%% Note that the Deadline value of 'nowait' has a special meaning. It means
%% that we will either return with data or with the with {error, NNNN}. In
%% wich case the caller will receive a select message at some later time.
-do_recv(SockRef, _OldRef, Length, EFlags, Acc, Timeout)
- when (Timeout =:= nowait) orelse
- (Timeout =:= infinity) orelse
- (is_integer(Timeout) andalso (Timeout > 0)) ->
- TS = timestamp(Timeout),
+%%
+do_recv(SockRef, Length, EFlags, Deadline, Acc) ->
+
RecvRef = make_ref(),
case nif_recv(SockRef, RecvRef, Length, EFlags) of
- {ok, true = _Complete, Bin} when (size(Acc) =:= 0) ->
- {ok, Bin};
+
{ok, true = _Complete, Bin} ->
- {ok, <<Acc/binary, Bin/binary>>};
+ {ok, bincat(Acc, Bin)};
+
%% It depends on the amount of bytes we tried to read:
%% 0 - Read everything available
%% We got something, but there may be more - keep reading.
%% > 0 - We got a part of the message and we will be notified
%% when there is more to read (a select message)
- {ok, false = _Complete, Bin} when (Length =:= 0) ->
- do_recv(SockRef, RecvRef,
- Length, EFlags,
- <<Acc/binary, Bin/binary>>,
- next_timeout(TS, Timeout));
-
+ {ok, false = _Complete, Bin} when Length =:= 0 ->
+ Timeout = timeout(Deadline),
+ if
+ 0 < Timeout ->
+ do_recv(
+ SockRef, Length, EFlags, Deadline, bincat(Acc, Bin));
+ true ->
+ {ok, bincat(Acc, Bin)}
+ end;
%% Did not get all the user asked for, but the user also
%% specified 'nowait', so deliver what we got and the
%% select info.
- {ok, false = _Completed, Bin} when (Timeout =:= nowait) andalso
- (size(Acc) =:= 0) ->
- {ok, {Bin, ?SELECT_INFO(recv, RecvRef)}};
+ {ok, false = _Completed, Bin} when Deadline =:= nowait ->
+ {ok, {bincat(Acc, Bin), ?SELECT_INFO(recv, RecvRef)}};
-
- {ok, false = _Completed, Bin} when (size(Acc) =:= 0) ->
- %% We got the first chunk of it.
- %% We will be notified (select message) when there
- %% is more to read.
- NewTimeout = next_timeout(TS, Timeout),
+ {ok, false = _Completed, Bin} ->
+ %% We got a chunk of it!
+ Timeout = timeout(Deadline),
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, RecvRef} ->
- do_recv(SockRef, RecvRef,
- Length-size(Bin), EFlags,
- Bin,
- next_timeout(TS, Timeout));
-
- {?SOCKET_TAG, _Socket, abort, {RecvRef, Reason}} ->
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, RecvRef} ->
+ if
+ 0 < Timeout ->
+ do_recv(
+ SockRef, Length - byte_size(Bin), EFlags,
+ Deadline, bincat(Acc, Bin));
+ true ->
+ {error, {timeout, bincat(Acc, Bin)}}
+ end;
+
+ {?ESOCK_TAG, _Socket, abort, {RecvRef, Reason}} ->
{error, Reason}
- after NewTimeout ->
+ after Timeout ->
cancel(SockRef, recv, RecvRef),
- {error, {timeout, Acc}}
+ {error, {timeout, bincat(Acc, Bin)}}
end;
- {ok, false = _Completed, Bin} ->
- %% We got a chunk of it!
- NewTimeout = next_timeout(TS, Timeout),
- receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, RecvRef} ->
- do_recv(SockRef, RecvRef,
- Length-size(Bin), EFlags,
- <<Acc/binary, Bin/binary>>,
- next_timeout(TS, Timeout));
- {?SOCKET_TAG, _Socket, abort, {RecvRef, Reason}} ->
- {error, Reason}
+ {error, exbusy} = Error when Deadline =:= nowait -> Error;
- after NewTimeout ->
- cancel(SockRef, recv, RecvRef),
- {error, {timeout, Acc}}
- end;
+ {error, exbusy = Reason} ->
+ %% Internal error:
+ %% we called recv, got eagain, and called recv again
+ %% - without waiting for select message
+ erlang:error(Reason);
%% The user does not want to wait!
%% The user will be informed that there is something to read
%% via the select socket message (see below).
-
- {error, eagain} when (Timeout =:= nowait) andalso (size(Acc) =:= 0) ->
- ?SELECT(recv, RecvRef);
- {error, eagain} when (Timeout =:= nowait) ->
- {ok, {Acc, ?SELECT_INFO(recv, RecvRef)}};
+ {error, eagain} when Deadline =:= nowait ->
+ if
+ byte_size(Acc) =:= 0 ->
+ ?SELECT(recv, RecvRef);
+ true ->
+ {ok, {Acc, ?SELECT_INFO(recv, RecvRef)}}
+ end;
%% We return with the accumulated binary (if its non-empty)
- {error, eagain} when (Length =:= 0) andalso (size(Acc) > 0) ->
- %% CAN WE REALLY DO THIS? THE NIF HAS SELECTED!! OR?
+ {error, eagain} when Length =:= 0, 0 < byte_size(Acc) ->
+ cancel(SockRef, recv, RecvRef),
{ok, Acc};
{error, eagain} ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
- NewTimeout = next_timeout(TS, Timeout),
+ Timeout = timeout(Deadline),
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, RecvRef} ->
- do_recv(SockRef, RecvRef,
- Length, EFlags,
- Acc,
- next_timeout(TS, Timeout));
-
- {?SOCKET_TAG, _Socket, abort, {RecvRef, Reason}} ->
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, RecvRef} ->
+ if
+ 0 < Timeout ->
+ do_recv(
+ SockRef, Length, EFlags, Deadline, Acc);
+ 0 < byte_size(Acc) ->
+ {error, {timeout, Acc}};
+ true ->
+ {error, timeout}
+ end;
+
+ {?ESOCK_TAG, _Socket, abort, {RecvRef, Reason}} ->
{error, Reason}
- after NewTimeout ->
+ after Timeout ->
cancel(SockRef, recv, RecvRef),
{error, timeout}
end;
- {error, closed = Reason} ->
- do_close(SockRef),
- if
- (size(Acc) =:= 0) ->
- {error, Reason};
- true ->
- {error, {Reason, Acc}}
- end;
- {error, _} = ERROR when (size(Acc) =:= 0) ->
+ {error, _} = ERROR when byte_size(Acc) =:= 0 ->
ERROR;
{error, Reason} ->
{error, {Reason, Acc}}
- end;
-
-do_recv(SockRef, RecvRef, 0 = _Length, _Eflags, Acc, _Timeout) ->
- %% The current recv operation is to be cancelled, so no need for a ref...
- %% The cancel will end our 'read everything you have' and "activate"
- %% any waiting reader.
- cancel(SockRef, recv, RecvRef),
- {ok, Acc};
-do_recv(_SockRef, _RecvRef, _Length, _EFlags, Acc, _Timeout)
- when (size(Acc) > 0) ->
- {error, {timeout, Acc}};
-do_recv(_SockRef, _RecvRef, _Length, _EFlags, _Acc, _Timeout) ->
- {error, timeout}.
+ end.
@@ -2177,8 +2192,8 @@ recvfrom(Socket) ->
recvfrom(Socket, BufSz) ->
recvfrom(Socket, BufSz,
- ?SOCKET_RECV_FLAGS_DEFAULT,
- ?SOCKET_RECV_TIMEOUT_DEFAULT).
+ ?ESOCK_RECV_FLAGS_DEFAULT,
+ ?ESOCK_RECV_TIMEOUT_DEFAULT).
-spec recvfrom(Socket, Flags, nowait) ->
{ok, {Source, Data}} |
@@ -2229,9 +2244,9 @@ recvfrom(Socket, BufSz) ->
recvfrom(Socket, Flags, Timeout) when is_list(Flags) ->
recvfrom(Socket, 0, Flags, Timeout);
recvfrom(Socket, BufSz, Flags) when is_list(Flags) ->
- recvfrom(Socket, BufSz, Flags, ?SOCKET_RECV_TIMEOUT_DEFAULT);
+ recvfrom(Socket, BufSz, Flags, ?ESOCK_RECV_TIMEOUT_DEFAULT);
recvfrom(Socket, BufSz, Timeout) ->
- recvfrom(Socket, BufSz, ?SOCKET_RECV_FLAGS_DEFAULT, Timeout).
+ recvfrom(Socket, BufSz, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
-spec recvfrom(Socket, BufSz, Flags, nowait) ->
{ok, {Source, Data}} |
@@ -2256,43 +2271,54 @@ recvfrom(Socket, BufSz, Timeout) ->
Reason :: term().
recvfrom(#socket{ref = SockRef}, BufSz, Flags, Timeout)
- when (is_integer(BufSz) andalso (BufSz >= 0)) andalso
- is_list(Flags) andalso
- (is_integer(Timeout) orelse
- (Timeout =:= infinity) orelse
- (Timeout =:= nowait)) ->
- EFlags = enc_recv_flags(Flags),
- do_recvfrom(SockRef, BufSz, EFlags, Timeout).
-
-do_recvfrom(SockRef, BufSz, EFlags, Timeout) ->
- TS = timestamp(Timeout),
+ when is_integer(BufSz), 0 =< BufSz, is_list(Flags) ->
+ try
+ EFlags = enc_recv_flags(Flags),
+ Deadline = deadline(Timeout),
+ do_recvfrom(SockRef, BufSz, EFlags, Deadline)
+ catch
+ throw:ERROR ->
+ ERROR
+ end.
+
+do_recvfrom(SockRef, BufSz, EFlags, Deadline) ->
+
RecvRef = make_ref(),
case nif_recvfrom(SockRef, RecvRef, BufSz, EFlags) of
+
{ok, {_Source, _NewData}} = OK ->
OK;
- {error, eagain} when (Timeout =:= nowait) ->
- ?SELECT(recvfrom, RecvRef);
+ {error, exbusy} = Error when Deadline =:= nowait -> Error;
+
+ {error, exbusy = Reason} ->
+ %% Internal error:
+ %% we called recvfrom, got eagain, and called recvfrom again
+ %% - without waiting for select message
+ erlang:error(Reason);
+ {error, eagain} when Deadline =:= nowait ->
+ ?SELECT(recvfrom, RecvRef);
+
{error, eagain} ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
- NewTimeout = next_timeout(TS, Timeout),
+ Timeout = timeout(Deadline),
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, RecvRef} ->
- do_recvfrom(SockRef, BufSz, EFlags,
- next_timeout(TS, Timeout));
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, RecvRef} ->
+ do_recvfrom(SockRef, BufSz, EFlags, Deadline);
- {?SOCKET_TAG, _Socket, abort, {RecvRef, Reason}} ->
+ {?ESOCK_TAG, _Socket, abort, {RecvRef, Reason}} ->
{error, Reason}
- after NewTimeout ->
+ after Timeout ->
cancel(SockRef, recvfrom, RecvRef),
{error, timeout}
end;
+
{error, _Reason} = ERROR ->
ERROR
@@ -2309,7 +2335,7 @@ do_recvfrom(SockRef, BufSz, EFlags, Timeout) ->
recvmsg(Socket) ->
recvmsg(Socket, 0, 0,
- ?SOCKET_RECV_FLAGS_DEFAULT, ?SOCKET_RECV_TIMEOUT_DEFAULT).
+ ?ESOCK_RECV_FLAGS_DEFAULT, ?ESOCK_RECV_TIMEOUT_DEFAULT).
-spec recvmsg(Socket, Flags) -> {ok, MsgHdr} | {error, Reason} when
Socket :: socket(),
@@ -2330,9 +2356,9 @@ recvmsg(Socket) ->
Reason :: term().
recvmsg(Socket, Flags) when is_list(Flags) ->
- recvmsg(Socket, 0, 0, Flags, ?SOCKET_RECV_TIMEOUT_DEFAULT);
+ recvmsg(Socket, 0, 0, Flags, ?ESOCK_RECV_TIMEOUT_DEFAULT);
recvmsg(Socket, Timeout) ->
- recvmsg(Socket, 0, 0, ?SOCKET_RECV_FLAGS_DEFAULT, Timeout).
+ recvmsg(Socket, 0, 0, ?ESOCK_RECV_FLAGS_DEFAULT, Timeout).
-spec recvmsg(Socket, Flags, nowait) -> {ok, MsgHdr} |
{select, SelectInfo} |
@@ -2357,9 +2383,9 @@ recvmsg(Socket, Timeout) ->
recvmsg(Socket, Flags, Timeout) when is_list(Flags) ->
recvmsg(Socket, 0, 0, Flags, Timeout);
-recvmsg(Socket, BufSz, CtrlSz) when is_integer(BufSz) andalso is_integer(CtrlSz) ->
+recvmsg(Socket, BufSz, CtrlSz) when is_integer(BufSz), is_integer(CtrlSz) ->
recvmsg(Socket, BufSz, CtrlSz,
- ?SOCKET_RECV_FLAGS_DEFAULT, ?SOCKET_RECV_TIMEOUT_DEFAULT).
+ ?ESOCK_RECV_FLAGS_DEFAULT, ?ESOCK_RECV_TIMEOUT_DEFAULT).
-spec recvmsg(Socket,
@@ -2386,47 +2412,55 @@ recvmsg(Socket, BufSz, CtrlSz) when is_integer(BufSz) andalso is_integer(CtrlSz)
Reason :: term().
recvmsg(#socket{ref = SockRef}, BufSz, CtrlSz, Flags, Timeout)
- when (is_integer(BufSz) andalso (BufSz >= 0)) andalso
- (is_integer(CtrlSz) andalso (CtrlSz >= 0)) andalso
- is_list(Flags) andalso
- (is_integer(Timeout) orelse
- (Timeout =:= infinity) orelse
- (Timeout =:= nowait)) ->
- EFlags = enc_recv_flags(Flags),
- do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Timeout).
-
-do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Timeout) ->
- TS = timestamp(Timeout),
+ when is_integer(BufSz), 0 =< BufSz,
+ is_integer(CtrlSz), 0 =< CtrlSz,
+ is_list(Flags) ->
+ try
+ EFlags = enc_recv_flags(Flags),
+ Deadline = deadline(Timeout),
+ do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Deadline)
+ catch
+ throw:ERROR ->
+ ERROR
+ end.
+
+do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Deadline) ->
+
RecvRef = make_ref(),
case nif_recvmsg(SockRef, RecvRef, BufSz, CtrlSz, EFlags) of
+
{ok, _MsgHdr} = OK ->
OK;
- {error, eagain} when (Timeout =:= nowait) ->
- ?SELECT(recvmsg, RecvRef);
+ {error, exbusy} = Error when Deadline =:= nowait -> Error;
+
+ {error, exbusy = Reason} ->
+ %% Internal error:
+ %% we called recvmsg, got eagain, and called recvmsg again
+ %% - without waiting for select message
+ erlang:error(Reason);
+ {error, eagain} when Deadline =:= nowait ->
+ ?SELECT(recvmsg, RecvRef);
+
{error, eagain} ->
%% There is nothing just now, but we will be notified when there
%% is something to read (a select message).
- NewTimeout = next_timeout(TS, Timeout),
+ Timeout = timeout(Deadline),
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, RecvRef} ->
- do_recvmsg(SockRef, BufSz, CtrlSz, EFlags,
- next_timeout(TS, Timeout));
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, RecvRef} ->
+ do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Deadline);
- {?SOCKET_TAG, _Socket, abort, {RecvRef, Reason}} ->
+ {?ESOCK_TAG, _Socket, abort, {RecvRef, Reason}} ->
{error, Reason}
- after NewTimeout ->
+ after Timeout ->
cancel(SockRef, recvmsg, RecvRef),
{error, timeout}
end;
- {error, closed} = ERROR ->
- do_close(SockRef),
- ERROR;
{error, _Reason} = ERROR ->
ERROR
@@ -2435,7 +2469,6 @@ do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Timeout) ->
-
%% ===========================================================================
%%
%% close - close a file descriptor
@@ -2455,9 +2488,6 @@ do_recvmsg(SockRef, BufSz, CtrlSz, EFlags, Timeout) ->
Reason :: term().
close(#socket{ref = SockRef}) ->
- do_close(SockRef).
-
-do_close(SockRef) ->
case nif_close(SockRef) of
ok ->
nif_finalize_close(SockRef);
@@ -2465,7 +2495,7 @@ do_close(SockRef) ->
%% We must wait for the socket_stop callback function to
%% complete its work
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, close, CloseRef} ->
+ {?ESOCK_TAG, #socket{ref = SockRef}, close, CloseRef} ->
nif_finalize_close(SockRef)
end;
{error, _} = ERROR ->
@@ -2487,10 +2517,7 @@ do_close(SockRef) ->
shutdown(#socket{ref = SockRef}, How) ->
try
- begin
- EHow = enc_shutdown_how(How),
- nif_shutdown(SockRef, EHow)
- end
+ nif_shutdown(SockRef, enc_shutdown_how(How))
catch
throw:T ->
T;
@@ -2559,23 +2586,15 @@ shutdown(#socket{ref = SockRef}, How) ->
setopt(#socket{ref = SockRef}, Level, Key, Value) ->
try
begin
- Domain = which_domain(SockRef),
- Type = which_type(SockRef),
- Protocol = which_protocol(SockRef),
+ {Domain, Type, Proto} = which_dtp(SockRef),
{EIsEncoded, ELevel} = enc_setopt_level(Level),
- EKey = enc_setopt_key(Level, Key, Domain, Type, Protocol),
- EVal = enc_setopt_value(Level, Key, Value, Domain, Type, Protocol),
+ EKey = enc_setopt_key(Level, Key, Domain, Type, Proto),
+ EVal = enc_setopt_value(Level, Key, Value, Domain, Type, Proto),
nif_setopt(SockRef, EIsEncoded, ELevel, EKey, EVal)
end
catch
- throw:T ->
- T;
- %% <WIN32-TEMPORARY>
- error:notsup:S ->
- erlang:raise(error, notsup, S);
- %% </WIN32-TEMPORARY>
- error:Reason ->
- {error, Reason} % Process more?
+ throw:ERROR ->
+ ERROR
end.
@@ -2635,33 +2654,26 @@ setopt(#socket{ref = SockRef}, Level, Key, Value) ->
getopt(#socket{ref = SockRef}, Level, Key) ->
try
begin
- Domain = which_domain(SockRef),
- Type = which_type(SockRef),
- Protocol = which_protocol(SockRef),
+ {Domain, Type, Proto} = which_dtp(SockRef),
{EIsEncoded, ELevel} = enc_getopt_level(Level),
- EKey = enc_getopt_key(Level, Key, Domain, Type, Protocol),
+ EKey = enc_getopt_key(Level, Key, Domain, Type, Proto),
%% We may need to decode the value (for the same reason
%% we (may have) needed to encode the value for setopt).
case nif_getopt(SockRef, EIsEncoded, ELevel, EKey) of
ok ->
ok;
{ok, EVal} ->
- Val = dec_getopt_value(Level, Key, EVal,
- Domain, Type, Protocol),
+ Val =
+ dec_getopt_value(
+ Level, Key, EVal, Domain, Type, Proto),
{ok, Val};
- {error, _} = ERROR ->
- ERROR
+ {error, _} = E ->
+ E
end
end
catch
- throw:E:_S ->
- E;
- %% <WIN32-TEMPORARY>
- error:notsup:S ->
- erlang:raise(error, notsup, S);
- %% </WIN32-TEMPORARY>
- error:Reason:_Stack ->
- {error, Reason} % Process more?
+ throw:ERROR ->
+ ERROR
end.
@@ -2674,43 +2686,77 @@ getopt(#socket{ref = SockRef}, Level, Key) ->
which_domain(SockRef) ->
case nif_getopt(SockRef, true,
- ?SOCKET_OPT_LEVEL_OTP, ?SOCKET_OPT_OTP_DOMAIN) of
+ ?ESOCK_OPT_LEVEL_OTP, ?ESOCK_OPT_OTP_DOMAIN) of
{ok, Domain} ->
- Domain;
+ if
+ is_atom(Domain) ->
+ Domain;
+ is_integer(Domain) ->
+ invalid_domain(Domain)
+ end;
{error, _} = ERROR ->
throw(ERROR)
end.
--spec which_type(SockRef) -> Type when
- SockRef :: reference(),
- Type :: type().
-
-which_type(SockRef) ->
- case nif_getopt(SockRef, true,
- ?SOCKET_OPT_LEVEL_OTP, ?SOCKET_OPT_OTP_TYPE) of
- {ok, Type} ->
- Type;
- {error, _} = ERROR ->
- throw(ERROR)
- end.
-
--spec which_protocol(SockRef) -> Protocol when
- SockRef :: reference(),
- Protocol :: protocol().
-
-which_protocol(SockRef) ->
- case nif_getopt(SockRef, true,
- ?SOCKET_OPT_LEVEL_OTP, ?SOCKET_OPT_OTP_PROTOCOL) of
- {ok, Proto} ->
- Proto;
+%%%-spec which_type(SockRef) -> Type when
+%%% SockRef :: reference(),
+%%% Type :: type().
+%%%
+%%%which_type(SockRef) ->
+%%% case nif_getopt(SockRef, true,
+%%% ?ESOCK_OPT_LEVEL_OTP, ?ESOCK_OPT_OTP_TYPE) of
+%%% {ok, Type} ->
+%%% if
+%%% is_atom(Type) ->
+%%% Type;
+%%% is_integer(Type) ->
+%%% invalid_type(Type)
+%%% end;
+%%% {error, _} = ERROR ->
+%%% throw(ERROR)
+%%% end.
+%%%
+%%%-spec which_protocol(SockRef) -> Protocol when
+%%% SockRef :: reference(),
+%%% Protocol :: protocol().
+%%%
+%%%which_protocol(SockRef) ->
+%%% case nif_getopt(SockRef, true,
+%%% ?ESOCK_OPT_LEVEL_OTP, ?ESOCK_OPT_OTP_PROTOCOL) of
+%%% {ok, Proto} ->
+%%% if
+%%% is_atom(Proto) ->
+%%% Proto;
+%%% is_integer(Proto) ->
+%%% invalid_protocol(Proto)
+%%% end;
+%%% {error, _} = ERROR ->
+%%% throw(ERROR)
+%%% end.
+
+which_dtp(SockRef) ->
+ case
+ nif_getopt(
+ SockRef, true, ?ESOCK_OPT_LEVEL_OTP, ?ESOCK_OPT_OTP_DTP)
+ of
+ {ok, {Domain, Type, Proto} = DTP} ->
+ if
+ is_integer(Domain) ->
+ invalid_domain(Domain);
+ is_integer(Type) ->
+ invalid_type(Type);
+ is_integer(Proto) ->
+ invalid_protocol(Proto);
+ is_atom(Domain), is_atom(Type), is_atom(Proto) ->
+ DTP
+ end;
{error, _} = ERROR ->
throw(ERROR)
end.
-
%% ===========================================================================
%%
%% sockname - return the current address of the socket.
@@ -2771,61 +2817,57 @@ cancel(#socket{ref = SockRef}, ?SELECT_INFO(Tag, Ref)) ->
%% -spec enc_domain(Domain) -> non_neg_integer() when
%% Domain :: domain().
-enc_domain(local) -> ?SOCKET_DOMAIN_LOCAL;
-enc_domain(inet) -> ?SOCKET_DOMAIN_INET;
-enc_domain(inet6) -> ?SOCKET_DOMAIN_INET6;
+enc_domain(local) -> ?ESOCK_DOMAIN_LOCAL;
+enc_domain(inet) -> ?ESOCK_DOMAIN_INET;
+enc_domain(inet6) -> ?ESOCK_DOMAIN_INET6;
enc_domain(Domain) -> invalid_domain(Domain).
-%% -spec enc_type(Domain, Type) -> non_neg_integer() when
-%% Domain :: domain(),
+%% -spec enc_type(Type) -> non_neg_integer() when
%% Type :: type().
-%% What combos are valid?
-enc_type(_, stream) -> ?SOCKET_TYPE_STREAM;
-enc_type(_, dgram) -> ?SOCKET_TYPE_DGRAM;
-enc_type(_, raw) -> ?SOCKET_TYPE_RAW;
-enc_type(_, seqpacket) -> ?SOCKET_TYPE_SEQPACKET;
-enc_type(_, Type) -> invalid_type(Type).
+enc_type(stream) -> ?ESOCK_TYPE_STREAM;
+enc_type(dgram) -> ?ESOCK_TYPE_DGRAM;
+enc_type(raw) -> ?ESOCK_TYPE_RAW;
+enc_type(seqpacket) -> ?ESOCK_TYPE_SEQPACKET;
+enc_type(Type) -> invalid_type(Type).
--spec enc_protocol(Type, Protocol) -> non_neg_integer() |
- {raw, non_neg_integer()} when
- Type :: type(),
+-spec enc_protocol(Protocol) -> non_neg_integer() |
+ {raw, non_neg_integer()} when
Protocol :: protocol().
-enc_protocol(_, default) -> ?SOCKET_PROTOCOL_DEFAULT;
-enc_protocol(dgram, ip) -> ?SOCKET_PROTOCOL_IP;
-enc_protocol(stream, tcp) -> ?SOCKET_PROTOCOL_TCP;
-enc_protocol(dgram, udp) -> ?SOCKET_PROTOCOL_UDP;
-enc_protocol(seqpacket, sctp) -> ?SOCKET_PROTOCOL_SCTP;
-enc_protocol(dgram, icmp) -> ?SOCKET_PROTOCOL_ICMP;
-enc_protocol(raw, icmp) -> ?SOCKET_PROTOCOL_ICMP;
-enc_protocol(raw, igmp) -> ?SOCKET_PROTOCOL_IGMP;
-enc_protocol(raw, {raw, P} = RAW) when is_integer(P) -> RAW;
-enc_protocol(Type, Proto) ->
- invalid_protocol(Type, Proto).
+enc_protocol(default) -> ?ESOCK_PROTOCOL_DEFAULT;
+enc_protocol(ip) -> ?ESOCK_PROTOCOL_IP;
+enc_protocol(tcp) -> ?ESOCK_PROTOCOL_TCP;
+enc_protocol(udp) -> ?ESOCK_PROTOCOL_UDP;
+enc_protocol(sctp) -> ?ESOCK_PROTOCOL_SCTP;
+enc_protocol(icmp) -> ?ESOCK_PROTOCOL_ICMP;
+enc_protocol(igmp) -> ?ESOCK_PROTOCOL_IGMP;
+enc_protocol({raw, P} = RAW) when is_integer(P) -> RAW;
+enc_protocol(Proto) ->
+ invalid_protocol(Proto).
-spec enc_send_flags(Flags) -> non_neg_integer() when
Flags :: send_flags().
enc_send_flags(Flags) ->
- EFlags = [{confirm, ?SOCKET_SEND_FLAG_CONFIRM},
- {dontroute, ?SOCKET_SEND_FLAG_DONTROUTE},
- {eor, ?SOCKET_SEND_FLAG_EOR},
- {more, ?SOCKET_SEND_FLAG_MORE},
- {nosignal, ?SOCKET_SEND_FLAG_NOSIGNAL},
- {oob, ?SOCKET_SEND_FLAG_OOB}],
+ EFlags = [{confirm, ?ESOCK_SEND_FLAG_CONFIRM},
+ {dontroute, ?ESOCK_SEND_FLAG_DONTROUTE},
+ {eor, ?ESOCK_SEND_FLAG_EOR},
+ {more, ?ESOCK_SEND_FLAG_MORE},
+ {nosignal, ?ESOCK_SEND_FLAG_NOSIGNAL},
+ {oob, ?ESOCK_SEND_FLAG_OOB}],
enc_flags(Flags, EFlags).
-spec enc_recv_flags(Flags) -> non_neg_integer() when
Flags :: recv_flags().
enc_recv_flags(Flags) ->
- EFlags = [{cmsg_cloexec, ?SOCKET_RECV_FLAG_CMSG_CLOEXEC},
- {errqueue, ?SOCKET_RECV_FLAG_ERRQUEUE},
- {oob, ?SOCKET_RECV_FLAG_OOB},
- {peek, ?SOCKET_RECV_FLAG_PEEK},
- {trunc, ?SOCKET_RECV_FLAG_TRUNC}],
+ EFlags = [{cmsg_cloexec, ?ESOCK_RECV_FLAG_CMSG_CLOEXEC},
+ {errqueue, ?ESOCK_RECV_FLAG_ERRQUEUE},
+ {oob, ?ESOCK_RECV_FLAG_OOB},
+ {peek, ?ESOCK_RECV_FLAG_PEEK},
+ {trunc, ?ESOCK_RECV_FLAG_TRUNC}],
enc_flags(Flags, EFlags).
@@ -2851,19 +2893,19 @@ enc_flags(Flags, EFlags) ->
EncodedLevel :: integer().
enc_setopt_level(otp) ->
- {true, ?SOCKET_OPT_LEVEL_OTP};
+ {true, ?ESOCK_OPT_LEVEL_OTP};
enc_setopt_level(socket) ->
- {true, ?SOCKET_OPT_LEVEL_SOCKET};
+ {true, ?ESOCK_OPT_LEVEL_SOCKET};
enc_setopt_level(ip) ->
- {true, ?SOCKET_OPT_LEVEL_IP};
+ {true, ?ESOCK_OPT_LEVEL_IP};
enc_setopt_level(ipv6) ->
- {true, ?SOCKET_OPT_LEVEL_IPV6};
+ {true, ?ESOCK_OPT_LEVEL_IPV6};
enc_setopt_level(tcp) ->
- {true, ?SOCKET_OPT_LEVEL_TCP};
+ {true, ?ESOCK_OPT_LEVEL_TCP};
enc_setopt_level(udp) ->
- {true, ?SOCKET_OPT_LEVEL_UDP};
+ {true, ?ESOCK_OPT_LEVEL_UDP};
enc_setopt_level(sctp) ->
- {true, ?SOCKET_OPT_LEVEL_SCTP};
+ {true, ?ESOCK_OPT_LEVEL_SCTP};
%% Any option that is of an plain level must be provided as a binary
%% already fully encoded!
enc_setopt_level(L) when is_integer(L) ->
@@ -2889,7 +2931,6 @@ enc_setopt_key(Level, Opt, Domain, Type, Protocol) ->
%% encode the value into an more "manageable" type.
%% It also handles "aliases" (see linger).
--dialyzer({nowarn_function, enc_setopt_value/6}).
-spec enc_setopt_value(otp, otp_socket_option(),
Value, Domain, Type, Protocol) -> term() when
Value :: term(),
@@ -2965,6 +3006,8 @@ enc_setopt_value(otp, sndctrlbuf, V, _, _, _) when (V =:= default) ->
0;
enc_setopt_value(otp, sndctrlbuf, V, _, _, _) when is_integer(V) andalso (V > 0) ->
V;
+enc_setopt_value(otp, meta, V, _, _, _) ->
+ V;
enc_setopt_value(otp = L, Opt, V, _D, _T, _P) ->
not_supported({L, Opt, V});
@@ -3355,12 +3398,6 @@ enc_getopt_key(Level, Opt, Domain, Type, Protocol) ->
%% For the most part, we simply let the value pass through, but for some
%% values we may need to do an actual decode.
%%
-%% For some reason dialyzer thinks that the only valid value for Opt to
-%% this function is otp_socket_option(). Of course without explaining
-%% how it came to that conclusion... And since I know that to be false...
-%%
-
--dialyzer({nowarn_function, dec_getopt_value/6}).
%% This string is NULL-terminated, but the general function we use
%% in the nif code does not know that. So, deal with it here.
@@ -3377,78 +3414,77 @@ dec_getopt_value(_L, _Opt, V, _D, _T, _P) ->
%% Most options are usable both for set and get, but some are
%% are only available for e.g. get.
--spec enc_sockopt_key(Level, Opt,
- Direction,
+-spec enc_sockopt_key(Level, Opt, Direction,
Domain, Type, Protocol) -> non_neg_integer() when
Level :: otp,
Direction :: set | get,
Opt :: otp_socket_option(),
Domain :: domain(),
Type :: type(),
- Protocol :: protocol()
- ; (Level, Direction, Opt,
+ Protocol :: protocol();
+ (Level, Opt, Direction,
Domain, Type, Protocol) -> non_neg_integer() when
Level :: socket,
Direction :: set | get,
Opt :: socket_option(),
Domain :: domain(),
Type :: type(),
- Protocol :: protocol()
- ; (Level, Direction, Opt,
+ Protocol :: protocol();
+ (Level, Opt, Direction,
Domain, Type, Protocol) -> non_neg_integer() when
Level :: ip,
Direction :: set | get,
Opt :: ip_socket_option(),
Domain :: domain(),
Type :: type(),
- Protocol :: protocol()
- ; (Level, Direction, Opt,
+ Protocol :: protocol();
+ (Level, Opt, Direction,
Domain, Type, Protocol) -> non_neg_integer() when
Level :: ipv6,
Direction :: set | get,
Opt :: ipv6_socket_option(),
Domain :: domain(),
Type :: type(),
- Protocol :: protocol()
- ; (Level, Direction, Opt,
- Domain, Type, Protocol) -> non_neg_integer() when
+ Protocol :: protocol();
+ (Level, Opt, Direction,
+ Domain, Type, Protocol) -> non_neg_integer() when
Level :: tcp,
Direction :: set | get,
Opt :: tcp_socket_option(),
Domain :: domain(),
Type :: type(),
- Protocol :: protocol()
- ; (Level, Direction, Opt,
+ Protocol :: protocol();
+ (Level, Opt, Direction,
Domain, Type, Protocol) -> non_neg_integer() when
Level :: udp,
Direction :: set | get,
Opt :: udp_socket_option(),
Domain :: domain(),
Type :: type(),
- Protocol :: protocol()
- ; (Level, Direction, Opt,
+ Protocol :: protocol();
+ (Level, Opt, Direction,
Domain, Type, Protocol) -> non_neg_integer() when
Level :: sctp,
Direction :: set | get,
Opt :: sctp_socket_option(),
Domain :: domain(),
Type :: type(),
- Protocol :: protocol()
- ; (Level, Direction, Opt,
- Domain, Type, Protocol) -> non_neg_integer() when
+ Protocol :: protocol();
+ (Level, Opt, Direction,
+ Domain, Type, Protocol) -> non_neg_integer() when
Level :: integer(),
Direction :: set,
Opt :: integer(),
Domain :: domain(),
Type :: type(),
- Protocol :: protocol()
- ; (Level, Direction, Opt,
- Domain, Type, Protocol) -> non_neg_integer() when
+ Protocol :: protocol();
+ (Level, Opt, Direction,
+ Domain, Type, Protocol) -> {NativeOpt, ValueSize} when
Level :: integer(),
Direction :: get,
Opt :: {NativeOpt, ValueSize},
NativeOpt :: integer(),
- ValueSize :: non_neg_integer(),
+ ValueSize :: non_neg_integer() | 'int' | 'bool',
Domain :: domain(),
Type :: type(),
Protocol :: protocol().
@@ -3456,25 +3492,27 @@ dec_getopt_value(_L, _Opt, V, _D, _T, _P) ->
%% +++ OTP socket options +++
enc_sockopt_key(otp, debug, _, _, _, _) ->
- ?SOCKET_OPT_OTP_DEBUG;
+ ?ESOCK_OPT_OTP_DEBUG;
enc_sockopt_key(otp, iow, _, _, _, _) ->
- ?SOCKET_OPT_OTP_IOW;
+ ?ESOCK_OPT_OTP_IOW;
enc_sockopt_key(otp, controlling_process, _, _, _, _) ->
- ?SOCKET_OPT_OTP_CTRL_PROC;
+ ?ESOCK_OPT_OTP_CTRL_PROC;
enc_sockopt_key(otp, rcvbuf, _, _, _, _) ->
- ?SOCKET_OPT_OTP_RCVBUF;
+ ?ESOCK_OPT_OTP_RCVBUF;
enc_sockopt_key(otp, rcvctrlbuf, _, _, _, _) ->
- ?SOCKET_OPT_OTP_RCVCTRLBUF;
+ ?ESOCK_OPT_OTP_RCVCTRLBUF;
enc_sockopt_key(otp, sndctrlbuf, _, _, _, _) ->
- ?SOCKET_OPT_OTP_SNDCTRLBUF;
+ ?ESOCK_OPT_OTP_SNDCTRLBUF;
enc_sockopt_key(otp, fd, get = _Dir, _, _, _) ->
- ?SOCKET_OPT_OTP_FD;
+ ?ESOCK_OPT_OTP_FD;
+enc_sockopt_key(otp, meta, _, _, _, _) ->
+ ?ESOCK_OPT_OTP_META;
enc_sockopt_key(otp = L, Opt, _, _, _, _) ->
not_supported({L, Opt});
%% +++ SOCKET socket options +++
enc_sockopt_key(socket = _L, acceptconn = _Opt, get = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_ACCEPTCONN;
+ ?ESOCK_OPT_SOCK_ACCEPTCONN;
enc_sockopt_key(socket = L, acceptconn = Opt, Dir, _D, _T, _P) ->
not_supported({L, Opt, Dir});
enc_sockopt_key(socket = L, acceptfilter = Opt, _Dir, _D, _T, _P) ->
@@ -3483,182 +3521,182 @@ enc_sockopt_key(socket = L, acceptfilter = Opt, _Dir, _D, _T, _P) ->
%% Maximum size of buffer for name: IFNAMSIZ
%% So, we let the implementation decide.
enc_sockopt_key(socket = _L, bindtodevice = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_BINDTODEVICE;
+ ?ESOCK_OPT_SOCK_BINDTODEVICE;
enc_sockopt_key(socket, broadcast = _Opt, _Dir, _D, dgram = _T, _P) ->
- ?SOCKET_OPT_SOCK_BROADCAST;
+ ?ESOCK_OPT_SOCK_BROADCAST;
enc_sockopt_key(socket = L, busy_poll = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(socket = _L, debug = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_DEBUG;
+ ?ESOCK_OPT_SOCK_DEBUG;
enc_sockopt_key(socket, domain = _Opt, get = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_DOMAIN;
+ ?ESOCK_OPT_SOCK_DOMAIN;
enc_sockopt_key(socket, dontroute = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_DONTROUTE;
+ ?ESOCK_OPT_SOCK_DONTROUTE;
enc_sockopt_key(socket = L, error = Opt, get = _Dir, _D, _T, _P) ->
not_supported({L, Opt});
%% This is only for connection-oriented sockets, but who are those?
%% Type = stream or Protocol = tcp?
%% For now, we just let is pass and it will fail later if not ok...
enc_sockopt_key(socket, keepalive = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_KEEPALIVE;
+ ?ESOCK_OPT_SOCK_KEEPALIVE;
enc_sockopt_key(socket, linger = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_LINGER;
+ ?ESOCK_OPT_SOCK_LINGER;
enc_sockopt_key(socket = L, mark = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(socket = _L, oobinline = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_OOBINLINE;
+ ?ESOCK_OPT_SOCK_OOBINLINE;
enc_sockopt_key(socket, passcred, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_PASSCRED;
+ ?ESOCK_OPT_SOCK_PASSCRED;
enc_sockopt_key(socket = L, peek_off = Opt, _Dir, local = _D, _T, _P) ->
- %% ?SOCKET_OPT_SOCK_PEEK_OFF;
+ %% ?ESOCK_OPT_SOCK_PEEK_OFF;
not_supported({L, Opt});
enc_sockopt_key(socket = L, peercred = Opt, get = _Dir, local = _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(socket, priority = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_PRIORITY;
+ ?ESOCK_OPT_SOCK_PRIORITY;
enc_sockopt_key(socket, protocol = _Opt, get = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_PROTOCOL;
+ ?ESOCK_OPT_SOCK_PROTOCOL;
enc_sockopt_key(socket, rcvbuf = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_RCVBUF;
+ ?ESOCK_OPT_SOCK_RCVBUF;
enc_sockopt_key(socket = L, rcvbufforce = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
%% May not work on linux.
enc_sockopt_key(socket = _L, rcvlowat = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_RCVLOWAT;
+ ?ESOCK_OPT_SOCK_RCVLOWAT;
enc_sockopt_key(socket = _L, rcvtimeo = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_RCVTIMEO;
+ ?ESOCK_OPT_SOCK_RCVTIMEO;
enc_sockopt_key(socket = _L, reuseaddr = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_REUSEADDR;
+ ?ESOCK_OPT_SOCK_REUSEADDR;
enc_sockopt_key(socket = _L, reuseport = _Opt, _Dir, D, _T, _P)
when ((D =:= inet) orelse (D =:= inet6)) ->
- ?SOCKET_OPT_SOCK_REUSEPORT;
+ ?ESOCK_OPT_SOCK_REUSEPORT;
enc_sockopt_key(socket = L, rxq_ovfl = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(socket = L, setfib = Opt, set = _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(socket = _L, sndbuf = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_SNDBUF;
+ ?ESOCK_OPT_SOCK_SNDBUF;
enc_sockopt_key(socket = L, sndbufforce = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
%% Not changeable on linux.
enc_sockopt_key(socket = _L, sndlowat = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_SNDLOWAT;
+ ?ESOCK_OPT_SOCK_SNDLOWAT;
enc_sockopt_key(socket = _L, sndtimeo = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_SNDTIMEO;
+ ?ESOCK_OPT_SOCK_SNDTIMEO;
enc_sockopt_key(socket = _L, timestamp = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_TIMESTAMP;
+ ?ESOCK_OPT_SOCK_TIMESTAMP;
enc_sockopt_key(socket = _L, type = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SOCK_TYPE;
+ ?ESOCK_OPT_SOCK_TYPE;
enc_sockopt_key(socket = L, UnknownOpt, _Dir, _D, _T, _P) ->
unknown({L, UnknownOpt});
%% +++ IP socket options +++
enc_sockopt_key(ip = _L, add_membership = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_ADD_MEMBERSHIP;
+ ?ESOCK_OPT_IP_ADD_MEMBERSHIP;
enc_sockopt_key(ip = _L, add_source_membership = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_ADD_SOURCE_MEMBERSHIP;
+ ?ESOCK_OPT_IP_ADD_SOURCE_MEMBERSHIP;
enc_sockopt_key(ip = _L, block_source = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_BLOCK_SOURCE;
+ ?ESOCK_OPT_IP_BLOCK_SOURCE;
%% FreeBSD only?
%% Only respected on udp and raw ip (unless the hdrincl option has been set).
enc_sockopt_key(ip = L, dontfrag = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ip = _L, drop_membership = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_DROP_MEMBERSHIP;
+ ?ESOCK_OPT_IP_DROP_MEMBERSHIP;
enc_sockopt_key(ip = _L, drop_source_membership = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_DROP_SOURCE_MEMBERSHIP;
+ ?ESOCK_OPT_IP_DROP_SOURCE_MEMBERSHIP;
%% Linux only?
enc_sockopt_key(ip = _L, freebind = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_FREEBIND;
+ ?ESOCK_OPT_IP_FREEBIND;
enc_sockopt_key(ip = _L, hdrincl = _Opt, _Dir, _D, raw = _T, _P) ->
- ?SOCKET_OPT_IP_HDRINCL;
+ ?ESOCK_OPT_IP_HDRINCL;
enc_sockopt_key(ip = _L, minttl = _Opt, _Dir, _D, raw = _T, _P) ->
- ?SOCKET_OPT_IP_MINTTL;
+ ?ESOCK_OPT_IP_MINTTL;
enc_sockopt_key(ip = _L, msfilter = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_MSFILTER;
+ ?ESOCK_OPT_IP_MSFILTER;
enc_sockopt_key(ip = _L, mtu = _Opt, get = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_MTU;
+ ?ESOCK_OPT_IP_MTU;
enc_sockopt_key(ip = _L, mtu_discover = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_MTU_DISCOVER;
+ ?ESOCK_OPT_IP_MTU_DISCOVER;
enc_sockopt_key(ip = _L, multicast_all = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_MULTICAST_ALL;
+ ?ESOCK_OPT_IP_MULTICAST_ALL;
enc_sockopt_key(ip = _L, multicast_if = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_MULTICAST_IF;
+ ?ESOCK_OPT_IP_MULTICAST_IF;
enc_sockopt_key(ip = _L, multicast_loop = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_MULTICAST_LOOP;
+ ?ESOCK_OPT_IP_MULTICAST_LOOP;
enc_sockopt_key(ip = _L, multicast_ttl = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_MULTICAST_TTL;
+ ?ESOCK_OPT_IP_MULTICAST_TTL;
enc_sockopt_key(ip = _L, nodefrag = _Opt, _Dir, _D, raw = _T, _P) ->
- ?SOCKET_OPT_IP_NODEFRAG;
+ ?ESOCK_OPT_IP_NODEFRAG;
enc_sockopt_key(ip = L, options = Opt, _Dir, _D, _T, _P) ->
not_supported({Opt, L});
enc_sockopt_key(ip = _L, pktinfo = _Opt, _Dir, _D, dgram = _T, _P) ->
- ?SOCKET_OPT_IP_PKTINFO;
+ ?ESOCK_OPT_IP_PKTINFO;
enc_sockopt_key(ip = _L, recvdstaddr = _Opt, _Dir, _D, T, _P) when (T =:= dgram) ->
- ?SOCKET_OPT_IP_RECVDSTADDR;
+ ?ESOCK_OPT_IP_RECVDSTADDR;
enc_sockopt_key(ip = _L, recverr = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_RECVERR;
+ ?ESOCK_OPT_IP_RECVERR;
enc_sockopt_key(ip = _L, recvif = _Opt, _Dir, _D, T, _P)
when (T =:= dgram) orelse (T =:= raw) ->
- ?SOCKET_OPT_IP_RECVIF;
+ ?ESOCK_OPT_IP_RECVIF;
enc_sockopt_key(ip = _L, recvopts = _Opt, _Dir, _D, T, _P) when (T =/= stream) ->
- ?SOCKET_OPT_IP_RECVOPTS;
+ ?ESOCK_OPT_IP_RECVOPTS;
enc_sockopt_key(ip = _L, recvorigdstaddr = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_RECVORIGDSTADDR;
+ ?ESOCK_OPT_IP_RECVORIGDSTADDR;
enc_sockopt_key(ip, recvtos = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_RECVTOS;
+ ?ESOCK_OPT_IP_RECVTOS;
enc_sockopt_key(ip = _L, recvttl = _Opt, _Dir, _D, T, _P) when (T =/= stream) ->
- ?SOCKET_OPT_IP_RECVTTL;
+ ?ESOCK_OPT_IP_RECVTTL;
enc_sockopt_key(ip = _L, retopts = _Opt, _Dir, _D, T, _P) when (T =/= stream) ->
- ?SOCKET_OPT_IP_RETOPTS;
+ ?ESOCK_OPT_IP_RETOPTS;
enc_sockopt_key(ip, router_alert = _Opt, _Dir, _D, raw = _T, _P) ->
- ?SOCKET_OPT_IP_ROUTER_ALERT;
+ ?ESOCK_OPT_IP_ROUTER_ALERT;
enc_sockopt_key(ip, sendsrcaddr = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_SENDSRCADDR;
+ ?ESOCK_OPT_IP_SENDSRCADDR;
%% On FreeBSD it specifies that this option is only valid
%% for stream, dgram and "some" raw sockets...
%% No such condition on linux (in the man page)...
enc_sockopt_key(ip, tos = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_TOS;
+ ?ESOCK_OPT_IP_TOS;
enc_sockopt_key(ip = _L, transparent = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_TRANSPARENT;
+ ?ESOCK_OPT_IP_TRANSPARENT;
enc_sockopt_key(ip, ttl = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_TTL;
+ ?ESOCK_OPT_IP_TTL;
enc_sockopt_key(ip = _L, unblock_source = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IP_UNBLOCK_SOURCE;
+ ?ESOCK_OPT_IP_UNBLOCK_SOURCE;
enc_sockopt_key(ip = L, UnknownOpt, _Dir, _D, _T, _P) ->
unknown({L, UnknownOpt});
%% IPv6 socket options
enc_sockopt_key(ipv6 = _L, addrform = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_ADDRFORM;
+ ?ESOCK_OPT_IPV6_ADDRFORM;
enc_sockopt_key(ipv6, add_membership = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_ADD_MEMBERSHIP;
+ ?ESOCK_OPT_IPV6_ADD_MEMBERSHIP;
enc_sockopt_key(ipv6 = _L, authhdr = _Opt, _Dir, _D, T, _P)
when ((T =:= dgram) orelse (T =:= raw)) ->
- ?SOCKET_OPT_IPV6_AUTHHDR;
+ ?ESOCK_OPT_IPV6_AUTHHDR;
enc_sockopt_key(ipv6 = L, auth_level = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = L, checksum = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6, drop_membership = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_DROP_MEMBERSHIP;
+ ?ESOCK_OPT_IPV6_DROP_MEMBERSHIP;
enc_sockopt_key(ipv6 = _L, dstopts = _Opt, _Dir, _D, T, _P)
when (T =:= dgram) orelse (T =:= raw) ->
- ?SOCKET_OPT_IPV6_DSTOPTS;
+ ?ESOCK_OPT_IPV6_DSTOPTS;
enc_sockopt_key(ipv6 = L, esp_trans_level = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = L, esp_network_level = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = _L, flowinfo = _Opt, _Dir, _D, T, _P)
when (T =:= dgram) orelse (T =:= raw) ->
- ?SOCKET_OPT_IPV6_FLOWINFO;
+ ?ESOCK_OPT_IPV6_FLOWINFO;
enc_sockopt_key(ipv6, hoplimit = _Opt, _Dir, _D, T, _P)
when (T =:= dgram) orelse (T =:= raw) ->
- ?SOCKET_OPT_IPV6_HOPLIMIT;
+ ?ESOCK_OPT_IPV6_HOPLIMIT;
enc_sockopt_key(ipv6 = _L, hopopts = _Opt, _Dir, _D, T, _P)
when ((T =:= dgram) orelse (T =:= raw)) ->
- ?SOCKET_OPT_IPV6_HOPOPTS;
+ ?ESOCK_OPT_IPV6_HOPOPTS;
enc_sockopt_key(ipv6 = L, ipcomp_level = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = L, join_group = Opt, _Dir, _D, _T, _P) ->
@@ -3666,44 +3704,44 @@ enc_sockopt_key(ipv6 = L, join_group = Opt, _Dir, _D, _T, _P) ->
enc_sockopt_key(ipv6 = L, leave_group = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = _L, mtu = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_MTU;
+ ?ESOCK_OPT_IPV6_MTU;
enc_sockopt_key(ipv6 = _L, mtu_discover = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_MTU_DISCOVER;
+ ?ESOCK_OPT_IPV6_MTU_DISCOVER;
enc_sockopt_key(ipv6 = _L, multicast_hops = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_MULTICAST_HOPS;
+ ?ESOCK_OPT_IPV6_MULTICAST_HOPS;
enc_sockopt_key(ipv6 = _L, multicast_if = _Opt, _Dir, _D, T, _P)
when (T =:= dgram) orelse (T =:= raw) ->
- ?SOCKET_OPT_IPV6_MULTICAST_IF;
+ ?ESOCK_OPT_IPV6_MULTICAST_IF;
enc_sockopt_key(ipv6 = _L, multicast_loop = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_MULTICAST_LOOP;
+ ?ESOCK_OPT_IPV6_MULTICAST_LOOP;
enc_sockopt_key(ipv6 = L, portrange = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = L, pktoptions = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = _L, recverr = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_RECVERR;
+ ?ESOCK_OPT_IPV6_RECVERR;
enc_sockopt_key(ipv6, recvhoplimit = _Opt, _Dir, _D, T, _P)
when (T =:= dgram) orelse (T =:= raw) ->
- ?SOCKET_OPT_IPV6_RECVHOPLIMIT;
+ ?ESOCK_OPT_IPV6_RECVHOPLIMIT;
enc_sockopt_key(ipv6 = _L, Opt, _Dir, _D, T, _P)
when ((Opt =:= recvpktinfo) orelse (Opt =:= pktinfo)) andalso
((T =:= dgram) orelse (T =:= raw)) ->
- ?SOCKET_OPT_IPV6_RECVPKTINFO;
+ ?ESOCK_OPT_IPV6_RECVPKTINFO;
enc_sockopt_key(ipv6 = _L, recvtclass = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_RECVTCLASS;
+ ?ESOCK_OPT_IPV6_RECVTCLASS;
enc_sockopt_key(ipv6 = _L, router_alert = _Opt, _Dir, _D, T, _P) when (T =:= raw) ->
- ?SOCKET_OPT_IPV6_ROUTER_ALERT;
+ ?ESOCK_OPT_IPV6_ROUTER_ALERT;
enc_sockopt_key(ipv6 = _L, rthdr = _Opt, _Dir, _D, T, _P)
when ((T =:= dgram) orelse (T =:= raw)) ->
- ?SOCKET_OPT_IPV6_RTHDR;
+ ?ESOCK_OPT_IPV6_RTHDR;
enc_sockopt_key(ipv6 = _L, tclass = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_TCLASS;
+ ?ESOCK_OPT_IPV6_TCLASS;
enc_sockopt_key(ipv6 = _L, unicast_hops = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_UNICAST_HOPS;
+ ?ESOCK_OPT_IPV6_UNICAST_HOPS;
enc_sockopt_key(ipv6 = L, use_min_mtu = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(ipv6 = _L, v6only = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_IPV6_V6ONLY;
+ ?ESOCK_OPT_IPV6_V6ONLY;
enc_sockopt_key(ipv6 = L, UnknownOpt, _Dir, _D, _T, _P) ->
unknown({L, UnknownOpt});
@@ -3711,9 +3749,9 @@ enc_sockopt_key(ipv6 = L, UnknownOpt, _Dir, _D, _T, _P) ->
%% There are other options that would be useful; info,
%% but they are difficult to get portable...
enc_sockopt_key(tcp, congestion = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_TCP_CONGESTION;
+ ?ESOCK_OPT_TCP_CONGESTION;
enc_sockopt_key(tcp = _L, cork = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_TCP_CORK;
+ ?ESOCK_OPT_TCP_CORK;
enc_sockopt_key(tcp = L, keepidle = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(tcp = L, keepintvl = Opt, _Dir, _D, _T, _P) ->
@@ -3721,11 +3759,11 @@ enc_sockopt_key(tcp = L, keepintvl = Opt, _Dir, _D, _T, _P) ->
enc_sockopt_key(tcp = L, keepcnt = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(tcp, maxseg = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_TCP_MAXSEG;
+ ?ESOCK_OPT_TCP_MAXSEG;
enc_sockopt_key(tcp = L, md5sig = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(tcp, nodelay = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_TCP_NODELAY;
+ ?ESOCK_OPT_TCP_NODELAY;
enc_sockopt_key(tcp = L, noopt = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(tcp = L, nopush = Opt, _Dir, _D, _T, _P) ->
@@ -3739,7 +3777,7 @@ enc_sockopt_key(tcp = L, UnknownOpt, _Dir, _D, _T, _P) ->
%% UDP socket options
enc_sockopt_key(udp, cork = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_UDP_CORK;
+ ?ESOCK_OPT_UDP_CORK;
enc_sockopt_key(udp = L, UnknownOpt, _Dir, _D, _T, _P) ->
unknown({L, UnknownOpt});
@@ -3747,7 +3785,7 @@ enc_sockopt_key(udp = L, UnknownOpt, _Dir, _D, _T, _P) ->
enc_sockopt_key(sctp = L, adaption_layer = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = _L, associnfo = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SCTP_ASSOCINFO;
+ ?ESOCK_OPT_SCTP_ASSOCINFO;
enc_sockopt_key(sctp = L, auth_active_key = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, auth_asconf = Opt, _Dir, _D, _T, _P) ->
@@ -3759,7 +3797,7 @@ enc_sockopt_key(sctp = L, auth_key = Opt, _Dir, _D, _T, _P) ->
enc_sockopt_key(sctp = L, auth_delete_key = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp, autoclose = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SCTP_AUTOCLOSE;
+ ?ESOCK_OPT_SCTP_AUTOCLOSE;
enc_sockopt_key(sctp = L, context = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, default_send_params = Opt, _Dir, _D, _T, _P) ->
@@ -3767,11 +3805,11 @@ enc_sockopt_key(sctp = L, default_send_params = Opt, _Dir, _D, _T, _P) ->
enc_sockopt_key(sctp = L, delayed_ack_time = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = _L, disable_fragments = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SCTP_DISABLE_FRAGMENTS;
+ ?ESOCK_OPT_SCTP_DISABLE_FRAGMENTS;
enc_sockopt_key(sctp = L, hmac_ident = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = _L, events = _Opt, set = _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SCTP_EVENTS;
+ ?ESOCK_OPT_SCTP_EVENTS;
enc_sockopt_key(sctp = L, explicit_eor = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, fragment_interleave = Opt, _Dir, _D, _T, _P) ->
@@ -3779,17 +3817,17 @@ enc_sockopt_key(sctp = L, fragment_interleave = Opt, _Dir, _D, _T, _P) ->
enc_sockopt_key(sctp = L, get_peer_addr_info = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = _L, initmsg = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SCTP_INITMSG;
+ ?ESOCK_OPT_SCTP_INITMSG;
enc_sockopt_key(sctp = L, i_want_mapped_v4_addr = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, local_auth_chunks = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = _L, maxseg = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SCTP_MAXSEG;
+ ?ESOCK_OPT_SCTP_MAXSEG;
enc_sockopt_key(sctp = L, maxburst = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp, nodelay = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SCTP_NODELAY;
+ ?ESOCK_OPT_SCTP_NODELAY;
enc_sockopt_key(sctp = L, partial_delivery_point = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, peer_addr_params = Opt, _Dir, _D, _T, _P) ->
@@ -3801,11 +3839,11 @@ enc_sockopt_key(sctp = L, primary_addr = Opt, _Dir, _D, _T, _P) ->
enc_sockopt_key(sctp = L, reset_streams = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = _L, rtoinfo = _Opt, _Dir, _D, _T, _P) ->
- ?SOCKET_OPT_SCTP_RTOINFO;
+ ?ESOCK_OPT_SCTP_RTOINFO;
enc_sockopt_key(sctp = L, set_peer_primary_addr = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, status = Opt, get = _Dir, _D, _T, _P) ->
- not_supported({L, Opt}); % ?SOCKET_OPT_SCTP_RTOINFO;
+ not_supported({L, Opt}); % ?ESOCK_OPT_SCTP_RTOINFO;
enc_sockopt_key(sctp = L, use_exp_recvinfo = Opt, _Dir, _D, _T, _P) ->
not_supported({L, Opt});
enc_sockopt_key(sctp = L, UnknownOpt, _Dir, _D, _T, _P) ->
@@ -3828,11 +3866,11 @@ enc_sockopt_key(Level, Opt, _Dir, _Domain, _Type, _Protocol) ->
enc_shutdown_how(read) ->
- ?SOCKET_SHUTDOWN_HOW_READ;
+ ?ESOCK_SHUTDOWN_HOW_READ;
enc_shutdown_how(write) ->
- ?SOCKET_SHUTDOWN_HOW_WRITE;
+ ?ESOCK_SHUTDOWN_HOW_WRITE;
enc_shutdown_how(read_write) ->
- ?SOCKET_SHUTDOWN_HOW_READ_WRITE.
+ ?ESOCK_SHUTDOWN_HOW_READ_WRITE.
@@ -3866,8 +3904,8 @@ ensure_sockaddr(#{family := local, path := Path} = SockAddr)
(byte_size(Path) > 0) andalso
(byte_size(Path) =< 255) ->
SockAddr;
-ensure_sockaddr(_SockAddr) ->
- einval().
+ensure_sockaddr(SockAddr) ->
+ invalid_address(SockAddr).
@@ -3875,19 +3913,29 @@ cancel(SockRef, Op, OpRef) ->
case nif_cancel(SockRef, Op, OpRef) of
%% The select has already completed
{error, select_sent} ->
- flush_select_msgs(SockRef, OpRef);
+ flush_select_msg(SockRef, OpRef),
+ _ = flush_abort_msg(SockRef, OpRef),
+ ok;
Other ->
+ _ = flush_abort_msg(SockRef, OpRef),
Other
end.
-flush_select_msgs(SockRef, Ref) ->
+flush_select_msg(SockRef, Ref) ->
receive
- {?SOCKET_TAG, #socket{ref = SockRef}, select, Ref} ->
- flush_select_msgs(SockRef, Ref)
+ {?ESOCK_TAG, #socket{ref = SockRef}, select, Ref} ->
+ ok
after 0 ->
ok
end.
+flush_abort_msg(SockRef, Ref) ->
+ receive
+ {?ESOCK_TAG, #socket{ref = SockRef}, abort, {Ref, Reason}} ->
+ Reason
+ after 0 ->
+ ok
+ end.
%% formated_timestamp() ->
%% format_timestamp(os:timestamp()).
@@ -3915,34 +3963,37 @@ flush_select_msgs(SockRef, Ref) ->
%% lists:flatten(FormatDate).
-%% A timestamp in ms
+deadline(Timeout) ->
+ case Timeout of
+ nowait -> Timeout;
+ infinity -> Timeout;
+ _ when is_integer(Timeout), 0 =< Timeout ->
+ timestamp() + Timeout;
+ _ ->
+ invalid_timeout(Timeout)
+ end.
-timestamp(nowait = T) ->
- T;
-timestamp(infinity) ->
- undefined;
-timestamp(_) ->
- timestamp().
+timeout(Deadline) ->
+ case Deadline of
+ nowait -> 0;
+ infinity -> infinity;
+ _ ->
+ Now = timestamp(),
+ if
+ Now < Deadline -> Deadline - Now;
+ true -> 0
+ end
+ end.
timestamp() ->
erlang:monotonic_time(milli_seconds).
-next_timeout(_, nowait = Timeout) ->
- Timeout;
-next_timeout(_, infinity = Timeout) ->
- Timeout;
-next_timeout(TS, Timeout) ->
- NewTimeout = Timeout - tdiff(TS, timestamp()),
- if
- (NewTimeout > 0) ->
- NewTimeout;
- true ->
- 0
- end.
-
-tdiff(T1, T2) ->
- T2 - T1.
+-compile({inline, [bincat/2]}).
+bincat(<<>>, <<_/binary>> = B) -> B;
+bincat(<<_/binary>> = A, <<>>) -> A;
+bincat(<<_/binary>> = A, <<_/binary>> = B) ->
+ <<A/binary, B/binary>>.
%% p(F) ->
@@ -3968,43 +4019,45 @@ tdiff(T1, T2) ->
-spec invalid_domain(Domain) -> no_return() when
Domain :: term().
-
invalid_domain(Domain) ->
error({invalid_domain, Domain}).
-spec invalid_type(Type) -> no_return() when
Type :: term().
-
invalid_type(Type) ->
error({invalid_type, Type}).
--spec invalid_protocol(Type, Proto) -> no_return() when
- Type :: term(),
+-spec invalid_protocol(Proto) -> no_return() when
Proto :: term().
+invalid_protocol(Proto) ->
+ error({invalid_protocol, Proto}).
+
+-spec invalid_address(SockAddr) -> no_return() when
+ SockAddr :: term().
+invalid_address(SockAddr) ->
+ error({invalid_address, SockAddr}).
-invalid_protocol(Type, Proto) ->
- error({invalid_protocol, {Type, Proto}}).
+-spec invalid_timeout(Timeout) -> no_return() when
+ Timeout :: term().
+invalid_timeout(Timeout) ->
+ error({invalid_timeout, Timeout}).
-spec not_supported(What) -> no_return() when
What :: term().
-
not_supported(What) ->
error({not_supported, What}).
-spec unknown(What) -> no_return() when
What :: term().
-
unknown(What) ->
error({unknown, What}).
-spec einval() -> no_return().
-
einval() ->
error(einval).
-spec error(Reason) -> no_return() when
Reason :: term().
-
error(Reason) ->
throw({error, Reason}).
diff --git a/erts/preloaded/src/socket_registry.erl b/erts/preloaded/src/socket_registry.erl
new file mode 100644
index 0000000000..284f90157b
--- /dev/null
+++ b/erts/preloaded/src/socket_registry.erl
@@ -0,0 +1,196 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2019-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%% =========================================================================
+%%
+%% This is a registry process for the socket module.
+%% The nif sends info here about all created and deleted socket(s).
+%%
+%% =========================================================================
+
+-module(socket_registry).
+
+-export([
+ start/0,
+ number_of/0,
+ which_sockets/1
+ ]).
+
+
+-record(esock_info,
+ {
+ sock :: socket:socket(),
+ atime :: integer() % Add time - erlang:monotonic_time(milli_seconds)
+ }).
+
+
+%% =========================================================================
+
+%% This is not a "normal" start function. Instead its the entry
+%% function for the socket registry process.
+start() ->
+ erlang:register(?MODULE, self()),
+ process_flag(trap_exit, true),
+ loop([]).
+
+number_of() ->
+ await_reply( request(number_of) ).
+
+which_sockets(Filter) when is_function(Filter, 1) ->
+ await_reply( request({which_sockets, Filter}) ).
+
+
+%% =========================================================================
+
+loop(DB) ->
+ receive
+ {'$socket', add, Socket} ->
+ loop( handle_add_socket(DB, Socket) );
+
+ {'$socket', del, Socket} ->
+ loop( handle_delete_socket(DB, Socket) );
+
+ {?MODULE, request, From, ReqId, Req} = _REQ ->
+ %% erlang:display(REQ),
+ {NewDB, Reply} = handle_request(DB, Req),
+ reply(ReqId, From, Reply),
+ loop(NewDB);
+
+ Msg ->
+ NewDB = handle_unexpected_msg(DB, Msg),
+ loop(NewDB)
+ end.
+
+
+%% =========================================================================
+
+handle_add_socket(DB, Sock) ->
+ [#esock_info{sock = Sock, atime = timestamp()} | DB].
+
+handle_delete_socket(DB, Sock) ->
+ lists:keydelete(Sock, #esock_info.sock, DB).
+
+
+handle_request(DB, number_of) ->
+ {DB, db_size(DB)};
+
+handle_request(DB, {which_sockets, Filter}) ->
+ {DB, do_which_sockets(DB, Filter)};
+
+handle_request(DB, BadRequest) ->
+ {DB, {error, {bad_request, BadRequest}}}.
+
+
+%% ---
+
+handle_unexpected_msg(DB, {'EXIT', Pid, Reason}) ->
+ F = "socket-registry received unexpected exit from ~p:"
+ "~n ~p",
+ A = [Pid, Reason],
+ handle_unexpected_msg(warning, F, A),
+ DB;
+handle_unexpected_msg(DB, X) ->
+ F = "socket-registry received unexpected:"
+ "~n ~p",
+ A = [X],
+ handle_unexpected_msg(warning, F, A),
+ DB.
+
+%% This is "stolen" from the init process. But level is set to warning instead.
+%% This "may" not be what you want, but we can always decrease to info instead...
+%% Also, we may receive (unexpected) messages that should be classified
+%% differently (info, warning, ...)...
+%%
+%% This is equal to calling logger:[info|warning]/3 which we don't
+%% want to do from this process, at least not during
+%% system boot. We don't want to call logger:timestamp()
+%% either.
+%%
+
+%% handle_unexpected_msg(info, F, A) ->
+%% do_handle_unexpected_msg( mk_unexpected_info_msg(F, A) ).
+handle_unexpected_msg(warning, F, A) ->
+ do_handle_unexpected_msg( mk_unexpected_warning_msg(F, A) ).
+
+do_handle_unexpected_msg(Msg) ->
+ catch logger ! Msg.
+
+
+%% mk_unexpected_info_msg(F, A) ->
+%% mk_unexpected_msg(info, info_msg, F, A).
+
+mk_unexpected_warning_msg(F, A) ->
+ mk_unexpected_msg(warning, warning_msg, F, A).
+
+mk_unexpected_msg(Level, Tag, F, A) ->
+ Meta = #{pid => self(),
+ gl => erlang:group_leader(),
+ time => os:system_time(microsecond),
+ error_logger => #{tag => Tag}},
+ {log, Level, F, A, Meta}.
+
+
+%% ---
+
+db_size(DB) ->
+ length(DB).
+
+do_which_sockets(DB, Filter) ->
+ try
+ begin
+ SocksInfo =
+ [{Sock, socket:info(Sock)} || #esock_info{sock = Sock} <- DB],
+ [Sock || {Sock, SockInfo} <- SocksInfo, Filter(SockInfo)]
+ end
+ catch
+ _:_:_ ->
+ [Sock || #esock_info{sock = Sock} <- DB]
+ end.
+
+
+
+%% =========================================================================
+
+request(Req) ->
+ ReqId = make_ref(),
+ ReqMsg = {?MODULE, request, self(), ReqId, Req},
+ Registry = whoami(),
+ erlang:send(Registry, ReqMsg),
+ ReqId.
+
+reply(ReqId, From, Reply) ->
+ RepMsg = {?MODULE, reply, self(), ReqId, Reply},
+ erlang:send(From, RepMsg).
+
+await_reply(ReqId) ->
+ Registry = whoami(),
+ receive
+ {?MODULE, reply, Registry, ReqId, Reply} ->
+ Reply
+ end.
+
+
+%% =========================================================================
+
+whoami() ->
+ whereis(?MODULE).
+
+timestamp() ->
+ erlang:monotonic_time(milli_seconds).
diff --git a/erts/vsn.mk b/erts/vsn.mk
index da4516530c..1e7f5b3118 100644
--- a/erts/vsn.mk
+++ b/erts/vsn.mk
@@ -18,7 +18,7 @@
# %CopyrightEnd%
#
-VSN = 10.6.1
+VSN = 10.6.4
# Port number 4365 in 4.2
# Port number 4366 in 4.3
diff --git a/lib/asn1/src/Makefile b/lib/asn1/src/Makefile
index ba459f6cd3..d9a4197600 100644
--- a/lib/asn1/src/Makefile
+++ b/lib/asn1/src/Makefile
@@ -190,7 +190,8 @@ asn1rtt_%.$(EMULATOR): asn1rtt_%.erl
$(V_ERLC) +debug_info $<
$(EVAL_CT_MODULES:%=%.erl): prepare_templates.$(EMULATOR) \
- $(EBIN)/asn1ct_rtt.$(EMULATOR)
+ $(EBIN)/asn1ct_rtt.$(EMULATOR) \
+ $(EBIN)/asn1ct_func.$(EMULATOR) \
#
# Dependencies
diff --git a/lib/common_test/doc/src/Makefile b/lib/common_test/doc/src/Makefile
index b5acdc6f95..ae06572752 100644
--- a/lib/common_test/doc/src/Makefile
+++ b/lib/common_test/doc/src/Makefile
@@ -74,6 +74,7 @@ XML_CHAPTER_FILES = \
ct_master_chapter.xml \
event_handler_chapter.xml \
ct_hooks_chapter.xml \
+ ct_property_test_chapter.xml \
dependencies_chapter.xml \
notes.xml
diff --git a/lib/common_test/doc/src/ct_property_test.xml b/lib/common_test/doc/src/ct_property_test.xml
index 1e01d9a5d7..1690e9962a 100644
--- a/lib/common_test/doc/src/ct_property_test.xml
+++ b/lib/common_test/doc/src/ct_property_test.xml
@@ -33,30 +33,39 @@
<file>ct_property_test.xml</file>
</header>
<module since="OTP 17.3">ct_property_test</module>
- <modulesummary>EXPERIMENTAL support in Common Test for calling
- property-based tests.</modulesummary>
+ <modulesummary>Support in Common Test for running property-based tests.</modulesummary>
<description>
- <p>EXPERIMENTAL support in <c>Common Test</c> for calling property-based
- tests.</p>
+ <p>This module helps running property-based tests in the
+ <c>Common Test</c> framework. One (or more) of the property testing tools
+ </p>
+ <list>
+ <item><url href="http://www.quviq.com">QuickCheck</url>,</item>
+ <item><url href="https://proper-testing.github.io">PropEr</url> or</item>
+ <item><url href="https://github.com/krestenkrab/triq">Triq</url></item>
+ </list>
+ <p>
+ is assumed to be installed.
+ </p>
- <p>This module is a first step to run property-based tests in the
- <c>Common Test</c> framework. A property testing tool like QuickCheck
- or PropEr is assumed to be installed.</p>
-
- <p>The idea is to have a <c>Common Test</c> test suite calling a property
- testing tool with special property test suites as defined by that tool.
- The usual Erlang application directory structure is assumed. The tests
- are collected in the <c>test</c> directory of the application. The
- <c>test</c> directory has a subdirectory <c>property_test</c>, where
- everything needed for the property tests is collected.</p>
+ <p>The idea with this module is to have a <c>Common Test</c> test suite calling
+ a property testing tool with special property test suites as defined by that tool.
+ The tests
+ are collected in the <c>test</c> directory of the application. The
+ <c>test</c> directory has a subdirectory <c>property_test</c>, where
+ everything needed for the property tests are collected.
+ The usual Erlang application directory structure is assumed.
+ </p>
<p>A typical <c>Common Test</c> test suite using <c>ct_property_test</c>
- is organized as follows:</p>
+ is organized as follows:</p>
+
+ <code>
+-module(my_prop_test_SUITE).
+-compile(export_all).
- <pre>
- -include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct.hrl").
all() -&gt; [prop_ftp_case].
@@ -66,51 +75,198 @@
%%%---- test case
prop_ftp_case(Config) -&gt;
ct_property_test:quickcheck(
- ftp_simple_client_server:prop_ftp(Config),
+ ftp_simple_client_server:prop_ftp(),
Config
- ).</pre>
+ ).</code>
+ <p>and the the property test module (in this example <c>ftp_simple_client_server.erl</c>)
+ as almost a usual property testing module
+ (More examples are in <seealso marker="ct_property_test_chapter">the User's Guide</seealso>):</p>
+ <code>
+-module(ftp_simple_client_server).
+-export([prop_ftp/0...]).
- <warning>
- <p>This is experimental code that can be changed or removed anytime
- without any warning.</p>
- </warning>
+-include_lib("common_test/include/ct_property_test.hrl").
+prop_ftp() -&gt;
+ ?FORALL( ....
+ </code>
</description>
<funcs>
<func>
<name since="OTP 17.3">init_per_suite(Config) -&gt; Config | {skip, Reason}</name>
- <fsummary>Initializes Config for property testing.</fsummary>
+ <fsummary>Initializes and extends Config for property testing.</fsummary>
<desc><marker id="init_per_suite-1"/>
- <p>Initializes <c>Config</c> for property testing.</p>
+ <p>Initializes and extends <c>Config</c> for property based testing.</p>
<p>This function investigates if support is available for either
- Quickcheck, PropEr, or Triq. The options
- <c>{property_dir,AbsPath}</c> and <c>{property_test_tool,Tool}</c>
- are set in the <c>Config</c> returned.</p>
+ <url href="http://www.quviq.com">QuickCheck</url>,
+ <url href="https://proper-testing.github.io">PropEr</url>
+ or <url href="https://github.com/krestenkrab/triq">Triq</url> and compiles the
+ properties with the first tool found.
+ It is supposed to be called in the <c>init_per_suite/1</c> function
+ in a CommonTest test suite.
+ </p>
+ <p>Which tools to check for, and in which order could be set with the option
+ <c>{prop_tools, list(eqc|proper|triq)}</c>
+ in the CommonTest configuration <c>Config</c>. The default value is
+ <c>[eqc, proper, triq]</c> with <c>eqc</c> being the first one searched for.
+ </p>
+ <p>If no support is found for any tool, this function returns
+ <c>{skip, Explanation}</c>.
+ </p>
+ <p>If support is found, the option <c>{property_test_tool,ToolModule}</c> with
+ the selected tool main module name (<c>eqc</c>, <c>proper</c> or <c>triq</c>)
+ is added to the list <c>Config</c> which then is returned.
+ </p>
+ <p>The property tests are assumed to be in a subdirectory named
+ <c>property_test</c>.
+ All found Erlang files in that directory are compiled with one of the macros
+ <c>'EQC'</c>, <c>'PROPER'</c> or <c>'TRIQ'</c> set, depending on which tool
+ that is first found. This could make parts of the Erlang property tests
+ code to be included or excluded with the macro directives
+ <c>-ifdef(Macro).</c> or <c>-ifndef(Macro).</c>.
+ </p>
+ <p>The file(s) in the <c>property_test</c> subdirectory could, or should,
+ include the ct_property_test include file:
+ </p>
+ <code>
+-include_lib("common_test/include/ct_property_test.hrl").
+ </code>
+ <p>This included file will:
+ </p>
+ <list>
+ <item>Include the correct tool's include file</item>
+ <item>Set the macro <c>'MOD_eqc'</c> to the correct module name for the
+ selected tool. That is, the macro <c>'MOD_eqc'</c> is set to either
+ <c>eqc</c>, <c>proper</c> or <c>triq</c>.
+ </item>
+ </list>
+ </desc>
+ </func>
- <p>The function is intended to be called in function
- <c>init_per_suite</c> in the test suite.</p>
+ <func>
+ <name since="OTP 17.3">quickcheck(Property, Config) -&gt; true | {fail, Reason}</name>
+ <fsummary>Calls quickcheck and returns the result in a form suitable for
+ Common Test.</fsummary>
+ <desc>
+ <p>Calls the selected tool's function for running the <c>Property</c>. It is usually and
+ by historical reasons called quickcheck, and that is why that name is used in
+ this module (<c>ct_property_test</c>).
+ </p>
+ <p>The result is returned in a form suitable for <c>Common Test</c> test suites.
+ </p>
+ <p>This function is intended to be called in test cases in test suites.
+ </p>
+ </desc>
+ </func>
- <p>The property tests are assumed to be in subdirectory
- <c>property_test</c>.</p>
+ <func>
+ <name since="">present_result(Module, Cmds, Triple, Config) -> Result</name>
+ <fsummary>Presents the result of statem property testing</fsummary>
+ <desc>
+ <p>Same as <seealso marker="#present_result/5"><c>present_result(Module, Cmds, Triple, Config, [])</c></seealso>
+ </p>
</desc>
</func>
<func>
- <name since="OTP 17.3">quickcheck(Property, Config) -&gt; true | {fail, Reason}</name>
- <fsummary>Calls quickcheck and returns the result in a form suitable for
- Common Test.</fsummary>
- <desc><marker id="quickcheck-2"/>
- <p>Calls quickcheck and returns the result in a form suitable for
- <c>Common Test</c>.</p>
+ <name since="">present_result(Module, Cmds, Triple, Config, Options) -> Result</name>
+ <fsummary>Presents the result of statem property testing</fsummary>
+ <type>
+ <v>Module = module()</v>
+ <d></d>
+
+ <v>Cmds =</v>
+ <d>the list of commands generated by the property testing tool, for example
+ by proper:commands/1 or by proper:parallel_commands/1
+ </d>
+
+ <v>Triple =</v>
+ <d>the output from for example proper:run_commands/2 or proper:run_parallel_commands/2</d>
+
+ <v>Config =</v>
+ <d>the Common Test <seealso marker="common_test#Module:Testcase/1">Config</seealso> in test cases.</d>
+
+ <v>Options = [present_option()]</v>
+ <v>present_option() = {print_fun, fun(Format,Args)}</v>
+ <v>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;| {spec, StatisticsSpec}</v>
+ <d>The <c>print_fun</c> defines which function to do the actual printout. The default is
+ <seealso marker="ct#log/2">ct:log/2</seealso>.
+ The <c>spec</c> defines what statistics are to be printed<!--, see the
+ <seealso marker="ct_property_test_chapter#spec_present_result">User's Guide</seealso>-->
+ </d>
+
+ <v>Result = boolean()</v>
+ <d>Is <c>false</c> if the test failed and is <c>true</c> if the test passed</d>
+ </type>
+ <desc>
+ <p>Presents the result of <i>stateful (statem) property testing</i> using the aggregate function in
+ PropEr, QuickCheck or other similar property testing tool.
+ </p>
+ <p>It is assumed to be called inside the property called by
+ <seealso marker="#quickcheck/2">quickcheck/2</seealso>:</p>
+ <code>
+...
+RunResult = run_parallel_commands(?MODULE, Cmds),
+ct_property_test:present_result(?MODULE, Cmds, RunResult, Config)
+...
+ </code>
+ <p>See the <seealso marker="ct_property_test_chapter#stateful1">User's Guide</seealso> for
+ an example of the usage and of the default printout.
+ </p>
+ <p>The <c>StatisticsSpec</c> is a list of the tuples:</p>
+ <list>
+ <item><c>{Title::string(), CollectFun::fun/1}</c></item>
+ <item><c>{Title::string(), FrequencyFun::/0, CollectFun::fun/1}</c></item>
+ </list>
+ <p>Each tuple will produce one table in the order of their places in the list.</p>
+ <list>
+ <item><c>Title</c> will be the title of one result table</item>
- <p>This function is intended to be called in the test cases in the
- test suite.</p>
+ <item><c>CollectFun</c> is called with one argument: the <c>Cmds</c>. It should return
+ a list of the values to be counted. The following pre-defined functions exist:
+ <list>
+ <item><c>ct_property_test:cmnd_names/1</c> returns a list of commands (function calls) generated in the <c>Cmnd</c>
+ sequence, without Module, Arguments and other details.</item>
+ <item><c>ct_property_test:num_calls/1</c> returns a list of the length of commands lists</item>
+ <item><c>ct_property_test:sequential_parallel/1</c> returns a list with information about sequential and
+ parallel parts from <c>Tool:parallel_commands/1,2</c></item>
+ </list>
+ </item>
+
+ <item><c>FrequencyFun/0</c> returns a fun/1 which is supposed to take a list of items as input,
+ and return an iolist wich will be printed as the table. Per default, the number of each item is counted
+ and the percentage is printed for each. The list [a,b,a,a,c] could for example return
+ <pre>
+ ["a 60%\n","b 20%\n","c 20%\n"]</pre>
+ which will be printed by the <c>print_fun</c>.
+ The default <c>print_fun</c> will print it as:
+ <pre>
+ a 60%
+ b 20%
+ c 20%</pre>
+ </item>
+ </list>
+ <p>The default <c>StatisticsSpec</c> is:</p>
+ <list>
+ <item>For sequential commands:
+ <code>
+[{"Function calls", fun cmnd_names/1},
+ {"Length of command sequences", fun print_frequency_ranges/0,
+ fun num_calls/1}]
+ </code></item>
+ <item>For parallel commands:
+ <code>
+[{"Distribution sequential/parallel", fun sequential_parallel/1},
+ {"Function calls", fun cmnd_names/1},
+ {"Length of command sequences", fun print_frequency_ranges/0,
+ fun num_calls/1}]
+ </code></item>
+ </list>
</desc>
</func>
+
</funcs>
</erlref>
-
-
diff --git a/lib/common_test/doc/src/ct_property_test_chapter.xml b/lib/common_test/doc/src/ct_property_test_chapter.xml
new file mode 100644
index 0000000000..131f3a962d
--- /dev/null
+++ b/lib/common_test/doc/src/ct_property_test_chapter.xml
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2019</year><year>2019</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+ </legalnotice>
+
+ <title>Common Test's Property Testing Support: ct_property_test</title>
+ <prepared>Hans Nilsson</prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>ct_property_test_chapter.xml</file>
+ </header>
+
+ <section>
+ <marker id="general"></marker>
+ <title>General</title>
+ <p>
+ The <em>Common Test Property Testing Support (ct_property_test)</em>
+ is an aid to run property based testing tools in Common Test test suites.
+ </p>
+ <p>
+ Basic knowledge of property based testing is assumed in the following.
+ It is also assumed that at least one of the following property based
+ testing tools is installed and available in the library path:
+ </p>
+ <list>
+ <item><url href="http://www.quviq.com">QuickCheck</url>,</item>
+ <item><url href="https://proper-testing.github.io">PropEr</url> or</item>
+ <item><url href="https://github.com/krestenkrab/triq">Triq</url></item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="supported"></marker>
+ <title>What Is Supported?</title>
+ <p>The <seealso marker="ct_property_test#">ct_property_test</seealso> module
+ does the following:
+ </p>
+ <list type="bulleted">
+ <item>Compiles the files with property tests in the subdirectory <c>property_test</c>
+ </item>
+ <item>Tests properties in those files using the first found Property Testing Tool.
+ </item>
+ <item>Saves the results - that is the printouts - in the usual Common Test Log
+ </item>
+ </list>
+ </section>
+
+
+ <section>
+ <title>Introductory Example</title>
+ <p>Assume that we want to test the lists:sort/1 function.
+ </p>
+ <p>We need a property to test the function. In normal way, we create
+ <c>property_test/ct_prop.erl</c> module in the <c>test</c> directory
+ in our application:
+ </p>
+
+ <code>
+-module(ct_prop).
+-export([prop_sort/0]).
+
+%%% This will include the .hrl file for the installed testing tool:
+-include_lib("common_test/include/ct_property_test.hrl").
+
+%%% The property we want to check:
+%%% For all possibly unsorted lists,
+%%% the result of lists:sort/1 is sorted.
+prop_sort() -&gt;
+ ?FORALL(UnSorted, list(),
+ is_sorted(lists:sort(UnSorted))
+ ).
+
+%%% Function to check that a list is sorted:
+is_sorted([]) ->
+ true;
+is_sorted([_]) ->
+ true;
+is_sorted([H1,H2|SortedTail]) when H1 =&lt; H2 ->
+ is_sorted([H2|SortedTail]);
+is_sorted(_) ->
+ false.
+ </code>
+
+ <p>We also need a CommonTest test suite:
+ </p>
+ <code>
+-module(ct_property_test_SUITE).
+-compile(export_all). % Only in tests!
+
+-include_lib("common_test/include/ct.hrl").
+
+all() -> [prop_sort
+ ].
+
+%%% First prepare Config and compile the property tests for the found tool:
+init_per_suite(Config) ->
+ ct_property_test:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ Config.
+
+%%%================================================================
+%%% Test suites
+%%%
+prop_sort(Config) ->
+ ct_property_test:quickcheck(
+ ct_prop:prop_sort(),
+ Config
+ ).
+ </code>
+
+ <p>We run it as usual, for example with ct_run in the OS shell:</p>
+ <pre>
+..../test$ ct_run -suite ct_property_test_SUITE
+.....
+Common Test: Running make in test directories...
+
+TEST INFO: 1 test(s), 1 case(s) in 1 suite(s)
+
+Testing lib.common_test.ct_property_test_SUITE: Starting test, 1 test cases
+
+----------------------------------------------------
+2019-12-18 10:44:46.293
+Found property tester proper
+at "/home/X/lib/proper/ebin/proper.beam"
+
+
+----------------------------------------------------
+2019-12-18 10:44:46.294
+Compiling in "/home/..../test/property_test"
+ Deleted: ["ct_prop.beam"]
+ ErlFiles: ["ct_prop.erl"]
+ MacroDefs: [{d,'PROPER'}]
+
+Testing lib.common_test.ct_property_test_SUITE: TEST COMPLETE, 1 ok, 0 failed of 1 test cases
+
+....
+ </pre>
+ </section>
+
+
+ <section>
+ <marker id="stateful1"></marker>
+ <title>A stateful testing example</title>
+ <p>Assume a test that generates some parallel stateful commands, and runs 300 tests:</p>
+ <code>
+prop_parallel(Config) ->
+ numtests(300,
+ ?FORALL(Cmds, parallel_commands(?MODULE),
+ begin
+ RunResult = run_parallel_commands(?MODULE, Cmds),
+ ct_property_test:present_result(?MODULE, Cmds, RunResult, Config)
+ end)).
+ </code>
+ <p>The
+ <seealso marker="ct_property_test#present_result/4">ct_property_test:present_result/4</seealso>
+ is a help function for printing some statistics in the CommonTest log file.</p>
+ <p>Our example test could for example be a simple test of an ftp server, where we perform get, put
+ and delete requests, some of them in parallel. Per default, the result has three sections:
+ </p>
+ <pre>
+*** User 2019-12-11 13:28:17.504 ***
+
+Distribution sequential/parallel
+
+ 57.7% sequential
+ 28.0% parallel_2
+ 14.3% parallel_1
+
+
+
+*** User 2019-12-11 13:28:17.505 ***
+
+Function calls
+
+ 44.4% get
+ 39.3% put
+ 16.3% delete
+
+
+
+*** User 2019-12-11 13:28:17.505 ***
+
+Length of command sequences
+
+Range : Number in range
+-------:----------------
+ 0 - 4: 8 2.7% &lt;-- min=3
+ 5 - 9: 44 14.7%
+10 - 14: 74 24.7%
+15 - 19: 60 20.0% &lt;-- mean=18.7 &lt;-- median=16.0
+20 - 24: 38 12.7%
+25 - 29: 26 8.7%
+30 - 34: 19 6.3%
+35 - 39: 19 6.3%
+40 - 44: 8 2.7%
+45 - 49: 4 1.3% &lt;-- max=47
+ ------
+ 300
+ </pre>
+ <p>The first part - <i>Distribution sequential/parallel</i> - shows the distribution in the
+ sequential and parallel part of the result of parallel_commands/1. See any property testing tool for
+ an explanation of this function.
+ The table shows that of all commands (get and put in our case),
+ 57.7% are executed in the sequential part prior to the parallel part,
+ 28.0% are executed in the first parallel list and the rest in the second parallel list.
+ </p>
+
+ <p>The second part - <i>Function calls</i> - shows the distribution of the three calls in the
+ generated command lists. We see that all of the three calls are executed. If it was so that we
+ thought that we also generated a fourth call, a table like this shows that we failed with that.
+ </p>
+
+ <p>The third and final part - <i>Length of command sequences</i> - show statistics of the
+ generated command sequences. We see that the shortest list has three elementes while the longest
+ has 47 elements. The mean and median values are also shown. Further we could for example see that
+ only 2.7% of the lists (that is eight lists) only has three or four elements.
+ </p>
+
+ </section>
+
+ <!--section>
+ <marker id="spec_present_result"></marker>
+ <title>The spec for present_result/5</title>
+ <p>To be written...
+ <seealso marker="ct_property_test#present_result/5">present_result/5</seealso>
+ </p>
+ </section-->
+</chapter>
diff --git a/lib/common_test/doc/src/ct_slave.xml b/lib/common_test/doc/src/ct_slave.xml
index 84e619482d..722ea20979 100644
--- a/lib/common_test/doc/src/ct_slave.xml
+++ b/lib/common_test/doc/src/ct_slave.xml
@@ -159,7 +159,7 @@
occurs during initialization or startup. Defaults to <c>true</c>.
Notice that the node can also be still alive it the boot time-out
occurred, but it is not killed in this case.</p></item>
- <tag><c>erlang_flags</c></tag>
+ <tag><c>erl_flags</c></tag>
<item><p>Specifies which flags are added to the parameters of the
executable <c>erl</c>.</p></item>
<tag><c>env</c></tag>
diff --git a/lib/common_test/doc/src/part.xml b/lib/common_test/doc/src/part.xml
index 000eb06b82..66dcf75258 100644
--- a/lib/common_test/doc/src/part.xml
+++ b/lib/common_test/doc/src/part.xml
@@ -48,6 +48,7 @@
<xi:include href="dependencies_chapter.xml"/>
<xi:include href="ct_hooks_chapter.xml"/>
<xi:include href="why_test_chapter.xml"/>
+ <xi:include href="ct_property_test_chapter.xml"/>
</part>
diff --git a/lib/common_test/include/ct_property_test.hrl b/lib/common_test/include/ct_property_test.hrl
new file mode 100644
index 0000000000..9d5933fde3
--- /dev/null
+++ b/lib/common_test/include/ct_property_test.hrl
@@ -0,0 +1,40 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-ifndef(CT_PROPERTY_TEST_HRL).
+ -define(CT_PROPERTY_TEST_HRL, true).
+
+ -ifdef(EQC).
+ -define(MOD_eqc, eqc).
+ -include_lib("eqc/include/eqc.hrl").
+ -else.
+ -ifdef(PROPER).
+ -define(MOD_eqc, proper).
+ -include_lib("proper/include/proper.hrl").
+ -else.
+ -ifdef(TRIQ).
+ -define(MOD_eqc, triq).
+ -include_lib("triq/include/triq.hrl").
+ -endif.
+ -endif.
+ -endif.
+
+-endif.
diff --git a/lib/common_test/src/Makefile b/lib/common_test/src/Makefile
index 76689dab8c..ffdef8ec39 100644
--- a/lib/common_test/src/Makefile
+++ b/lib/common_test/src/Makefile
@@ -96,7 +96,8 @@ HRL_FILES = \
ct_netconfc.hrl
EXTERNAL_HRL_FILES = \
../include/ct.hrl \
- ../include/ct_event.hrl
+ ../include/ct_event.hrl \
+ ../include/ct_property_test.hrl
EXTERNAL_INC_PATH = ../include
diff --git a/lib/common_test/src/ct_property_test.erl b/lib/common_test/src/ct_property_test.erl
index 93642a0970..251a0a4896 100644
--- a/lib/common_test/src/ct_property_test.erl
+++ b/lib/common_test/src/ct_property_test.erl
@@ -18,26 +18,40 @@
%% %CopyrightEnd%
%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% %%%
-%%% WARNING %%%
-%%% %%%
-%%% This is experimental code which may be changed or removed %%%
-%%% anytime without any warning. %%%
-%%% %%%
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
-module(ct_property_test).
-%% API
+%%% API
+%% Main functions
-export([init_per_suite/1,
- quickcheck/2]).
+ quickcheck/2
+ ]).
+
+%% Result presentation
+-export([present_result/4, present_result/5,
+ title/2, title/3,
+ sequential_parallel/1,
+ cmnd_names/1,
+ num_calls/1,
+ print_frequency_ranges/0,
+ print_frequency/0
+ ]).
+%%% Mandatory include
-include_lib("common_test/include/ct.hrl").
+%%%================================================================
+%%%
+%%% API
+%%%
+
+%%%----------------------------------------------------------------
+%%%
+%%% Search for a property tester in the lib path, and if found, compile
+%%% the property tests
+%%%
init_per_suite(Config) ->
- case which_module_exists([eqc,proper,triq]) of
+ ToolsToCheck = proplists:get_value(prop_tools, Config, [eqc,proper,triq]),
+ case which_module_exists(ToolsToCheck) of
{ok,ToolModule} ->
case code:where_is_file(lists:concat([ToolModule,".beam"])) of
non_existing ->
@@ -66,12 +80,71 @@ init_per_suite(Config) ->
{skip, "No property testing tool found"}
end.
+%%%----------------------------------------------------------------
+%%%
+%%% Call the found property tester (if any)
+%%%
quickcheck(Property, Config) ->
Tool = proplists:get_value(property_test_tool,Config),
F = function_name(quickcheck, Tool),
mk_ct_return( Tool:F(Property), Tool ).
+%%%----------------------------------------------------------------
+%%%
+%%% Present a nice table of the statem result
+%%%
+present_result(Module, Cmds, Triple, Config) ->
+ present_result(Module, Cmds, Triple, Config, []).
+
+present_result(Module, Cmds, {H,Sf,Result}, Config, Options0) ->
+ DefSpec =
+ if
+ is_tuple(Cmds) ->
+ [{"Distribution sequential/parallel", fun sequential_parallel/1}];
+ is_list(Cmds) ->
+ []
+ end
+ ++ [{"Function calls", fun cmnd_names/1},
+ {"Length of command sequences", fun print_frequency_ranges/0, fun num_calls/1}
+ ],
+ Options = add_default_options(Options0,
+ [{print_fun, fun ct:log/2},
+ {spec, DefSpec}
+ ]),
+ do_present_result(Module, Cmds, H, Sf, Result, Config, Options).
+
+
+title(Str, Fun) ->
+ title(Str, Fun, fun io:format/2).
+
+title(Str, Fun, PrintFun) ->
+ fun(L) -> PrintFun("~n~s~n~n~s~n", [Str,Fun(L)]) end.
+
+print_frequency() ->
+ fun(L) ->
+ [io_lib:format("~5.1f% ~p~n",[Pcnt,V])
+ || {V,_Num,Pcnt} <-
+ with_percentage(get_frequencies_no_range(L), length(L))
+ ]
+ end.
+
+print_frequency_ranges() ->
+ print_frequency_ranges([{ngroups,10}]).
+
+print_frequency_ranges(Options0) ->
+ fun([]) ->
+ io_lib:format('Empty list!~n',[]);
+ (L ) ->
+ try
+ Options = set_default_print_freq_range_opts(Options0, L),
+ do_print_frequency_ranges(L, Options)
+ catch
+ C:E:S ->
+ ct:pal("~p:~p ~p:~p~n~p~n~p",[?MODULE,?LINE,C,E,S,L])
+ end
+ end.
+
%%%================================================================
%%%
%%% Local functions
@@ -155,3 +228,217 @@ macro_def(triq) -> [{d, 'TRIQ'}].
function_name(quickcheck, triq) -> check;
function_name(F, _) -> F.
+
+%%%================================================================
+%%%================================================================
+%%%================================================================
+%%%
+%%% Result presentation part
+%%%
+do_present_result(_Module, Cmds, _H, _Sf, ok, Config, Options) ->
+ [PrintFun, Spec] = [proplists:get_value(K,Options) || K <- [print_fun,spec]],
+ Tool = proplists:get_value(property_test_tool,Config),
+ AGGREGATE = function_name(aggregate, Tool),
+ lists:foldr(fun({Title, FreqFun, CollecFun}, Result) ->
+ Tool:AGGREGATE(title(Title, FreqFun(), PrintFun),
+ CollecFun(Cmds),
+ Result);
+ ({Title, CollecFun}, Result) ->
+ Tool:AGGREGATE(title(Title, print_frequency(), PrintFun),
+ CollecFun(Cmds),
+ Result)
+ end, true, Spec);
+
+do_present_result(Module, Cmds, H, Sf, Result, _Config, Options) ->
+ [PrintFun] = [proplists:get_value(K,Options) || K <- [print_fun]],
+ PrintFun("Module = ~p,~n"
+ "Commands = ~p,~n"
+ "History = ~p,~n"
+ "FinalDynState = ~p,~n"
+ "Result = ~p",
+ [Module, Cmds, H, Sf, Result]),
+ Result == ok. % Proper dislikes non-boolean results while eqc treats non-true as false.
+
+%%%================================================================
+cmnd_names(Cs) -> traverse_commands(fun cmnd_name/1, Cs).
+cmnd_name(L) -> [F || {set,_Var,{call,_Mod,F,_As}} <- L].
+
+num_calls(Cs) -> traverse_commands(fun num_call/1, Cs).
+num_call(L) -> [length(L)].
+
+sequential_parallel(Cs) ->
+ traverse_commands(fun(L) -> dup_module(L, sequential) end,
+ fun(L) -> [dup_module(L1, mkmod("parallel",num(L1,L))) || L1<-L] end,
+ Cs).
+dup_module(L, ModName) -> lists:duplicate(length(L), ModName).
+mkmod(PfxStr,N) -> list_to_atom(PfxStr++"_"++integer_to_list(N)).
+
+%% Meta functions for the aggregate functions
+traverse_commands(Fun, L) when is_list(L) -> Fun(L);
+traverse_commands(Fun, {Seq, ParLs}) -> Fun(lists:append([Seq|ParLs])).
+
+traverse_commands(Fseq, _Fpar, L) when is_list(L) -> Fseq(L);
+traverse_commands(Fseq, Fpar, {Seq, ParLs}) -> lists:append([Fseq(Seq)|Fpar(ParLs)]).
+
+%%%================================================================
+-define(middle_dot, 0183).
+
+set_default_print_freq_range_opts(Opts0, L) ->
+ add_default_options(Opts0, [{ngroups, 10},
+ {min, 0},
+ {max, max_in_list(L)}
+ ]).
+
+add_default_options(Opts0, DefaultOpts) ->
+ [set_def_opt(Key,DefVal,Opts0) || {Key,DefVal} <- DefaultOpts].
+
+set_def_opt(Key, DefaultValue, Opts) ->
+ {Key, proplists:get_value(Key, Opts, DefaultValue)}.
+
+max_in_list(L) ->
+ case lists:last(L) of
+ Max when is_integer(Max) -> Max;
+ {Max,_} -> Max
+ end.
+
+do_print_frequency_ranges(L0, Options) ->
+ [N,Min,Max] = [proplists:get_value(K,Options) || K <- [ngroups, min, max]],
+ L = if
+ N>Max ->
+ %% There will be less than the demanded number of classes,
+ %% insert one last with zero values in it. That will force
+ %% the generation of N classes.
+ L0++[{N,0}];
+ N=<Max ->
+ L0
+ end,
+ try
+ Interval = round((Max-Min)/N),
+ IntervalLowerLimits = lists:seq(Min,Max,Interval),
+ Ranges = [{I,I+Interval-1} || I <- IntervalLowerLimits],
+ Acc0 = [{Rng,0} || Rng <- Ranges],
+ Fs0 = get_frequencies(L, Acc0),
+ SumVal = lists:sum([V||{_,V}<-Fs0]),
+ Fs = with_percentage(Fs0, SumVal),
+ DistInfo = [{"min", lists:min(L)},
+ {"mean", mean(L)},
+ {"median", median(L)},
+ {"max", lists:max(L)}],
+
+ Npos_value = num_digits(SumVal),
+ Npos_range = num_digits(Max),
+ [%% Table heading:
+ io_lib:format("Range~*s: ~s~n",[2*Npos_range-2,"", "Number in range"]),
+ %% Line under heading:
+ io_lib:format("~*c:~*c~n",[2*Npos_range+3,$-, max(16,Npos_value+10),$- ]),
+ %% Lines with values:
+ [io_lib:format("~*w - ~*w: ~*w ~5.1f% ~s~n",
+ [Npos_range,Rlow,
+ Npos_range,Rhigh,
+ Npos_value,Val,
+ Percent,
+ cond_prt_vals(DistInfo, Interv)
+ ])
+ || {Interv={Rlow,Rhigh},Val,Percent} <- Fs],
+ %% Line under the table for the total number of values:
+ io_lib:format('~*c ~*c~n',[2*Npos_range,32, Npos_value+3,$-]),
+ %% The total number of values:
+ io_lib:format('~*c ~*w~n',[2*Npos_range,32, Npos_value,SumVal])
+ ]
+ catch
+ C:E ->
+ ct:pal('*** Failed printing (~p:~p) for~n~p~n',[C,E,L])
+ end.
+
+cond_prt_vals(LVs, CurrentInterval) ->
+ [prt_val(Label, Value, CurrentInterval) || {Label,Value} <- LVs].
+
+prt_val(Label, Value, CurrentInterval) ->
+ case in_interval(Value, CurrentInterval) of
+ true ->
+ io_lib:format(" <-- ~s=" ++ if
+ is_float(Value) -> "~.1f";
+ true -> "~p"
+ end,
+ [Label,Value]);
+ false ->
+ ""
+ end.
+
+get_frequencies([{I,Num}|T], [{{Lower,Upper},Cnt}|Acc]) when Lower=<I,I=<Upper ->
+ get_frequencies(T, [{{Lower,Upper},Cnt+Num}|Acc]);
+get_frequencies(L=[{I,_Num}|_], [Ah={{_Lower,Upper},_Cnt}|Acc]) when I>Upper ->
+ [Ah | get_frequencies(L,Acc)];
+get_frequencies([I|T], Acc) when is_integer(I) ->
+ get_frequencies([{I,1}|T], Acc);
+get_frequencies([], Acc) ->
+ Acc.
+
+get_frequencies_no_range([]) ->
+ io_lib:format("No values~n", []);
+get_frequencies_no_range(L) ->
+ [H|T] = lists:sort(L),
+ get_frequencies_no_range(T, H, 1, []).
+
+get_frequencies_no_range([H|T], H, N, Acc) ->
+ get_frequencies_no_range(T, H, N+1, Acc);
+get_frequencies_no_range([H1|T], H, N, Acc) ->
+ get_frequencies_no_range(T, H1, 1, [{H,N}|Acc]);
+get_frequencies_no_range([], H, N, Acc) ->
+ lists:reverse(
+ lists:keysort(2, [{H,N}|Acc])).
+
+%% get_frequencies_percent(L) ->
+%% with_percentage(get_frequencies_no_range(L), length(L)).
+
+
+with_percentage(Fs, Sum) ->
+ [{Rng,Val,100*Val/Sum} || {Rng,Val} <- Fs].
+
+
+num_digits(I) -> 1+trunc(math:log(I)/math:log(10)).
+
+num(Elem, List) -> length(lists:takewhile(fun(E) -> E /= Elem end, List)) + 1.
+
+%%%---- Just for naming an operation for readability
+is_odd(I) -> (I rem 2) == 1.
+
+in_interval(Value, {Rlow,Rhigh}) ->
+ try
+ Rlow=<round(Value) andalso round(Value)=<Rhigh
+ catch
+ _:_ -> false
+ end.
+
+%%%================================================================
+%%% Statistical functions
+
+%%%---- Mean value
+mean(L = [X|_]) when is_number(X) ->
+ lists:sum(L) / length(L);
+mean(L = [{_Value,_Weight}|_]) ->
+ SumOfWeights = lists:sum([W||{_,W}<-L]),
+ WeightedSum = lists:sum([W*V||{V,W}<-L]),
+ WeightedSum / SumOfWeights;
+mean(_) ->
+ undefined.
+
+%%%---- Median
+median(L = [X|_]) when is_number(X) ->
+ Len = length(L),
+ case is_odd(Len) of
+ true ->
+ hd(lists:nthtail(Len div 2, L));
+ false ->
+ %% 1) L has at least one element (the one in the is_number test).
+ %% 2) Length is even.
+ %% => Length >= 2
+ [M1,M2|_] = lists:nthtail((Len div 2)-1, L),
+ (M1+M2) / 2
+ end;
+%% integer Weights...
+median(L = [{_Value,_Weight}|_]) ->
+ median( lists:append([lists:duplicate(W,V) || {V,W} <- L]) );
+median(_) ->
+ undefined.
+
diff --git a/lib/common_test/test/Makefile b/lib/common_test/test/Makefile
index e510b74d6a..2371c4ddd0 100644
--- a/lib/common_test/test/Makefile
+++ b/lib/common_test/test/Makefile
@@ -76,7 +76,8 @@ MODULES= \
ct_unicode_SUITE \
ct_auto_clean_SUITE \
ct_util_SUITE \
- ct_tc_repeat_SUITE
+ ct_tc_repeat_SUITE \
+ ct_property_test_SUITE
ERL_FILES= $(MODULES:%=%.erl)
HRL_FILES= test_server_test_lib.hrl
@@ -133,6 +134,6 @@ release_tests_spec:
$(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(COVERFILE) "$(RELSYSDIR)"
$(INSTALL_DATA) common_test.spec common_test.cover "$(RELSYSDIR)"
chmod -R u+w "$(RELSYSDIR)"
- @tar cf - *_SUITE_data | (cd "$(RELSYSDIR)"; tar xf -)
+ @tar cf - *_SUITE_data property_test | (cd "$(RELSYSDIR)"; tar xf -)
release_docs_spec:
diff --git a/lib/common_test/test/ct_property_test_SUITE.erl b/lib/common_test/test/ct_property_test_SUITE.erl
new file mode 100644
index 0000000000..1f8c9e08cf
--- /dev/null
+++ b/lib/common_test/test/ct_property_test_SUITE.erl
@@ -0,0 +1,24 @@
+-module(ct_property_test_SUITE).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct.hrl").
+
+all() -> [prop_sort
+ ].
+
+%%% First prepare Config and compile the property tests for the found tool:
+init_per_suite(Config) ->
+ ct_property_test:init_per_suite(Config).
+
+end_per_suite(Config) ->
+ Config.
+
+%%%================================================================
+%%% Test suites
+%%%
+prop_sort(Config) ->
+ ct_property_test:quickcheck(
+ ct_prop:prop_sort(),
+ Config
+ ).
diff --git a/lib/common_test/test/property_test/ct_prop.erl b/lib/common_test/test/property_test/ct_prop.erl
new file mode 100644
index 0000000000..67ab3f3e6b
--- /dev/null
+++ b/lib/common_test/test/property_test/ct_prop.erl
@@ -0,0 +1,18 @@
+-module(ct_prop).
+-export([prop_sort/0]).
+
+-include_lib("common_test/include/ct_property_test.hrl").
+
+prop_sort() ->
+ ?FORALL(UnSorted, list(),
+ is_sorted(lists:sort(UnSorted))
+ ).
+
+is_sorted([]) ->
+ true;
+is_sorted([_]) ->
+ true;
+is_sorted([H1,H2|SortedTail]) when H1 =< H2 ->
+ is_sorted([H2|SortedTail]);
+is_sorted(_) ->
+ false.
diff --git a/lib/compiler/doc/src/notes.xml b/lib/compiler/doc/src/notes.xml
index 6919d2310f..dc509bbf60 100644
--- a/lib/compiler/doc/src/notes.xml
+++ b/lib/compiler/doc/src/notes.xml
@@ -32,6 +32,57 @@
<p>This document describes the changes made to the Compiler
application.</p>
+<section><title>Compiler 7.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug that could cause the compiler to reject
+ valid code that used the <c>is_map_key/2</c> BIF.</p>
+ <p>
+ Own Id: OTP-16452 Aux Id: ERL-1161 </p>
+ </item>
+ <item>
+ <p>Fixed a bug that could cause the compiler to reject
+ valid code that matched the same map key several
+ times.</p>
+ <p>
+ Own Id: OTP-16456 Aux Id: ERL-1163 </p>
+ </item>
+ <item>
+ <p>The compiler could crash when compiling a convoluted
+ <c>receive</c> statement.</p>
+ <p>
+ Own Id: OTP-16466 Aux Id: ERL-1170 </p>
+ </item>
+ <item>
+ <p>The compiler could crash when a fun was created but
+ never used.</p>
+ <p>The compiler could crash when compiling the expression
+ <c>true = 0 / X</c>.</p>
+ <p>
+ Own Id: OTP-16467 Aux Id: ERL-1166, ERL-1167 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Compiler 7.5.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>Fixed a bug in the compiler that could cause it to
+ reject valid code.</p>
+ <p>
+ Own Id: OTP-16385 Aux Id: ERL-1128 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Compiler 7.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/compiler/src/beam_except.erl b/lib/compiler/src/beam_except.erl
index 2b9c1b0cf5..04a5e3430a 100644
--- a/lib/compiler/src/beam_except.erl
+++ b/lib/compiler/src/beam_except.erl
@@ -131,7 +131,8 @@ fix_block(Is, 0) ->
fix_block(Is, Words) ->
reverse(fix_block_1(Is, Words)).
-fix_block_1([{set,[],[],{alloc,Live,{F1,F2,Needed0,F3}}}|Is], Words) ->
+fix_block_1([{set,[],[],{alloc,Live,{F1,F2,Needed0,F3}}}|Is], Words)
+ when is_integer(Needed0) ->
case Needed0 - Words of
0 ->
Is;
diff --git a/lib/compiler/src/beam_jump.erl b/lib/compiler/src/beam_jump.erl
index 74f80ca70e..2d5d3dc457 100644
--- a/lib/compiler/src/beam_jump.erl
+++ b/lib/compiler/src/beam_jump.erl
@@ -278,7 +278,12 @@ share(Is0) ->
share_1([{label,L}=Lbl|Is], Dict0, Lbls0, [_|_]=Seq, Acc) ->
case maps:find(Seq, Dict0) of
error ->
- Dict = maps:put(Seq, L, Dict0),
+ Dict = case is_shareable(Seq) of
+ true ->
+ maps:put(Seq, L, Dict0);
+ false ->
+ Dict0
+ end,
share_1(Is, Dict, Lbls0, [], [[Lbl|Seq]|Acc]);
{ok,Label} ->
Lbls = maps:put(L, Label, Lbls0),
@@ -313,6 +318,13 @@ share_1([I|Is], Dict, Lbls, Seq, Acc) ->
share_1(Is, Dict, Lbls, [I], Acc)
end.
+is_shareable([{'catch',_,_}|_]) -> false;
+is_shareable([{catch_end,_}|_]) -> false;
+is_shareable([{'try',_,_}|_]) -> false;
+is_shareable([{try_case,_}|_]) -> false;
+is_shareable([{try_end,_}|_]) -> false;
+is_shareable(_) -> true.
+
clean_non_sharable(Dict0, Lbls0) ->
%% We are passing in or out of a 'catch' or 'try' block. Remove
%% sequences that should not be shared over the boundaries of the
diff --git a/lib/compiler/src/beam_kernel_to_ssa.erl b/lib/compiler/src/beam_kernel_to_ssa.erl
index df95749fb3..aa04a75804 100644
--- a/lib/compiler/src/beam_kernel_to_ssa.erl
+++ b/lib/compiler/src/beam_kernel_to_ssa.erl
@@ -702,12 +702,16 @@ bif_cg(#k_bif{op=#k_remote{mod=#k_atom{val=erlang},name=#k_atom{val=Name}},
internal_cg(make_fun, [Name0,Arity0|As], Rs, _Le, St0) ->
#k_atom{val=Name} = Name0,
#k_int{val=Arity} = Arity0,
- [#k_var{name=Dst0}] = Rs,
- {Dst,St} = new_ssa_var(Dst0, St0),
- Args = ssa_args(As, St),
- Local = #b_local{name=#b_literal{val=Name},arity=Arity},
- MakeFun = #b_set{op=make_fun,dst=Dst,args=[Local|Args]},
- {[MakeFun],St};
+ case Rs of
+ [#k_var{name=Dst0}] ->
+ {Dst,St} = new_ssa_var(Dst0, St0),
+ Args = ssa_args(As, St),
+ Local = #b_local{name=#b_literal{val=Name},arity=Arity},
+ MakeFun = #b_set{op=make_fun,dst=Dst,args=[Local|Args]},
+ {[MakeFun],St};
+ [] ->
+ {[],St0}
+ end;
internal_cg(bs_init_writable=I, As, [#k_var{name=Dst0}], _Le, St0) ->
%% This behaves like a function call.
{Dst,St} = new_ssa_var(Dst0, St0),
diff --git a/lib/compiler/src/beam_peep.erl b/lib/compiler/src/beam_peep.erl
index 5730e9704e..2a9fcf1e52 100644
--- a/lib/compiler/src/beam_peep.erl
+++ b/lib/compiler/src/beam_peep.erl
@@ -22,7 +22,7 @@
-export([module/2]).
--import(lists, [reverse/1,member/2]).
+-import(lists, [reverse/1,member/2,usort/1]).
-spec module(beam_utils:module_code(), [compile:option()]) ->
{'ok',beam_utils:module_code()}.
@@ -207,7 +207,7 @@ simplify_has_map_fields(Fail, [Src|Keys0],
[{test,has_map_fields,Fail,[Src|Keys1]}|Acc]) ->
case are_keys_literals(Keys0) andalso are_keys_literals(Keys1) of
true ->
- Keys = Keys0 ++ Keys1,
+ Keys = usort(Keys0 ++ Keys1),
{ok,[{test,has_map_fields,Fail,[Src|Keys]}|Acc]};
false ->
error
diff --git a/lib/compiler/src/beam_ssa_bsm.erl b/lib/compiler/src/beam_ssa_bsm.erl
index cb36f1c242..d950ef58ec 100644
--- a/lib/compiler/src/beam_ssa_bsm.erl
+++ b/lib/compiler/src/beam_ssa_bsm.erl
@@ -520,20 +520,29 @@ cm_register_prior(Src, DstCtx, Lbl, State) ->
State#cm{ prior_matches = PriorMatches }.
cm_combine_tail(Src, DstCtx, Bool, Acc, State0) ->
- SrcCtx = match_context_of(Src, State0#cm.definitions),
+ SrcCtx0 = match_context_of(Src, State0#cm.definitions),
+
+ {SrcCtx, Renames} = cm_combine_tail_1(Bool, DstCtx, SrcCtx0,
+ State0#cm.renames),
%% We replace the source with a context alias as it normally won't be used
%% on the happy path after being matched, and the added cost of conversion
%% is negligible if it is.
Aliases = maps:put(Src, {0, SrcCtx}, State0#cm.match_aliases),
-
- Renames0 = State0#cm.renames,
- Renames = Renames0#{ Bool => #b_literal{val=true}, DstCtx => SrcCtx },
-
State = State0#cm{ match_aliases = Aliases, renames = Renames },
{Acc, State}.
+cm_combine_tail_1(Bool, DstCtx, SrcCtx, Renames0) ->
+ case Renames0 of
+ #{ SrcCtx := New } ->
+ cm_combine_tail_1(Bool, DstCtx, New, Renames0);
+ #{} ->
+ Renames = Renames0#{ Bool => #b_literal{val=true},
+ DstCtx => SrcCtx },
+ {SrcCtx, Renames}
+ end.
+
%% Lets functions accept match contexts as arguments. The parameter must be
%% unused before the bs_start_match instruction, and it must be matched in the
%% first block.
diff --git a/lib/compiler/src/beam_validator.erl b/lib/compiler/src/beam_validator.erl
index e83c5f7762..12aaa01b6b 100644
--- a/lib/compiler/src/beam_validator.erl
+++ b/lib/compiler/src/beam_validator.erl
@@ -601,6 +601,158 @@ valfun_1({jump,{f,Lbl}}, Vst) ->
%% The next instruction is never executed.
kill_state(SuccVst)
end);
+
+valfun_1(return, Vst) ->
+ assert_durable_term({x,0}, Vst),
+ verify_return(Vst),
+ kill_state(Vst);
+
+valfun_1({set_tuple_element,Src,Tuple,N}, Vst) ->
+ I = N + 1,
+ assert_term(Src, Vst),
+ assert_type({tuple_element,I}, Tuple, Vst),
+ %% Manually update the tuple type; we can't rely on the ordinary update
+ %% helpers as we must support overwriting (rather than just widening or
+ %% narrowing) known elements, and we can't use extract_term either since
+ %% the source tuple may be aliased.
+ {tuple, Sz, Es0} = get_term_type(Tuple, Vst),
+ Es = set_element_type({integer,I}, get_term_type(Src, Vst), Es0),
+ override_type({tuple, Sz, Es}, Tuple, Vst);
+
+%% Match instructions.
+valfun_1({select_val,Src,{f,Fail},{list,Choices}}, Vst) ->
+ assert_term(Src, Vst),
+ assert_choices(Choices),
+ validate_select_val(Fail, Choices, Src, Vst);
+valfun_1({select_tuple_arity,Tuple,{f,Fail},{list,Choices}}, Vst) ->
+ assert_type(tuple, Tuple, Vst),
+ assert_arities(Choices),
+ validate_select_tuple_arity(Fail, Choices, Tuple, Vst);
+
+%% New bit syntax matching instructions.
+valfun_1({test,bs_start_match3,{f,Fail},Live,[Src],Dst}, Vst) ->
+ validate_bs_start_match(Fail, Live, bsm_match_state(), Src, Dst, Vst);
+valfun_1({test,bs_start_match2,{f,Fail},Live,[Src,Slots],Dst}, Vst) ->
+ validate_bs_start_match(Fail, Live, bsm_match_state(Slots), Src, Dst, Vst);
+valfun_1({test,bs_match_string,{f,Fail},[Ctx,_,_]}, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ branch(Fail, Vst, fun(V) -> V end);
+valfun_1({test,bs_skip_bits2,{f,Fail},[Ctx,Src,_,_]}, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ assert_term(Src, Vst),
+ branch(Fail, Vst, fun(V) -> V end);
+valfun_1({test,bs_test_tail2,{f,Fail},[Ctx,_]}, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ branch(Fail, Vst, fun(V) -> V end);
+valfun_1({test,bs_test_unit,{f,Fail},[Ctx,_]}, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ branch(Fail, Vst, fun(V) -> V end);
+valfun_1({test,bs_skip_utf8,{f,Fail},[Ctx,Live,_]}, Vst) ->
+ validate_bs_skip_utf(Fail, Ctx, Live, Vst);
+valfun_1({test,bs_skip_utf16,{f,Fail},[Ctx,Live,_]}, Vst) ->
+ validate_bs_skip_utf(Fail, Ctx, Live, Vst);
+valfun_1({test,bs_skip_utf32,{f,Fail},[Ctx,Live,_]}, Vst) ->
+ validate_bs_skip_utf(Fail, Ctx, Live, Vst);
+valfun_1({test,bs_get_integer2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
+valfun_1({test,bs_get_float2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {float, []}, Dst, Vst);
+valfun_1({test,bs_get_binary2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, binary, Dst, Vst);
+valfun_1({test,bs_get_utf8=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
+valfun_1({test,bs_get_utf16=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
+valfun_1({test,bs_get_utf32=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
+ validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
+valfun_1({bs_save2,Ctx,SavePoint}, Vst) ->
+ bsm_save(Ctx, SavePoint, Vst);
+valfun_1({bs_restore2,Ctx,SavePoint}, Vst) ->
+ bsm_restore(Ctx, SavePoint, Vst);
+valfun_1({bs_get_position, Ctx, Dst, Live}, Vst0) ->
+ bsm_validate_context(Ctx, Vst0),
+ verify_live(Live, Vst0),
+ verify_y_init(Vst0),
+ Vst = prune_x_regs(Live, Vst0),
+ create_term(ms_position, bs_get_position, [Ctx], Dst, Vst, Vst0);
+valfun_1({bs_set_position, Ctx, Pos}, Vst) ->
+ bsm_validate_context(Ctx, Vst),
+ assert_type(ms_position, Pos, Vst),
+ Vst;
+valfun_1({test,has_map_fields,{f,Lbl},Src,{list,List}}, Vst) ->
+ assert_type(map, Src, Vst),
+ assert_unique_map_keys(List),
+ branch(Lbl, Vst, fun(V) -> V end);
+valfun_1({test,is_atom,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, {atom,[]}, Src, Vst);
+valfun_1({test,is_binary,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, binary, Src, Vst);
+valfun_1({test,is_bitstr,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, binary, Src, Vst);
+valfun_1({test,is_boolean,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, bool, Src, Vst);
+valfun_1({test,is_float,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, {float,[]}, Src, Vst);
+valfun_1({test,is_tuple,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, {tuple,[0],#{}}, Src, Vst);
+valfun_1({test,is_integer,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, {integer,[]}, Src, Vst);
+valfun_1({test,is_nonempty_list,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, cons, Src, Vst);
+valfun_1({test,is_number,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, number, Src, Vst);
+valfun_1({test,is_list,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, list, Src, Vst);
+valfun_1({test,is_map,{f,Lbl},[Src]}, Vst) ->
+ type_test(Lbl, map, Src, Vst);
+valfun_1({test,is_nil,{f,Lbl},[Src]}, Vst) ->
+ %% is_nil is an exact check against the 'nil' value, and should not be
+ %% treated as a simple type test.
+ assert_term(Src, Vst),
+ branch(Lbl, Vst,
+ fun(FailVst) ->
+ update_ne_types(Src, nil, FailVst)
+ end,
+ fun(SuccVst) ->
+ update_eq_types(Src, nil, SuccVst)
+ end);
+valfun_1({test,test_arity,{f,Lbl},[Tuple,Sz]}, Vst) when is_integer(Sz) ->
+ assert_type(tuple, Tuple, Vst),
+ Type = {tuple, Sz, #{}},
+ type_test(Lbl, Type, Tuple, Vst);
+valfun_1({test,is_tagged_tuple,{f,Lbl},[Src,Sz,Atom]}, Vst) ->
+ assert_term(Src, Vst),
+ Type = {tuple, Sz, #{ {integer,1} => Atom }},
+ type_test(Lbl, Type, Src, Vst);
+valfun_1({test,is_eq_exact,{f,Lbl},[Src,Val]=Ss}, Vst) ->
+ validate_src(Ss, Vst),
+ branch(Lbl, Vst,
+ fun(FailVst) ->
+ update_ne_types(Src, Val, FailVst)
+ end,
+ fun(SuccVst) ->
+ update_eq_types(Src, Val, SuccVst)
+ end);
+valfun_1({test,is_ne_exact,{f,Lbl},[Src,Val]=Ss}, Vst) ->
+ validate_src(Ss, Vst),
+ branch(Lbl, Vst,
+ fun(FailVst) ->
+ update_eq_types(Src, Val, FailVst)
+ end,
+ fun(SuccVst) ->
+ update_ne_types(Src, Val, SuccVst)
+ end);
+valfun_1({test,_Op,{f,Lbl},Src}, Vst) ->
+ %% is_pid, is_reference, et cetera.
+ validate_src(Src, Vst),
+ branch(Lbl, Vst, fun(V) -> V end);
+
+%% Map instructions.
+valfun_1({put_map_assoc=Op,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
+ verify_put_map(Op, Fail, Src, Dst, Live, List, Vst);
+valfun_1({get_map_elements,{f,Fail},Src,{list,List}}, Vst) ->
+ verify_get_map(Fail, Src, List, Vst);
+
valfun_1(I, Vst) ->
valfun_2(I, Vst).
@@ -687,6 +839,8 @@ valfun_3(I, Vst) ->
end.
%% Instructions that can cause exceptions.
+valfun_4({put_map_exact=Op,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
+ verify_put_map(Op, Fail, Src, Dst, Live, List, Vst);
valfun_4({apply,Live}, Vst) ->
call(apply, Live+2, Vst);
valfun_4({apply_last,Live,_}, Vst) ->
@@ -782,10 +936,6 @@ valfun_4({gc_bif,Op,{f,Fail},Live,Ss,Dst}, #vst{current=St0}=Vst0) ->
%% registers were pruned before the branch.
extract_term(Type, {gc_bif,Op}, Ss, Dst, SuccVst, Vst0)
end);
-valfun_4(return, Vst) ->
- assert_durable_term({x,0}, Vst),
- verify_return(Vst),
- kill_state(Vst);
valfun_4({loop_rec,{f,Fail},Dst}, Vst) ->
%% This term may not be part of the root set until remove_message/0 is
%% executed. If control transfers to the loop_rec_end/1 instruction, no
@@ -813,146 +963,8 @@ valfun_4(timeout, Vst0) ->
prune_x_regs(0, Vst);
valfun_4(send, Vst) ->
call(send, 2, Vst);
-valfun_4({set_tuple_element,Src,Tuple,N}, Vst) ->
- I = N + 1,
- assert_term(Src, Vst),
- assert_type({tuple_element,I}, Tuple, Vst),
- %% Manually update the tuple type; we can't rely on the ordinary update
- %% helpers as we must support overwriting (rather than just widening or
- %% narrowing) known elements, and we can't use extract_term either since
- %% the source tuple may be aliased.
- {tuple, Sz, Es0} = get_term_type(Tuple, Vst),
- Es = set_element_type({integer,I}, get_term_type(Src, Vst), Es0),
- override_type({tuple, Sz, Es}, Tuple, Vst);
-%% Match instructions.
-valfun_4({select_val,Src,{f,Fail},{list,Choices}}, Vst) ->
- assert_term(Src, Vst),
- assert_choices(Choices),
- validate_select_val(Fail, Choices, Src, Vst);
-valfun_4({select_tuple_arity,Tuple,{f,Fail},{list,Choices}}, Vst) ->
- assert_type(tuple, Tuple, Vst),
- assert_arities(Choices),
- validate_select_tuple_arity(Fail, Choices, Tuple, Vst);
-
-%% New bit syntax matching instructions.
-valfun_4({test,bs_start_match3,{f,Fail},Live,[Src],Dst}, Vst) ->
- validate_bs_start_match(Fail, Live, bsm_match_state(), Src, Dst, Vst);
-valfun_4({test,bs_start_match2,{f,Fail},Live,[Src,Slots],Dst}, Vst) ->
- validate_bs_start_match(Fail, Live, bsm_match_state(Slots), Src, Dst, Vst);
-valfun_4({test,bs_match_string,{f,Fail},[Ctx,_,_]}, Vst) ->
- bsm_validate_context(Ctx, Vst),
- branch(Fail, Vst, fun(V) -> V end);
-valfun_4({test,bs_skip_bits2,{f,Fail},[Ctx,Src,_,_]}, Vst) ->
- bsm_validate_context(Ctx, Vst),
- assert_term(Src, Vst),
- branch(Fail, Vst, fun(V) -> V end);
-valfun_4({test,bs_test_tail2,{f,Fail},[Ctx,_]}, Vst) ->
- bsm_validate_context(Ctx, Vst),
- branch(Fail, Vst, fun(V) -> V end);
-valfun_4({test,bs_test_unit,{f,Fail},[Ctx,_]}, Vst) ->
- bsm_validate_context(Ctx, Vst),
- branch(Fail, Vst, fun(V) -> V end);
-valfun_4({test,bs_skip_utf8,{f,Fail},[Ctx,Live,_]}, Vst) ->
- validate_bs_skip_utf(Fail, Ctx, Live, Vst);
-valfun_4({test,bs_skip_utf16,{f,Fail},[Ctx,Live,_]}, Vst) ->
- validate_bs_skip_utf(Fail, Ctx, Live, Vst);
-valfun_4({test,bs_skip_utf32,{f,Fail},[Ctx,Live,_]}, Vst) ->
- validate_bs_skip_utf(Fail, Ctx, Live, Vst);
-valfun_4({test,bs_get_integer2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
-valfun_4({test,bs_get_float2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Op, Fail, Ctx, Live, {float, []}, Dst, Vst);
-valfun_4({test,bs_get_binary2=Op,{f,Fail},Live,[Ctx,_,_,_],Dst}, Vst) ->
- validate_bs_get(Op, Fail, Ctx, Live, binary, Dst, Vst);
-valfun_4({test,bs_get_utf8=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
-valfun_4({test,bs_get_utf16=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
-valfun_4({test,bs_get_utf32=Op,{f,Fail},Live,[Ctx,_],Dst}, Vst) ->
- validate_bs_get(Op, Fail, Ctx, Live, {integer, []}, Dst, Vst);
-valfun_4({bs_save2,Ctx,SavePoint}, Vst) ->
- bsm_save(Ctx, SavePoint, Vst);
-valfun_4({bs_restore2,Ctx,SavePoint}, Vst) ->
- bsm_restore(Ctx, SavePoint, Vst);
-valfun_4({bs_get_position, Ctx, Dst, Live}, Vst0) ->
- bsm_validate_context(Ctx, Vst0),
- verify_live(Live, Vst0),
- verify_y_init(Vst0),
- Vst = prune_x_regs(Live, Vst0),
- create_term(ms_position, bs_get_position, [Ctx], Dst, Vst, Vst0);
-valfun_4({bs_set_position, Ctx, Pos}, Vst) ->
- bsm_validate_context(Ctx, Vst),
- assert_type(ms_position, Pos, Vst),
- Vst;
%% Other test instructions.
-valfun_4({test,has_map_fields,{f,Lbl},Src,{list,List}}, Vst) ->
- assert_type(map, Src, Vst),
- assert_unique_map_keys(List),
- branch(Lbl, Vst, fun(V) -> V end);
-valfun_4({test,is_atom,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, {atom,[]}, Src, Vst);
-valfun_4({test,is_binary,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, binary, Src, Vst);
-valfun_4({test,is_bitstr,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, binary, Src, Vst);
-valfun_4({test,is_boolean,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, bool, Src, Vst);
-valfun_4({test,is_float,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, {float,[]}, Src, Vst);
-valfun_4({test,is_tuple,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, {tuple,[0],#{}}, Src, Vst);
-valfun_4({test,is_integer,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, {integer,[]}, Src, Vst);
-valfun_4({test,is_nonempty_list,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, cons, Src, Vst);
-valfun_4({test,is_number,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, number, Src, Vst);
-valfun_4({test,is_list,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, list, Src, Vst);
-valfun_4({test,is_map,{f,Lbl},[Src]}, Vst) ->
- type_test(Lbl, map, Src, Vst);
-valfun_4({test,is_nil,{f,Lbl},[Src]}, Vst) ->
- %% is_nil is an exact check against the 'nil' value, and should not be
- %% treated as a simple type test.
- assert_term(Src, Vst),
- branch(Lbl, Vst,
- fun(FailVst) ->
- update_ne_types(Src, nil, FailVst)
- end,
- fun(SuccVst) ->
- update_eq_types(Src, nil, SuccVst)
- end);
-valfun_4({test,test_arity,{f,Lbl},[Tuple,Sz]}, Vst) when is_integer(Sz) ->
- assert_type(tuple, Tuple, Vst),
- Type = {tuple, Sz, #{}},
- type_test(Lbl, Type, Tuple, Vst);
-valfun_4({test,is_tagged_tuple,{f,Lbl},[Src,Sz,Atom]}, Vst) ->
- assert_term(Src, Vst),
- Type = {tuple, Sz, #{ {integer,1} => Atom }},
- type_test(Lbl, Type, Src, Vst);
-valfun_4({test,is_eq_exact,{f,Lbl},[Src,Val]=Ss}, Vst) ->
- validate_src(Ss, Vst),
- branch(Lbl, Vst,
- fun(FailVst) ->
- update_ne_types(Src, Val, FailVst)
- end,
- fun(SuccVst) ->
- update_eq_types(Src, Val, SuccVst)
- end);
-valfun_4({test,is_ne_exact,{f,Lbl},[Src,Val]=Ss}, Vst) ->
- validate_src(Ss, Vst),
- branch(Lbl, Vst,
- fun(FailVst) ->
- update_eq_types(Src, Val, FailVst)
- end,
- fun(SuccVst) ->
- update_ne_types(Src, Val, SuccVst)
- end);
-valfun_4({test,_Op,{f,Lbl},Src}, Vst) ->
- %% is_pid, is_reference, et cetera.
- validate_src(Src, Vst),
- branch(Lbl, Vst, fun(V) -> V end);
valfun_4({bs_add,{f,Fail},[A,B,_],Dst}, Vst) ->
assert_term(A, Vst),
assert_term(B, Vst),
@@ -1061,13 +1073,6 @@ valfun_4({bs_put_utf32,{f,Fail},_,Src}, Vst) ->
fun(SuccVst) ->
update_type(fun meet/2, {integer,[]}, Src, SuccVst)
end);
-%% Map instructions.
-valfun_4({put_map_assoc=Op,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
- verify_put_map(Op, Fail, Src, Dst, Live, List, Vst);
-valfun_4({put_map_exact=Op,{f,Fail},Src,Dst,Live,{list,List}}, Vst) ->
- verify_put_map(Op, Fail, Src, Dst, Live, List, Vst);
-valfun_4({get_map_elements,{f,Fail},Src,{list,List}}, Vst) ->
- verify_get_map(Fail, Src, List, Vst);
valfun_4(_, _) ->
error(unknown_instruction).
@@ -2824,6 +2829,7 @@ bif_return_type(is_function, [_,_], _) -> bool;
bif_return_type(is_integer, [_], _) -> bool;
bif_return_type(is_list, [_], _) -> bool;
bif_return_type(is_map, [_], _) -> bool;
+bif_return_type(is_map_key, [_, _], _) -> bool;
bif_return_type(is_number, [_], _) -> bool;
bif_return_type(is_pid, [_], _) -> bool;
bif_return_type(is_port, [_], _) -> bool;
diff --git a/lib/compiler/src/sys_core_fold.erl b/lib/compiler/src/sys_core_fold.erl
index 4939a94a92..eb1f69269c 100644
--- a/lib/compiler/src/sys_core_fold.erl
+++ b/lib/compiler/src/sys_core_fold.erl
@@ -2791,7 +2791,11 @@ opt_simple_let_2(Let0, Vs0, Arg0, Body, PrevBody, Sub) ->
true ->
Let1 = Let0#c_let{vars=Vars0,arg=Arg1,body=Body},
post_opt_let(Let1, Sub)
- end
+ end;
+ {[],Arg,Body} ->
+ %% The argument for a sequence must be a single value (not
+ %% #c_values{}). Therefore, we must keep the let.
+ post_opt_let(#c_let{vars=[],arg=Arg,body=Body}, Sub)
end.
%% post_opt_let(Let, Sub)
diff --git a/lib/compiler/test/beam_except_SUITE.erl b/lib/compiler/test/beam_except_SUITE.erl
index f52239f2a8..c8dfc81969 100644
--- a/lib/compiler/test/beam_except_SUITE.erl
+++ b/lib/compiler/test/beam_except_SUITE.erl
@@ -130,8 +130,14 @@ coverage(_) ->
{'EXIT',{function_clause,[{?MODULE,fake_function_clause,[{a,b},42.0],_}|_]}} =
(catch fake_function_clause({a,b})),
+ {'EXIT',{{badmatch,0.0},_}} = (catch coverage_1(id(42))),
+ {'EXIT',{badarith,_}} = (catch coverage_1(id(a))),
ok.
+coverage_1(X) ->
+ %% ERL-1167: Would crash beam_except.
+ true = 0 / X.
+
fake_function_clause(A) -> error(function_clause, [A,42.0]).
diff --git a/lib/compiler/test/beam_validator_SUITE.erl b/lib/compiler/test/beam_validator_SUITE.erl
index fe20fad500..a3f42213e8 100644
--- a/lib/compiler/test/beam_validator_SUITE.erl
+++ b/lib/compiler/test/beam_validator_SUITE.erl
@@ -36,7 +36,8 @@
val_dsetel/1,bad_tuples/1,bad_try_catch_nesting/1,
receive_stacked/1,aliased_types/1,type_conflict/1,
infer_on_eq/1,infer_dead_value/1,
- receive_marker/1]).
+ receive_marker/1,safe_instructions/1,
+ missing_return_type/1]).
-include_lib("common_test/include/ct.hrl").
@@ -66,7 +67,8 @@ groups() ->
map_field_lists,cover_bin_opt,val_dsetel,
bad_tuples,bad_try_catch_nesting,
receive_stacked,aliased_types,type_conflict,
- infer_on_eq,infer_dead_value,receive_marker]}].
+ infer_on_eq,infer_dead_value,receive_marker,
+ safe_instructions,missing_return_type]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -735,6 +737,30 @@ receive_marker(Config) when is_list(Config) ->
ok.
+%% ERL-1128: the validator erroneously thought that many non-throwing
+%% instructions like is_eq_exact could throw.
+safe_instructions(Config) when is_list(Config) ->
+ Errors = do_val(safe_instructions, Config),
+
+ [] = Errors,
+
+ ok.
+
+missing_return_type(Config) when is_list(Config) ->
+ %% ERL-1161: the validator didn't know that is_map_key always returns a
+ %% bool.
+ Map = #{ hello => there },
+ true = mrt_1(true),
+ false = mrt_1(false),
+ true = mrt_1(is_map_key(id(hello), Map)),
+ false = mrt_1(is_map_key(id(there), Map)),
+
+ ok.
+
+mrt_1(Bool) ->
+ true = is_boolean(Bool),
+ Bool.
+
%%%-------------------------------------------------------------------------
transform_remove(Remove, Module) ->
diff --git a/lib/compiler/test/beam_validator_SUITE_data/safe_instructions.S b/lib/compiler/test/beam_validator_SUITE_data/safe_instructions.S
new file mode 100644
index 0000000000..4266c64741
--- /dev/null
+++ b/lib/compiler/test/beam_validator_SUITE_data/safe_instructions.S
@@ -0,0 +1,102 @@
+{module, safe_instructions}. %% version = 0
+
+{exports, [{module_info,0},{module_info,1},{send_request,1}]}.
+
+{attributes, []}.
+
+{labels, 18}.
+
+
+{function, send_request, 1, 2}.
+ {label,1}.
+ {line,[{location,"t.erl",6}]}.
+ {func_info,{atom,t},{atom,send_request},1}.
+ {label,2}.
+ {allocate,3,1}.
+ {init,{y,0}}.
+ {move,{x,0},{y,1}}.
+ {'try',{y,2},{f,7}}.
+ {move,nil,{x,0}}.
+ {line,[{location,"t.erl",8}]}.
+ {call,1,{f,9}}.
+ {move,{x,0},{y,0}}.
+ {'try',{y,1},{f,3}}.
+ {line,[{location,"t.erl",9}]}.
+ {call,0,{f,13}}.
+ {'%',{type_info,{x,0},{atom,ok}}}.
+ {try_end,{y,1}}.
+ {jump,{f,4}}.
+ {label,3}.
+ {try_case,{y,1}}.
+ {label,4}.
+ {test,is_eq_exact,{f,5},[{y,0},{atom,ok}]}.
+ {move,{atom,ok},{x,0}}.
+ {jump,{f,6}}.
+ {label,5}.
+ {move,{y,0},{x,0}}.
+ {label,6}.
+ {try_end,{y,2}}.
+ {deallocate,3}.
+ return.
+ {label,7}.
+ {try_case,{y,2}}.
+ {test_heap,2,0}.
+ {put_list,{y,1},nil,{x,1}}.
+ {move,{literal,"error: sending file to ~s"},{x,0}}.
+ {line,[{location,"t.erl",16}]}.
+ {call_ext,2,{extfunc,lager,debug,2}}.
+ {move,{atom,ok},{x,0}}.
+ {deallocate,3}.
+ return.
+
+
+{function, ftp_cmds, 1, 9}.
+ {label,8}.
+ {line,[{location,"t.erl",21}]}.
+ {func_info,{atom,t},{atom,ftp_cmds},1}.
+ {label,9}.
+ {test,is_nonempty_list,{f,11},[{x,0}]}.
+ {allocate,1,1}.
+ {get_list,{x,0},{x,0},{y,0}}.
+ {line,[{location,"t.erl",23}]}.
+ {call_fun,0}.
+ {test,is_eq_exact,{f,10},[{x,0},{atom,ok}]}.
+ {move,{y,0},{x,0}}.
+ {call_last,1,{f,9},1}.
+ {label,10}.
+ {deallocate,1}.
+ return.
+ {label,11}.
+ {test,is_nil,{f,8},[{x,0}]}.
+ {move,{atom,ok},{x,0}}.
+ return.
+
+
+{function, ftp_close, 0, 13}.
+ {label,12}.
+ {line,[{location,"t.erl",29}]}.
+ {func_info,{atom,t},{atom,ftp_close},0}.
+ {label,13}.
+ {move,{atom,ok},{x,0}}.
+ return.
+
+
+{function, module_info, 0, 15}.
+ {label,14}.
+ {line,[]}.
+ {func_info,{atom,t},{atom,module_info},0}.
+ {label,15}.
+ {move,{atom,t},{x,0}}.
+ {line,[]}.
+ {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.
+
+
+{function, module_info, 1, 17}.
+ {label,16}.
+ {line,[]}.
+ {func_info,{atom,t},{atom,module_info},1}.
+ {label,17}.
+ {move,{x,0},{x,1}}.
+ {move,{atom,t},{x,0}}.
+ {line,[]}.
+ {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.
diff --git a/lib/compiler/test/bs_match_SUITE.erl b/lib/compiler/test/bs_match_SUITE.erl
index a789b82910..2e91f7b53e 100644
--- a/lib/compiler/test/bs_match_SUITE.erl
+++ b/lib/compiler/test/bs_match_SUITE.erl
@@ -45,7 +45,8 @@
expression_before_match/1,erl_689/1,restore_on_call/1,
restore_after_catch/1,matches_on_parameter/1,big_positions/1,
matching_meets_apply/1,bs_start_match2_defs/1,
- exceptions_after_match_failure/1, bad_phi_paths/1]).
+ exceptions_after_match_failure/1, bad_phi_paths/1,
+ combine_empty_segments/1]).
-export([coverage_id/1,coverage_external_ignore/2]).
@@ -82,7 +83,8 @@ groups() ->
expression_before_match,erl_689,restore_on_call,
matches_on_parameter,big_positions,
matching_meets_apply,bs_start_match2_defs,
- exceptions_after_match_failure,bad_phi_paths]}].
+ exceptions_after_match_failure,bad_phi_paths,
+ combine_empty_segments]}].
init_per_suite(Config) ->
@@ -2033,4 +2035,14 @@ bad_phi_paths_1(Arg) ->
end,
id(B).
+combine_empty_segments(_Config) ->
+ <<0,1,2,3>> = combine_empty_segments_1(<<0,1,2,3>>),
+ ok.
+
+combine_empty_segments_1(A) ->
+ <<B/bits>> = A,
+ <<C/bits>> = B,
+ <<D/bits>> = C,
+ D.
+
id(I) -> I.
diff --git a/lib/compiler/test/core_fold_SUITE.erl b/lib/compiler/test/core_fold_SUITE.erl
index adfebd5158..f3bf716037 100644
--- a/lib/compiler/test/core_fold_SUITE.erl
+++ b/lib/compiler/test/core_fold_SUITE.erl
@@ -28,7 +28,8 @@
mixed_matching_clauses/1,unnecessary_building/1,
no_no_file/1,configuration/1,supplies/1,
redundant_stack_frame/1,export_from_case/1,
- empty_values/1,cover_letrec_effect/1]).
+ empty_values/1,cover_letrec_effect/1,
+ receive_effect/1]).
-export([foo/0,foo/1,foo/2,foo/3]).
@@ -48,7 +49,8 @@ groups() ->
mixed_matching_clauses,unnecessary_building,
no_no_file,configuration,supplies,
redundant_stack_frame,export_from_case,
- empty_values,cover_letrec_effect]}].
+ empty_values,cover_letrec_effect,
+ receive_effect]}].
init_per_suite(Config) ->
@@ -641,4 +643,12 @@ cover_letrec_effect(_Config) ->
end,
ok.
+receive_effect(_Config) ->
+ self() ! whatever,
+ {} = do_receive_effect(),
+ ok.
+
+do_receive_effect() ->
+ {} = receive _ -> {} = {} end.
+
id(I) -> I.
diff --git a/lib/compiler/test/fun_SUITE.erl b/lib/compiler/test/fun_SUITE.erl
index 7fc6195e31..89dea136b3 100644
--- a/lib/compiler/test/fun_SUITE.erl
+++ b/lib/compiler/test/fun_SUITE.erl
@@ -23,7 +23,7 @@
init_per_group/2,end_per_group/2,
test1/1,overwritten_fun/1,otp_7202/1,bif_fun/1,
external/1,eep37/1,eep37_dup/1,badarity/1,badfun/1,
- duplicated_fun/1]).
+ duplicated_fun/1,unused_fun/1]).
%% Internal exports.
-export([call_me/1,dup1/0,dup2/0]).
@@ -38,7 +38,7 @@ all() ->
groups() ->
[{p,[parallel],
[test1,overwritten_fun,otp_7202,bif_fun,external,eep37,
- eep37_dup,badarity,badfun,duplicated_fun]}].
+ eep37_dup,badarity,badfun,duplicated_fun,unused_fun]}].
init_per_suite(Config) ->
test_lib:recompile(?MODULE),
@@ -277,5 +277,13 @@ duplicated_fun(_Config) ->
duplicated_fun_helper(_) ->
ok.
+%% ERL-1166: beam_kernel_to_ssa would crash if a fun was unused.
+unused_fun(_Config) ->
+ _ = fun() -> ok end,
+ try id(ok) of
+ _ -> fun() -> ok end
+ catch _ -> ok end,
+ ok.
+
id(I) ->
I.
diff --git a/lib/compiler/test/map_SUITE.erl b/lib/compiler/test/map_SUITE.erl
index 440b632381..2bcb6133da 100644
--- a/lib/compiler/test/map_SUITE.erl
+++ b/lib/compiler/test/map_SUITE.erl
@@ -73,7 +73,8 @@
t_reused_key_variable/1,
%% new in OTP 22
- t_mixed_clause/1,cover_beam_trim/1
+ t_mixed_clause/1,cover_beam_trim/1,
+ t_duplicate_keys/1
]).
suite() -> [].
@@ -130,7 +131,8 @@ all() ->
t_reused_key_variable,
%% new in OTP 22
- t_mixed_clause,cover_beam_trim
+ t_mixed_clause,cover_beam_trim,
+ t_duplicate_keys
].
groups() -> [].
@@ -2191,6 +2193,26 @@ do_cover_beam_trim(Id, OldMax, Max, Id, M) ->
#{Id:=Val} = id(M),
Val.
+t_duplicate_keys(Config) when is_list(Config) ->
+ Map = #{ gurka => gaffel },
+ Map = dup_keys_1(id(Map)),
+
+ ok = dup_keys_1(#{ '__struct__' => ok }),
+
+ ok.
+
+dup_keys_1(Map) ->
+ case Map of
+ #{'__struct__' := _} ->
+ case Map of
+ #{'__struct__' := _} ->
+ ok;
+ O1 ->
+ O1
+ end;
+ O2 ->
+ O2
+ end.
%% aux
diff --git a/lib/compiler/vsn.mk b/lib/compiler/vsn.mk
index f0bcff01da..87cb90522c 100644
--- a/lib/compiler/vsn.mk
+++ b/lib/compiler/vsn.mk
@@ -1 +1 @@
-COMPILER_VSN = 7.5
+COMPILER_VSN = 7.5.2
diff --git a/lib/crypto/c_src/api_ng.c b/lib/crypto/c_src/api_ng.c
index 002a74724d..5fc161f382 100644
--- a/lib/crypto/c_src/api_ng.c
+++ b/lib/crypto/c_src/api_ng.c
@@ -261,7 +261,7 @@ static int get_update_args(ErlNifEnv* env,
if (!enif_inspect_binary(env, indata_arg, &in_data_bin) )
{
*return_term = EXCP_BADARG(env, "Bad 2:nd arg");
- goto err;
+ goto err0;
}
ASSERT(in_data_bin.size <= INT_MAX);
@@ -294,7 +294,7 @@ static int get_update_args(ErlNifEnv* env,
if (!enif_alloc_binary((size_t)in_data_bin.size+block_size, &out_data_bin))
{
*return_term = EXCP_ERROR(env, "Can't allocate outdata");
- goto err;
+ goto err0;
}
if (!EVP_CipherUpdate(ctx_res->ctx, out_data_bin.data, &out_len, in_data_bin.data, in_data_bin.size))
@@ -318,6 +318,8 @@ static int get_update_args(ErlNifEnv* env,
return 1;
err:
+ enif_release_binary(&out_data_bin);
+ err0:
return 0;
}
diff --git a/lib/crypto/doc/src/crypto.xml b/lib/crypto/doc/src/crypto.xml
index 5c1f6af016..ff7479f605 100644
--- a/lib/crypto/doc/src/crypto.xml
+++ b/lib/crypto/doc/src/crypto.xml
@@ -772,7 +772,7 @@
Do a complete encrypt or decrypt with an AEAD cipher of the full text.
</p>
<p>For encryption, set the <c>EncryptFlag</c> to <c>true</c> and set the <c>TagOrTagLength</c>
- to the wanted size of the tag, that is, the tag length. If the default length is wanted, the
+ to the wanted size (in bytes) of the tag, that is, the tag length. If the default length is wanted, the
<c>crypto_aead/6</c> form may be used.
</p>
<p>For decryption, set the <c>EncryptFlag</c> to <c>false</c> and put the tag to be checked
diff --git a/lib/crypto/doc/src/notes.xml b/lib/crypto/doc/src/notes.xml
index 2d238582b2..7333124709 100644
--- a/lib/crypto/doc/src/notes.xml
+++ b/lib/crypto/doc/src/notes.xml
@@ -31,6 +31,21 @@
</header>
<p>This document describes the changes made to the Crypto application.</p>
+<section><title>Crypto 4.6.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Constant time comparisons added.</p>
+ <p>
+ Own Id: OTP-16376</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.6.3</title>
<section><title>Improvements and New Features</title>
@@ -296,6 +311,21 @@
</section>
+<section><title>Crypto 4.4.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Constant time comparisons added.</p>
+ <p>
+ Own Id: OTP-16376</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.4.2.1</title>
<section><title>Improvements and New Features</title>
@@ -610,6 +640,21 @@
</section>
+<section><title>Crypto 4.2.2.4</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Constant time comparisons added.</p>
+ <p>
+ Own Id: OTP-16376</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Crypto 4.2.2.3</title>
<section><title>Improvements and New Features</title>
diff --git a/lib/crypto/src/crypto.erl b/lib/crypto/src/crypto.erl
index 965697578d..b19fdadfcd 100644
--- a/lib/crypto/src/crypto.erl
+++ b/lib/crypto/src/crypto.erl
@@ -24,6 +24,7 @@
-export([start/0, stop/0, info_lib/0, info_fips/0, supports/0, enable_fips_mode/1,
version/0, bytes_to_integer/1]).
+-export([equal_const_time/2]).
-export([cipher_info/1, hash_info/1]).
-export([hash/2, hash_init/1, hash_update/2, hash_final/1]).
-export([sign/4, sign/5, verify/5, verify/6]).
@@ -552,6 +553,35 @@ enable_fips_mode(_) -> ?nif_stub.
%%%================================================================
%%%
+%%% Compare in constant time
+%%%
+%%%================================================================
+
+%%% Candidate for a NIF
+
+equal_const_time(X1, X2) ->
+ equal_const_time(X1, X2, true).
+
+
+equal_const_time(<<B1,R1/binary>>, <<B2,R2/binary>>, Truth) ->
+ equal_const_time(R1, R2, Truth and (B1 == B2));
+equal_const_time(<<_,R1/binary>>, <<>>, Truth) ->
+ equal_const_time(R1, <<>>, Truth and false);
+equal_const_time(<<>>, <<>>, Truth) ->
+ Truth;
+
+equal_const_time([H1|T1], [H2|T2], Truth) ->
+ equal_const_time(T1, T2, Truth and (H1 == H2));
+equal_const_time([_|T1], [], Truth) ->
+ equal_const_time(T1, [], Truth and false);
+equal_const_time([], [], Truth) ->
+ Truth;
+
+equal_const_time(_, _, _) ->
+ false.
+
+%%%================================================================
+%%%
%%% Hashing
%%%
%%%================================================================
diff --git a/lib/crypto/test/crypto_bench_SUITE.erl b/lib/crypto/test/crypto_bench_SUITE.erl
index c66a27f0c8..d738902ac8 100644
--- a/lib/crypto/test/crypto_bench_SUITE.erl
+++ b/lib/crypto/test/crypto_bench_SUITE.erl
@@ -67,7 +67,7 @@ init_per_suite(Config0) ->
calibrate([{sec_goal,10} | Config1])
catch _:_ ->
- {fail, "Crypto did not start"}
+ {skip, "Crypto did not start"}
end.
end_per_suite(_Config) ->
diff --git a/lib/crypto/test/crypto_property_test_SUITE.erl b/lib/crypto/test/crypto_property_test_SUITE.erl
index 75a3d4872f..bcfd5d3de1 100644
--- a/lib/crypto/test/crypto_property_test_SUITE.erl
+++ b/lib/crypto/test/crypto_property_test_SUITE.erl
@@ -24,13 +24,28 @@
-include_lib("common_test/include/ct.hrl").
-all() -> [encrypt_decrypt__crypto_one_time,
- prop__crypto_init_update
+all() -> [encrypt_decrypt_one_time,
+ init_update,
+ init_update_multi
].
%%% First prepare Config and compile the property tests for the found tool:
init_per_suite(Config) ->
- ct_property_test:init_per_suite(Config).
+ case
+ try crypto:start() of
+ ok -> true;
+ {error, already_started} -> true;
+ _ -> false
+ catch
+ _:_ -> false
+ end
+ of
+ true ->
+ ct_property_test:init_per_suite(Config);
+ false ->
+ {skip, "Crypto did not start"}
+ end.
+
end_per_suite(Config) ->
Config.
@@ -38,13 +53,21 @@ end_per_suite(Config) ->
%%%================================================================
%%% Test suites
%%%
-encrypt_decrypt__crypto_one_time(Config) ->
+encrypt_decrypt_one_time(Config) ->
ct_property_test:quickcheck(
crypto_ng_api:prop__crypto_one_time(),
Config
).
-prop__crypto_init_update(Config) ->
+
+init_update(Config) ->
ct_property_test:quickcheck(
crypto_ng_api:prop__crypto_init_update(),
Config
).
+
+init_update_multi(Config) ->
+ ct_property_test:quickcheck(
+ crypto_ng_api_stateful:prop__crypto_init_multi(Config),
+ Config
+ ).
+
diff --git a/lib/crypto/test/engine_SUITE.erl b/lib/crypto/test/engine_SUITE.erl
index 41cd132734..572f86e3c9 100644
--- a/lib/crypto/test/engine_SUITE.erl
+++ b/lib/crypto/test/engine_SUITE.erl
@@ -80,7 +80,7 @@ groups() ->
init_per_suite(Config) ->
- case {os:type(), crypto:info_lib()} of
+ try {os:type(), crypto:info_lib()} of
{_, [{_,_, <<"OpenSSL 1.0.1s-freebsd 1 Mar 2016">>}]} ->
{skip, "Problem with engine on OpenSSL 1.0.1s-freebsd"};
@@ -100,6 +100,8 @@ init_per_suite(Config) ->
catch _:_ ->
{skip, "Crypto did not start"}
end
+ catch _:_ ->
+ {skip, "Crypto not loaded"}
end.
end_per_suite(_Config) ->
diff --git a/lib/crypto/test/property_test/crypto_ng_api.erl b/lib/crypto/test/property_test/crypto_ng_api.erl
index c3a21b0804..14753a4eba 100644
--- a/lib/crypto/test/property_test/crypto_ng_api.erl
+++ b/lib/crypto/test/property_test/crypto_ng_api.erl
@@ -23,35 +23,7 @@
-compile(export_all).
--proptest(eqc).
--proptest([triq,proper]).
-
--ifndef(EQC).
--ifndef(PROPER).
--ifndef(TRIQ).
-%%-define(EQC,true).
--define(PROPER,true).
-%%-define(TRIQ,true).
--endif.
--endif.
--endif.
-
--ifdef(EQC).
--include_lib("eqc/include/eqc.hrl").
--define(MOD_eqc,eqc).
-
--else.
--ifdef(PROPER).
--include_lib("proper/include/proper.hrl").
--define(MOD_eqc,proper).
--else.
--ifdef(TRIQ).
--define(MOD_eqc,triq).
--include_lib("triq/include/triq.hrl").
-
--endif.
--endif.
--endif.
+-include_lib("common_test/include/ct_property_test.hrl").
-include("crypto_prop_generators.hrl").
@@ -62,9 +34,12 @@ prop__crypto_one_time() ->
numtests(10000,
?FORALL({TextPlain, Cipher, Key, IV}, ?LET(Ciph,cipher(),
{text_plain(), Ciph, key(Ciph), iv(Ciph)}),
- equal(TextPlain,
- full_blocks(TextPlain, Cipher),
- decrypt_encrypt_one_time(Cipher, Key, IV, TextPlain))
+ begin
+ R = equal(TextPlain,
+ full_blocks(TextPlain, Cipher),
+ decrypt_encrypt_one_time(Cipher, Key, IV, TextPlain)),
+ prt_inf(Cipher, TextPlain, R)
+ end
)
).
@@ -72,12 +47,25 @@ prop__crypto_init_update() ->
numtests(10000,
?FORALL({TextPlain, Cipher, Key, IV}, ?LET(Ciph,cipher(),
{text_plain(), Ciph, key(Ciph), iv(Ciph)}),
- equal(TextPlain,
- full_blocks(TextPlain, Cipher),
- decrypt_encrypt_init_update(Cipher, Key, IV, TextPlain))
- )
+ begin
+ R = equal(TextPlain,
+ full_blocks(TextPlain, Cipher),
+ decrypt_encrypt_init_update(Cipher, Key, IV, TextPlain)),
+ prt_inf(Cipher, TextPlain, R)
+ end)
).
+prt_inf(Cipher, TextPlain, R) ->
+ aggregate(ct_property_test:title("text lengths",
+ ct_property_test:print_frequency_ranges(),
+ fun ct:pal/2),
+ [iolist_size(TextPlain)],
+ aggregate(ct_property_test:title("ciphers",
+ ct_property_test:print_frequency(),
+ fun ct:pal/2),
+ [Cipher],
+ R)).
+
%%%================================================================
%%% Lib
diff --git a/lib/crypto/test/property_test/crypto_ng_api_stateful.erl b/lib/crypto/test/property_test/crypto_ng_api_stateful.erl
new file mode 100644
index 0000000000..21bbe272dc
--- /dev/null
+++ b/lib/crypto/test/property_test/crypto_ng_api_stateful.erl
@@ -0,0 +1,161 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-2017. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+%%
+
+-module(crypto_ng_api_stateful).
+
+-compile(export_all).
+
+-include_lib("common_test/include/ct_property_test.hrl").
+-include("crypto_prop_generators.hrl").
+
+%%%================================================================
+%%% Properties:
+
+prop__crypto_init_multi(Config) ->
+ numtests(300,
+ ?FORALL(Cmds, parallel_commands(?MODULE),
+ begin
+ RunResult = run_parallel_commands(?MODULE, Cmds),
+ ct_property_test:present_result(?MODULE, Cmds, RunResult, Config)
+ end)).
+
+%%%================================================================
+-define(call(F,As), {call,?MODULE,F,As}).
+
+initial_state() ->
+ #{}.
+
+
+command(S) ->
+ frequency(
+ lists:flatten(
+ [
+ {max(0,5-maps:size(S)),
+ ?call(init_crypto, ?LET(Ciph, cipher(),
+ [Ciph, key(Ciph), iv(Ciph), block_size(Ciph)]))},
+
+ [{10, ?call(encrypt, [oneof(refs(S)), binary()])
+ }
+ || refs(S) =/= []],
+
+ [{30, ?call(decrypt, ?LET({Refs,{_,[CT|_]}}, oneof(Sc),
+ [Refs, CT]))
+ }
+ || Sc <- [[R || {_,{_,Cs}} = R <- maps:to_list(S),
+ Cs =/= []]
+ ],
+ Sc =/= [] ],
+[] ])).
+
+
+precondition(S, {call,?MODULE,decrypt,[Refs,CrT]}) ->
+ %% io:format("precondition(1) ~p Args = ~p, S = ~p", [decrypt,[Refs,CrT],S]),
+ case maps:get(Refs, S) of
+ {_BlockSize, [CrT|_]} ->
+ %% io:format(" (sym) true~n",[]),
+ true;
+ {_BlockSize, [CrT|_], _} ->
+ %% io:format(" (dyn) true~n",[]),
+ true;
+ _Other ->
+ %% io:format(" _Other=~p false~n",[_Other]),
+ false
+ end;
+precondition(_S, {call,?MODULE,_Name,_Args}) ->
+ %% io:format("precondition ~p Args = ~p, S = ~p~n", [_Name,_Args,_S]),
+ true.
+
+
+postcondition(_D, _Call, error) ->
+ %% io:format("postcondition ~p:~p error _Call = ~p~n",[?MODULE,?LINE,_Call]),
+ false;
+postcondition(D, {call,?MODULE,decrypt,[Refs,_CrT]}, Result) ->
+ #{Refs := {_BlockSize, _CT, PT}} = D,
+ Size = size(Result),
+ <<Expect:Size/binary, _/binary>> = PT,
+ Expect == Result;
+postcondition(_D, _Call, _Result) ->
+ true.
+
+
+symbolic({var,_}) -> true;
+symbolic(_) -> false.
+
+
+next_state(S, Refs, {call,?MODULE,init_crypto,[_Cipher, _Key, _IV, BlockSize]}=_C) ->
+ case symbolic(Refs) of
+ true ->
+ S#{Refs => {BlockSize, []} };
+ false ->
+ S#{Refs => {BlockSize, [], <<>>} }
+ end;
+
+next_state(S, Res, {call,?MODULE,encrypt,[Refs,Ptxt]}=_C) ->
+%% io:format("next_state enrypt Refs = ~p, S = ~p~n", [Refs,S]),
+ case S of
+ #{Refs := {BlockSize, Cs}} ->
+ S#{Refs := {BlockSize, Cs++[Res]}};
+
+ #{Refs := {BlockSize, Cs,Ps}} ->
+ S#{Refs := {BlockSize, Cs++[Res], <<Ps/binary,Ptxt/binary>>}}
+ end;
+
+next_state(S, Result, {call,?MODULE,decrypt,[Refs,CrT]}=_C) ->
+%% io:format("next_state decrypt Refs = ~p, CrT = ~p, S = ~p~n", [Refs,CrT,S]),
+ case S of
+ #{Refs := {BlockSize, [CrT|Cs]}} ->
+ S#{Refs := {BlockSize, Cs}};
+
+ #{Refs := {BlockSize, [CrT|Cs], Ps0}} ->
+ Sz = size(Result),
+ <<Result:Sz/binary,Ps/binary>> = Ps0,
+ S#{Refs := {BlockSize,Cs,Ps}}
+ end.
+
+%%%================================================================
+-define(ok_error(X),
+ try X of
+ __R -> %% io:format("~p:~p ok! Result = ~p~n", [?MODULE,?LINE,__R]),
+ __R
+ catch
+ _CC:_EE:_SS ->
+ io:format("******* ~p:~p ~p ~p~n~p", [?MODULE,?LINE,_CC,_EE,_SS]),
+ error
+ end).
+
+init_crypto(Cipher, Key, IV, _BlockSize) ->
+ %% io:format("~p:~p init_crypto~n (~p,~n ~p,~n ~p,~n ~p)", [?MODULE,?LINE,Cipher,Key,IV,_BlockSize]),
+ ?ok_error({
+ crypto:crypto_init(Cipher, Key, IV, true),
+ crypto:crypto_init(Cipher, Key, IV, false)
+ }).
+
+encrypt({EncRef,_DecRef}, PlainText) ->
+ %% io:format("~p:~p encrypt~n (~p,~n ~p) ", [?MODULE,?LINE,EncRef,PlainText]),
+ ?ok_error(crypto:crypto_update(EncRef, PlainText)).
+
+decrypt({_EncRef,DecRef}, CT) ->
+ %% io:format("~p:~p decrypt~n (~p,~n ~p)", [?MODULE,?LINE,DecRef,CT]),
+ ?ok_error(crypto:crypto_update(DecRef, CT)).
+
+%%%----------------------------------------------------------------
+refs(S) -> [Refs || {Refs,_} <- maps:to_list(S)].
+
diff --git a/lib/crypto/test/property_test/crypto_prop_generators.erl b/lib/crypto/test/property_test/crypto_prop_generators.erl
index 5a53a000f0..3a7e9ecb87 100644
--- a/lib/crypto/test/property_test/crypto_prop_generators.erl
+++ b/lib/crypto/test/property_test/crypto_prop_generators.erl
@@ -21,37 +21,19 @@
-module(crypto_prop_generators).
--compile(export_all).
-
--proptest(eqc).
--proptest([triq,proper]).
-
--ifndef(EQC).
--ifndef(PROPER).
--ifndef(TRIQ).
-%%-define(EQC,true).
--define(PROPER,true).
-%%-define(TRIQ,true).
--endif.
--endif.
--endif.
-
--ifdef(EQC).
--include_lib("eqc/include/eqc.hrl").
--define(MOD_eqc,eqc).
-
--else.
--ifdef(PROPER).
--include_lib("proper/include/proper.hrl").
--define(MOD_eqc,proper).
--else.
--ifdef(TRIQ).
--define(MOD_eqc,triq).
--include_lib("triq/include/triq.hrl").
-
--endif.
--endif.
--endif.
+-export([text_plain/0,
+ cipher/0,
+ key/1,
+ iv/1,
+ iolist/0,
+ mybinary/1,
+ non_aead_ciphers/0,
+ block_size/1,
+ key_length/1,
+ iv_length/1
+ ]).
+
+-include_lib("common_test/include/ct_property_test.hrl").
%%%================================================================
%%% Generators
diff --git a/lib/crypto/vsn.mk b/lib/crypto/vsn.mk
index c773529c84..b86553d0a6 100644
--- a/lib/crypto/vsn.mk
+++ b/lib/crypto/vsn.mk
@@ -1 +1 @@
-CRYPTO_VSN = 4.6.3
+CRYPTO_VSN = 4.6.4
diff --git a/lib/dialyzer/doc/src/typer.xml b/lib/dialyzer/doc/src/typer.xml
index 1cfbe94807..524956ed4b 100644
--- a/lib/dialyzer/doc/src/typer.xml
+++ b/lib/dialyzer/doc/src/typer.xml
@@ -64,7 +64,7 @@ typer [--help] [--version] [--plt PLT] [--edoc]
<taglist>
- <tag><c>--r</c></tag>
+ <tag><c>-r</c></tag>
<item>
<p>Search directories recursively for .erl files below them.</p>
</item>
diff --git a/lib/diameter/doc/src/diameter.xml b/lib/diameter/doc/src/diameter.xml
index 85522c99b2..aa4eb6ad45 100644
--- a/lib/diameter/doc/src/diameter.xml
+++ b/lib/diameter/doc/src/diameter.xml
@@ -23,7 +23,7 @@
<copyright>
<year>2011</year>
-<year>2019</year>
+<year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -1046,8 +1046,9 @@ each node from which requests are sent.</p>
<tag><c>&transport_opt;</c></tag>
<item>
<p>
-Any transport option except <c>applications</c> or
-<c>capabilities</c>.
+Any transport option except <c>applications</c>,
+<c>capabilities</c>, <c>transport_config</c>, and
+<c>transport_module</c>.
Used as defaults for transport configuration, values passed to
&add_transport; overriding values configured on the service.</p>
</item>
@@ -1398,10 +1399,11 @@ Options <c>monitor</c> and <c>link</c> are ignored in the list-valued
case.
An MFA is applied with an additional term prepended to its argument
list, and should return either the pid of the handler process that
-invokes <c>diameter_traffic:request/1</c> on the term in order to
+invokes <c>diameter_traffic:request/1</c> on the argument in order to
process the request, or the atom <c>discard</c>.
-The handler process need not be local, but diameter must be started on
-the remote node.</p>
+The handler process need not be local, and diameter need not be
+started on the remote node, but diameter and relevant application
+callbacks must be on the code path.</p>
<p>
Defaults to the empty list.</p>
diff --git a/lib/diameter/doc/src/notes.xml b/lib/diameter/doc/src/notes.xml
index 8dcba93273..780b0b894a 100644
--- a/lib/diameter/doc/src/notes.xml
+++ b/lib/diameter/doc/src/notes.xml
@@ -43,6 +43,57 @@ first.</p>
<!-- ===================================================================== -->
+<section><title>diameter 2.2.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The possibility of choosing a handler process for an
+ incoming Diameter request with a configured MFA was
+ documented in OTP 20.0, but counters (with
+ {traffic_counters, true}) were not incremented when this
+ process was on a remote node. Counters are now
+ incremented on the node that configures the transport in
+ question.</p>
+ <p>
+ Introduced in OTP 21.3.</p>
+ <p>
+ Own Id: OTP-16457</p>
+ </item>
+ <item>
+ <p>
+ Transport options differing from those passed to
+ diameter:add_transport/2 were used in several situations:
+ when starting a transport process after connect_timer
+ expiry after an initial connection attempt has failed,
+ when starting a transport process after a connection has
+ been accepted, when sending events, when returning
+ options in diameter:service_info/2, and possibly more. In
+ particular, the following configuration options to
+ diameter:add_transport/2 were dropped: avp_dictionaries,
+ incoming_maxlen, spawn_opt, strict_mbit.</p>
+ <p>
+ Moreover, any service options mistakenly passed to
+ diameter:add_transport/2 were interpreted as such,
+ instead of being ignored as the documentation states,
+ with the consequence that outgoing and incoming requests
+ saw different values of some options, some were always
+ taken from transport options, and others from service
+ options.</p>
+ <p>
+ diameter:add_transport/2 must be called in new code for
+ the fix to have effect.</p>
+ <p>
+ Introduced in OTP 20.1.</p>
+ <p>
+ Own Id: OTP-16459</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>diameter 2.2.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/diameter/examples/code/GNUmakefile b/lib/diameter/examples/code/GNUmakefile
index f5c2e5f869..9efb966e65 100644
--- a/lib/diameter/examples/code/GNUmakefile
+++ b/lib/diameter/examples/code/GNUmakefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2015. All Rights Reserved.
+# Copyright Ericsson AB 2010-2020. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -18,10 +18,10 @@
# %CopyrightEnd%
#
-EXAMPLES = client server relay # redirect proxy
+EXAMPLES = client server relay redirect # proxy
CALLBACKS = $(EXAMPLES:%=%_cb)
-MODULES = node $(EXAMPLES) $(EXAMPLES:%=%_cb)
+MODULES = $(EXAMPLES) $(EXAMPLES:%=%_cb)
BEAM = $(MODULES:%=%.beam)
diff --git a/lib/diameter/examples/code/README b/lib/diameter/examples/code/README
new file mode 100644
index 0000000000..b639849390
--- /dev/null
+++ b/lib/diameter/examples/code/README
@@ -0,0 +1,105 @@
+
+This directory contains small examples of simple Diameter nodes. They
+don't do everything a real node should do obviously, but they're a
+starting point.
+
+Each example consists of an interface module with functions to start
+and stop a service and add transport, and a corresponding callback
+module for the Diameter application the service configures. A real
+node might support multiple Diameter applications, either with the
+same callback or sharing a common callback, maybe using extra
+arguments to distinguish between callbacks for the different
+applications.
+
+The interface functions are named start, stop, connect, and listen;
+the client example also has a call function that sends an example
+message. Service names should be atoms in these modules (since the
+default setting of Origin-Host assumes this), but doesn't need to be
+in general. Options are passed directly to diameter:start_service/2
+and diameter:add_transport/2, with some additional convenience options
+for the latter; in particular, the atoms tcp and sctp to connect to or
+listen on default endpoints (127.0.01:3868), or tuples with protocol
+and another endpoint {eg. {tcp, {192,168,1,5}, 3869}. This convenience
+makes the simplest usage like this in an Erlang shell:
+
+ diameter:start().
+ server:start().
+ server:listen(tcp).
+ client:start().
+ client:connect(tcp).
+ client:call().
+
+Or put a relay between the client and server:
+
+ diameter:start().
+ server:start().
+ server:listen(sctp).
+ relay:start().
+ relay:connect(sctp).
+ relay:listen(tcp).
+ client:start().
+ client:connect(tcp).
+ client:call().
+
+Most services should probably set the following options, which have
+been added to solve various problems over the years, while the
+defaults have not been changed for backwards compatibility.
+
+ {decode_format, map}
+
+ Provide decoded messages in #diameter_packet.msg of a
+ handle_request or handle_answer callback in the form [Name | Avps],
+ where Name is the atom() name of the message in the (Diameter)
+ application dictionary in question (eg. 'ACR') and Avps is a map
+ of AVP values. This avoids compile-time dependencies on the
+ generated records and their (generally) long-winded names. The
+ hrl files generated from dictionaries are best avoided.
+
+ {restrict_connections, false}
+
+ Accept multiple connections with the same peer. By default,
+ diameter will only accept a single connection with a given peer,
+ which the Diameter RFC can be interpreted as requiring. In
+ practice, wanting multiple connections to the same peer is
+ common.
+
+ {string_decode, false}
+
+ Disable the decoding of string-ish Diameter types to Erlang
+ strings, leaving them as binary(). Strings can be costly if
+ decoded Diameter messages are passed between processes.
+
+ {strict_mbit, false}
+
+ Relax the interpretation of the M-bit so that an AVP setting
+ this bit is not regarded as a 5001 error when the message
+ grammar in question doesn't explicitly list the AVP. Without
+ this, a Redirect-Host AVP received in a 3006
+ (DIAMETER_REDIRECT_INDICATION) answer-message from a redirect
+ agent will be treated as error, and there have been other
+ situations in which the default value has caused problems (or at
+ least surprise).
+
+ {call_mutates_state, false} (on each configured application)
+
+ Avoid pick_peer and subsequent callbacks going through a single
+ process, which can be a bottleneck. Better to use the tid() of
+ an ets table as (immutable) state, for example.
+
+Other options that are particularly useful/necessary in some
+situations are:
+
+ pool_size - Create a pool of accepting processes for a listening
+ transport, to avoid refused connections when many peers
+ connect simultaneously. Can also be used on a connecting
+ transport to establish multiple connections with a
+ single call to diameter:add_transport/2.
+
+ sequence - Ensure unique End-to-End and Hop-by-Hop identifiers over
+ a cluster of Erlang nodes.
+
+ share_peers - Share peer connections across a cluster of
+ use_shared_peers Erlang nodes.
+
+ spawn_opt - Replace diameter's spawning of a new handler process for
+ each request by something else: diameter_dist is an example.
diff --git a/lib/diameter/examples/code/client.erl b/lib/diameter/examples/code/client.erl
index 0864919cdd..04c91e37fa 100644
--- a/lib/diameter/examples/code/client.erl
+++ b/lib/diameter/examples/code/client.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,120 +18,173 @@
%% %CopyrightEnd%
%%
+-module(client).
+
%%
-%% An example Diameter client that can sends base protocol RAR
+%% An example Diameter client that can sends base protocol ACR
%% requests to a connected peer.
%%
-%% The simplest usage is as follows this to connect to a server
-%% listening on the default port on the local host, assuming diameter
-%% is already started (eg. diameter:start()).
+%% Simplest usage to connect to a server listening on TCP at
+%% 127.0.0.1:3868:
%%
%% client:start().
%% client:connect(tcp).
%% client:call().
%%
-%% The first call starts the a service with the default name of
-%% ?MODULE, the second defines a connecting transport that results in
-%% a connection to the peer (if it's listening), the third sends it a
-%% RAR and returns the answer.
-%%
-
--module(client).
-
--include_lib("diameter/include/diameter.hrl").
-export([start/1, %% start a service
start/2, %%
connect/2, %% add a connecting transport
- call/1, %% send using the record encoding
- cast/1, %% send using the list encoding and detached
+ call/2, %% send a request
stop/1]). %% stop a service
-%% A real application would typically choose an encoding and whether
-%% they want the call to return the answer or not. Sending with
-%% both the record and list encoding here, one detached and one not,
-%% is just for demonstration purposes.
%% Convenience functions using the default service name.
-export([start/0,
connect/1,
stop/0,
call/0,
- cast/0]).
+ call/1]).
-define(DEF_SVC_NAME, ?MODULE).
-define(L, atom_to_list).
+-define(LOOPBACK, {127,0,0,1}).
-%% The service configuration. As in the server example, a client
-%% supporting multiple Diameter applications may or may not want to
-%% configure a common callback module on all applications.
+%% Service configuration.
-define(SERVICE(Name), [{'Origin-Host', ?L(Name) ++ ".example.com"},
{'Origin-Realm', "example.com"},
{'Vendor-Id', 0},
{'Product-Name', "Client"},
{'Auth-Application-Id', [0]},
- {string_decode, false},
{decode_format, map},
+ {restrict_connections, false},
+ {strict_mbit, false},
+ {string_decode, false},
{application, [{alias, common},
{dictionary, diameter_gen_base_rfc6733},
- {module, client_cb}]}]).
+ {module, client_cb},
+ {answer_errors, callback},
+ {call_mutates_state, false}]}]).
-%% start/1
+%% start/2
-start(Name)
- when is_atom(Name) ->
- start(Name, []);
+start(Name, Opts) ->
+ Defaults = [T || {K,_} = T <- ?SERVICE(Name),
+ not lists:keymember(K, 1, Opts)],
+ diameter:start_service(Name, Opts ++ Defaults).
-start(Opts)
- when is_list(Opts) ->
+%% start/1
+
+start(Opts) ->
start(?DEF_SVC_NAME, Opts).
%% start/0
start() ->
- start(?DEF_SVC_NAME).
+ start(?DEF_SVC_NAME, []).
-%% start/2
+%% connect/1
-start(Name, Opts) ->
- node:start(Name, Opts ++ [T || {K,_} = T <- ?SERVICE(Name),
- false == lists:keymember(K, 1, Opts)]).
+connect(Opts) ->
+ connect(?DEF_SVC_NAME, Opts).
%% connect/2
+connect(Name, Opts)
+ when is_list(Opts) ->
+ diameter:add_transport(Name, {connect, lists:flatmap(fun opts/1, Opts)});
+
+%% backwards compatibility with old config
+connect(Name, {T, Opts}) ->
+ connect(Name, [T | Opts]);
connect(Name, T) ->
- node:connect(Name, T).
+ connect(Name, [T]).
-connect(T) ->
- connect(?DEF_SVC_NAME, T).
+%% call/2
-%% call/1
+call(Name, #{'Session-Id' := _} = Avps) ->
+ Defaults = #{'Destination-Realm' => "example.com",
+ 'Accounting-Record-Type' => 1, %% EVENT_RECORD
+ 'Accounting-Record-Number' => 0},
+ ACR = ['ACR' | maps:merge(Defaults, Avps)],
+ diameter:call(Name, common, ACR, []);
-call(Name) ->
- SId = diameter:session_id(?L(Name)),
- RAR = ['RAR' | #{'Session-Id' => SId,
- 'Auth-Application-Id' => 0,
- 'Re-Auth-Request-Type' => 0}],
- diameter:call(Name, common, RAR, []).
+call(Name, #{} = Avps) ->
+ call(Name, Avps#{'Session-Id' => diameter:session_id(?L(Name))});
-call() ->
- call(?DEF_SVC_NAME).
+call(Name, Avps) ->
+ call(Name, maps:from_list(Avps)).
-%% cast/1
+%% call/1
+
+call(Avps) ->
+ call(?DEF_SVC_NAME, Avps).
-cast(Name) ->
- SId = diameter:session_id(?L(Name)),
- RAR = ['RAR', {'Session-Id', SId},
- {'Auth-Application-Id', 0},
- {'Re-Auth-Request-Type', 1}],
- diameter:call(Name, common, RAR, [detach]).
+%% call/0
-cast() ->
- cast(?DEF_SVC_NAME).
+call() ->
+ call(?DEF_SVC_NAME, #{}).
%% stop/1
stop(Name) ->
- node:stop(Name).
+ diameter:stop_service(Name).
stop() ->
stop(?DEF_SVC_NAME).
+
+%% ===========================================================================
+
+%% opts/1
+%%
+%% Map some terms to transport_module/transport_config pairs as a
+%% convenience, pass everything else unmodified.
+
+opts(T)
+ when T == any;
+ T == tcp;
+ T == sctp ->
+ opts({T, loopback, 3868});
+
+opts({T, RA, RP}) ->
+ opts({T, [], RA, RP});
+
+opts({T, loopback, RA, RP}) ->
+ opts({T, ?LOOPBACK, RA, RP});
+
+opts({T, LA, RA, RP})
+ when is_tuple(LA) ->
+ opts({T, [{ip, LA}], RA, RP});
+
+opts({any, Opts, RA, RP}) ->
+ All = Opts ++ opts(RA, RP),
+ [{transport_module, diameter_sctp},
+ {transport_config, All, 2000},
+ {transport_module, diameter_tcp},
+ {transport_config, All}];
+
+opts({tcp, Opts, RA, RP}) ->
+ opts({diameter_tcp, Opts, RA, RP});
+
+opts({sctp, Opts, RA, RP}) ->
+ opts({diameter_sctp, Opts, RA, RP});
+
+opts({Mod, Opts, loopback, RP}) ->
+ opts({Mod, Opts, ?LOOPBACK, RP});
+
+opts({Mod, Opts, RA, default}) ->
+ opts({Mod, Opts, RA, 3868});
+
+opts({Mod, Opts, RA, RP}) ->
+ [{transport_module, Mod},
+ {transport_config, opts(RA, RP) ++ Opts}];
+
+opts(T) ->
+ [T].
+
+%% opts/2
+
+opts(loopback, RP) ->
+ opts(?LOOPBACK, RP);
+
+opts(RA, RP) ->
+ [{raddr, RA}, {rport, RP}, {reuseaddr, true}].
diff --git a/lib/diameter/examples/code/client_cb.erl b/lib/diameter/examples/code/client_cb.erl
index af2d4d6da7..7721c47a9a 100644
--- a/lib/diameter/examples/code/client_cb.erl
+++ b/lib/diameter/examples/code/client_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
-module(client_cb).
-include_lib("diameter/include/diameter.hrl").
--include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
%% diameter callbacks
-export([peer_up/3,
@@ -50,28 +49,16 @@ pick_peer([Peer | _], _, _SvcName, _State) ->
%% prepare_request/3
-prepare_request(#diameter_packet{msg = ['RAR' = T | Avps]}, _, {_, Caps}) ->
- #diameter_caps{origin_host = {OH, DH},
- origin_realm = {OR, DR}}
+prepare_request(#diameter_packet{msg = [Name | Avps]}, _, {_, Caps}) ->
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}
= Caps,
-
- {send, [T | if is_map(Avps) ->
- Avps#{'Origin-Host' => OH,
- 'Origin-Realm' => OR,
- 'Destination-Host' => DH,
- 'Destination-Realm' => DR};
- is_list(Avps) ->
- [{'Origin-Host', OH},
- {'Origin-Realm', OR},
- {'Destination-Host', DH},
- {'Destination-Realm', DR}
- | Avps]
- end]}.
+ {send, [Name | Avps#{'Origin-Host' => OH, 'Origin-Realm' => OR}]}.
%% prepare_retransmit/3
-prepare_retransmit(Packet, SvcName, Peer) ->
- prepare_request(Packet, SvcName, Peer).
+prepare_retransmit(Pkt, _SvcName, _Peer) ->
+ {send, Pkt}.
%% handle_answer/4
@@ -86,4 +73,4 @@ handle_error(Reason, _Request, _SvcName, _Peer) ->
%% handle_request/3
handle_request(_Packet, _SvcName, _Peer) ->
- erlang:error({unexpected, ?MODULE, ?LINE}).
+ {answer_message, 3001}. %% DIAMETER_COMMAND_UNSUPPORTED
diff --git a/lib/diameter/examples/code/node.erl b/lib/diameter/examples/code/node.erl
deleted file mode 100644
index 77810bf893..0000000000
--- a/lib/diameter/examples/code/node.erl
+++ /dev/null
@@ -1,202 +0,0 @@
-%%
-%% %CopyrightBegin%
-%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
-%%
-%% Licensed under the Apache License, Version 2.0 (the "License");
-%% you may not use this file except in compliance with the License.
-%% You may obtain a copy of the License at
-%%
-%% http://www.apache.org/licenses/LICENSE-2.0
-%%
-%% Unless required by applicable law or agreed to in writing, software
-%% distributed under the License is distributed on an "AS IS" BASIS,
-%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-%% See the License for the specific language governing permissions and
-%% limitations under the License.
-%%
-%% %CopyrightEnd%
-%%
-
-%%
-%% A library module used by the example Diameter nodes. Does little
-%% more than provide an alternate/simplified transport configuration.
-%%
-
--module(node).
-
--export([start/2,
- listen/2,
- connect/2,
- stop/1]).
-
--export([message/3]).
-
--type protocol()
- :: tcp | sctp.
-
--type ip_address()
- :: default
- | inet:ip_address().
-
--type server_transport()
- :: protocol()
- | {protocol(), ip_address(), non_neg_integer()}.
-
--type server_opts()
- :: server_transport()
- | {server_transport(), [diameter:transport_opt()]}
- | [diameter:transport_opt()].
-
--type client_transport()
- :: protocol() | any
- | {protocol() | any, ip_address(), non_neg_integer()}
- | {protocol() | any, ip_address(), ip_address(), non_neg_integer()}.
-
--type client_opts()
- :: client_transport()
- | {client_transport(), [diameter:transport_opt()]}
- | [diameter:transport_opt()].
-
-%% The server_transport() and client_transport() config is just
-%% convenience: arbitrary options can be specifed as a
-%% [diameter:transport_opt()].
-
--define(DEFAULT_PORT, 3868).
-
-%% ---------------------------------------------------------------------------
-%% Interface functions
-%% ---------------------------------------------------------------------------
-
-%% start/2
-
--spec start(diameter:service_name(), [diameter:service_opt()])
- -> ok
- | {error, term()}.
-
-start(Name, Opts)
- when is_atom(Name), is_list(Opts) ->
- diameter:start_service(Name, Opts).
-
-%% connect/2
-
--spec connect(diameter:service_name(), client_opts())
- -> {ok, diameter:transport_ref()}
- | {error, term()}.
-
-connect(Name, Opts)
- when is_list(Opts) ->
- diameter:add_transport(Name, {connect, Opts});
-
-connect(Name, {T, Opts}) ->
- connect(Name, Opts ++ client_opts(T));
-
-connect(Name, T) ->
- connect(Name, [{connect_timer, 5000} | client_opts(T)]).
-
-%% listen/2
-
--spec listen(diameter:service_name(), server_opts())
- -> {ok, diameter:transport_ref()}
- | {error, term()}.
-
-listen(Name, Opts)
- when is_list(Opts) ->
- diameter:add_transport(Name, {listen, Opts});
-
-listen(Name, {T, Opts}) ->
- listen(Name, Opts ++ server_opts(T));
-
-listen(Name, T) ->
- listen(Name, server_opts(T)).
-
-%% stop/1
-
--spec stop(diameter:service_name())
- -> ok
- | {error, term()}.
-
-stop(Name) ->
- diameter:stop_service(Name).
-
-%% ---------------------------------------------------------------------------
-%% Internal functions
-%% ---------------------------------------------------------------------------
-
-%% server_opts/1
-%%
-%% Return transport options for a listening transport.
-
-server_opts({T, Addr, Port}) ->
- [{transport_module, tmod(T)},
- {transport_config, [{reuseaddr, true},
- {sender, true},
- {message_cb, [fun ?MODULE:message/3, 0]},
- {ip, addr(Addr)},
- {port, Port}]}];
-
-server_opts(T) ->
- server_opts({T, loopback, ?DEFAULT_PORT}).
-
-%% client_opts/1
-%%
-%% Return transport options for a connecting transport.
-
-client_opts({T, LA, RA, RP})
- when T == all; %% backwards compatibility
- T == any ->
- [[S, {C,Os}], T] = [client_opts({P, LA, RA, RP}) || P <- [sctp,tcp]],
- [S, {C,Os,2000} | T];
-
-client_opts({T, LA, RA, RP}) ->
- [{transport_module, tmod(T)},
- {transport_config, [{raddr, addr(RA)},
- {rport, RP},
- {reuseaddr, true}
- | ip(LA)]}];
-
-client_opts({T, RA, RP}) ->
- client_opts({T, default, RA, RP});
-
-client_opts(T) ->
- client_opts({T, loopback, loopback, ?DEFAULT_PORT}).
-
-%% ---------------------------------------------------------------------------
-
-tmod(tcp) -> diameter_tcp;
-tmod(sctp) -> diameter_sctp.
-
-ip(default) ->
- [];
-ip(loopback) ->
- [{ip, {127,0,0,1}}];
-ip(Addr) ->
- [{ip, Addr}].
-
-addr(loopback) ->
- {127,0,0,1};
-addr(A) ->
- A.
-
-%% ---------------------------------------------------------------------------
-
-%% message/3
-%%
-%% Simple message callback that limits the number of concurrent
-%% requests on the peer connection in question.
-
-%% Incoming request.
-message(recv, <<_:32, 1:1, _/bits>> = Bin, N) ->
- [Bin, N < 32, fun ?MODULE:message/3, N+1];
-
-%% Outgoing request.
-message(ack, <<_:32, 1:1, _/bits>>, _) ->
- [];
-
-%% Incoming answer or request discarded.
-message(ack, _, N) ->
- [N =< 32, fun ?MODULE:message/3, N-1];
-
-%% Outgoing message or incoming answer.
-message(_, Bin, _) ->
- [Bin].
diff --git a/lib/diameter/examples/code/redirect.erl b/lib/diameter/examples/code/redirect.erl
index 6934e54507..1f9749ba84 100644
--- a/lib/diameter/examples/code/redirect.erl
+++ b/lib/diameter/examples/code/redirect.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -20,52 +20,80 @@
-module(redirect).
--include_lib("diameter/include/diameter.hrl").
--include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
+%%
+%% An example Diameter redirect agent.
+%%
+%% Simplest usage to listen on TCP at 127.0.0.1:3868.
+%%
+%% redirect:start().
+%% redirect:listen(tcp).
+%%
+%% Interface.
-export([start/1,
listen/2,
stop/1]).
+%% Convenience functions using the default service name.
-export([start/0,
listen/1,
stop/0]).
--define(APP_ALIAS, ?MODULE).
--define(SVC_NAME, ?MODULE).
--define(CALLBACK_MOD, redirect_mod).
+-define(DEF_SVC_NAME, ?MODULE).
%% The service configuration.
-define(SERVICE(Name), [{'Origin-Host', atom_to_list(Name) ++ ".example.com"},
{'Origin-Realm', "example.com"},
{'Vendor-Id', 193},
{'Product-Name', "RedirectAgent"},
- {'Auth-Application-Id', [?DIAMETER_APP_ID_RELAY]},
- {application, [{alias, ?APP_ALIAS},
- {dictionary, ?DIAMETER_DICT_RELAY},
- {module, ?CALLBACK_MOD}]}]).
+ {'Auth-Application-Id', [16#FFFFFFFF]},
+ {decode_format, map},
+ {restrict_connections, false},
+ {strict_mbit, false},
+ {string_decode, false},
+ {application, [{alias, redirect},
+ {dictionary, diameter_gen_relay},
+ {module, redirect_cb},
+ {call_mutates_state, false}]}]).
+
+%% start/0
+
+start() ->
+ start(?DEF_SVC_NAME).
%% start/1
start(Name)
when is_atom(Name) ->
- peer:start(Name, ?SERVICE(Name)).
+ start(Name, []);
-start() ->
- start(?SVC_NAME).
+start(Opts)
+ when is_list(Opts) ->
+ start(?DEF_SVC_NAME, Opts).
+
+%% start/2
+
+start(Name, Opts) ->
+ Defaults = [T || {K,_} = T <- ?SERVICE(Name),
+ not lists:keymember(K, 1, Opts)],
+ diameter:start_service(Name, Opts ++ Defaults).
%% listen/2
-listen(Name, T) ->
- peer:listen(Name, T).
+listen(Name, Opts) ->
+ server:listen(Name, Opts).
+
+%% listen/1
-listen(T) ->
- listen(?SVC_NAME, T).
+listen(Opts) ->
+ listen(?DEF_SVC_NAME, Opts).
%% stop/1
stop(Name) ->
- peer:stop(Name).
+ diameter:stop_service(Name).
+
+%% stop.0
stop() ->
- stop(?SVC_NAME).
+ stop(?DEF_SVC_NAME).
diff --git a/lib/diameter/examples/code/redirect_cb.erl b/lib/diameter/examples/code/redirect_cb.erl
index 8325e86391..76ab091be3 100644
--- a/lib/diameter/examples/code/redirect_cb.erl
+++ b/lib/diameter/examples/code/redirect_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
-module(redirect_cb).
-include_lib("diameter/include/diameter.hrl").
--include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
%% diameter callbacks
-export([peer_up/3,
@@ -33,30 +32,71 @@
handle_error/4,
handle_request/3]).
--define(UNEXPECTED, erlang:error({unexpected, ?MODULE, ?LINE})).
+%% Dictionary to encode answer-message AVPs with.
+-define(Dict, diameter_gen_base_rfc6733).
+
+%% Raise an error on callbacks that aren't expected.
+-define(ERROR, error({unexpected, ?MODULE, ?LINE})).
+
+%% peer_up/3
peer_up(_SvcName, _Peer, State) ->
State.
+%% peer_down/3
+
peer_down(_SvcName, _Peer, State) ->
State.
+%% pick_peer/4
+
pick_peer(_, _, _SvcName, _State) ->
- ?UNEXPECTED.
+ false.
+
+%% prepare_request/3
prepare_request(_, _SvcName, _Peer) ->
- ?UNEXPECTED.
+ ?ERROR.
+
+%% prepare_retransmit/3
prepare_retransmit(_Packet, _SvcName, _Peer) ->
- ?UNEXPECTED.
+ ?ERROR.
+
+%% handle_answer/4
handle_answer(_Packet, _Request, _SvcName, _Peer) ->
- ?UNEXPECTED.
+ ?ERROR.
+
+%% handle_error/4
handle_error(_Reason, _Request, _SvcName, _Peer) ->
- ?UNEXPECTED.
+ ?ERROR.
+
+%% handle_request/3
-handle_request(#diameter_packet{msg = _, errors = []}, _SvcName, {_, Caps}) ->
- #diameter_caps{}
+handle_request(#diameter_packet{avps = Avps}, _, {_, Caps}) ->
+ #diameter_caps{origin_host = {OH, _},
+ origin_realm = {OR, _}}
= Caps,
- discard. %% TODO
+
+ Tail = [#diameter_avp{data = {?Dict, A, V}}
+ || {A,V} <- [{'Origin-Host', OH},
+ {'Origin-Realm', OR},
+ {'Result-Code', 3006}, %% DIAMETER_REDIRECT_INDICATION
+ {'Redirect-Host', <<"aaa://server.example.com:3868">>}]],
+
+ {reply, ['answer-message' | lists:append([session(Avps), Tail])]}.
+
+%% ===========================================================================
+
+%% session/1
+
+session(Avps) ->
+ try
+ [] = [A || #diameter_avp{code = 263, vendor_id = undefined} = A
+ <- Avps,
+ throw(A)]
+ catch
+ Avp -> [Avp]
+ end.
diff --git a/lib/diameter/examples/code/relay.erl b/lib/diameter/examples/code/relay.erl
index 806f79915b..ec53ac01f1 100644
--- a/lib/diameter/examples/code/relay.erl
+++ b/lib/diameter/examples/code/relay.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,81 +18,94 @@
%% %CopyrightEnd%
%%
+-module(relay).
+
%%
%% An example Diameter relay agent.
%%
-%% Usage to connect to a server listening on the default port over TCP
-%% and to listen on the default port over SCTP is as follows, assuming
-%% diameter is already started (eg. diameter:start()).
+%% Simplets usage to connect to a server listening on TCP at
+%% 127.0.0.1:3868 and listen for connections on TCP at the same
+%% endpoint:
%%
-%% Eg. relay:start().
-%% relay:connect(tcp).
-%% relay:listen(sctp).
+%% relay:start().
+%% relay:connect(tcp).
+%% relay:listen(sctp).
%%
--module(relay).
-
+%% Interface.
-export([start/1,
start/2,
listen/2,
connect/2,
stop/1]).
+%% Convenience functions using the default service name.
-export([start/0,
listen/1,
connect/1,
stop/0]).
+%% Default service name.
-define(DEF_SVC_NAME, ?MODULE).
-%% The service configuration.
+%% Service configuration.
-define(SERVICE(Name), [{'Origin-Host', atom_to_list(Name) ++ ".example.com"},
{'Origin-Realm', "example.com"},
{'Vendor-Id', 193},
{'Product-Name', "RelayAgent"},
{'Auth-Application-Id', [16#FFFFFFFF]},
+ {decode_format, map},
+ {restrict_connections, false},
{string_decode, false},
+ {strict_mbit, false},
{application, [{alias, relay},
{dictionary, diameter_gen_relay},
- {module, relay_cb}]}]).
+ {module, relay_cb},
+ {call_mutates_state, false}]}]).
-%% start/1
+%% start/2
-start(Name)
- when is_atom(Name) ->
- start(Name, []).
+start(Name, Opts) ->
+ Defaults = [T || {K,_} = T <- ?SERVICE(Name),
+ not lists:keymember(K, 1, Opts)],
+ diameter:start_service(Name, Opts ++ Defaults).
%% start/1
-start() ->
- start(?DEF_SVC_NAME).
+start(Opts) ->
+ start(?DEF_SVC_NAME, Opts).
-%% start/2
+%% start/0
-start(Name, Opts) ->
- node:start(Name, Opts ++ [T || {K,_} = T <- ?SERVICE(Name),
- false == lists:keymember(K, 1, Opts)]).
+start() ->
+ start(?DEF_SVC_NAME, []).
%% listen/2
-listen(Name, T) ->
- node:listen(Name, T).
+listen(Name, Opts) ->
+ server:listen(Name, Opts).
-listen(T) ->
- listen(?DEF_SVC_NAME, T).
+%% listen/1
+
+listen(Opts) ->
+ listen(?DEF_SVC_NAME, Opts).
%% connect/2
-connect(Name, T) ->
- node:connect(Name, T).
+connect(Name, Opts) ->
+ client:connect(Name, Opts).
+
+%% connect/1
-connect(T) ->
- connect(?DEF_SVC_NAME, T).
+connect(Opts) ->
+ connect(?DEF_SVC_NAME, Opts).
%% stop/1
stop(Name) ->
- node:stop(Name).
+ diameter:stop_service(Name).
+
+%% stop/0
stop() ->
stop(?DEF_SVC_NAME).
diff --git a/lib/diameter/examples/code/relay_cb.erl b/lib/diameter/examples/code/relay_cb.erl
index 6df1738143..0d56a14401 100644
--- a/lib/diameter/examples/code/relay_cb.erl
+++ b/lib/diameter/examples/code/relay_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -21,48 +21,59 @@
-module(relay_cb).
-include_lib("diameter/include/diameter.hrl").
--include_lib("diameter/include/diameter_gen_base_rfc3588.hrl").
%% diameter callbacks
-export([peer_up/3,
peer_down/3,
- pick_peer/5,
- prepare_request/4,
- prepare_retransmit/4,
- handle_answer/5,
- handle_error/5,
+ pick_peer/4,
+ prepare_request/3,
+ prepare_retransmit/3,
+ handle_answer/4,
+ handle_error/4,
handle_request/3]).
+%% peer_up/3
+
peer_up(_SvcName, _Peer, State) ->
State.
+%% peer_down/3
+
peer_down(_SvcName, _Peer, State) ->
State.
-%% Returning 'relay' from handle_request causes diameter to resend the
-%% incoming request, which leads to pick_peer and prepare_request
-%% callbacks as if sending explicitly. The 'extra' argument is
-%% appended to the argument list for callbacks following from
-%% resending of the request.
+%% handle_request/3
+
+%% Assume the destination is directly connected; filter
+%% correspondingly; don't relay to the sender.
+handle_request(_Pkt, _SvcName, {_, Caps}) ->
+ #diameter_caps{origin_host = {_, OH}}
+ = Caps,
+ {relay, [{timeout, 2000},
+ {filter, {all, [host, realm, {neg, {host, OH}}]}}]}.
-handle_request(_Pkt, _SvcName, _Peer) ->
- {relay, [{timeout, 1000}, {extra, [relayed]}]}.
+%% pick_peer/4
-%% diameter will filter the sender in the Peers list.
-pick_peer([Peer | _], _, _SvcName, _State, relayed) ->
+pick_peer([Peer | _], _, _SvcName, _State) ->
{ok, Peer}.
-prepare_request(Pkt, _SvcName, _Peer, relayed) ->
+%% prepare_request/3
+
+prepare_request(Pkt, _SvcName, _Peer) ->
{send, Pkt}.
-prepare_retransmit(Pkt, _SvcName, _Peer, relayed) ->
+%% prepare_request/3
+
+prepare_retransmit(Pkt, _SvcName, _Peer) ->
{send, Pkt}.
-%% diameter expects handle_answer to return the diameter_packet record
-%% containing the answer when called for a relayed request.
+%% handle_answer/4
-handle_answer(Pkt, _Request, _SvcName, _Peer, relayed) ->
+%% Relay an answer by returning the first argument.
+handle_answer(Pkt, _Request, _SvcName, _Peer) ->
Pkt.
-handle_error(Reason, _Request, _SvcName, _Peer, relayed) ->
+%% handle_error/4
+
+handle_error(Reason, _Request, _SvcName, _Peer) ->
{error, Reason}.
diff --git a/lib/diameter/examples/code/server.erl b/lib/diameter/examples/code/server.erl
index a91be70664..6ee49fb678 100644
--- a/lib/diameter/examples/code/server.erl
+++ b/lib/diameter/examples/code/server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,23 +18,20 @@
%% %CopyrightEnd%
%%
+-module(server).
+
%%
-%% An example Diameter server that can respond to the base protocol
-%% RAR sent by the client example.
+%% An example Diameter server that answers the base protocol ACR sent
+%% by the client example.
%%
-%% The simplest example to start a server listening on the loopback
-%% address (which will serve the example usage given in client.erl) is
-%% like this assuming diameter is already started (eg. diameter:start()):
+%% Simplest usage to listen on TCP at 127.0.0.1:3868:
%%
%% server:start().
%% server:listen(tcp).
%%
-%% The first call starts a service, the second adds a transport listening
-%% on the default port.
-%%
--module(server).
+%% Interface.
-export([start/1, %% start a service
start/2, %%
listen/2, %% add a listening transport
@@ -45,6 +42,9 @@
listen/1,
stop/0]).
+%% Internal callback.
+-export([message/3]).
+
-define(DEF_SVC_NAME, ?MODULE).
%% The service configuration. In a server supporting multiple Diameter
@@ -55,45 +55,110 @@
{'Vendor-Id', 193},
{'Product-Name', "Server"},
{'Auth-Application-Id', [0]},
+ {decode_format, map},
{restrict_connections, false},
+ {strict_mbit, false},
{string_decode, false},
{application, [{alias, common},
{dictionary, diameter_gen_base_rfc6733},
- {module, server_cb}]}]).
+ {module, server_cb},
+ {call_mutates_state, false}]}]).
-%% start/1
+%% start/2
-start(Name)
- when is_atom(Name) ->
- start(Name, []);
+start(Name, Opts) ->
+ Defaults = [T || {K,_} = T <- ?SERVICE(Name),
+ not lists:keymember(K, 1, Opts)],
+ diameter:start_service(Name, Opts ++ Defaults).
-start(Opts)
- when is_list(Opts) ->
+%% start/1
+
+start(Opts) ->
start(?DEF_SVC_NAME, Opts).
%% start/0
start() ->
- start(?DEF_SVC_NAME).
-
-%% start/2
-
-start(Name, Opts) ->
- node:start(Name, Opts ++ [T || {K,_} = T <- ?SERVICE(Name),
- false == lists:keymember(K, 1, Opts)]).
+ start(?DEF_SVC_NAME, []).
%% listen/2
+listen(Name, Opts)
+ when is_list(Opts) ->
+ diameter:add_transport(Name, {listen, lists:flatmap(fun opts/1, Opts)});
+
+%% backwards compatibility with old config
+listen(Name, {T, Opts}) ->
+ listen(Name, [T | Opts]);
listen(Name, T) ->
- node:listen(Name, T).
+ listen(Name, [T]).
-listen(T) ->
- listen(?DEF_SVC_NAME, T).
+%% listen/1
+
+listen(Opts) ->
+ listen(?DEF_SVC_NAME, Opts).
%% stop/1
stop(Name) ->
- node:stop(Name).
+ diameter:stop_service(Name).
+
+%% stop/0
stop() ->
stop(?DEF_SVC_NAME).
+
+%% ===========================================================================
+
+%% opts/1
+%%
+%% Map a 3-tuple a transport_module/transport_config pair as a
+%% convenience, pass everything else unmodified.
+
+opts(T)
+ when T == tcp;
+ T == sctp ->
+ opts({T, loopback, default});
+
+opts({tcp, Addr, Port}) ->
+ opts({diameter_tcp, Addr, Port});
+
+opts({sctp, Addr, Port}) ->
+ opts({diameter_sctp, Addr, Port});
+
+opts({Mod, loopback, Port}) ->
+ opts({Mod, {127,0,0,1}, Port});
+
+opts({Mod, Addr, default}) ->
+ opts({Mod, Addr, 3868});
+
+opts({Mod, Addr, Port}) ->
+ [{transport_module, Mod},
+ {transport_config, [{reuseaddr, true},
+ {sender, true},
+ {message_cb, {?MODULE, message, [0]}},
+ {ip, Addr},
+ {port, Port}]}];
+opts(T) ->
+ [T].
+
+%% message/3
+%%
+%% Simple message callback that limits the number of concurrent
+%% requests on the peer connection in question.
+
+%% Incoming request.
+message(recv, <<_:32, 1:1, _/bits>> = Bin, N) ->
+ [Bin, N < 32, {?MODULE, message, [N+1]}];
+
+%% Outgoing request.
+message(ack, <<_:32, 1:1, _/bits>>, _) ->
+ [];
+
+%% Incoming answer or request discarded.
+message(ack, _, N) ->
+ [N =< 32, {?MODULE, message, [N-1]}];
+
+%% Outgoing message or incoming answer.
+message(_, Bin, _) ->
+ [Bin].
diff --git a/lib/diameter/examples/code/server_cb.erl b/lib/diameter/examples/code/server_cb.erl
index a2fb8fbda6..5662717c00 100644
--- a/lib/diameter/examples/code/server_cb.erl
+++ b/lib/diameter/examples/code/server_cb.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2015. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -25,7 +25,6 @@
-module(server_cb).
-include_lib("diameter/include/diameter.hrl").
--include_lib("diameter/include/diameter_gen_base_rfc6733.hrl").
%% diameter callbacks
-export([peer_up/3,
@@ -37,67 +36,87 @@
handle_error/4,
handle_request/3]).
--define(UNEXPECTED, erlang:error({unexpected, ?MODULE, ?LINE})).
+%% Raise an error on callbacks that aren't expected.
+-define(ERROR, error({unexpected, ?MODULE, ?LINE})).
+
+%% peer_up/3
peer_up(_SvcName, _Peer, State) ->
State.
+%% peer_down/3
+
peer_down(_SvcName, _Peer, State) ->
State.
-pick_peer(_, _, _SvcName, _State) ->
- ?UNEXPECTED.
+%% pick_peer/3
+
+%% Don't let requests be sent, so other request callbacks shouldn't
+%% happen.
+pick_peer(_LocalCandidates, _RemoteCandidates, _SvcName, _State) ->
+ false.
+
+%% prepare_request/3
-prepare_request(_, _SvcName, _Peer) ->
- ?UNEXPECTED.
+prepare_request(_Packet, _SvcName, _Peer) ->
+ ?ERROR.
+
+%% prepare_retransmit/3
prepare_retransmit(_Packet, _SvcName, _Peer) ->
- ?UNEXPECTED.
+ ?ERROR.
+
+%% handle_answer/4
handle_answer(_Packet, _Request, _SvcName, _Peer) ->
- ?UNEXPECTED.
+ ?ERROR.
+
+%% handle_error/4
handle_error(_Reason, _Request, _SvcName, _Peer) ->
- ?UNEXPECTED.
+ ?ERROR.
+
+%% handle_request/3
-%% A request whose decode was successful ...
-handle_request(#diameter_packet{msg = Req, errors = []}, _SvcName, {_, Caps})
- when is_record(Req, diameter_base_RAR) ->
+%% ACR without decode errors.
+handle_request(#diameter_packet{msg = ['ACR' | #{} = Request],
+ errors = []},
+ _SvcName,
+ {_, Caps}) ->
#diameter_caps{origin_host = {OH,_},
origin_realm = {OR,_}}
= Caps,
- #diameter_base_RAR{'Session-Id' = Id,
- 'Re-Auth-Request-Type' = Type}
- = Req,
-
- {reply, #diameter_base_RAA{'Result-Code' = rc(Type),
- 'Origin-Host' = OH,
- 'Origin-Realm' = OR,
- 'Session-Id' = Id}};
-
-%% ... or one that wasn't. 3xxx errors are answered by diameter itself
-%% but these are 5xxx errors for which we must contruct a reply.
-%% diameter will set Result-Code and Failed-AVP's.
-handle_request(#diameter_packet{msg = Req}, _SvcName, {_, Caps})
- when is_record(Req, diameter_base_RAR) ->
+
+ #{'Session-Id' := Sid,
+ 'Accounting-Record-Type' := T,
+ 'Accounting-Record-Number' := N}
+ = Request,
+
+ Answer = #{'Result-Code' => 2001, %% DIAMETER_SUCCESS
+ 'Origin-Host' => OH,
+ 'Origin-Realm' => OR,
+ 'Session-Id' => Sid,
+ 'Accounting-Record-Type' => T,
+ 'Accounting-Record-Number' => N},
+
+ {reply, ['ACA' | Answer]};
+
+%% ACR with decode errors.
+handle_request(#diameter_packet{msg = ['ACR' | #{} = Request]},
+ _SvcName,
+ {_, Caps}) ->
#diameter_caps{origin_host = {OH,_},
origin_realm = {OR,_}}
= Caps,
- #diameter_base_RAR{'Session-Id' = Id}
- = Req,
- {reply, #diameter_base_RAA{'Origin-Host' = OH,
- 'Origin-Realm' = OR,
- 'Session-Id' = Id}};
+ Answer = maps:merge(maps:with(['Session-Id'], Request),
+ #{'Origin-Host' => OH,
+ 'Origin-Realm' => OR}),
-%% Answer that any other message is unsupported.
+ %% Let diameter set Result-Code and Failed-AVP if there were
+ %% decode errors.
+ {reply, ['answer-message' | Answer]};
+
+%% Answer anything else as unsupported.
handle_request(#diameter_packet{}, _SvcName, _) ->
{answer_message, 3001}. %% DIAMETER_COMMAND_UNSUPPORTED
-
-%% Map Re-Auth-Request-Type to Result-Code just for the purpose of
-%% generating different answers.
-
-rc(0) ->
- 2001; %% DIAMETER_SUCCESS
-rc(_) ->
- 5012. %% DIAMETER_UNABLE_TO_COMPLY
diff --git a/lib/diameter/src/Makefile b/lib/diameter/src/Makefile
index 98636ed6e2..d6854cfd27 100644
--- a/lib/diameter/src/Makefile
+++ b/lib/diameter/src/Makefile
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2018. All Rights Reserved.
+# Copyright Ericsson AB 2010-2020. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -210,12 +210,16 @@ realclean: clean
PLT = ./otp.plt
-plt:
+plt: $(PLT)
+
+$(PLT):
dialyzer --build_plt \
--apps erts stdlib kernel \
xmerl ssl public_key crypto \
compiler syntax_tools runtime_tools \
- --output_plt $(PLT) \
+ --output_plt $@ \
+ --get_warnings \
+ --statistics \
--verbose
dialyze: opt $(PLT)
@@ -224,9 +228,12 @@ dialyze: opt $(PLT)
-Wno_improper_lists \
$(EBIN)/diameter_gen_base_rfc3588.$(EMULATOR) \
$(patsubst %, $(EBIN)/%.$(EMULATOR), \
- $(notdir $(RT_MODULES) $(CT_MODULES) $(INFO_MODULES)))
+ $(notdir $(DICT_YRL) \
+ $(RT_MODULES) \
+ $(CT_MODULES) \
+ $(INFO_MODULES)))
# Omit all but the common dictionary module since these
-# (diameter_gen_relay in particular) generate warning depending on how
+# (diameter_gen_relay in particular) generate warnings depending on how
# much of the included diameter_gen.hrl they use.
# ----------------------------------------------------
diff --git a/lib/diameter/src/base/diameter.erl b/lib/diameter/src/base/diameter.erl
index 7f172e1fa1..2982486a10 100644
--- a/lib/diameter/src/base/diameter.erl
+++ b/lib/diameter/src/base/diameter.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -146,8 +146,9 @@ services() ->
%% service_info/2
%% ---------------------------------------------------------------------------
--spec service_info(service_name(), atom() | [atom()])
- -> any().
+-spec service_info(service_name(), Item | [Item])
+ -> any()
+ when Item :: atom() | peer_ref().
service_info(SvcName, Option) ->
diameter_service:info(SvcName, Option).
@@ -351,45 +352,45 @@ call(SvcName, App, Message) ->
%% Options common to both start_service/2 and add_transport/2.
-type common_opt()
- :: {pool_size, pos_integer()}
+ :: {avp_dictionaries, [module()]}
| {capabilities_cb, eval()}
| {capx_timeout, 'Unsigned32'()}
- | {strict_capx, boolean()}
- | {strict_mbit, boolean()}
- | {avp_dictionaries, [module()]}
+ | {connect_timer, 'Unsigned32'()}
| {disconnect_cb, eval()}
- | {dpr_timeout, 'Unsigned32'()}
| {dpa_timeout, 'Unsigned32'()}
+ | {dpr_timeout, 'Unsigned32'()}
| {incoming_maxlen, message_length()}
| {length_errors, exit | handle | discard}
- | {connect_timer, 'Unsigned32'()}
- | {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}}
+ | {pool_size, pos_integer()}
+ | {spawn_opt, list() | mfa()}
+ | {strict_capx, boolean()}
+ | {strict_mbit, boolean()}
| {watchdog_config, [{okay|suspect, non_neg_integer()}]}
- | {spawn_opt, list() | mfa()}.
+ | {watchdog_timer, 'Unsigned32'() | {module(), atom(), list()}}.
%% Options passed to start_service/2
-type service_opt()
:: capability()
| {application, [application_opt()]}
+ | {decode_format, decode_format()}
| {restrict_connections, restriction()}
| {sequence, sequence() | eval()}
| {share_peers, remotes()}
- | {decode_format, decode_format()}
- | {traffic_counters, boolean()}
- | {string_decode, boolean()}
| {strict_arities, true | strict_arities()}
+ | {string_decode, boolean()}
+ | {traffic_counters, boolean()}
| {use_shared_peers, remotes()}
| common_opt().
-type application_opt()
:: {alias, app_alias()}
+ | {answer_errors, callback|report|discard}
+ | {call_mutates_state, boolean()}
| {dictionary, module()}
| {module, app_module()}
- | {state, any()}
- | {call_mutates_state, boolean()}
- | {answer_errors, callback|report|discard}
- | {request_errors, answer_3xxx|answer|callback}.
+ | {request_errors, answer_3xxx|answer|callback}
+ | {state, any()}.
-type app_alias()
:: any().
@@ -407,11 +408,11 @@ call(SvcName, App, Message) ->
%% Options passed to add_transport/2
-type transport_opt()
- :: {transport_module, atom()}
+ :: {applications, [app_alias()]}
+ | {capabilities, [capability()]}
| {transport_config, any()}
| {transport_config, any(), 'Unsigned32'() | infinity}
- | {applications, [app_alias()]}
- | {capabilities, [capability()]}
+ | {transport_module, atom()}
| common_opt()
| {private, any()}.
@@ -430,8 +431,8 @@ call(SvcName, App, Message) ->
%% Options passed to call/4
-type call_opt()
- :: {extra, list()}
+ :: detach
+ | {extra, list()}
| {filter, peer_filter()}
- | {timeout, 'Unsigned32'()}
| {peer, peer_ref()}
- | detach.
+ | {timeout, 'Unsigned32'()}.
diff --git a/lib/diameter/src/base/diameter_codec.erl b/lib/diameter/src/base/diameter_codec.erl
index 493a6ab1e3..7f6baf666a 100644
--- a/lib/diameter/src/base/diameter_codec.erl
+++ b/lib/diameter/src/base/diameter_codec.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -208,7 +208,7 @@ values(Avps) ->
encode_avps(_, _, [#diameter_avp{} | _] = Avps, Opts) ->
encode_avps(Avps, Opts);
-%% ... or as a tuple list or record.
+%% ... or as a tuple list, map, or record.
encode_avps(Mod, MsgName, Values, Opts) ->
Mod:encode_avps(MsgName, Values, Opts).
diff --git a/lib/diameter/src/base/diameter_config.erl b/lib/diameter/src/base/diameter_config.erl
index 36ae4c2276..495e57e456 100644
--- a/lib/diameter/src/base/diameter_config.erl
+++ b/lib/diameter/src/base/diameter_config.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -661,6 +661,9 @@ opt(transport, {transport_module, M}) ->
opt(transport, {transport_config, _, Tmo}) ->
?IS_UINT32(Tmo) orelse Tmo == infinity;
+opt(transport, {transport_config, _}) ->
+ true;
+
opt(transport, {applications, As}) ->
is_list(As);
@@ -720,15 +723,16 @@ opt(_, {K, _})
when K == disconnect_cb;
K == capabilities_cb ->
true;
-opt(transport, {K, _})
- when K == transport_config;
- K == private ->
+opt(transport, {private, _}) ->
true;
-%% Anything else, which is ignored in transport config. This makes
-%% options sensitive to spelling mistakes, but arbitrary options are
-%% passed by some users as a way to identify transports so can't just
-%% do away with it.
+%% Anything else is ignored in transport config. This makes options
+%% sensitive to spelling mistakes and unintentionally passing service
+%% options, but arbitrary options are passed by some users as a way to
+%% identify transports (they can be returned by diameter:service_info/2
+%% for example) so can't just do away with it, although silently
+%% swallowing service options is at least debatable. The documentation
+%% says anything, so accept anything.
opt(K, _) ->
K == transport.
diff --git a/lib/diameter/src/base/diameter_dist.erl b/lib/diameter/src/base/diameter_dist.erl
index ed23152b8b..1edca58eb9 100644
--- a/lib/diameter/src/base/diameter_dist.erl
+++ b/lib/diameter/src/base/diameter_dist.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2019. All Rights Reserved.
+%% Copyright Ericsson AB 2019-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,21 @@
%% transport configuration, to be able to distribute incoming Diameter
%% requests to handler processes (local or remote) in various ways.
%%
+%% The gen_server implemented here must be started on each node on
+%% which {diameter_dist, route_session, _} is configured as a
+%% spawn_opt MFA, as well as each node that wants to receive requests.
+%% This happens as a consequence of diameter application start, but a
+%% minimal solution could start only this server on nodes that should
+%% handle requests but not configure transport. (Although the typical
+%% case is probably that diameter should be started in any case; for
+%% example, to be able to originate requests.)
+%%
+%% Moreover, attach/1 must be called to communicate the list of
+%% services for which the local node is willing to handle requests.
+%% The servers on different nodes communicate so that each server
+%% knows which nodes are prepared to handle requests for which
+%% services.
+%%
%% spawn_opt callbacks
-export([spawn_local/2,
diff --git a/lib/diameter/src/base/diameter_peer_fsm.erl b/lib/diameter/src/base/diameter_peer_fsm.erl
index cf5e7f21d3..b86dcaf923 100644
--- a/lib/diameter/src/base/diameter_peer_fsm.erl
+++ b/lib/diameter/src/base/diameter_peer_fsm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
diff --git a/lib/diameter/src/base/diameter_service.erl b/lib/diameter/src/base/diameter_service.erl
index 77d184cfc7..520a7233cc 100644
--- a/lib/diameter/src/base/diameter_service.erl
+++ b/lib/diameter/src/base/diameter_service.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -735,29 +735,31 @@ init_peers() ->
%% Alias,
%% TPid}
+%% Valid service options are all 2-tuples.
service_opts(Opts) ->
- remove([{strict_arities, true},
- {avp_dictionaries, []}],
- maps:merge(maps:from_list([{monitor, false} | def_opts()]),
- maps:from_list(Opts))).
+ remove([{strict_arities, true}, {avp_dictionaries, []}],
+ merge(lists:append([[{monitor, false}] | def_opts()]), Opts)).
+
+merge(List1, List2) ->
+ maps:merge(maps:from_list(List1), maps:from_list(List2)).
remove(List, Map) ->
maps:filter(fun(K,V) -> not lists:member({K,V}, List) end,
Map).
-def_opts() -> %% defaults on the service map
- [{share_peers, false},
- {use_shared_peers, false},
- {sequence, {0,32}},
- {restrict_connections, nodes},
- {incoming_maxlen, 16#FFFFFF},
- {strict_arities, true},
- {strict_mbit, true},
- {decode_format, record},
- {avp_dictionaries, []},
- {traffic_counters, true},
- {string_decode, true},
- {spawn_opt, []}].
+def_opts() -> %% defaults on the options map
+ [[{decode_format, record}, %% service options
+ {restrict_connections, nodes},
+ {sequence, {0,32}},
+ {share_peers, false},
+ {strict_arities, true},
+ {string_decode, true},
+ {traffic_counters, true},
+ {use_shared_peers, false}],
+ [{avp_dictionaries, []}, %% common options
+ {incoming_maxlen, 16#FFFFFF},
+ {spawn_opt, []},
+ {strict_mbit, true}]].
mref(false = No) ->
No;
@@ -875,27 +877,46 @@ start(Ref, Type, Opts, N, #state{watchdogT = WatchdogT,
= Svc1
= merge_service(Opts, Svc0),
Svc = binary_caps(Svc1, SD),
- {SOpts, TOpts} = merge_opts(SvcOpts, Opts),
- RecvData = diameter_traffic:make_recvdata([SvcName, PeerT, Apps, SOpts]),
- T = {TOpts, SOpts, RecvData, Svc},
+ {Map, Rest} = merge_opts(SvcOpts, Opts),
+ RecvData = diameter_traffic:make_recvdata([SvcName, PeerT, Apps, Map]),
+ T = {Rest, Map, RecvData, Svc},
Rec = #watchdog{type = Type,
ref = Ref,
- options = TOpts},
-
+ options = Opts}, %% original options, returned
+ %% by service_info/2
diameter_lib:fold_n(fun(_,A) ->
[wd(Type, Ref, T, WatchdogT, Rec) | A]
end,
[],
N).
-merge_opts(SvcOpts, Opts) ->
- Keys = [K || {K,_} <- def_opts()],
- SO = [T || {K,_} = T <- Opts, lists:member(K, Keys)],
- TO = Opts -- SO,
- {maps:merge(maps:with(Keys, SvcOpts), maps:from_list(SO)),
- TO ++ [T || {K,_} = T <- maps:to_list(SvcOpts),
- not lists:member(K, Keys),
- not lists:keymember(K, 1, Opts)]}.
+%% This is awkward. We have service options that have been passed to
+%% diameter:start_service/2 (minus application and capabilities
+%% options, removed in diameter_config) and transport options passed
+%% to diameter:add_transport/2. The former can include defaults for
+%% the latter, but the latter can also contain arbitrary options that
+%% are just returned by diameter:service_info/2. There's nothing
+%% stopping these arbitrary options from being valid service options,
+%% but these aren't interpreted as such.
+%%
+%% The options are merged (transport defaults have already been merged
+%% into the service options in service_opts/1) and split into a map
+%% for the service options and a few transport options, and a list for
+%% the rest. This is historical convolution. Some options are are
+%% pulled out of the list on the way to starting the transport process
+%% in diameter_peer_fsm, but more work could probably be done here to
+%% simplify things.
+%%
+%% Transport options are not necessarily 2-tuples: the transport_config
+%% 3-tuple means they can't just be turned into a map.
+merge_opts(SOpts, TOpts) ->
+ [SD,TD] = Def = def_opts(),
+ Keys = [K || L <- Def, {K,_} <- L],
+ Opts = [T || {K,_} = T <- TOpts, lists:keymember(K, 1, TD)],
+ {maps:merge(maps:with(Keys, SOpts), maps:from_list(Opts)),%% merge TOpts
+ TOpts ++ [T || {K,_} = T <- maps:to_list(SOpts), %% append SOpts
+ not lists:keymember(K, 1, SD),
+ [] == [A || {A,_} <- TOpts, A == K]]}.
binary_caps(Svc, true) ->
Svc;
diff --git a/lib/diameter/src/base/diameter_traffic.erl b/lib/diameter/src/base/diameter_traffic.erl
index 8423e30269..4667bbc3f2 100644
--- a/lib/diameter/src/base/diameter_traffic.erl
+++ b/lib/diameter/src/base/diameter_traffic.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -86,6 +86,7 @@
string_decode := boolean(),
strict_arities => diameter:strict_arities(),
strict_mbit := boolean(),
+ ordered_encode => boolean(),
incoming_maxlen := diameter:message_length()}}).
%% Note that incoming_maxlen is currently handled in diameter_peer_fsm,
%% so that any message exceeding the maximum is discarded. Retain the
@@ -284,12 +285,18 @@ recv(false, false, TPid, Pkt, _, _) ->
spawn_request(false, _, _, _, _, _, _) -> %% no transport
discard;
-%% An MFA should return the pid() of a process in which the argument
-%% fun in applied, or the atom 'discard' if the fun is not applied.
-%% The latter results in an acknowledgment back to the transport
-%% process when appropriate, to ensure that send/recv callbacks can
-%% count outstanding requests. Acknowledgement is implicit if the
-%% handler process dies (in a handle_request callback for example).
+%% An MFA should return the pid() of a process that invokes
+%% diameter_traffic:request(ReqT), or the atom 'discard' if the
+%% function is not called. The latter results in an acknowledgment
+%% back to the transport process when appropriate, to ensure that
+%% send/recv callbacks can count outstanding requests. Acknowledgement
+%% is implicit if the handler process dies (in a handle_request
+%% callback for example).
+%%
+%% There is no requirement that diameter be started on nodes on which
+%% handler processes are spawned, just that diameter and application
+%% callbacks are on the code path. (Although the MFA itself may have
+%% requirements, as in the case of diameter_dist.)
spawn_request(AppT, {M,F,A}, Ack, TPid, Pkt, Dict0, RecvData) ->
%% Term to pass to request/1 in an appropriate process. Module
%% diameter_dist implements callbacks.
@@ -520,7 +527,7 @@ request_cb(noreply, _App, EvalPktFs, EvalFs) ->
%% 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
-%% will be detected by examining Route-Record AVP's, (3) a
+%% will be detected by examining Route-Record AVP's, (2) a
%% Route-Record AVP will be added to the outgoing request and (3) the
%% End-to-End Identifier will default to that in the
%% #diameter_header{} without the need for an end_to_end_identifier
@@ -556,14 +563,7 @@ request_cb(T, App, _, _) ->
send_A({reply, Ans}, TPid, App, Dict0, RecvData, Pkt, _Caps, Fs) ->
AppDict = App#diameter_app.dictionary,
MsgDict = msg_dict(AppDict, Dict0, Ans),
- send_answer(Ans,
- TPid,
- MsgDict,
- AppDict,
- Dict0,
- RecvData,
- Pkt,
- Fs);
+ send_answer(Ans, TPid, MsgDict, AppDict, Dict0, RecvData, Pkt, Fs);
send_A({call, Opts}, TPid, App, Dict0, RecvData, Pkt, Caps, Fs) ->
AppDict = App#diameter_app.dictionary,
@@ -667,7 +667,7 @@ is_answer_message(#diameter_packet{msg = Msg}, Dict0) ->
is_answer_message([#diameter_header{is_request = R, is_error = E} | _], _) ->
E andalso not R;
-%% Message sent as a map or tagged avp/value list.
+%% Message sent as a map or avp list.
is_answer_message([Name | _], _) ->
Name == 'answer-message';
@@ -1239,7 +1239,12 @@ is_result(RC, true, _) ->
%% incr/2
incr(TPid, Counter) ->
- diameter_stats:incr(Counter, TPid, 1).
+ Node = node(TPid),
+ if Node == node() ->
+ diameter_stats:incr(Counter, TPid, 1);
+ true ->
+ spawn(Node, diameter_stats, incr, [Counter, TPid, 1])
+ end.
%% rcc/1
@@ -1866,23 +1871,26 @@ z(#diameter_packet{header = H, bin = Bin, transport_data = T}) ->
transport_data = T}.
%% send/1
+%%
+%% Send from a remote node using a peer connection on this one. Pkt is
+%% already stripped.
send({TPid, Pkt, #request{handler = Pid} = Req0, SvcName, Timeout, TRef}) ->
Req = Req0#request{handler = self()},
- recv(TPid, Pid, TRef, zend_requezt(TPid, Pkt, Req, SvcName, Timeout)).
+ Pid ! recv(TPid, TRef, send_request(TPid, Pkt, Req, SvcName, Timeout)).
-%% recv/4
+%% recv/3
%%
%% Relay an answer from a remote node.
-recv(TPid, Pid, TRef, {LocalTRef, MRef}) ->
+recv(TPid, TRef, {LocalTRef, MRef}) ->
receive
{answer, _, _, _, _} = A ->
- Pid ! A;
+ A;
{'DOWN', MRef, process, _, _} ->
- Pid ! {failover, TRef};
+ {failover, TRef};
{failover = T, LocalTRef} ->
- Pid ! {T, TRef};
+ {T, TRef};
T ->
exit({timeout, LocalTRef, TPid} = T)
end.
diff --git a/lib/diameter/src/diameter.appup.src b/lib/diameter/src/diameter.appup.src
index bb2a4a8e92..627213637b 100644
--- a/lib/diameter/src/diameter.appup.src
+++ b/lib/diameter/src/diameter.appup.src
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -62,7 +62,15 @@
{"2.1.4.1", [{restart_application, diameter}]}, %% 20.3.8.19
{"2.1.5", [{restart_application, diameter}]}, %% 21.0
{"2.1.6", [{restart_application, diameter}]}, %% 21.1
- {"2.2", [{update, diameter_dist, {advanced, "2.2"}}]} %% 21.3
+ {"2.2", [{restart_application, diameter}]}, %% 21.3
+ {"2.2.1", [{load_module, diameter}, %% 21.3.5
+ {load_module, diameter_codec},
+ {update, diameter_config},
+ {update, diameter_dist},
+ {update, diameter_peer_fsm},
+ {update, diameter_service},
+ {load_module, diameter_traffic},
+ {update, diameter_tcp}]}
],
[
{"0.9", [{restart_application, diameter}]},
@@ -106,6 +114,14 @@
{"2.1.4.1", [{restart_application, diameter}]},
{"2.1.5", [{restart_application, diameter}]},
{"2.1.6", [{restart_application, diameter}]},
- {"2.2", [{restart_application, diameter}]}
+ {"2.2", [{restart_application, diameter}]},
+ {"2.2.1", [{load_module, diameter},
+ {load_module, diameter_codec},
+ {update, diameter_config},
+ {update, diameter_dist},
+ {update, diameter_peer_fsm},
+ {update, diameter_service},
+ {load_module, diameter_traffic},
+ {update, diameter_tcp}]}
]
}.
diff --git a/lib/diameter/src/modules.mk b/lib/diameter/src/modules.mk
index d16292bb88..cf938785e3 100644
--- a/lib/diameter/src/modules.mk
+++ b/lib/diameter/src/modules.mk
@@ -1,7 +1,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2010-2019. All Rights Reserved.
+# Copyright Ericsson AB 2010-2020. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -98,13 +98,14 @@ BINS = \
# Released files relative to ../examples.
EXAMPLES = \
code/GNUmakefile \
- code/node.erl \
code/client.erl \
code/client_cb.erl \
code/server.erl \
code/server_cb.erl \
code/relay.erl \
code/relay_cb.erl \
+ code/redirect.erl \
+ code/redirect_cb.erl \
dict/rfc4004_mip.dia \
dict/rfc4005_nas.dia \
dict/rfc4006_cc.dia \
diff --git a/lib/diameter/src/transport/diameter_tcp.erl b/lib/diameter/src/transport/diameter_tcp.erl
index e5e766d2a0..a051aeb156 100644
--- a/lib/diameter/src/transport/diameter_tcp.erl
+++ b/lib/diameter/src/transport/diameter_tcp.erl
@@ -569,7 +569,11 @@ m({'DOWN', M, process, P, _} = T, #monitor{parent = MRef,
%% l/2
%%
-%% Transition listener state.
+%% Transition listener state. Or not anymore since any message causes
+%% the process to exit.
+
+-spec l(tuple(), #listener{})
+ -> no_return().
%% Service process has died.
l({'DOWN', _, process, Pid, _} = T, #listener{service = Pid,
diff --git a/lib/diameter/test/diameter_dist_SUITE.erl b/lib/diameter/test/diameter_dist_SUITE.erl
index b2e4c35b9a..2fda2830ae 100644
--- a/lib/diameter/test/diameter_dist_SUITE.erl
+++ b/lib/diameter/test/diameter_dist_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2019. All Rights Reserved.
+%% Copyright Ericsson AB 2019-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -160,15 +160,32 @@ ping(Config) ->
%%
%% Start diameter services.
-start(SvcName)
- when is_atom(SvcName) ->
+%% There's no need to start diameter on a node that only services
+%% diameter_dist as a handler of incoming requests, but the
+%% diameter_dist server must be started since the servers communicate
+%% to determine who services what. The typical case is probably that
+%% handler nodes also want to be able to send Diameter requests, in
+%% which case the application needs to be started and diameter_dist is
+%% started as a part of this, but only start the server here to ensure
+%% everything still works as expected.
+start({_SvcName, [_, {S1, _}, {S2, _}, _]})
+ when node() == S1; %% server1
+ node() == S2 -> %% server2
+ Mod = diameter_dist,
+ {ok, _} = gen_server:start({local, Mod}, Mod, _Args = [], _Opts = []),
+ ok;
+
+start({SvcName, [{S0, _}, _, _, {C, _}]})
+ when node() == S0; %% server0
+ node() == C -> %% client
ok = diameter:start(),
ok = diameter:start_service(SvcName, ?SERVICE((?L(SvcName))));
-start(Config) ->
+start(Config)
+ when is_list(Config) ->
Nodes = ?util:read_priv(Config, nodes),
[] = [{N,RC} || {N,S} <- Nodes,
- RC <- [rpc:call(N, ?MODULE, start, [S])],
+ RC <- [rpc:call(N, ?MODULE, start, [{S, Nodes}])],
RC /= ok].
sequence() ->
@@ -194,13 +211,12 @@ origin(Server) ->
%% Establish one connection from the client, terminated on the first
%% server node, the others handling requests.
-connect({?SERVER, Config, [{Node, _} | _]}) ->
- if Node == node() -> %% server0
- ?util:write_priv(Config, lref, {Node, ?util:listen(?SERVER, tcp)});
- true ->
- diameter_dist:attach([?SERVER])
- end,
- ok;
+connect({?SERVER, Config, [{Node, _} | _]})
+ when Node == node() -> %% server0
+ ok = ?util:write_priv(Config, lref, {Node, ?util:listen(?SERVER, tcp)});
+
+connect({?SERVER, _Config, _}) -> %% server[12]: register to receive requests
+ ok = diameter_dist:attach([?SERVER]);
connect({?CLIENT, Config, _}) ->
?util:connect(?CLIENT, tcp, ?util:read_priv(Config, lref)),
@@ -239,7 +255,18 @@ send(Config) ->
send(Config, 0, Dict) ->
[{Server0, _} | _] = ?util:read_priv(Config, nodes) ,
Node = atom_to_binary(Server0, utf8),
- {false, _} = {dict:is_key(Node, Dict), dict:to_list(Dict)};
+ {false, _} = {dict:is_key(Node, Dict), dict:to_list(Dict)},
+ %% Check that counters have been incremented as expected on server0.
+ [Info] = rpc:call(Server0, diameter, service_info, [?SERVER, connections]),
+ {[Stats], _} = {[S || {statistics, S} <- Info], Info},
+ {[{recv, 1, 100}, {send, 0, 100}], _}
+ = {[{D,R,N} || T <- [recv, send],
+ {{{0,275,R}, D}, N} <- Stats,
+ D == T],
+ Stats},
+ {[{send, 0, 100, 2001}], _}
+ = {[{D,R,N,C} || {{{0,275,R}, D, {'Result-Code', C}}, N} <- Stats],
+ Stats};
send(Config, N, Dict) ->
#diameter_base_STA{'Result-Code' = ?SUCCESS,
diff --git a/lib/diameter/test/diameter_event_SUITE.erl b/lib/diameter/test/diameter_event_SUITE.erl
index a291dde6be..6d1d1dfd8f 100644
--- a/lib/diameter/test/diameter_event_SUITE.erl
+++ b/lib/diameter/test/diameter_event_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,6 +28,8 @@
-export([suite/0,
all/0,
+ init_per_suite/1,
+ end_per_suite/1,
init_per_testcase/2,
end_per_testcase/2]).
@@ -85,6 +87,13 @@ all() ->
cea_timeout,
stop].
+%% Not used, but a convenient place to enable trace.
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
init_per_testcase(Name, Config) ->
[{name, Name} | Config].
@@ -109,17 +118,19 @@ start_server(Config) ->
%% Connect with matching capabilities and expect the connection to
%% come up.
up(Config) ->
- {Svc, Ref} = connect(Config, [{connect_timer, 5000},
- {watchdog_timer, 15000}]),
+ {Svc, Ref, T} = connect(Config, [{strict_mbit, false},
+ {connect_timer, 5000},
+ {watchdog_timer, 15000}]),
start = event(Svc),
- {up, Ref, {TPid, Caps}, Cfg, #diameter_packet{msg = M}} = event(Svc),
+ {{up, Ref, {TPid, Caps}, T, #diameter_packet{msg = M}}, _}
+ = {event(Svc), T},
['CEA' | #{}] = M, %% assert
{watchdog, Ref, _, {initial, okay}, _} = event(Svc),
%% Kill the transport process and see that the connection is
%% reestablished after a watchdog timeout, not after connect_timer
%% expiry.
exit(TPid, kill),
- {down, Ref, {TPid, Caps}, Cfg} = event(Svc),
+ {{down, Ref, {TPid, Caps}, T}, _} = {event(Svc), T},
{watchdog, Ref, _, {okay, down}, _} = event(Svc),
{reconnect, Ref, _} = event(Svc, 10000, 20000).
@@ -127,24 +138,25 @@ up(Config) ->
%% to indicate as much and then for the transport to be restarted
%% (after connect_timer).
down(Config) ->
- {Svc, Ref} = connect(Config, [{capabilities, [{'Acct-Application-Id',
- [?DICT_ACCT:id()]}]},
- {applications, [?DICT_ACCT]},
- {connect_timer, 5000},
- {watchdog_timer, 20000}]),
+ {Svc, Ref, T} = connect(Config, [{capabilities, [{'Acct-Application-Id',
+ [?DICT_ACCT:id()]}]},
+ {applications, [?DICT_ACCT]},
+ {connect_timer, 5000},
+ {watchdog_timer, 20000}]),
start = event(Svc),
- {closed, Ref, {'CEA', ?NO_COMMON_APP, _, #diameter_packet{msg = M}}, _}
- = event(Svc),
+ {{closed, Ref, {'CEA', ?NO_COMMON_APP, _, #diameter_packet{msg = M}}, T},
+ _}
+ = {event(Svc), T},
['CEA' | #{}] = M, %% assert
{reconnect, Ref, _} = event(Svc, 4000, 10000).
%% Connect with matching capabilities but have the server delay its
%% CEA and cause the client to timeout.
cea_timeout(Config) ->
- {Svc, Ref} = connect(Config, [{capx_timeout, ?SERVER_CAPX_TMO div 2},
- {connect_timer, 2*?SERVER_CAPX_TMO}]),
+ {Svc, Ref, T} = connect(Config, [{capx_timeout, ?SERVER_CAPX_TMO div 2},
+ {connect_timer, 2*?SERVER_CAPX_TMO}]),
start = event(Svc),
- {closed, Ref, {'CEA', timeout}, _} = event(Svc).
+ {{closed, Ref, {'CEA', timeout}, T}, _} = {event(Svc), T}.
stop(_Config) ->
ok = diameter:stop().
@@ -168,8 +180,9 @@ connect(Config, Opts) ->
Name = Pre ++ uniq() ++ ?CLIENT,
diameter:subscribe(Name),
ok = start_service(Name, ?SERVICE(Name, [?DICT_COMMON, ?DICT_ACCT])),
- {ok, Ref} = diameter:add_transport(Name, opts(Config, Opts)),
- {Name, Ref}.
+ {connect, _} = T = opts(Config, Opts),
+ {ok, Ref} = diameter:add_transport(Name, T),
+ {Name, Ref, T}.
uniq() ->
"-" ++ diameter_util:unique_string().
diff --git a/lib/diameter/test/diameter_examples_SUITE.erl b/lib/diameter/test/diameter_examples_SUITE.erl
index ee44ed8dc9..7d47efd527 100644
--- a/lib/diameter/test/diameter_examples_SUITE.erl
+++ b/lib/diameter/test/diameter_examples_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2013-2017. All Rights Reserved.
+%% Copyright Ericsson AB 2013-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,6 +27,8 @@
-export([suite/0,
all/0,
groups/0,
+ init_per_suite/1,
+ end_per_suite/1,
init_per_group/2,
end_per_group/2]).
@@ -85,6 +87,13 @@ groups() ->
[{all, [parallel], [{group, P} || P <- ?PROTS]}
| [{P, [], Tc} || P <- ?PROTS]].
+%% Not used, but a convenient place to enable trace.
+init_per_suite(Config) ->
+ Config.
+
+end_per_suite(_Config) ->
+ ok.
+
init_per_group(all, Config) ->
Config;
@@ -216,12 +225,14 @@ make_name(Dict) ->
%% Compile example code under examples/code.
code(Config) ->
- Node = slave(compile, here()),
- [] = rpc:call(Node,
- ?MODULE,
- install,
- [proplists:get_value(priv_dir, Config)]),
- {ok, Node} = ct_slave:stop(compile).
+ try
+ [] = rpc:call(slave(compile, here()),
+ ?MODULE,
+ install,
+ [proplists:get_value(priv_dir, Config)])
+ after
+ {ok, _} = ct_slave:stop(compile)
+ end.
%% Compile on another node since the code path may be modified.
install(PrivDir) ->
diff --git a/lib/diameter/test/diameter_traffic_SUITE.erl b/lib/diameter/test/diameter_traffic_SUITE.erl
index 47b00c25a2..452bd28333 100644
--- a/lib/diameter/test/diameter_traffic_SUITE.erl
+++ b/lib/diameter/test/diameter_traffic_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2010-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2010-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -128,7 +128,7 @@
%% ===========================================================================
%% Fraction of shuffle/parallel groups to randomly skip.
--define(SKIP, 0.25).
+-define(SKIP, 0.90).
%% Positive number of testcases from which to select (randomly) from
%% tc(), the list of testcases to run, or [] to run all. The random
@@ -305,7 +305,8 @@ names() ->
S <- ?STRING_DECODES,
ST <- ?CALLBACKS,
SS <- ?SENDERS,
- CS <- ?SENDERS].
+ CS <- ?SENDERS,
+ ?SKIP =< rand:uniform()].
names(Names, []) ->
[N || N <- Names,
@@ -336,14 +337,9 @@ init_per_group(_) ->
init_per_group(Name, Config)
when Name == shuffle;
Name == parallel ->
- case rand:uniform() < ?SKIP of
- true ->
- {skip, random};
- false ->
- start_services(Config),
- add_transports(Config),
- replace({sleep, Name == parallel}, Config)
- end;
+ start_services(Config),
+ add_transports(Config),
+ replace({sleep, Name == parallel}, Config);
init_per_group(sctp = Name, Config) ->
{_, Sctp} = lists:keyfind(Name, 1, Config),
diff --git a/lib/diameter/vsn.mk b/lib/diameter/vsn.mk
index a8fbca5bc8..e72b6216a7 100644
--- a/lib/diameter/vsn.mk
+++ b/lib/diameter/vsn.mk
@@ -17,5 +17,5 @@
# %CopyrightEnd%
APPLICATION = diameter
-DIAMETER_VSN = 2.2.1
+DIAMETER_VSN = 2.2.2
APP_VSN = $(APPLICATION)-$(DIAMETER_VSN)$(PRE_VSN)
diff --git a/lib/erl_interface/configure.in b/lib/erl_interface/configure.in
index f0e9b2eb3f..230dba25d6 100644
--- a/lib/erl_interface/configure.in
+++ b/lib/erl_interface/configure.in
@@ -315,6 +315,12 @@ if test "x$GCC" = xyes; then
WFLAGS="$WFLAGS -fno-strict-aliasing";;
esac
CFLAGS="$WERRORFLAGS $CFLAGS"
+
+ # Use -fno-common for gcc, that is link error if multiple definitions of
+ # global variables are encountered. This is ISO C compliant.
+ # Until version 10, gcc has had -fcommon as default, which allows and merges
+ # such dubious duplicates.
+ LM_TRY_ENABLE_CFLAG([-fno-common], [CFLAGS])
else
WFLAGS=""
WERRORFLAGS=""
diff --git a/lib/erl_interface/src/misc/ei_portio.h b/lib/erl_interface/src/misc/ei_portio.h
index 84ebc5039a..5172d085b4 100644
--- a/lib/erl_interface/src/misc/ei_portio.h
+++ b/lib/erl_interface/src/misc/ei_portio.h
@@ -47,7 +47,7 @@ int ei_writev_fill_ctx_t__(ei_socket_callbacks *cbs, void *ctx, const struct iov
int ei_socket_callbacks_have_writev__(ei_socket_callbacks *cbs);
#endif
-ei_socket_callbacks ei_default_socket_callbacks;
+extern ei_socket_callbacks ei_default_socket_callbacks;
#define EI_FD_AS_CTX__(FD) \
((void *) (long) (FD))
diff --git a/lib/eunit/src/eunit_surefire.erl b/lib/eunit/src/eunit_surefire.erl
index 2b9f82b075..002a069a92 100644
--- a/lib/eunit/src/eunit_surefire.erl
+++ b/lib/eunit/src/eunit_surefire.erl
@@ -451,6 +451,11 @@ escape_xml([$< | Tail], Acc, ForAttr) -> escape_xml(Tail, [$;, $t, $l, $& | Acc]
escape_xml([$> | Tail], Acc, ForAttr) -> escape_xml(Tail, [$;, $t, $g, $& | Acc], ForAttr);
escape_xml([$& | Tail], Acc, ForAttr) -> escape_xml(Tail, [$;, $p, $m, $a, $& | Acc], ForAttr);
escape_xml([$" | Tail], Acc, true) -> escape_xml(Tail, [$;, $t, $o, $u, $q, $& | Acc], true); % "
+escape_xml([Char | Tail], Acc, ForAttr) when
+ Char == $\n; Char == $\r; Char == $\t -> escape_xml(Tail, [Char | Acc], ForAttr);
+%% Strip C0 control codes which are not allowed in XML 1.0
+escape_xml([Char | Tail], Acc, ForAttr) when
+ 0 =< Char, Char =< 31 -> escape_xml(Tail, Acc, ForAttr);
escape_xml([Char | Tail], Acc, ForAttr) when is_integer(Char) -> escape_xml(Tail, [Char | Acc], ForAttr).
%% the input may be utf8 or latin1; the resulting list is unicode
diff --git a/lib/eunit/test/Makefile b/lib/eunit/test/Makefile
index b6ece61b43..7c1e56c867 100644
--- a/lib/eunit/test/Makefile
+++ b/lib/eunit/test/Makefile
@@ -22,6 +22,7 @@ include $(ERL_TOP)/make/$(TARGET)/otp.mk
MODULES = \
eunit_SUITE \
+ tc0 \
tlatin \
tutf8
diff --git a/lib/eunit/test/eunit_SUITE.erl b/lib/eunit/test/eunit_SUITE.erl
index 63bdc6c334..b9f4ea4557 100644
--- a/lib/eunit/test/eunit_SUITE.erl
+++ b/lib/eunit/test/eunit_SUITE.erl
@@ -21,14 +21,16 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
- app_test/1,appup_test/1,eunit_test/1,surefire_utf8_test/1,surefire_latin_test/1]).
+ app_test/1,appup_test/1,eunit_test/1,surefire_utf8_test/1,surefire_latin_test/1,
+ surefire_c0_test/1]).
-include_lib("common_test/include/ct.hrl").
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [app_test, appup_test, eunit_test, surefire_utf8_test, surefire_latin_test].
+ [app_test, appup_test, eunit_test, surefire_utf8_test, surefire_latin_test,
+ surefire_c0_test].
groups() ->
[].
@@ -65,11 +67,24 @@ surefire_utf8_test(Config) when is_list(Config) ->
check_surefire(tutf8),
ok.
+surefire_c0_test(Config) when is_list(Config) ->
+ ok = file:set_cwd(proplists:get_value(priv_dir, Config, ".")),
+ Chars = check_surefire(tc0),
+ %% Check that these characters were not stripped
+ true = lists:member($\n, Chars),
+ true = lists:member($\r, Chars),
+ true = lists:member($\t, Chars),
+ ok.
+
check_surefire(Module) ->
File = "TEST-"++atom_to_list(Module)++".xml",
file:delete(File),
% ignore test result, some fail on purpose
eunit:test(Module, [{report,{eunit_surefire,[{dir,"."}]}}]),
{ok, Bin} = file:read_file(File),
- [_|_] = unicode:characters_to_list(Bin, unicode),
- ok. \ No newline at end of file
+ Chars = unicode:characters_to_list(Bin, unicode),
+ %% Check that unicode decoding succeeded
+ [_|_] = Chars,
+ %% Check that file is valid XML
+ xmerl_scan:file(File),
+ Chars.
diff --git a/lib/eunit/test/tc0.erl b/lib/eunit/test/tc0.erl
new file mode 100644
index 0000000000..8c90633fc8
--- /dev/null
+++ b/lib/eunit/test/tc0.erl
@@ -0,0 +1,14 @@
+-module(tc0).
+
+-include_lib("eunit/include/eunit.hrl").
+
+'c0_bad_output_test_'() ->
+ [{integer_to_list(C), fun() -> io:format("'~c'", [C]) end}
+ || C <- lists:seq(0, 31)].
+
+'c0_bad_description_test_'() ->
+ [{[C], fun() -> ok end}
+ || C <- lists:seq(0, 31)].
+
+'c0_bad_name__test'() ->
+ ok.
diff --git a/lib/hipe/icode/hipe_beam_to_icode.erl b/lib/hipe/icode/hipe_beam_to_icode.erl
index 995c961e09..efdaeecca3 100644
--- a/lib/hipe/icode/hipe_beam_to_icode.erl
+++ b/lib/hipe/icode/hipe_beam_to_icode.erl
@@ -557,21 +557,32 @@ trans_fun([{move,Src,Dst}|Instructions], Env) ->
Dst1 = mk_var(Dst),
Src1 = trans_arg(Src),
[hipe_icode:mk_move(Dst1,Src1) | trans_fun(Instructions,Env)];
-%%
-%% try/catch -- THESE ARE KNOWN TO MISCOMPILE, SEE OTP-15949
-%%
-trans_fun([{'catch'=Name,_,_}|_], _Env) ->
- nyi(Name);
-trans_fun([{catch_end=Name,_}|_], _Env) ->
- nyi(Name);
-trans_fun([{'try'=Name,_,_}|_], _Env) ->
- nyi(Name);
-trans_fun([{try_end=Name,_}|_], _Env) ->
- nyi(Name);
-trans_fun([{try_case=Name,_}|_], _Env) ->
- nyi(Name);
-trans_fun([{try_case_end=Name,_}|_], _Env) ->
- nyi(Name);
+%%--- catch --- ITS PROCESSING IS POSTPONED
+trans_fun([{'catch',N,{_,EndLabel}}|Instructions], Env) ->
+ NewContLbl = mk_label(new),
+ [{'catch',N,EndLabel},NewContLbl | trans_fun(Instructions,Env)];
+%%--- catch_end --- ITS PROCESSING IS POSTPONED
+trans_fun([{catch_end,_N}=I|Instructions], Env) ->
+ [I | trans_fun(Instructions,Env)];
+%%--- try --- ITS PROCESSING IS POSTPONED
+trans_fun([{'try',N,{_,EndLabel}}|Instructions], Env) ->
+ NewContLbl = mk_label(new),
+ [{'try',N,EndLabel},NewContLbl | trans_fun(Instructions,Env)];
+%%--- try_end ---
+trans_fun([{try_end,_N}|Instructions], Env) ->
+ [hipe_icode:mk_end_try() | trans_fun(Instructions,Env)];
+%%--- try_case --- ITS PROCESSING IS POSTPONED
+trans_fun([{try_case,_N}=I|Instructions], Env) ->
+ [I | trans_fun(Instructions,Env)];
+%%--- try_case_end ---
+trans_fun([{try_case_end,Arg}|Instructions], Env) ->
+ BadArg = trans_arg(Arg),
+ ErrVar = mk_var(new),
+ Vs = [mk_var(new)],
+ Atom = hipe_icode:mk_move(ErrVar,hipe_icode:mk_const(try_clause)),
+ Tuple = hipe_icode:mk_primop(Vs,mktuple,[ErrVar,BadArg]),
+ Fail = hipe_icode:mk_fail(Vs,error),
+ [Atom,Tuple,Fail | trans_fun(Instructions,Env)];
%%--- raise ---
trans_fun([{raise,{f,0},[Reg1,Reg2],{x,0}}|Instructions], Env) ->
V1 = trans_arg(Reg1),
@@ -2292,9 +2303,7 @@ fix_catch(Type, Lbl, ContLbl, Code, HandledCatchLbls, Instr) ->
TLbl = {Type, Lbl},
case gb_trees:lookup(TLbl, HandledCatchLbls) of
{value, Catch} when is_integer(Catch) ->
- NewCode = fix_catches(Code, HandledCatchLbls),
- Cont = hipe_icode:label_name(ContLbl),
- [hipe_icode:mk_begin_try(Catch,Cont),ContLbl | NewCode];
+ nyi(unsafe_catch);
none ->
OldCatch = map_label(Lbl),
OldCatchLbl = hipe_icode:mk_label(OldCatch),
diff --git a/lib/hipe/icode/hipe_icode_primops.erl b/lib/hipe/icode/hipe_icode_primops.erl
index a1f1128124..63b34f23a4 100644
--- a/lib/hipe/icode/hipe_icode_primops.erl
+++ b/lib/hipe/icode/hipe_icode_primops.erl
@@ -133,6 +133,7 @@ is_safe({hipe_bs_primop, {bs_append, _, _, _, _}}) -> false;
is_safe({hipe_bs_primop, {bs_private_append, _, _}}) -> false;
is_safe({hipe_bs_primop, bs_init_writable}) -> true;
is_safe(build_stacktrace) -> true;
+is_safe(raw_raise) -> false;
is_safe(#mkfun{}) -> true;
is_safe(#unsafe_element{}) -> true;
is_safe(#unsafe_update_element{}) -> true;
diff --git a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
index ba9c03d4ba..9f79231e5a 100644
--- a/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
+++ b/lib/hipe/test/basic_SUITE_data/basic_exceptions.erl
@@ -25,6 +25,7 @@ test() ->
ok = test_guard_bif(),
ok = test_eclectic(),
ok = test_raise(),
+ ok = test_effect(),
ok.
%%--------------------------------------------------------------------
@@ -675,4 +676,18 @@ do_test_raise_3(Expr) ->
erlang:raise(exit, {exception,C,E}, Stk)
end.
+test_effect() ->
+ ok = effect_try(2),
+ {'EXIT',{badarith,_}} = (catch effect_try(bad)),
+ ok.
+
+effect_try(X) ->
+ try
+ X + 1
+ catch
+ C:E:Stk ->
+ erlang:raise(C, E, Stk)
+ end,
+ ok.
+
id(I) -> I.
diff --git a/lib/kernel/doc/src/erl_epmd.xml b/lib/kernel/doc/src/erl_epmd.xml
index 2adbf11a28..31f49a05cb 100644
--- a/lib/kernel/doc/src/erl_epmd.xml
+++ b/lib/kernel/doc/src/erl_epmd.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2018</year><year>2018</year>
+ <year>2018</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -36,7 +36,7 @@
<p>This module communicates with the EPMD daemon, see <seealso
marker="erts:epmd">epmd</seealso>. To implement your own epmd module please
see <seealso marker="erts:alt_disco">ERTS User's Guide: How to Implement an
- Alternative Service Discovery for Erlang Distribution</seealso></p>
+ Alternative Node Discovery for Erlang Distribution</seealso></p>
</description>
<funcs>
diff --git a/lib/kernel/doc/src/notes.xml b/lib/kernel/doc/src/notes.xml
index 39da9ef3d6..7cf7ab3b4d 100644
--- a/lib/kernel/doc/src/notes.xml
+++ b/lib/kernel/doc/src/notes.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2004</year><year>2018</year>
+ <year>2004</year><year>2019</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -1048,7 +1048,7 @@
marker="kernel:erl_epmd"><c>erl_epmd</c></seealso>
reference manual and ERTS User's Guide <seealso
marker="erts:alt_disco">How to Implement an Alternative
- Service Discovery for Erlang Distribution</seealso>.</p>
+ Node Discovery for Erlang Distribution</seealso>.</p>
<p>
Own Id: OTP-15086 Aux Id: PR-1694 </p>
</item>
diff --git a/lib/kernel/src/code_server.erl b/lib/kernel/src/code_server.erl
index 68e1205301..5469d8694c 100644
--- a/lib/kernel/src/code_server.erl
+++ b/lib/kernel/src/code_server.erl
@@ -1437,11 +1437,16 @@ error_msg(Format, Args) ->
%% This is equal to calling logger:error/3 which we don't want to
%% do from code_server. We don't want to call logger:timestamp()
%% either.
- logger ! {log,error,Format,Args,
- #{pid=>self(),
- gl=>group_leader(),
- time=>os:system_time(microsecond),
- error_logger=>#{tag=>error}}},
+ _ = try
+ logger ! {log,error,Format,Args,
+ #{pid=>self(),
+ gl=>group_leader(),
+ time=>os:system_time(microsecond),
+ error_logger=>#{tag=>error}}}
+ catch _:_ ->
+ erlang:display({?MODULE,error}),
+ erlang:display({Format,Args})
+ end,
ok.
-spec info_msg(io:format(), [term()]) -> 'ok'.
@@ -1449,11 +1454,11 @@ info_msg(Format, Args) ->
%% This is equal to calling logger:info/3 which we don't want to
%% do from code_server. We don't want to call logger:timestamp()
%% either.
- logger ! {log,info,Format,Args,
- #{pid=>self(),
- gl=>group_leader(),
- time=>os:system_time(microsecond),
- error_logger=>#{tag=>info_msg}}},
+ catch logger ! {log,info,Format,Args,
+ #{pid=>self(),
+ gl=>group_leader(),
+ time=>os:system_time(microsecond),
+ error_logger=>#{tag=>info_msg}}},
ok.
objfile_extension() ->
diff --git a/lib/kernel/src/dist_util.erl b/lib/kernel/src/dist_util.erl
index 09ed31f10c..d8571c01be 100644
--- a/lib/kernel/src/dist_util.erl
+++ b/lib/kernel/src/dist_util.erl
@@ -344,22 +344,11 @@ shutdown(_Module, _Line, _Data, Reason) ->
?shutdown_trace("Net Kernel 2: shutting down connection "
"~p:~p, data ~p,reason ~p~n",
[_Module,_Line, _Data, Reason]),
- flush_down(),
exit(Reason).
%% Use this line to debug connection.
%% Set net_kernel verbose = 1 as well.
%% exit({Reason, ?MODULE, _Line, _Data, erlang:timestamp()}).
-
-flush_down() ->
- receive
- {From, get_status} ->
- From ! {self(), get_status, error},
- flush_down()
- after 0 ->
- ok
- end.
-
handshake_we_started(#hs_data{request_type=ReqType,
other_node=Node,
add_flags=AddFlgs0,
diff --git a/lib/kernel/src/inet_dns.erl b/lib/kernel/src/inet_dns.erl
index 6c98d2aab7..e03f124fe6 100644
--- a/lib/kernel/src/inet_dns.erl
+++ b/lib/kernel/src/inet_dns.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2017. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -109,8 +109,8 @@ lists_member(H, [H|_]) -> true;
lists_member(H, [_|T]) -> lists_member(H, T).
-
--define(DECODE_ERROR, fmt). % must match a clause in inet_res:query_nss_e?dns
+%% must match a clause in inet_res:query_nss_e?dns
+-define(DECODE_ERROR, formerr).
%%
%% Decode a dns buffer.
diff --git a/lib/kernel/src/inet_res.erl b/lib/kernel/src/inet_res.erl
index 6454802b04..7886ef83ac 100644
--- a/lib/kernel/src/inet_res.erl
+++ b/lib/kernel/src/inet_res.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -691,21 +691,22 @@ udp_send(#sock{inet=I}, {A,B,C,D}=IP, Port, Buffer)
gen_udp:send(I, IP, Port, Buffer).
udp_recv(#sock{inet6=I}, {A,B,C,D,E,F,G,H}=IP, Port, Timeout, Decode)
- when ?ip6(A,B,C,D,E,F,G,H), ?port(Port) ->
- do_udp_recv(I, IP, Port, Timeout, Decode, time_now(), Timeout);
+ when ?ip6(A,B,C,D,E,F,G,H), ?port(Port), 0 =< Timeout ->
+ do_udp_recv(I, IP, Port, Timeout, Decode, deadline(Timeout), Timeout);
udp_recv(#sock{inet=I}, {A,B,C,D}=IP, Port, Timeout, Decode)
- when ?ip(A,B,C,D), ?port(Port) ->
- do_udp_recv(I, IP, Port, Timeout, Decode, time_now(), Timeout).
+ when ?ip(A,B,C,D), ?port(Port), 0 =< Timeout ->
+ do_udp_recv(I, IP, Port, Timeout, Decode, deadline(Timeout), Timeout).
-do_udp_recv(_I, _IP, _Port, 0, _Decode, _Start, _T) ->
+do_udp_recv(_I, _IP, _Port, 0, _Decode, _Deadline, PollCnt)
+ when PollCnt =< 0 ->
timeout;
-do_udp_recv(I, IP, Port, Timeout, Decode, Start, T) ->
- case gen_udp:recv(I, 0, T) of
+do_udp_recv(I, IP, Port, Timeout, Decode, Deadline, PollCnt) ->
+ case gen_udp:recv(I, 0, Timeout) of
{ok,Reply} ->
case Decode(Reply) of
- false when T =:= 0 ->
+ false when Timeout =:= 0 ->
%% This is a compromize between the hard way i.e
- %% in the clause below if NewT becomes 0 bailout
+ %% in the clause below if Timeout becomes 0 bailout
%% immediately and risk that the right reply lies
%% ahead after some bad id replies, and the
%% forgiving way i.e go on with Timeout 0 until
@@ -713,15 +714,12 @@ do_udp_recv(I, IP, Port, Timeout, Decode, Start, T) ->
%% which opens for a DOS attack by a malicious
%% DNS server flooding with bad id replies causing
%% an infinite loop here.
- %%
- %% Timeout is used as a sanity limit counter
- %% just to put an end to the loop.
- NewTimeout = erlang:max(0, Timeout - 50),
- do_udp_recv(I, IP, Port, NewTimeout, Decode, Start, T);
+ %%
+ do_udp_recv(
+ I, IP, Port, Timeout, Decode, Deadline, PollCnt-50);
false ->
- Now = time_now(),
- NewT = erlang:max(0, Timeout - now_ms(Now, Start)),
- do_udp_recv(I, IP, Port, Timeout, Decode, Start, NewT);
+ T = timeout(Deadline),
+ do_udp_recv(I, IP, Port, T, Decode, Deadline, PollCnt);
Result ->
Result
end;
@@ -758,71 +756,122 @@ udp_close(#sock{inet=I,inet6=I6}) ->
%% And that is what the code seems to do, now fixed, hopefully...
do_query(_Q, [], _Timer) ->
+ %% We have no name server to ask, so say nxdomain
{error,nxdomain};
do_query(#q{options=#options{retry=Retry}}=Q, NSs, Timer) ->
- query_retries(Q, NSs, Timer, Retry, 0, #sock{}).
-
-query_retries(_Q, _NSs, _Timer, Retry, Retry, S) ->
- udp_close(S),
- {error,timeout};
-query_retries(_Q, [], _Timer, _Retry, _I, S) ->
- udp_close(S),
- {error,timeout};
-query_retries(Q, NSs, Timer, Retry, I, S0) ->
- case query_nss(Q, NSs, Timer, Retry, I, S0, []) of
- {S,{noanswer,ErrNSs}} -> %% remove unreachable nameservers
- query_retries(Q, NSs--ErrNSs, Timer, Retry, I+1, S);
- {S,Result} ->
- udp_close(S),
- Result
- end.
+ %% We have at least one name server,
+ %% so a failure will be a timeout,
+ %% unless a name server says otherwise
+ Reason = timeout,
+ query_retries(Q, NSs, Timer, Retry, 0, #sock{}, Reason).
-query_nss(_Q, [], _Timer, _Retry, _I, S, ErrNSs) ->
- {S,{noanswer,ErrNSs}};
-query_nss(#q{edns=undefined}=Q, NSs, Timer, Retry, I, S, ErrNSs) ->
- query_nss_dns(Q, NSs, Timer, Retry, I, S, ErrNSs);
-query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs) ->
- query_nss_edns(Q, NSs, Timer, Retry, I, S, ErrNSs).
+%% Loop until out of name servers or retries
+%%
+query_retries(_Q, _NSs, _Timer, Retry, Retry, S, Reason) ->
+ query_retries_error(S, Reason);
+query_retries(_Q, [], _Timer, _Retry, _I, S, Reason) ->
+ query_retries_error(S, Reason);
+query_retries(Q, NSs, Timer, Retry, I, S_0, Reason) ->
+ query_nss(Q, NSs, Timer, Retry, I, S_0, Reason, NSs).
+
+%% Loop for all name servers, for each:
+%% If EDNS is enabled, try that first,
+%% and for selected failures fall back to plain DNS.
+%%
+query_nss(Q, NSs, Timer, Retry, I, S, Reason, []) ->
+ %% End of name servers list, do a new retry
+ query_retries(Q, NSs, Timer, Retry, I+1, S, Reason);
+query_nss(#q{edns = undefined}=Q, NSs, Timer, Retry, I, S, Reason, TryNSs) ->
+ query_nss_dns(Q, NSs, Timer, Retry, I, S, Reason, TryNSs);
+query_nss(Q, NSs, Timer, Retry, I, S, Reason, TryNSs) ->
+ query_nss_edns(Q, NSs, Timer, Retry, I, S, Reason, TryNSs).
query_nss_edns(
- #q{options=#options{udp_payload_size=PSz}=Options,edns={Id,Buffer}}=Q,
- [{IP,Port}=NS|NSs]=NSs0, Timer, Retry, I, S0, ErrNSs) ->
- {S,Res}=Reply =
- query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, PSz),
- case Res of
- timeout -> {S,{error,timeout}}; % Bailout timeout
- {ok,_} -> Reply;
- {error,{nxdomain,_}} -> Reply;
- {error,{E,_}} when E =:= qfmterror; E =:= notimp; E =:= servfail;
- E =:= badvers ->
- query_nss_dns(Q, NSs0, Timer, Retry, I, S, ErrNSs);
- {error,E} when E =:= fmt; E =:= enetunreach; E =:= econnrefused ->
- query_nss(Q, NSs, Timer, Retry, I, S, [NS|ErrNSs]);
- _Error ->
- query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs)
+ #q{options =
+ #options{
+ udp_payload_size = PSz}=Options,
+ edns = {Id,Buffer}}=Q,
+ NSs, Timer, Retry, I, S_0, Reason, [{IP,Port}=NS|TryNSs]=TryNSs_0) ->
+ %%
+ {S,Result} =
+ query_ns(
+ S_0, Id, Buffer, IP, Port, Timer, Retry, I, Options, PSz),
+ case Result of
+ {error,{E,_}}
+ when E =:= qfmterror;
+ E =:= notimp;
+ E =:= servfail;
+ E =:= badvers ->
+ %% The server did not like that,
+ %% ignore that error and try plain DNS
+ query_nss_dns(
+ Q, NSs, Timer, Retry, I, S, Reason, TryNSs_0);
+ _ ->
+ query_nss_result(
+ Q, NSs, Timer, Retry, I, S, Reason, TryNSs, NS, Result)
end.
query_nss_dns(
- #q{dns=Qdns}=Q0,
- [{IP,Port}=NS|NSs], Timer, Retry, I, S0, ErrNSs) ->
- #q{options=Options,dns={Id,Buffer}}=Q =
+ #q{dns = Qdns}=Q_0,
+ NSs, Timer, Retry, I, S_0, Reason, [{IP,Port}=NS|TryNSs]) ->
+ %%
+ #q{options = Options,
+ dns = {Id,Buffer}}=Q =
if
- is_function(Qdns, 0) -> Q0#q{dns=Qdns()};
- true -> Q0
+ is_function(Qdns, 0) -> Q_0#q{dns=Qdns()};
+ true -> Q_0
end,
- {S,Res}=Reply =
+ {S,Result} =
query_ns(
- S0, Id, Buffer, IP, Port, Timer, Retry, I, Options, ?PACKETSZ),
- case Res of
- timeout -> {S,{error,timeout}}; % Bailout timeout
- {ok,_} -> Reply;
- {error,{E,_}} when E =:= nxdomain; E =:= qfmterror -> Reply;
- {error,E} when E =:= fmt; E =:= enetunreach; E =:= econnrefused ->
- query_nss(Q, NSs, Timer, Retry, I, S, [NS|ErrNSs]);
- _Error ->
- query_nss(Q, NSs, Timer, Retry, I, S, ErrNSs)
+ S_0, Id, Buffer, IP, Port, Timer, Retry, I, Options, ?PACKETSZ),
+ query_nss_result(
+ Q, NSs, Timer, Retry, I, S, Reason, TryNSs, NS, Result).
+
+query_nss_result(Q, NSs, Timer, Retry, I, S, Reason, TryNSs, NS, Result) ->
+ case Result of
+ {ok,_} ->
+ _ = udp_close(S),
+ Result;
+ timeout -> % Out of total time timeout
+ query_retries_error(S, Reason); % The best reason we have
+ {error,timeout} -> % Query timeout
+ %% Try next server, may retry this server later
+ query_nss(Q, NSs, Timer, Retry, I, S, Reason, TryNSs);
+ {error,{nxdomain,_}=NewReason} ->
+ query_retries_error(S, NewReason); % Definite answer
+ {error,{E,_}=NewReason}
+ when E =:= qfmterror;
+ E =:= notimp;
+ E =:= refused;
+ E =:= badvers ->
+ %% The server did not like that.
+ %% Remove this server from retry list since
+ %% it will not answer differently on the next retry.
+ NewNSs = lists:delete(NS, NSs),
+ query_nss(Q, NewNSs, Timer, Retry, I, S, NewReason, TryNSs);
+ {error,E=NewReason}
+ when E =:= formerr;
+ E =:= enetunreach;
+ E =:= econnrefused ->
+ %% Could not decode answer, or network problem.
+ %% Remove this server from retry list.
+ NewNSs = lists:delete(NS, NSs),
+ query_nss(Q, NewNSs, Timer, Retry, I, S, NewReason, TryNSs);
+ {error,NewReason} ->
+ %% Try next server, may retry this server later
+ query_nss(Q, NSs, Timer, Retry, I, S, NewReason, TryNSs)
end.
+query_retries_error(S, Reason) ->
+ _ = udp_close(S),
+ case Reason of
+ {nxdomain, _} ->
+ {error, nxdomain};
+ _ ->
+ {error, Reason}
+ end.
+
+
query_ns(S0, Id, Buffer, IP, Port, Timer, Retry, I,
#options{timeout=Tm,usevc=UseVC,verbose=Verbose},
PSz) ->
@@ -1035,10 +1084,11 @@ dns_msg(Msg) ->
{Type,dns_msg(Fields)}
end.
--compile({inline, [now_ms/2]}).
-now_ms(Int1, Int0) ->
- Int1 - Int0.
-
--compile({inline, [time_now/0]}).
-time_now() ->
- erlang:monotonic_time(1000).
+-compile({inline, [deadline/1, timeout/1]}).
+deadline(Timeout) -> % When is the deadline? [ms]
+ erlang:monotonic_time(1000) + Timeout.
+timeout(Deadline) -> % How long to deadline? [ms] >= 0
+ case Deadline - erlang:monotonic_time(1000) of
+ Timeout when 0 =< Timeout -> Timeout;
+ _ -> 0
+ end.
diff --git a/lib/kernel/src/logger_config.erl b/lib/kernel/src/logger_config.erl
index 5024d20cfe..af8ebfd4e9 100644
--- a/lib/kernel/src/logger_config.erl
+++ b/lib/kernel/src/logger_config.erl
@@ -41,7 +41,7 @@ delete(Tid,Id) ->
allow(Tid,Level,Module) ->
LevelInt = level_to_int(Level),
- case ets:lookup(Tid,Module) of
+ try ets:lookup(Tid,Module) of
[{Module,{ModLevel,cached}}] when is_integer(ModLevel),
LevelInt =< ModLevel ->
true;
@@ -53,11 +53,17 @@ allow(Tid,Level,Module) ->
allow(Tid,Level);
_ ->
false
+ catch error:badarg ->
+ true
end.
allow(Tid,Level) ->
- GlobalLevelInt = ets:lookup_element(Tid,?PRIMARY_KEY,2),
- level_to_int(Level) =< GlobalLevelInt.
+ try ets:lookup_element(Tid,?PRIMARY_KEY,2) of
+ GlobalLevelInt ->
+ level_to_int(Level) =< GlobalLevelInt
+ catch error:badarg ->
+ true
+ end.
exist(Tid,What) ->
ets:member(Tid,table_key(What)).
diff --git a/lib/kernel/src/logger_proxy.erl b/lib/kernel/src/logger_proxy.erl
index 24b293805c..6ab8e3e4c5 100644
--- a/lib/kernel/src/logger_proxy.erl
+++ b/lib/kernel/src/logger_proxy.erl
@@ -42,11 +42,16 @@
StringOrReport :: unicode:chardata() | logger:report(),
Meta :: logger:metadata().
log(RemoteLog) ->
- Olp = persistent_term:get(?MODULE),
- case logger_olp:get_pid(Olp) =:= self() of
+ Olp = persistent_term:get(?MODULE, undefined),
+ case (Olp =:= undefined) orelse (logger_olp:get_pid(Olp) =:= self()) of
true ->
%% This happens when the log event comes from the
%% emulator, and the group leader is on a remote node.
+ %%
+ %% OR
+ %%
+ %% when we are to log a remote message before the logger_proxy
+ %% has started
_ = handle_load(RemoteLog, no_state),
ok;
false ->
@@ -112,9 +117,12 @@ init([]) ->
%% Log event to send to the node where the group leader of it's client resides
handle_load({remote,Node,Log},State) ->
- %% If the connection is overloaded (send_nosuspend returns false),
- %% we drop the message.
- _ = erlang:send_nosuspend({?SERVER,Node},Log),
+ case erlang:send({?SERVER,Node},Log,[nosuspend]) of
+ _ok_or_nosuspend ->
+ %% If the connection is overloaded (send returns nosuspend),
+ %% we drop the message.
+ ok
+ end,
State;
%% Log event to log on this node
handle_load({log,Level,Format,Args,Meta},State) ->
diff --git a/lib/kernel/src/net_kernel.erl b/lib/kernel/src/net_kernel.erl
index 4a68e6676d..e4b214a6c5 100644
--- a/lib/kernel/src/net_kernel.erl
+++ b/lib/kernel/src/net_kernel.erl
@@ -121,17 +121,23 @@
-define(LISTEN_ID, #listen.listen).
-define(ACCEPT_ID, #listen.accept).
+-type connection_state() :: pending | up | up_pending.
+-type connection_type() :: normal | hidden.
+
+-include("net_address.hrl").
+
+%% Relaxed typing to allow ets:select without Dialyzer complains.
-record(connection, {
- node, %% remote node name
- conn_id, %% Connection identity
- state, %% pending | up | up_pending
- owner, %% owner pid
- ctrlr, %% Controller port or pid
- pending_owner, %% possible new owner
- address, %% #net_address
- waiting = [], %% queued processes
- type %% normal | hidden
- }).
+ node :: node() | '_', %% remote node name
+ conn_id, %% Connection identity
+ state :: connection_state() | '_',
+ owner :: pid() | '_', %% owner pid
+ ctrlr, %% Controller port or pid
+ pending_owner :: pid() | '_' | undefined, %% possible new owner
+ address :: #net_address{} | '_',
+ waiting = [], %% queued processes
+ type :: connection_type() | '_'
+}).
-record(barred_connection, {
node %% remote node name
@@ -151,8 +157,6 @@
%% the connection setup.
-define(SETUPTIME, 7000).
--include("net_address.hrl").
-
%%% BIF
-export([dflag_unicode_io/1]).
@@ -180,9 +184,31 @@ longnames() -> request(longnames).
Reason :: not_allowed | not_found.
stop() -> erl_distribution:stop().
-node_info(Node) -> get_node_info(Node).
-node_info(Node, Key) -> get_node_info(Node, Key).
-nodes_info() -> get_nodes_info().
+-type node_info() ::
+ {address, #net_address{}} |
+ {type, connection_type()} |
+ {in, non_neg_integer()} |
+ {out, non_neg_integer()} |
+ {owner, pid()} |
+ {state, connection_state()}.
+
+-spec node_info(node()) -> {ok, [node_info()]} | {error, bad_node}.
+node_info(Node) ->
+ get_node_info(Node).
+
+-spec node_info(node(), address) -> {ok, Address} | {error, bad_node} when Address :: #net_address{};
+ (node(), type) -> {ok, Type} | {error, bad_node} when Type :: connection_type();
+ (node(), in | out) -> {ok, Bytes} | {error, bad_node} when Bytes :: non_neg_integer();
+ (node(), owner) -> {ok, Owner} | {error, bad_node} when Owner :: pid();
+ (node(), state) -> {ok, State} | {error, bad_node} when State :: connection_state().
+ %(node(), term()) -> {error, invalid_key} | {error, bad_node}.
+node_info(Node, Key) ->
+ get_node_info(Node, Key).
+
+-spec nodes_info() -> {ok, [{node(), [node_info()]}]}.
+nodes_info() ->
+ get_nodes_info().
+
i() -> print_info().
i(Node) -> print_info(Node).
@@ -1621,61 +1647,73 @@ connecttime() ->
get_node_info(Node) ->
case ets:lookup(sys_dist, Node) of
- [Conn = #connection{owner = Owner, state = State}] ->
- case get_status(Owner, Node, State) of
- {ok, In, Out} ->
- {ok, [{owner, Owner},
- {state, State},
- {address, Conn#connection.address},
- {type, Conn#connection.type},
- {in, In},
- {out, Out}]};
+ [#connection{owner = Owner, state = up, address = Addr, type = Type}] ->
+ MRef = monitor(process, Owner),
+ Owner ! {self(), get_status},
+ receive
+ {Owner, get_status, {ok, Read, Write}} ->
+ demonitor(MRef, [flush]),
+ {ok, [{owner, Owner}, {state, up}, {address, Addr},
+ {type, Type}, {in, Read}, {out, Write}]};
+ {'DOWN', MRef, process, Owner, _Info} ->
+ {error, bad_node}
+ end;
+ [#connection{owner = Owner, state = State, address = Addr, type = Type}] ->
+ {ok, [{owner, Owner}, {state, State}, {address, Addr},
+ {type, Type}, {in, 0}, {out, 0}]};
_ ->
{error, bad_node}
- end;
- _ ->
- {error, bad_node}
end.
-%%
-%% We can't do monitor_node here incase the node is pending,
-%% the monitor_node/2 call hangs until the connection is ready.
-%% We will not ask about in/out information either for pending
-%% connections as this also would block this call awhile.
-%%
-get_status(Owner, Node, up) ->
- monitor_node(Node, true),
- Owner ! {self(), get_status},
- receive
- {Owner, get_status, Res} ->
- monitor_node(Node, false),
- Res;
- {nodedown, Node} ->
- error
- end;
-get_status(_, _, _) ->
- {ok, 0, 0}.
-
get_node_info(Node, Key) ->
case get_node_info(Node) of
- {ok, Info} ->
- case lists:keysearch(Key, 1, Info) of
- {value, {Key, Value}} -> {ok, Value};
- _ -> {error, invalid_key}
- end;
- Error ->
- Error
+ {ok, Info} ->
+ case lists:keyfind(Key, 1, Info) of
+ {Key, Value} ->
+ {ok, Value};
+ false ->
+ {error, invalid_key}
+ end;
+ {error, bad_node} ->
+ {error, bad_node}
end.
+
get_nodes_info() ->
- Nodes = ets:select(sys_dist, [{#connection{node = '$1', _ = '_'}, [], ['$1']}]),
- {ok, lists:filtermap(
- fun(Node) ->
- case get_node_info(Node) of
- {ok, Info} -> {true, {Node, Info}};
- _ -> false
- end
- end, Nodes)}.
+ Conns = ets:select(sys_dist, [{#connection{_ = '_'}, [], ['$_']}]),
+ Info = multi_info(Conns, {self(), get_status}, #{}, []),
+ {ok, Info}.
+
+multi_info([], _Msg, PidToRef, NodeInfos) ->
+ multi_receive(PidToRef, NodeInfos);
+multi_info([#connection{owner = Owner, state = up} = Conn | Conns], Msg, PidToRef, NodeInfos) ->
+ % connection is up, try to figure out in/out bytes
+ MRef = erlang:monitor(process, Owner),
+ Owner ! Msg,
+ multi_info(Conns, Msg, maps:put(Owner, {MRef, Conn}, PidToRef), NodeInfos);
+multi_info([#connection{node = Node, owner = Owner, type = Type,
+ state = State, address = Addr} | Conns], Msg, PidToRef, NodeInfos) ->
+ % connection is not up: in/out bytes are zero
+ multi_info(Conns, Msg, PidToRef, [
+ {Node, [{owner, Owner}, {state, State}, {address, Addr}, {type, Type}, {in, 0}, {out, 0}]}
+ | NodeInfos]).
+
+multi_receive(PidToRef, NodeInfos) when map_size(PidToRef) =:= 0 ->
+ NodeInfos;
+multi_receive(PidToRef, NodeInfos) ->
+ receive
+ {DistProc, get_status, {ok, Read, Write}} ->
+ {{MRef, #connection{node = Node, owner = Owner, type = Type,
+ state = State, address = Addr}}, NewRefs} = maps:take(DistProc, PidToRef),
+ erlang:demonitor(MRef, [flush]),
+ multi_receive(NewRefs, [
+ {Node, [{owner, Owner}, {state, State}, {address, Addr}, {type, Type}, {in, Read}, {out, Write}]}
+ | NodeInfos]);
+ {'DOWN', _MRef, process, Pid, _Info} ->
+ % connection went down: reproducing compatible behaviour with
+ % not showing any information about this connection
+ multi_receive(maps:remove(Pid, PidToRef), NodeInfos)
+ end.
%% ------------------------------------------------------------
%% Misc. functions
diff --git a/lib/kernel/test/code_SUITE.erl b/lib/kernel/test/code_SUITE.erl
index 6b133f8d6b..131e3fed34 100644
--- a/lib/kernel/test/code_SUITE.erl
+++ b/lib/kernel/test/code_SUITE.erl
@@ -28,7 +28,7 @@
delete/1, purge/1, purge_many_exits/0, purge_many_exits/1,
soft_purge/1, is_loaded/1, all_loaded/1,
load_binary/1, dir_req/1, object_code/1, set_path_file/1,
- upgrade/1,
+ upgrade/0, upgrade/1,
sticky_dir/1, pa_pz_option/1, add_del_path/1,
dir_disappeared/1, ext_mod_dep/1, clash/1,
where_is_file/1,
@@ -523,6 +523,9 @@ load_binary(Config) when is_list(Config) ->
ok.
+upgrade() ->
+ [{timetrap,{minutes,2}}].
+
upgrade(Config) ->
DataDir = proplists:get_value(data_dir, Config),
diff --git a/lib/kernel/test/gen_udp_SUITE.erl b/lib/kernel/test/gen_udp_SUITE.erl
index 70d8caf478..2720d3cc77 100644
--- a/lib/kernel/test/gen_udp_SUITE.erl
+++ b/lib/kernel/test/gen_udp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2019. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -35,7 +35,8 @@
-export([send_to_closed/1, active_n/1,
buffer_size/1, binary_passive_recv/1, max_buffer_size/1, bad_address/1,
- read_packets/1, open_fd/1, connect/1, implicit_inet6/1,
+ read_packets/1, recv_poll_after_active_once/1,
+ open_fd/1, connect/1, implicit_inet6/1,
recvtos/1, recvtosttl/1, recvttl/1, recvtclass/1,
sendtos/1, sendtosttl/1, sendttl/1, sendtclass/1,
local_basic/1, local_unbound/1,
@@ -47,7 +48,8 @@ suite() ->
all() ->
[send_to_closed, buffer_size, binary_passive_recv, max_buffer_size,
- bad_address, read_packets, open_fd, connect,
+ bad_address, read_packets, recv_poll_after_active_once,
+ open_fd, connect,
implicit_inet6, active_n,
recvtos, recvtosttl, recvttl, recvtclass,
sendtos, sendtosttl, sendttl, sendtclass,
@@ -436,6 +438,27 @@ flush() ->
end.
+%% OTP-16059
+%% UDP recv with timeout 0 corrupts internal state so that after a
+%% recv under {active, once} the UDP recv poll wastes incoming data
+recv_poll_after_active_once(Config) when is_list(Config) ->
+ Msg1 = <<"Hej!">>,
+ Msg2 = <<"Hej igen!">>,
+ Addr = {127,0,0,1},
+ {ok,S1} = gen_udp:open(0, [binary, {active, once}]),
+ {ok,P1} = inet:port(S1),
+ {ok,S2} = gen_udp:open(0, [binary, {active, false}]),
+ {ok,P2} = inet:port(S2),
+ ok = gen_udp:send(S2, Addr, P1, Msg1),
+ receive
+ {udp, S1, Addr, P2, Msg1} ->
+ {error, timeout} = gen_udp:recv(S1, 0, 0),
+ ok = gen_udp:send(S2, Addr, P1, Msg2),
+ receive after 500 -> ok end, % Give the kernel time to deliver
+ {ok, {Addr, P2, Msg2}} = gen_udp:recv(S1, 0, 0),
+ ok
+ end.
+
%% Test that the 'fd' option works.
open_fd(Config) when is_list(Config) ->
diff --git a/lib/kernel/test/inet_res_SUITE.erl b/lib/kernel/test/inet_res_SUITE.erl
index 6b545fa414..8b3f1aa2a9 100644
--- a/lib/kernel/test/inet_res_SUITE.erl
+++ b/lib/kernel/test/inet_res_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2009-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2009-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -28,7 +28,7 @@
init_per_group/2,end_per_group/2,
init_per_testcase/2, end_per_testcase/2]).
-export([basic/1, resolve/1, edns0/1, txt_record/1, files_monitor/1,
- last_ms_answer/1]).
+ last_ms_answer/1, intermediate_error/1]).
-export([
gethostbyaddr/0, gethostbyaddr/1,
gethostbyaddr_v6/0, gethostbyaddr_v6/1,
@@ -64,7 +64,7 @@ suite() ->
all() ->
[basic, resolve, edns0, txt_record, files_monitor,
- last_ms_answer,
+ last_ms_answer, intermediate_error,
gethostbyaddr, gethostbyaddr_v6, gethostbyname,
gethostbyname_v6, getaddr, getaddr_v6, ipv4_to_ipv6,
host_and_addr].
@@ -91,6 +91,9 @@ zone_dir(TC) ->
edns0 -> otptest;
files_monitor -> otptest;
last_ms_answer -> otptest;
+ intermediate_error ->
+ {internal,
+ #{rcode => ?REFUSED}};
_ -> undefined
end.
@@ -106,6 +109,9 @@ init_per_testcase(Func, Config) ->
inet_db:ins_alt_ns(IP, Port);
_ -> ok
end,
+ %% dbg:tracer(),
+ %% dbg:p(all, c),
+ %% dbg:tpl(inet_res, query_nss_res, cx),
[{nameserver,NsSpec},{res_lookup,Lookup}|Config]
catch
SkipReason ->
@@ -120,6 +126,7 @@ end_per_testcase(_Func, Config) ->
inet_db:del_alt_ns(IP, Port);
_ -> ok
end,
+ %% dbg:stop(),
ns_end(NsSpec, proplists:get_value(priv_dir, Config)).
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -130,15 +137,18 @@ ns(Config) ->
NS.
ns_init(ZoneDir, PrivDir, DataDir) ->
- case os:type() of
- {unix,_} when ZoneDir =:= undefined -> undefined;
- {unix,_} ->
+ case {os:type(),ZoneDir} of
+ {_,{internal,ServerSpec}} ->
+ ns_start_internal(ServerSpec);
+ {{unix,_},undefined} ->
+ undefined;
+ {{unix,_},otptest} ->
PortNum = case {os:type(),os:version()} of
{{unix,solaris},{M,V,_}} when M =< 5, V < 10 ->
11895 + rand:uniform(100);
_ ->
- {ok,S} = gen_udp:open(0, [{reuseaddr,true}]),
- {ok,PNum} = inet:port(S),
+ S = ok(gen_udp:open(0, [{reuseaddr,true}])),
+ PNum = ok(inet:port(S)),
gen_udp:close(S),
PNum
end,
@@ -170,12 +180,43 @@ ns_start(ZoneDir, PrivDir, NS, P) ->
ns_start(ZoneDir, PrivDir, NS, P)
end.
+ns_start_internal(ServerSpec) ->
+ Parent = self(),
+ Tag = make_ref(),
+ {P,Mref} =
+ spawn_monitor(
+ fun () ->
+ _ = process_flag(trap_exit, true),
+ IP = {127,0,0,1},
+ SocketOpts = [{ip,IP},binary,{active,once}],
+ S = ok(gen_udp:open(0, SocketOpts)),
+ Port = ok(inet:port(S)),
+ ParentMref = monitor(process, Parent),
+ Parent ! {Tag,{IP,Port},self()},
+ ns_internal(ServerSpec, ParentMref, Tag, S)
+ end),
+ receive
+ {Tag,_NS,P} = NsSpec ->
+ demonitor(Mref, [flush]),
+ NsSpec;
+ {'DOWN',Mref,_,_,Reason} ->
+ exit({ns_start_internal,Reason})
+ end.
+
ns_end(undefined, _PrivDir) -> undefined;
-ns_end({ZoneDir,_NS,P}, PrivDir) ->
+ns_end({ZoneDir,_NS,P}, PrivDir) when is_port(P) ->
port_command(P, ["quit",io_lib:nl()]),
ns_stop(P),
ns_printlog(filename:join([PrivDir,ZoneDir,"named.log"])),
- ok.
+ ok;
+ns_end({Tag,_NS,P}, _PrivDir) when is_pid(P) ->
+ Mref = erlang:monitor(process, P),
+ P ! Tag,
+ receive
+ {'DOWN',Mref,_,_,Reason} ->
+ Reason = normal,
+ ok
+ end.
ns_stop(P) ->
case ns_collect(P) of
@@ -209,6 +250,44 @@ ns_printlog(Fname) ->
end.
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Internal name server
+
+ns_internal(ServerSpec, Mref, Tag, S) ->
+ receive
+ {'DOWN',Mref,_,_,Reason} ->
+ exit(Reason);
+ Tag ->
+ ok;
+ {udp,S,IP,Port,Data} ->
+ Req = ok(inet_dns:decode(Data)),
+ Resp = ns_internal(ServerSpec, Req),
+ RespData = inet_dns:encode(Resp),
+ _ = ok(gen_udp:send(S, IP, Port, RespData)),
+ _ = ok(inet:setopts(S, [{active,once}])),
+ ns_internal(ServerSpec, Mref, Tag, S)
+ end.
+
+ns_internal(#{rcode := Rcode}, Req) ->
+ Hdr = inet_dns:msg(Req, header),
+ Opcode = inet_dns:header(Hdr, opcode),
+ Id = inet_dns:header(Hdr, id),
+ Rd = inet_dns:header(Hdr, rd),
+ %%
+ Qdlist = inet_dns:msg(Req, qdlist),
+ inet_dns:make_msg(
+ [{header,
+ inet_dns:make_header(
+ [{id,Id},
+ {qr,true},
+ {opcode,Opcode},
+ {aa,true},
+ {tc,false},
+ {rd,Rd},
+ {ra,false},
+ {rcode,Rcode}])},
+ {qdlist,Qdlist}]).
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Behaviour modifying nameserver proxy
proxy_start(TC, {NS,P}) ->
@@ -672,6 +751,23 @@ last_ms_answer(Config) when is_list(Config) ->
ok.
%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% First name server answers ?REFUSED, second does not answer.
+%% Check that we get the error code from the first server.
+
+intermediate_error(Config) when is_list(Config) ->
+ NS = ns(Config),
+ Name = "ns.otptest",
+ IP = {127,0,0,1},
+ %% A "name server" that does not respond
+ S = ok(gen_udp:open(0, [{ip,IP},{active,false}])),
+ Port = ok(inet:port(S)),
+ NSs = [NS,{IP,Port}],
+ {error,{refused,_}} =
+ inet_res:resolve(Name, in, a, [{nameservers,NSs},verbose], 500),
+ _ = gen_udp:close(S),
+ ok.
+
+%% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Compatibility tests. Call the inet_SUITE tests, but with
%% lookup = [file,dns] instead of [native]
@@ -729,3 +825,8 @@ tolower([C|Cs]) when is_integer(C) ->
end;
tolower([]) ->
[].
+
+-compile({inline,[ok/1]}).
+ok(ok) -> ok;
+ok({ok,X}) -> X;
+ok({error,Reason}) -> error(Reason).
diff --git a/lib/kernel/test/init_SUITE.erl b/lib/kernel/test/init_SUITE.erl
index a0154b2694..9d35611d93 100644
--- a/lib/kernel/test/init_SUITE.erl
+++ b/lib/kernel/test/init_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -68,7 +68,7 @@ end_per_group(_GroupName, Config) ->
Config.
-init_per_testcase(Func, Config) ->
+init_per_testcase(_Func, Config) ->
Config.
end_per_testcase(_Func, _Config) ->
@@ -368,7 +368,8 @@ restart(Config) when is_list(Config) ->
io:format("SysProcs0=~p~n", [SysProcs0]),
[InitPid, PurgerPid, LitCollectorPid,
DirtySigNPid, DirtySigHPid, DirtySigMPid,
- PrimFilePid] = SysProcs0,
+ PrimFilePid,
+ ESockRegPid] = SysProcs0,
InitPid = rpc:call(Node, erlang, whereis, [init]),
PurgerPid = rpc:call(Node, erlang, whereis, [erts_code_purger]),
Procs = rpc:call(Node, erlang, processes, []),
@@ -387,7 +388,8 @@ restart(Config) when is_list(Config) ->
io:format("SysProcs1=~p~n", [SysProcs1]),
[InitPid1, PurgerPid1, LitCollectorPid1,
DirtySigNPid1, DirtySigHPid1, DirtySigMPid1,
- PrimFilePid1] = SysProcs1,
+ PrimFilePid1,
+ ESockRegPid1] = SysProcs1,
%% Still the same init process!
InitPid1 = rpc:call(Node, erlang, whereis, [init]),
@@ -417,6 +419,10 @@ restart(Config) when is_list(Config) ->
PrimFileP = pid_to_list(PrimFilePid),
PrimFileP = pid_to_list(PrimFilePid1),
+ %% and same socket_registry helper process!
+ ESockRegP = pid_to_list(ESockRegPid),
+ ESockRegP = pid_to_list(ESockRegPid1),
+
NewProcs0 = rpc:call(Node, erlang, processes, []),
NewProcs = NewProcs0 -- SysProcs1,
case check_processes(NewProcs, MaxPid) of
@@ -444,7 +450,8 @@ restart(Config) when is_list(Config) ->
dirty_sig_handler_normal,
dirty_sig_handler_high,
dirty_sig_handler_max,
- prim_file}).
+ prim_file,
+ socket_registry}).
find_system_processes() ->
find_system_procs(processes(), #sys_procs{}).
@@ -456,7 +463,8 @@ find_system_procs([], SysProcs) ->
SysProcs#sys_procs.dirty_sig_handler_normal,
SysProcs#sys_procs.dirty_sig_handler_high,
SysProcs#sys_procs.dirty_sig_handler_max,
- SysProcs#sys_procs.prim_file];
+ SysProcs#sys_procs.prim_file,
+ SysProcs#sys_procs.socket_registry];
find_system_procs([P|Ps], SysProcs) ->
case process_info(P, [initial_call, priority]) of
[{initial_call,{erl_init,start,2}},_] ->
@@ -483,6 +491,9 @@ find_system_procs([P|Ps], SysProcs) ->
[{initial_call,{prim_file,start,0}},_] ->
undefined = SysProcs#sys_procs.prim_file,
find_system_procs(Ps, SysProcs#sys_procs{prim_file = P});
+ [{initial_call,{socket_registry,start,0}},_] ->
+ undefined = SysProcs#sys_procs.socket_registry,
+ find_system_procs(Ps, SysProcs#sys_procs{socket_registry = P});
_ ->
find_system_procs(Ps, SysProcs)
end.
diff --git a/lib/kernel/test/logger_proxy_SUITE.erl b/lib/kernel/test/logger_proxy_SUITE.erl
index 777531e4ed..bae2bd8d17 100644
--- a/lib/kernel/test/logger_proxy_SUITE.erl
+++ b/lib/kernel/test/logger_proxy_SUITE.erl
@@ -72,6 +72,7 @@ all() ->
[basic,
emulator,
remote,
+ remote_disconnect,
remote_emulator,
config,
restart_after,
@@ -118,6 +119,19 @@ remote(Config) ->
remote(cleanup,_Config) ->
ok = logger:remove_handler(?HNAME).
+remote_disconnect(Config) ->
+ {ok,_,Node} = logger_test_lib:setup(Config,[{logger,[{proxy,#{}}]}]),
+ ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}),
+ RemoteGL = rpc:call(Node, erlang, whereis, [user]),
+ net_kernel:disconnect(Node),
+ L1 = ?LOC#{ gl => RemoteGL }, logger:notice("Log from ~p; ~p",[?FUNCTION_NAME,?LINE],L1),
+ ok = ensure(L1),
+ L2 = ?LOC#{ gl => RemoteGL }, logger:notice([{test_case,?FUNCTION_NAME},{line,?LINE}],L2),
+ ok = ensure(L2),
+ ok.
+remote_disconnect(cleanup,_Config) ->
+ ok = logger:remove_handler(?HNAME).
+
remote_emulator(Config) ->
{ok,_,Node} = logger_test_lib:setup(Config,[{logger,[{proxy,#{}}]}]),
ok = logger:add_handler(?HNAME,?MODULE,#{config=>self()}),
diff --git a/lib/kernel/test/net_SUITE.erl b/lib/kernel/test/net_SUITE.erl
index 4f27628bed..1e657a6cdd 100644
--- a/lib/kernel/test/net_SUITE.erl
+++ b/lib/kernel/test/net_SUITE.erl
@@ -219,6 +219,8 @@ api_b_getifaddrs() ->
i("IfAddrs: "
"~n ~p", [IfAddrs]),
ok;
+ {error, enotsup = Reason} ->
+ skip(Reason);
{error, Reason} ->
?FAIL(Reason)
end.
diff --git a/lib/megaco/src/app/megaco.erl b/lib/megaco/src/app/megaco.erl
index 2c96ea25d7..a876ff02f8 100644
--- a/lib/megaco/src/app/megaco.erl
+++ b/lib/megaco/src/app/megaco.erl
@@ -66,7 +66,8 @@
decode_binary_term_id/2,
encode_sdp/1,
- decode_sdp/1,
+ decode_sdp/1,
+ get_sdp_record_from_PropertyGroup/2,
versions1/0, versions2/0,
print_version_info/0, print_version_info/1,
@@ -491,6 +492,18 @@ decode_sdp(PP) ->
%%-----------------------------------------------------------------
+%% dget_sdp_record_from_PropertyGroup(Type, PG) ->
+%%
+%% [sdp()]}
+%%
+%% Get all sdp records of a certain type from a property group
+%%-----------------------------------------------------------------
+
+get_sdp_record_from_PropertyGroup(Type, PG) ->
+ megaco_sdp:get_sdp_record_from_PropertyGroup(Type, PG).
+
+
+%%-----------------------------------------------------------------
%% {ok, Vs} = megaco:versions1(), megaco:format_versions(Vs).
print_version_info() ->
diff --git a/lib/megaco/test/megaco_codec_flex_lib.erl b/lib/megaco/test/megaco_codec_flex_lib.erl
index e322c21dad..566ab0fe47 100644
--- a/lib/megaco/test/megaco_codec_flex_lib.erl
+++ b/lib/megaco/test/megaco_codec_flex_lib.erl
@@ -60,6 +60,8 @@ init(Config) when is_list(Config) ->
%% "~n", [?MODULE, Res]),
process_flag(trap_exit, Flag),
case Res of
+ {error, {failed_loading_flex_scanner_driver, Reason}} ->
+ skip(?F("Failed loading flex driver: ~p", [Reason]));
{error, Reason} ->
skip(Reason);
{ok, FlexConfig} ->
diff --git a/lib/megaco/test/megaco_load_SUITE.erl b/lib/megaco/test/megaco_load_SUITE.erl
index e5dc5a027a..876e16ecfb 100644
--- a/lib/megaco/test/megaco_load_SUITE.erl
+++ b/lib/megaco/test/megaco_load_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,6 +48,7 @@
]).
+-include_lib("common_test/include/ct.hrl").
-include_lib("megaco/include/megaco.hrl").
-include_lib("megaco/include/megaco_message_v1.hrl").
-include("megaco_test_lib.hrl").
@@ -243,20 +244,7 @@ single_user_light_load(suite) ->
single_user_light_load(doc) ->
[];
single_user_light_load(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(tc, single_user_light_load),
- put(sname, "TEST"),
- i("starting"),
-
- load_controller(Config,
- fun(Env) ->
- populate(Env),
- exit( single_user_load(5) )
- end),
-
- i("done", []),
- ok.
-
+ try_single_user_load(single_user_light_load, Config, 5).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -266,19 +254,7 @@ single_user_medium_load(suite) ->
single_user_medium_load(doc) ->
[];
single_user_medium_load(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(tc, single_user_medium_load),
- put(sname, "TEST"),
- i("starting"),
-
- load_controller(Config,
- fun(Env) ->
- populate(Env),
- exit( single_user_load(15) )
- end),
-
- i("done", []),
- ok.
+ try_single_user_load(single_user_medium_load, Config, 15).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -288,19 +264,7 @@ single_user_heavy_load(suite) ->
single_user_heavy_load(doc) ->
[];
single_user_heavy_load(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(tc, single_user_heavy_load),
- put(sname, "TEST"),
- i("starting"),
-
- load_controller(Config,
- fun(Env) ->
- populate(Env),
- exit( single_user_load(25) )
- end),
-
- i("done", []),
- ok.
+ try_single_user_load(single_user_heavy_load, Config, 25).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -310,19 +274,7 @@ single_user_extreme_load(suite) ->
single_user_extreme_load(doc) ->
[];
single_user_extreme_load(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(tc, single_user_extreme_load),
- put(sname, "TEST"),
- i("starting"),
-
- load_controller(Config,
- fun(Env) ->
- populate(Env),
- exit( single_user_load(100) )
- end),
-
- i("done", []),
- ok.
+ try_single_user_load(single_user_extreme_load, Config, 100).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -332,19 +284,7 @@ multi_user_light_load(suite) ->
multi_user_light_load(doc) ->
[];
multi_user_light_load(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(tc, multi_user_light_load),
- put(sname, "TEST"),
- i("starting"),
-
- load_controller(Config,
- fun(Env) ->
- populate(Env),
- exit( multi_user_load(3,1) )
- end),
-
- i("done", []),
- ok.
+ try_multi_user_load(multi_user_light_load, Config, 3, 1).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -354,19 +294,7 @@ multi_user_medium_load(suite) ->
multi_user_medium_load(doc) ->
[];
multi_user_medium_load(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(tc, multi_user_medium_load),
- put(sname, "TEST"),
- i("starting"),
-
- load_controller(Config,
- fun(Env) ->
- populate(Env),
- exit( multi_user_load(3,5) )
- end),
-
- i("done", []),
- ok.
+ try_multi_user_load(multi_user_medium_load, Config, 3, 5).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -376,19 +304,7 @@ multi_user_heavy_load(suite) ->
multi_user_heavy_load(doc) ->
[];
multi_user_heavy_load(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(tc, multi_user_heavy_load),
- put(sname, "TEST"),
- i("starting"),
-
- load_controller(Config,
- fun(Env) ->
- populate(Env),
- exit( multi_user_load(3,10) )
- end),
-
- i("done", []),
- ok.
+ try_multi_user_load(multi_user_heavy_load, Config, 3, 10).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -398,19 +314,7 @@ multi_user_extreme_load(suite) ->
multi_user_extreme_load(doc) ->
[];
multi_user_extreme_load(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(tc, multi_user_extreme_load),
- put(sname, "TEST"),
- i("starting"),
-
- load_controller(Config,
- fun(Env) ->
- populate(Env),
- exit( multi_user_load(3,15) )
- end),
-
- i("done", []),
- ok.
+ try_multi_user_load(multi_user_extreme_load, Config, 3, 15).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -462,14 +366,46 @@ load_controller(Config, Fun) when is_list(Config) and is_function(Fun) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-single_user_load(NumLoaders) ->
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("Nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p", [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+try_single_user_load(Name, Config, NumLoaders0) ->
+ Factor = ?config(megaco_factor, Config),
+ NumLoaders =
+ if
+ (Factor =:= 1) ->
+ NumLoaders0;
+ (Factor > NumLoaders0) ->
+ 1;
+ true ->
+ NumLoaders0 div Factor
+ end,
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("Nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p", [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun(State) -> single_user_load(State, Config, NumLoaders) end,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(Name, Pre, Case, Post).
+
+
+single_user_load(State, Config, NumLoaders) ->
+ i("starting with ~w loader(s)", [NumLoaders]),
+ Res = load_controller(Config,
+ fun(Env) ->
+ populate(Env),
+ exit( single_user_load(State, NumLoaders) )
+ end),
+ i("done"),
+ Res.
+
+single_user_load([MgcNode, MgNode], NumLoaders) ->
%% Start the MGC and MGs
i("[MGC] start"),
MgcMid = {deviceName, "ctrl"},
@@ -532,16 +468,52 @@ single_user_load(NumLoaders) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-multi_user_load(NumUsers, NumLoaders)
+try_multi_user_load(Name, Config, NumUsers, NumLoaders0) ->
+ Factor = ?config(megaco_factor, Config),
+ NumLoaders =
+ if
+ (Factor =:= 1) ->
+ NumLoaders0;
+ (Factor > NumLoaders0) ->
+ 1;
+ true ->
+ NumLoaders0 div Factor
+ end,
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNodes = make_node_names(mg, NumUsers),
+ d("Nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNodes: ~p", [MgcNode, MgNodes]),
+ Nodes = [MgcNode | MgNodes],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun(State) ->
+ multi_user_load(State, Config, NumUsers, NumLoaders)
+ end,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(Name, Pre, Case, Post).
+
+
+multi_user_load(State, Config, NumUsers, NumLoaders) ->
+ i("starting with ~w loader(s)", [NumLoaders]),
+ Res = load_controller(
+ Config,
+ fun(Env) ->
+ populate(Env),
+ exit( multi_user_load(State, NumUsers, NumLoaders) )
+ end),
+ i("done"),
+ Res.
+
+
+multi_user_load([MgcNode | MgNodes], NumUsers, NumLoaders)
when (is_integer(NumUsers) andalso (NumUsers > 1) andalso
is_integer(NumLoaders) andalso (NumLoaders >= 1)) ->
- MgcNode = make_node_name(mgc),
- MgNodes = make_node_names(mg, NumUsers),
- d("Nodes: "
- "~n MgcNode: ~p"
- "~n MgNodes: ~p", [MgcNode, MgNodes]),
- ok = megaco_test_lib:start_nodes([MgcNode| MgNodes], ?FILE, ?LINE),
-
%% Start the MGC and MGs
i("[MGC] start"),
MgcMid = {deviceName, "ctrl"},
@@ -761,6 +733,15 @@ maybe_display_system_info(_) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try_tc(TCName, Pre, Case, Post) ->
+ try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
+
+try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
+ ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
min(M) -> timer:minutes(M).
p(F, A) ->
diff --git a/lib/megaco/test/megaco_mess_SUITE.erl b/lib/megaco/test/megaco_mess_SUITE.erl
index bb4e3eb1ee..f3dfc053c6 100644
--- a/lib/megaco/test/megaco_mess_SUITE.erl
+++ b/lib/megaco/test/megaco_mess_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -499,6 +499,9 @@ end_per_group(_GroupName, Config) ->
%%
init_per_testcase(Case, Config) ->
+ process_flag(trap_exit, true),
+
+ ?ANNOUNCE_CASE_INIT(Case),
p("init_per_testcase -> entry with"
"~n Config: ~p"
@@ -689,31 +692,35 @@ request_and_no_reply(suite) ->
request_and_no_reply(doc) ->
[];
request_and_no_reply(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, request_and_no_reply),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- Mg1Node = make_node_name(mg1),
- Mg2Node = make_node_name(mg2),
- Mg3Node = make_node_name(mg3),
- Mg4Node = make_node_name(mg4),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n Mg1Node: ~p"
- "~n Mg2Node: ~p"
- "~n Mg3Node: ~p"
- "~n Mg4Node: ~p",
- [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
- Nodes = [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node],
- ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ Mg3Node = make_node_name(mg3),
+ Mg4Node = make_node_name(mg4),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p"
+ "~n Mg3Node: ~p"
+ "~n Mg4Node: ~p",
+ [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
+ Nodes = [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_request_and_no_reply/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(request_and_no_reply, Pre, Case, Post).
+
+do_request_and_no_reply([MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]) ->
%% Start the MGC
i("[MGC] start"),
ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
- {ok, Mgc} =
- ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
+ {ok, Mgc} = ?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, [], ?MGC_VERBOSITY),
?SLEEP(?SECONDS(1)),
i("[MG] start"),
@@ -833,9 +840,31 @@ request_and_no_reply(Config) when is_list(Config) ->
d("MG4 user info: ~p", [?MG_USER_INFO(Mg4, all)]),
d("MG4 conn info: ~p", [?MG_CONN_INFO(Mg4, all)]),
+ %% Tell MG4 to stop
+ i("[MG4] stop"),
+ ?MG_STOP(Mg4),
+
+ %% Tell MG3 to stop
+ i("[MG3] stop"),
+ ?MG_STOP(Mg3),
+
+ %% Tell MG2 to stop
+ i("[MG2] stop"),
+ ?MG_STOP(Mg2),
+
+ %% Tell MG1 to stop
+ i("[MG1] stop"),
+ ?MG_STOP(Mg1),
+
+ %% Tell Mgc to stop
+ i("[MGC] stop"),
+ ?MGC_STOP(Mgc),
+
+ i("done", []),
ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
request_and_reply_pending_ack_no_pending(suite) ->
@@ -845,20 +874,26 @@ request_and_reply_pending_ack_no_pending(doc) ->
"value handle_pending_ack from handle_trans_request when NO "
"pending message has been sent"];
request_and_reply_pending_ack_no_pending(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rar_panp),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- Nodes = [MgcNode, MgNode],
- ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_request_and_reply_pending_ack_no_pending/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes)),
+ ok
+ end,
+ try_tc(rar_panp, Pre, Case, Post).
+
+do_request_and_reply_pending_ack_no_pending([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -871,9 +906,6 @@ request_and_reply_pending_ack_no_pending(Config) when is_list(Config) ->
d("[MGC] start the simulation"),
{ok, MgcId} = megaco_test_megaco_generator:exec(Mgc, MgcEvSeq),
- %% i("wait some time before starting the MG simulator"),
- %% sleep(1000),
-
i("await MGC ready announcement"),
receive
announce_mgc ->
@@ -1444,19 +1476,25 @@ request_and_reply_pending_ack_one_pending(doc) ->
"value handle_pending_ack from handle_trans_request when ONE "
"pending message has been sent"];
request_and_reply_pending_ack_one_pending(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rar_paop),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_request_and_reply_pending_ack_one_pending/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rar_paop, Pre, Case, Post).
+
+do_request_and_reply_pending_ack_one_pending([MgcNode, MgNode]) ->
d("[MGC] start the simulator"),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -2136,20 +2174,25 @@ single_trans_req_and_reply(doc) ->
"The MGC is a megaco instance (megaco event sequence) and the "
"MG is emulated (tcp event sequence)"];
single_trans_req_and_reply(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, strar),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_single_trans_req_and_reply/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(strar, Pre, Case, Post).
+
+do_single_trans_req_and_reply([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -2646,26 +2689,31 @@ single_trans_req_and_reply_sendopts(doc) ->
"The MGC is a megaco instance (megaco event sequence) and the "
"MG is emulated (tcp event sequence)"];
single_trans_req_and_reply_sendopts(Config) when is_list(Config) ->
- %% <CONDITIONAL-SKIP>
- Skippable = [{unix, [darwin, linux]}],
- Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
- ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
- %% </CONDITIONAL-SKIP>
-
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, straro),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
-
+ Pre = fun() ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin, linux]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_single_trans_req_and_reply_sendopts/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(straro, Pre, Case, Post).
+
+do_single_trans_req_and_reply_sendopts([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -3208,19 +3256,25 @@ request_and_reply_and_ack(suite) ->
request_and_reply_and_ack(doc) ->
["This test case tests that megaco correctly handles three-way-handshake"];
request_and_reply_and_ack(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, raraa),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_request_and_reply_and_ack/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(raraa, Pre, Case, Post).
+
+do_request_and_reply_and_ack([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -3829,19 +3883,26 @@ request_and_reply_and_no_ack(doc) ->
["This test case tests that megaco handles a failed three-way-handshake,"
" i.e. when the ack never arrives"];
request_and_reply_and_no_ack(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rarana),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_request_and_reply_and_no_ack/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rarana, Pre, Case, Post).
+
+
+do_request_and_reply_and_no_ack([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -4436,19 +4497,25 @@ request_and_reply_and_late_ack(doc) ->
["This test case tests that megaco handles three-way-handshake "
"when the ack is late (and requeire a retransmission)"];
request_and_reply_and_late_ack(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rarala),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_request_and_reply_and_late_ack/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rarala, Pre, Case, Post).
+
+do_request_and_reply_and_late_ack([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -5067,26 +5134,31 @@ trans_req_and_reply_and_req(doc) ->
"The MGC is a megaco instance (megaco event sequence) and the "
"MG is emulated (tcp event sequence)"];
trans_req_and_reply_and_req(Config) when is_list(Config) ->
- %% <CONDITIONAL-SKIP>
- Skippable = [{unix, [darwin, linux]}],
- Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
- ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
- %% </CONDITIONAL-SKIP>
-
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, trarar),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
-
+ Pre = fun() ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin, linux]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_trans_req_and_reply_and_req/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(request_and_no_reply, Pre, Case, Post).
+
+do_trans_req_and_reply_and_req([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -5730,19 +5802,25 @@ pending_ack_plain(doc) ->
"i.e. return with {pending, _} and expect a call to the "
"long request function"];
pending_ack_plain(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, pap),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_pending_ack_plain/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(pap, Pre, Case, Post).
+
+do_pending_ack_plain([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -6423,19 +6501,25 @@ request_and_pending_and_late_reply(doc) ->
"i.e. return with {pending, _}. Then, expect the sender "
"to keep re-sending the request until the reply is sent."];
request_and_pending_and_late_reply(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rapalr),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_request_and_pending_and_late_reply/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rapalr, Pre, Case, Post).
+
+do_request_and_pending_and_late_reply([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -7269,19 +7353,25 @@ otp_4359_analyze_encoded_message(RH, ExpErrorCode, M)
otp_4836(suite) ->
[];
otp_4836(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_4836),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_4836/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_4836, Pre, Case, Post).
+
+do_otp_4836([MgcNode, MgNode]) ->
d("start the MGC simulator (generator)"),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -7522,19 +7612,25 @@ otp_4836_mgc_verify_notify_req_msg(M) ->
otp_5805(suite) ->
[];
otp_5805(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_5805),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_5805/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_5805, Pre, Case, Post).
+
+do_otp_5805([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -8005,7 +8101,8 @@ otp_5881(Config) when is_list(Config) ->
"~n MgcNode: ~p"
"~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
d("start the MGC simulator (generator)"),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -8071,6 +8168,10 @@ otp_5881(Config) when is_list(Config) ->
i("[MGC] stop generator"),
megaco_test_tcp_generator:stop(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes)),
+
i("done", []),
ok.
@@ -8247,19 +8348,25 @@ otp_5881_mgc_verify_notify_req_msg(M) ->
otp_5887(suite) ->
[];
otp_5887(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_5887),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_5887/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_5887, Pre, Case, Post).
+
+do_otp_5887([MgcNode, MgNode]) ->
d("start the MGC simulator (generator)"),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -8590,19 +8697,25 @@ otp_6253(Config) when is_list(Config) ->
otp_6275(suite) ->
[];
otp_6275(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_6275),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_6275/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_6275, Pre, Case, Post).
+
+do_otp_6275([MgcNode, MgNode]) ->
d("start the MGC simulator (generator)"),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -9083,21 +9196,27 @@ otp_6276(suite) ->
otp_6276(doc) ->
"OTP-6276: Cancel when receiving reply raise condition";
otp_6276(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_6276),
- i("starting"),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_6276/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_6276, Pre, Case, Post).
+
+do_otp_6276([MgcNode, MgNode]) ->
d("create sequence controller"),
CtrlPid = otp_6276_sequence_controller_start(),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -9762,19 +9881,25 @@ otp_6276(Config) when is_list(Config) ->
otp_6442_resend_request1(suite) ->
[];
otp_6442_resend_request1(Config) when is_list(Config) ->
- put(verbosity, debug),
- put(sname, "TEST"),
- put(tc, otp6442rreq1),
- i("starting"),
-
- MgNode = make_node_name(mg),
- d("start (MG) node: ~p", [MgNode]),
- ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
-
- d("[MG] start the simulator "),
+ Pre = fun() ->
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ Nodes = [MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_6442_resend_request1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp6442rreq1, Pre, Case, Post).
+
+do_otp_6442_resend_request1([MgNode]) ->
+ d("[MG] start the simulator"),
{ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
- d("[MG] create the event sequence"),
+ d("[MG] create the event sequence (~p)", [Mg]),
MgMid = {deviceName,"mg"},
MgEvSeq = otp_6442_resend_request1_mg_event_sequence(MgMid),
@@ -9978,11 +10103,6 @@ otp_6442_resend_request1_mg_event_sequence(Mid) ->
?otp_6442_resend_request1_mg_verify_service_change_rep_fun(),
NotifyReplyVerify =
?otp_6442_resend_request1_mg_verify_notify_rep_fun(),
- %% ConnectVerify =
- %% otp_6442_resend_request1_mg_verify_handle_connect_fun(),
- %% ServiceChangeReplyVerify =
- %% otp_6442_resend_request1_mg_verify_service_change_reply_fun(),
- %% NotifyReplyVerify = otp_6442_resend_request1_mg_verify_notify_reply_fun(),
EvSeq = [
{debug, false},
megaco_start,
@@ -10132,15 +10252,21 @@ otp_6442_resend_request1_mg_notify_request_ar(Rid, Tid, Cid) ->
otp_6442_resend_request2(suite) ->
[];
otp_6442_resend_request2(Config) when is_list(Config) ->
- put(verbosity, debug),
- put(sname, "TEST"),
- put(tc, otp6442rreq2),
- i("starting"),
-
- MgNode = make_node_name(mg),
- d("start (MG) node: ~p", [MgNode]),
- ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ Nodes = [MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_6442_resend_request2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp6442rreq2, Pre, Case, Post).
+
+do_otp_6442_resend_request2([MgNode]) ->
d("[MG] start the simulator "),
{ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
@@ -10434,15 +10560,21 @@ otp_6442_resend_request2_mg_notify_request_ar(Rid, Tid, Cid) ->
otp_6442_resend_reply1(suite) ->
[];
otp_6442_resend_reply1(Config) when is_list(Config) ->
- put(sname, "TEST"),
- put(verbosity, debug),
- put(tc, otp6442rrep1),
- i("starting"),
-
- MgNode = make_node_name(mg),
- d("start (MG) node: ~p", [MgNode]),
- ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ Nodes = [MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_6442_resend_reply1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(request_and_no_reply, Pre, Case, Post).
+
+do_otp_6442_resend_reply1([MgNode]) ->
d("[MG] start the simulator "),
{ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
@@ -10823,15 +10955,21 @@ otp_6442_resend_reply1_err_desc(T) ->
otp_6442_resend_reply2(suite) ->
[];
otp_6442_resend_reply2(Config) when is_list(Config) ->
- put(sname, "TEST"),
- put(verbosity, debug),
- put(tc, otp6442rrep2),
- i("starting"),
-
- MgNode = make_node_name(mg),
- d("start (MG) node: ~p", [MgNode]),
- ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ Nodes = [MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_6442_resend_reply2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp6442rrep2, Pre, Case, Post).
+
+do_otp_6442_resend_reply2([MgNode]) ->
d("[MG] start the simulator "),
{ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
@@ -11323,7 +11461,8 @@ otp_6865_request_and_reply_plain_extra2(Config) when is_list(Config) ->
"~n MgcNode: ~p"
"~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
d("[MGC] start the simulator "),
@@ -11371,6 +11510,10 @@ otp_6865_request_and_reply_plain_extra2(Config) when is_list(Config) ->
i("stop tc controller"),
ok = megaco_tc_controller:stop(),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes)),
+
i("done", []),
ok.
@@ -12187,19 +12330,25 @@ otp_7189(suite) ->
otp_7189(doc) ->
"...";
otp_7189(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_7189),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_7189/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_7189, Pre, Case, Post).
+
+do_otp_7189([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -12705,15 +12854,21 @@ otp_7259(suite) ->
otp_7259(doc) ->
["This is a variant of ticket OTP-6442"];
otp_7259(Config) when is_list(Config) ->
- put(verbosity, debug),
- put(sname, "TEST"),
- put(tc, otp7259rr),
- i("starting"),
-
- MgNode = make_node_name(mg),
- d("start (MG) node: ~p", [MgNode]),
- ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ Nodes = [MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_7259/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp7259rr, Pre, Case, Post).
+
+do_otp_7259([MgNode]) ->
d("[MG] start the simulator "),
{ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
@@ -13138,15 +13293,26 @@ otp_7713(Config) when is_list(Config) ->
otp_8183_request1(suite) ->
[];
otp_8183_request1(Config) when is_list(Config) ->
+ Pre = fun() ->
put(verbosity, debug),
put(sname, "TEST"),
put(tc, otp8183r1),
i("starting"),
- MgNode = make_node_name(mg),
- d("start (MG) node: ~p", [MgNode]),
- ok = megaco_test_lib:start_nodes([MgNode], ?FILE, ?LINE),
-
+ MgNode = make_node_name(mg),
+ d("start (MG) node: ~p", [MgNode]),
+ Nodes = [MgNode],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_otp_8183_request1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp8183r1, Pre, Case, Post).
+
+do_otp_8183_request1([MgNode]) ->
d("[MG] start the simulator "),
{ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
@@ -13972,6 +14138,46 @@ sleep(X) -> receive after X -> ok end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+to(To, Start) ->
+ To - (mtime() - Start).
+
+%% Time in milli seconds
+mtime() ->
+ {A,B,C} = erlang:timestamp(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+try_tc(TCName, Pre, Case, Post) ->
+ try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
+
+try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
+ ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% p(F) ->
+%% p(F, []).
+
+p(F, A) ->
+ p(get(sname), F, A).
+
+p(S, F, A) when is_list(S) ->
+ io:format("*** [~s] ~p ~s ***"
+ "~n " ++ F ++ "~n",
+ [?FTS(), self(), S | A]);
+p(_S, F, A) ->
+ io:format("*** [~s] ~p *** "
+ "~n " ++ F ++ "~n",
+ [?FTS(), self() | A]).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
i(F) ->
i(F, []).
@@ -13995,7 +14201,7 @@ print(Severity, Verbosity, Ts, Tc, P, F, A) ->
print(true, TS, TC, P, F, A) ->
S = ?F("*** [~s] ~s ~p ~s:~w ***"
"~n " ++ F ++ "~n",
- [megaco:format_timestamp(TS), P, self(), get(sname), TC | A]),
+ [?FTS(TS), P, self(), get(sname), TC | A]),
io:format("~s", [S]),
io:format(user, "~s", [S]);
print(_, _, _, _, _, _) ->
@@ -14008,33 +14214,3 @@ printable(_,_) -> false.
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-to(To, Start) ->
- To - (mtime() - Start).
-
-%% Time in milli seconds
-mtime() ->
- {A,B,C} = erlang:timestamp(),
- A*1000000000+B*1000+(C div 1000).
-
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-%% p(F) ->
-%% p(F, []).
-
-p(F, A) ->
- p(get(sname), F, A).
-
-p(S, F, A) when is_list(S) ->
- io:format("*** [~s] ~p ~s ***"
- "~n " ++ F ++ "~n",
- [?FTS(), self(), S | A]);
-p(_S, F, A) ->
- io:format("*** [~s] ~p *** "
- "~n " ++ F ++ "~n",
- [?FTS(), self() | A]).
-
-
diff --git a/lib/megaco/test/megaco_mib_SUITE.erl b/lib/megaco/test/megaco_mib_SUITE.erl
index 8763145bbc..e040705b05 100644
--- a/lib/megaco/test/megaco_mib_SUITE.erl
+++ b/lib/megaco/test/megaco_mib_SUITE.erl
@@ -53,8 +53,8 @@
-include("megaco_test_lib.hrl").
-define(TEST_VERBOSITY, info). % silence | info | debug
--define(MGC_VERBOSITY, info).
--define(MG_VERBOSITY, info).
+-define(MGC_VERBOSITY, debug).
+-define(MG_VERBOSITY, debug).
-define(LOAD_COUNTER_START, 100).
-define(A4444, ["11111111", "00000000", "00000000"]).
@@ -292,28 +292,40 @@ connect(suite) ->
connect(doc) ->
[];
connect(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- i("connect -> starting"),
- progress("start nodes"),
- MgcNode = make_node_name(mgc),
- Mg1Node = make_node_name(mg1),
- Mg2Node = make_node_name(mg2),
- d("connect -> Nodes: "
- "~n MgcNode: ~p"
- "~n Mg1Node: ~p"
- "~n Mg2Node: ~p", [MgcNode, Mg1Node, Mg2Node]),
- ok = ?START_NODES([MgcNode, Mg1Node, Mg2Node]),
-
+ Pre = fun() ->
+ progress("start nodes"),
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ d("connect -> Nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p", [MgcNode, Mg1Node, Mg2Node]),
+ Nodes = [MgcNode, Mg1Node, Mg2Node],
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_connect/1,
+ Post = fun(Nodes) ->
+ progress("stop nodes"),
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(connect, Pre, Case, Post).
+
+do_connect([MgcNode, Mg1Node, Mg2Node]) ->
%% Start the MGC and MGs
- ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
- progress("start MGC"),
+
+ ET = [{text, tcp}, {text, udp}, {binary, tcp}, {binary, udp}],
+ progress("start MGC (on ~p)", [MgcNode]),
{ok, Mgc} =
start_mgc(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
- progress("start MG1"),
+
+ progress("start MG1 (on ~p) using tcp", [Mg1Node]),
{ok, Mg1} =
start_mg(Mg1Node, {deviceName, "mg1"}, text, tcp, ?MG_VERBOSITY),
- progress("start MG2"),
+
+ progress("start MG2 (on ~p) using udp", [Mg2Node]),
{ok, Mg2} =
start_mg(Mg2Node, {deviceName, "mg2"}, binary, udp, ?MG_VERBOSITY),
@@ -385,7 +397,6 @@ connect(Config) when is_list(Config) ->
stop(Mgc),
i("connect -> done", []),
- progress("done"),
ok.
@@ -397,27 +408,36 @@ traffic(suite) ->
traffic(doc) ->
[];
traffic(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- i("traffic -> starting"),
- progress("start nodes"),
- MgcNode = make_node_name(mgc),
- Mg1Node = make_node_name(mg1),
- Mg2Node = make_node_name(mg2),
- Mg3Node = make_node_name(mg3),
- Mg4Node = make_node_name(mg4),
- d("traffic -> Nodes: "
- "~n MgcNode: ~p"
- "~n Mg1Node: ~p"
- "~n Mg2Node: ~p"
- "~n Mg3Node: ~p"
- "~n Mg4Node: ~p",
- [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
- ok = ?START_NODES([MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
-
+ Pre = fun() ->
+ progress("start nodes"),
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ Mg3Node = make_node_name(mg3),
+ Mg4Node = make_node_name(mg4),
+ Nodes = [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node],
+ d("traffic -> Nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p"
+ "~n Mg3Node: ~p"
+ "~n Mg4Node: ~p",
+ [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
+ ok = ?START_NODES(Nodes, true),
+ Nodes
+ end,
+ Case = fun do_traffic/1,
+ Post = fun(Nodes) ->
+ progress("stop nodes"),
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(traffic, Pre, Case, Post).
+
+do_traffic([MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]) ->
%% Start the MGC and MGs
- i("traffic -> start the MGC"),
- progress("start MGC"),
+ i("start the MGC"),
+ progress("start MGC (on ~p)", [MgcNode]),
ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
{ok, Mgc} =
start_mgc(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
@@ -550,7 +570,6 @@ traffic(Config) when is_list(Config) ->
stop(Mgc),
i("traffic -> done", []),
- progress("done"),
ok.
@@ -671,10 +690,12 @@ traffic_connect_mg([{Node, Name, Coding, Trans}|Mg], Acc) ->
traffic_connect_mg(Mg, [{Name, Pid}|Acc]).
traffic_connect_mg(Node, Name, Coding, Trans) ->
+ progress("start (and connect) ~s (on ~p) using ~p", [Name, Node, Trans]),
Mid = {deviceName, Name},
{ok, Pid} = start_mg(Node, Mid, Coding, Trans, ?MG_VERBOSITY),
%% Ask the MGs to do a service change
+ progress("perform ~s service change", [Name]),
{ok, Res} = service_change(Pid),
d("traffic_connect_mg -> (~s) service change result: ~p", [Name, Res]),
Pid.
@@ -831,8 +852,12 @@ mgc_init(Config) ->
RH = megaco:user_info(Mid,receive_handle),
d("mgc_init -> parse receive info"),
ListenTo = mgc_parse_receive_info(RI, RH),
- i("mgc_init -> start transport(s)"),
+ i("mgc_init -> start transport(s) with:"
+ "~n ListenTo: ~p", [ListenTo]),
{Tcp, Udp} = mgc_start_transports(ListenTo),
+ i("mgc_init -> transport(s) started:"
+ "~n Tcp: ~p"
+ "~n Udp: ~p", [Tcp, Udp]),
{Mid, Tcp, Udp}.
@@ -1247,10 +1272,15 @@ mg_loop(#mg{state = State} = S) ->
%% Do a service change
{service_change, Parent} when S#mg.parent == Parent,
State == initiated ->
- i("mg_loop(~p) -> received request to perform service change",
- [State]),
+ i("mg_loop(~p) -> received request to perform service change when:"
+ "~n Conn Handle: ~p"
+ "~n Conn Data: ~p",
+ [State,
+ S#mg.conn_handle,
+ megaco:conn_info(S#mg.conn_handle, conn_data)]),
Res = mg_service_change(S#mg.conn_handle),
- d("mg_loop(~p) -> result: ~p", [State, Res]),
+ d("mg_loop(~p) -> service change request send result: ~p",
+ [State, Res]),
mg_loop(S#mg{state = connecting});
@@ -1358,9 +1388,12 @@ mg_start_tcp(MgcPort, RH) ->
{port, MgcPort},
{receive_handle, RH},
{tcp_options, [{nodelay, true}]}],
+ i("tcp transport started: attempt (tcp) connect to MGC at:"
+ "~n ~p", [LocalHost]),
case megaco_tcp:connect(Sup, Opts) of
{ok, SendHandle, ControlPid} ->
PrelMgcMid = preliminary_mid,
+ i("tcp transport (tcp) connected: attempt (megaco) connect:"),
{ok, ConnHandle} =
megaco:connect(RH, PrelMgcMid,
SendHandle, ControlPid),
@@ -1382,12 +1415,18 @@ mg_start_udp(MgcPort, RH) ->
%% local host. Try instead to "figure out" tha actual address...
LocalAddr = which_local_addr(),
Opts = [{port, 0}, {receive_handle, RH}],
+ i("udp transport started: attempt (udp) open"),
case megaco_udp:open(Sup, Opts) of
{ok, Handle, ControlPid} ->
MgcMid = preliminary_mid,
+ i("udp transport open: "
+ "now create send handle with MGC address: "
+ "~n ~p", [LocalAddr]),
SendHandle = megaco_udp:create_send_handle(Handle,
LocalAddr,
MgcPort),
+ i("udp transport: attempt (megaco) connect to:"
+ "~n ~p", [SendHandle]),
{ok, ConnHandle} =
megaco:connect(RH, MgcMid,
SendHandle, ControlPid),
@@ -1712,6 +1751,7 @@ get_conf(Key, Config) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Tries to find a valid local address...
which_local_addr() ->
case inet:getifaddrs() of
{ok, IFs} ->
@@ -1722,10 +1762,10 @@ which_local_addr() ->
?SKIP({failed_get_local_addr, Reason})
end.
+%% We explicitly skip some interfaces that we know is not "valid"
+%% (docker stuff)
which_local_addr([]) ->
?SKIP(failed_get_local_addr);
-which_local_addr([{"lo" = _IfName, _IfOpts}|IFs]) ->
- which_local_addr(IFs);
which_local_addr([{"br-" ++ _ = _IfName, _IfOpts}|IFs]) ->
which_local_addr(IFs);
which_local_addr([{"docker" ++ _ = _IfName, _IfOpts}|IFs]) ->
@@ -1738,14 +1778,38 @@ which_local_addr([{_IfName, IfOpts}|IFs]) ->
which_local_addr(IFs)
end.
+which_local_addr2(IfOpts) ->
+ case if_is_running(IfOpts) of
+ true ->
+ which_local_addr3(IfOpts);
+ false ->
+ error
+ end.
-which_local_addr2([]) ->
+if_is_running(If) ->
+ lists:keymember(flags, 1, If) andalso
+ begin
+ {value, {flags, Flags}} = lists:keysearch(flags, 1, If),
+ (not lists:member(loopback, Flags)) andalso lists:member(running, Flags)
+ end.
+
+which_local_addr3([]) ->
error;
-which_local_addr2([{addr, Addr}|_])
+which_local_addr3([{addr, Addr}|_])
when (size(Addr) =:= 4) andalso (element(1, Addr) =/= 127) ->
{ok, Addr};
-which_local_addr2([_|T]) ->
- which_local_addr2(T).
+which_local_addr3([_|T]) ->
+ which_local_addr3(T).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+try_tc(TCName, Pre, Case, Post) ->
+ try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
+
+try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
+ ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/megaco/test/megaco_mreq_SUITE.erl b/lib/megaco/test/megaco_mreq_SUITE.erl
index 9596389d2b..b53e99a995 100644
--- a/lib/megaco/test/megaco_mreq_SUITE.erl
+++ b/lib/megaco/test/megaco_mreq_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@
req_and_rep/1,
req_and_pending/1,
req_and_cancel/1
+
]).
-include_lib("megaco/include/megaco.hrl").
@@ -182,177 +183,198 @@ req_and_rep(suite) ->
req_and_rep(doc) ->
[];
req_and_rep(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- i("req_and_rep -> starting"),
- MgcNode = make_node_name(mgc),
- Mg1Node = make_node_name(mg1),
- Mg2Node = make_node_name(mg2),
- Mg3Node = make_node_name(mg3),
- Mg4Node = make_node_name(mg4),
- d("req_and_rep -> Nodes: "
- "~n MgcNode: ~p"
- "~n Mg1Node: ~p"
- "~n Mg2Node: ~p"
- "~n Mg3Node: ~p"
- "~n Mg4Node: ~p",
- [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
- ok = megaco_test_lib:start_nodes([MgcNode,
- Mg1Node, Mg2Node, Mg3Node, Mg4Node],
- ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ Mg1Node = make_node_name(mg1),
+ Mg2Node = make_node_name(mg2),
+ Mg3Node = make_node_name(mg3),
+ Mg4Node = make_node_name(mg4),
+ d("try start nodes: "
+ "~n MgcNode: ~p"
+ "~n Mg1Node: ~p"
+ "~n Mg2Node: ~p"
+ "~n Mg3Node: ~p"
+ "~n Mg4Node: ~p",
+ [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]),
+ Nodes = [MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_req_and_rep/1,
+ Post = fun(Nodes) ->
+ d("stop nodes (in the reverse order):"
+ "~n ~p", [Nodes]),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(req_and_rep, Pre, Case, Post).
+
+do_req_and_rep([MgcNode, Mg1Node, Mg2Node, Mg3Node, Mg4Node]) ->
%% Start the MGC and MGs
- i("req_and_rep -> start the MGC"),
+ i("start the MGC"),
ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
{ok, Mgc} =
?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
- i("req_and_rep -> start and connect the MGs"),
+ i("start and connect the MGs"),
MgConf0 = [{Mg1Node, "mg1", text, tcp, ?MG_VERBOSITY},
{Mg2Node, "mg2", text, udp, ?MG_VERBOSITY},
{Mg3Node, "mg3", binary, tcp, ?MG_VERBOSITY},
{Mg4Node, "mg4", binary, udp, ?MG_VERBOSITY}],
- MgConf = req_and_rep_connect_mg(MgConf0, []),
+ MgConf = rar_connect_mg(MgConf0, []),
%% Collect the (initial) MGs statistics
- Stats1 = req_and_rep_get_mg_stats(MgConf, []),
- d("req_and_rep -> stats for the MGs: ~n~p", [Stats1]),
+ Stats1 = rar_get_mg_stats(MgConf, []),
+ d("stats for the MGs: "
+ "~n ~p", [Stats1]),
%% Collect and check the MGC statistics
- i("req_and_rep -> collect and check the MGC stats"),
+ i("collect and check the MGC stats"),
{ok, MgcStats1} = ?MGC_GET_STATS(Mgc, 1),
- d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats1]),
+ d("stats (1) for Mgc: "
+ "~n ~p"
+ "~n", [MgcStats1]),
sleep(1000),
%% And apply some load
- i("req_and_rep -> apply traffic load"),
- ok = req_and_rep_apply_load(MgConf),
+ i("apply traffic load"),
+ ok = rar_apply_load(MgConf),
%% Await completion of load part and the collect traffic
- i("req_and_rep -> await load completion"),
- ok = req_and_rep_await_load_complete(MgConf),
+ i("await load completion"),
+ ok = rar_await_load_complete(MgConf),
sleep(1000),
- i("req_and_rep -> collect the MGs statistics"),
- Stats2 = req_and_rep_get_mg_stats(MgConf, []),
- d("req_and_rep -> stats for MGs: ~n~p", [Stats2]),
+ i("collect the MGs statistics"),
+ Stats2 = rar_get_mg_stats(MgConf, []),
+ d("stats for MGs: "
+ "~n ~p", [Stats2]),
- i("req_and_rep -> collect the MGC statistics"),
+ i("collect the MGC statistics"),
{ok, MgcStats2} = ?MGC_GET_STATS(Mgc, 1),
- d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats2]),
+ d("stats (1) for Mgc: "
+ "~n ~p"
+ "~n", [MgcStats2]),
sleep(1000),
%% Reset counters
- i("req_and_rep -> reset the MGs statistics"),
- req_and_rep_reset_mg_stats(MgConf),
- Stats3 = req_and_rep_get_mg_stats(MgConf, []),
- d("req_and_rep -> stats for the MGs: ~n~p", [Stats3]),
-
- i("req_and_rep -> reset the MGC statistics"),
- req_and_rep_reset_mgc_stats(Mgc),
+ i("reset the MGs statistics"),
+ rar_reset_mg_stats(MgConf),
+ Stats3 = rar_get_mg_stats(MgConf, []),
+ d("stats for the MGs: "
+ "~n ~p", [Stats3]),
+
+ i("reset the MGC statistics"),
+ rar_reset_mgc_stats(Mgc),
{ok, MgcStats3} = ?MGC_GET_STATS(Mgc, 1),
- d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats3]),
+ d("stats (1) for Mgc: "
+ "~n ~p"
+ "~n", [MgcStats3]),
sleep(1000),
%% Tell MGs to stop
- i("req_and_rep -> stop the MGs"),
- req_and_rep_stop_mg(MgConf),
+ i("stop the MGs"),
+ rar_stop_mg(MgConf),
sleep(1000),
%% Collect the statistics
- i("req_and_rep -> collect the MGC statistics"),
+ i("collect the MGC statistics"),
{ok, MgcStats4} = ?MGC_GET_STATS(Mgc, 1),
- d("req_and_rep -> stats (1) for Mgc: ~n~p~n", [MgcStats4]),
+ d("stats (1) for Mgc: "
+ "~n ~p", [MgcStats4]),
{ok, MgcStats5} = ?MGC_GET_STATS(Mgc, 2),
- d("req_and_rep -> stats (2) for Mgc: ~n~p~n", [MgcStats5]),
+ d("stats (2) for Mgc: "
+ "~n ~p"
+ "~n", [MgcStats5]),
%% Tell Mgc to stop
- i("req_and_rep -> stop the MGC"),
+ i("stop the MGC"),
?MGC_STOP(Mgc),
- i("req_and_rep -> done", []),
+ i("done", []),
ok.
-req_and_rep_connect_mg([], Acc) ->
+rar_connect_mg([], Acc) ->
lists:reverse(Acc);
-req_and_rep_connect_mg([{Node, Name, Coding, Trans, Verb}|Mg], Acc) ->
- Pid = req_and_rep_connect_mg(Node, Name, Coding, Trans, Verb),
- req_and_rep_connect_mg(Mg, [{Name, Pid}|Acc]).
+rar_connect_mg([{Node, Name, Coding, Trans, Verb}|Mg], Acc) ->
+ Pid = rar_connect_mg(Node, Name, Coding, Trans, Verb),
+ rar_connect_mg(Mg, [{Name, Pid}|Acc]).
-req_and_rep_connect_mg(Node, Name, Coding, Trans, Verb) ->
+rar_connect_mg(Node, Name, Coding, Trans, Verb) ->
Mid = {deviceName, Name},
{ok, Pid} = ?MG_START(Node, Mid, Coding, Trans, Verb),
%% Ask the MGs to do a service change
Res = ?MG_SERV_CHANGE(Pid),
- d("req_and_rep_connect_mg -> (~s) service change result: ~p", [Name,Res]),
+ d("rar_connect_mg -> (~s) service change result: ~p", [Name,Res]),
Pid.
-req_and_rep_stop_mg(MGs) ->
+rar_stop_mg(MGs) ->
[?MG_STOP(Pid) || {_Name, Pid} <- MGs].
-req_and_rep_get_mg_stats([], Acc) ->
+rar_get_mg_stats([], Acc) ->
lists:reverse(Acc);
-req_and_rep_get_mg_stats([{Name, Pid}|Mgs], Acc) ->
+rar_get_mg_stats([{Name, Pid}|Mgs], Acc) ->
{ok, Stats} = ?MG_GET_STATS(Pid),
- d("req_and_rep_get_mg_stats -> stats for ~s: ~n~p~n", [Name, Stats]),
- req_and_rep_get_mg_stats(Mgs, [{Name, Stats}|Acc]).
+ d("rar_get_mg_stats -> stats for ~s: "
+ "~n ~p"
+ "~n", [Name, Stats]),
+ rar_get_mg_stats(Mgs, [{Name, Stats}|Acc]).
-req_and_rep_apply_load([]) ->
+rar_apply_load([]) ->
ok;
-req_and_rep_apply_load([{_, MG}|MGs]) ->
+rar_apply_load([{_, MG}|MGs]) ->
?MG_APPLY_LOAD(MG,?LOAD_COUNTER_START),
- req_and_rep_apply_load(MGs).
+ rar_apply_load(MGs).
-req_and_rep_reset_mg_stats([]) ->
+rar_reset_mg_stats([]) ->
ok;
-req_and_rep_reset_mg_stats([{Name, Pid}|MGs]) ->
- d("req_and_rep_reset_mg_stats -> resetting ~s", [Name]),
+rar_reset_mg_stats([{Name, Pid}|MGs]) ->
+ d("rar_reset_mg_stats -> resetting ~s", [Name]),
?MG_RESET_STATS(Pid),
- req_and_rep_reset_mg_stats(MGs).
+ rar_reset_mg_stats(MGs).
-req_and_rep_reset_mgc_stats(Mgc) ->
- d("req_and_rep_reset_mgc_stats -> resetting ~p", [Mgc]),
+rar_reset_mgc_stats(Mgc) ->
+ d("rar_reset_mgc_stats -> resetting ~p", [Mgc]),
?MGC_RESET_STATS(Mgc).
-req_and_rep_await_load_complete([]) ->
+rar_await_load_complete([]) ->
ok;
-req_and_rep_await_load_complete(MGs0) ->
+rar_await_load_complete(MGs0) ->
receive
{load_complete, Pid} ->
d("received load_complete from ~p", [Pid]),
MGs1 = lists:keydelete(Pid, 2, MGs0),
- req_and_rep_await_load_complete(lists:delete(Pid, MGs1));
+ rar_await_load_complete(lists:delete(Pid, MGs1));
{'EXIT', Pid, Reason} ->
- i("exit signal from ~p: ~p", [Pid, Reason]),
+ e("exit signal from ~p: ~p", [Pid, Reason]),
case lists:keymember(Pid, 2, MGs0) of
true ->
exit({mg_exit, Pid, Reason});
false ->
MGs1 = lists:keydelete(Pid, 2, MGs0),
- req_and_rep_await_load_complete(lists:delete(Pid, MGs1))
+ rar_await_load_complete(lists:delete(Pid, MGs1))
end
end.
@@ -364,54 +386,60 @@ req_and_pending(suite) ->
req_and_pending(doc) ->
[];
req_and_pending(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- i("req_and_pending -> starting"),
-
- MgcNode = make_node_name(mgc),
- Mg1Node = make_node_name(mg1),
-
- d("req_and_pending -> Nodes: "
- "~n MgcNode: ~p"
- "~n Mg1Node: ~p",
- [MgcNode, Mg1Node]),
- ok = megaco_test_lib:start_nodes([MgcNode, Mg1Node],
- ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("try starting nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p", [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_req_and_pending/1,
+ Post = fun(Nodes) ->
+ d("stop nodes (in the reverse order):"
+ "~n ~p", [Nodes]),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(req_and_pending, Pre, Case, Post).
+
+do_req_and_pending([MgcNode, MgNode]) ->
%% Start the MGC and MGs
- i("req_and_pending -> start the MGC"),
+ i("try start the MGC"),
ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
{ok, Mgc} =
?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
- i("req_and_pending -> start the MG"),
- {ok, Mg1} =
- ?MG_START(Mg1Node, {deviceName, "mg1"}, text, tcp, ?MG_VERBOSITY),
+ i("try start the MG"),
+ {ok, Mg} =
+ ?MG_START(MgNode, {deviceName, "mg"}, text, tcp, ?MG_VERBOSITY),
- i("req_and_pending -> connect the MG"),
- Res1 = ?MG_SERV_CHANGE(Mg1),
- d("req_and_pending -> service change result: ~p", [Res1]),
+ i("connect MG (to MFC)"),
+ Res1 = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [Res1]),
sleep(1000),
- i("req_and_pending -> change request action to pending"),
- {ok, _} = ?MGC_REQ_PEND(Mgc,3500),
+ i("[MGC] change request action to pending"),
+ {ok, _} = ?MGC_REQ_PEND(Mgc, 3500),
- i("req_and_pending -> send notify request"),
- {ok, Res2} = ?MG_NOTIF_RAR(Mg1),
- d("req_and_pending -> notify reply: ~p",[Res2]),
+ i("[MG] send notify request"),
+ {ok, Res2} = ?MG_NOTIF_RAR(Mg),
+ d("notify reply: ~p", [Res2]),
sleep(1000),
- %% Tell MGs to stop
- i("req_and_rep -> stop the MGs"),
- ?MG_STOP(Mg1),
+ %% Tell MG to stop
+ i("stop the MG"),
+ ?MG_STOP(Mg),
%% Tell Mgc to stop
- i("req_and_pending -> stop the MGC"),
+ i("stop the MGC"),
?MGC_STOP(Mgc),
- i("req_and_pending -> done", []),
+ i("done", []),
ok.
@@ -423,80 +451,91 @@ req_and_cancel(suite) ->
req_and_cancel(doc) ->
[];
req_and_cancel(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- i("req_and_cancel -> starting"),
-
- MgcNode = make_node_name(mgc),
- Mg1Node = make_node_name(mg1),
-
- d("req_and_cancel -> Nodes: "
- "~n MgcNode: ~p"
- "~n Mg1Node: ~p",
- [MgcNode, Mg1Node]),
- ok = megaco_test_lib:start_nodes([MgcNode, Mg1Node],
- ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("try start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_req_and_cancel/1,
+ Post = fun(Nodes) ->
+ d("stop nodes (in the reverse order):"
+ "~n ~p", [Nodes]),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(req_and_cancel, Pre, Case, Post).
+
+do_req_and_cancel([MgcNode, MgNode]) ->
%% Start the MGC and MGs
- i("req_and_cancel -> start the MGC"),
+ i("start the MGC"),
ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
{ok, Mgc} =
?MGC_START(MgcNode, {deviceName, "ctrl"}, ET, ?MGC_VERBOSITY),
- i("req_and_cancel -> start the MG"),
- {ok, Mg1} =
- ?MG_START(Mg1Node, {deviceName, "mg1"}, text, tcp, ?MG_VERBOSITY),
+ i("start the MG"),
+ {ok, Mg} =
+ ?MG_START(MgNode, {deviceName, "mg"}, text, tcp, ?MG_VERBOSITY),
- i("req_and_cancel -> connect the MG"),
- Res1 = ?MG_SERV_CHANGE(Mg1),
- d("req_and_cancel -> service change result: ~p", [Res1]),
+ i("connect the MG"),
+ Res1 = ?MG_SERV_CHANGE(Mg),
+ d("service change result: ~p", [Res1]),
sleep(1000),
- i("req_and_cancel -> change request action to pending"),
+ i("change request action to pending"),
{ok, _} = ?MGC_REQ_DISC(Mgc,5000),
- i("req_and_cancel -> send notify request"),
- ?MG_NOTIF_REQ(Mg1),
+ i("send notify request"),
+ ?MG_NOTIF_REQ(Mg),
- d("req_and_cancel -> wait some to get it going",[]),
+ d("wait some to get it going",[]),
sleep(1000),
- i("req_and_cancel -> now cancel the notify request"),
- ok = ?MG_CANCEL(Mg1,req_and_cancel),
+ i("now cancel the notify request"),
+ ok = ?MG_CANCEL(Mg, req_and_cancel),
- i("req_and_cancel -> now await the notify request result"),
- Res2 = ?MG_NOTIF_AR(Mg1),
- req_and_cancel_analyze_result(Res2),
+ i("now await the notify request result"),
+ Res2 = ?MG_NOTIF_AR(Mg),
+ rac_analyze_result(Res2),
%% Tell MGs to stop
- i("req_and_rep -> stop the MGs"),
- ?MG_STOP(Mg1),
+ i("stop the MG"),
+ ?MG_STOP(Mg),
%% Tell Mgc to stop
- i("req_and_cancel -> stop the MGC"),
+ i("stop the MGC"),
?MGC_STOP(Mgc),
- i("req_and_cancel -> done", []),
- ok.% ?SKIP(not_implemented_yet).
+ i("done", []),
+ ok.
-req_and_cancel_analyze_result({ok,{_PV,Res}}) ->
- i("req_and_cancel -> notify request result: ~n ~p", [Res]),
- req_and_cancel_analyze_result2(Res);
-req_and_cancel_analyze_result(Unexpected) ->
- exit({unexpected_result,Unexpected}).
+rac_analyze_result({ok, {_PV,Res}}) ->
+ i("rac_analyze_result -> notify request result:"
+ "~n ~p", [Res]),
+ rac_analyze_result2(Res);
+rac_analyze_result(Unexpected) ->
+ e("rac_analyze_result -> unexpected result: "
+ "~n ~p", [Unexpected]),
+ exit({unexpected_result, Unexpected}).
-req_and_cancel_analyze_result2({error,{user_cancel,req_and_cancel}}) ->
+rac_analyze_result2({error,{user_cancel, req_and_cancel}}) ->
ok;
-req_and_cancel_analyze_result2([]) ->
+rac_analyze_result2([]) ->
ok;
-req_and_cancel_analyze_result2([{error,{user_cancel,req_and_cancel}}|Res]) ->
- req_and_cancel_analyze_result2(Res);
-req_and_cancel_analyze_result2([Unknown|_Res]) ->
- exit({unknown_result,Unknown}).
+rac_analyze_result2([{error,{user_cancel, req_and_cancel}}|Res]) ->
+ rac_analyze_result2(Res);
+rac_analyze_result2([Unknown|_Res]) ->
+ e("rac_analyze_result2 -> unexpected result: "
+ "~n ~p", [Unknown]),
+ exit({unknown_result, Unknown}).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -518,36 +557,53 @@ sleep(X) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try_tc(TCName, Pre, Case, Post) ->
+ try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
+
+try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
+ ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
p(F, A) ->
io:format("*** [~s] ~p ***"
"~n " ++ F ++ "~n",
[?FTS(), self() | A]).
+%% e(F) ->
+%% i(F, []).
+
+e(F, A) ->
+ print(info, get(verbosity), "ERROR", get(tc), F, A).
+
+
i(F) ->
i(F, []).
i(F, A) ->
- print(info, get(verbosity), "", F, A).
+ print(info, get(verbosity), "INFO", get(tc), F, A).
%% d(F) ->
%% d(F, []).
d(F, A) ->
- print(debug, get(verbosity), "DBG: ", F, A).
+ print(debug, get(verbosity), "DBG", get(tc), F, A).
printable(_, debug) -> true;
printable(info, info) -> true;
printable(_,_) -> false.
-print(Severity, Verbosity, P, F, A) ->
- print(printable(Severity,Verbosity), P, F, A).
+print(Severity, Verbosity, P, TC, F, A) ->
+ print(printable(Severity,Verbosity), P, TC, F, A).
-print(true, P, F, A) ->
- io:format("*** [~s] ~s ~p ~s ***"
+print(true, P, TC, F, A) ->
+ io:format("*** [~s] [~s] ~p ~s:~w ***"
"~n " ++ F ++ "~n",
- [?FTS(), P, self(), get(sname) | A]);
-print(_, _, _, _) ->
+ [?FTS(), P, self(), get(sname), TC | A]);
+print(_, _, _, _, _) ->
ok.
diff --git a/lib/megaco/test/megaco_pending_limit_SUITE.erl b/lib/megaco/test/megaco_pending_limit_SUITE.erl
index ca802023c2..d5db6e6bc0 100644
--- a/lib/megaco/test/megaco_pending_limit_SUITE.erl
+++ b/lib/megaco/test/megaco_pending_limit_SUITE.erl
@@ -244,7 +244,9 @@ end_per_group(_Group, Config) ->
init_per_testcase(Case, Config) ->
process_flag(trap_exit, true),
- p("init_per_suite -> entry with"
+ ?ANNOUNCE_CASE_INIT(Case),
+
+ p("init_per_testcase -> entry with"
"~n Config: ~p"
"~n Nodes: ~p", [Config, erlang:nodes()]),
@@ -284,10 +286,10 @@ sent_timer_late_reply(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -340,6 +342,10 @@ sent_timer_late_reply(Config) when is_list(Config) ->
i("[MGC] stop"),
?MGC_STOP(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -359,10 +365,10 @@ sent_timer_exceeded(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -413,6 +419,10 @@ sent_timer_exceeded(Config) when is_list(Config) ->
i("[MGC] stop"),
?MGC_STOP(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -432,10 +442,10 @@ sent_timer_exceeded_long(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -484,6 +494,10 @@ sent_timer_exceeded_long(Config) when is_list(Config) ->
i("[MGC] stop"),
?MGC_STOP(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -508,10 +522,10 @@ sent_resend_late_reply(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -573,6 +587,10 @@ sent_resend_late_reply(Config) when is_list(Config) ->
i("[MGC] stop"),
?MGC_STOP(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -608,10 +626,10 @@ sent_resend_exceeded(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -668,6 +686,10 @@ sent_resend_exceeded(Config) when is_list(Config) ->
i("[MGC] stop"),
?MGC_STOP(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -703,10 +725,10 @@ sent_resend_exceeded_long(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -764,6 +786,10 @@ sent_resend_exceeded_long(Config) when is_list(Config) ->
i("[MGC] stop"),
?MGC_STOP(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -799,10 +825,10 @@ recv_limit_exceeded1(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -842,6 +868,10 @@ recv_limit_exceeded1(Config) when is_list(Config) ->
i("[MG] stop generator"),
megaco_test_megaco_generator:stop(Mg),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -1200,10 +1230,10 @@ otp_4956(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -1243,6 +1273,10 @@ otp_4956(Config) when is_list(Config) ->
i("[MG] stop generator"),
megaco_test_tcp_generator:stop(Mg),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -1758,10 +1792,10 @@ otp_5310(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -1871,6 +1905,10 @@ otp_5310(Config) when is_list(Config) ->
i("[MGC] stop"),
?MGC_STOP(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
@@ -1921,10 +1959,10 @@ otp_5619(Config) when is_list(Config) ->
MgcNode = make_node_name(mgc),
MgNode = make_node_name(mg),
d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
[MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ ok = ?START_NODES([MgcNode, MgNode], true),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -1989,6 +2027,10 @@ otp_5619(Config) when is_list(Config) ->
i("[MGC] stop~n"),
?MGC_STOP(Mgc),
+ %% Cleanup
+ d("stop nodes"),
+ ?STOP_NODES([MgcNode, MgNode]),
+
i("done", []),
ok.
diff --git a/lib/megaco/test/megaco_segment_SUITE.erl b/lib/megaco/test/megaco_segment_SUITE.erl
index 0d3cc660f2..08b86606de 100644
--- a/lib/megaco/test/megaco_segment_SUITE.erl
+++ b/lib/megaco/test/megaco_segment_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -47,6 +47,7 @@
]).
+-include_lib("common_test/include/ct.hrl").
-include("megaco_test_lib.hrl").
-include_lib("megaco/include/megaco.hrl").
-include_lib("megaco/include/megaco_message_v3.hrl").
@@ -197,18 +198,25 @@ send_segmented_msg_plain1(doc) ->
"First plain test that it is possible to send segmented messages. "
"Send window = infinity. ";
send_segmented_msg_plain1(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, ssmp1),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_send_segmented_msg_plain1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(ssmp1, Pre, Case, Post).
+
+do_send_segmented_msg_plain1([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -792,32 +800,41 @@ ssmp1_mg_notify_reply_ar(Cid, Tid) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
send_segmented_msg_plain2(suite) ->
[];
send_segmented_msg_plain2(doc) ->
"Second plain test that it is possible to send segmented messages. "
"Send window = infinity. ";
send_segmented_msg_plain2(Config) when is_list(Config) ->
- %% <CONDITIONAL-SKIP>
- Skippable = [{unix, [linux]}],
- Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
- ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
- %% </CONDITIONAL-SKIP>
-
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, ssmp2),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ %% We leave it commented out as test
+ %% All the other changes to the framework
+ %% may have "solved" the issues...
+
+ %% <CONDITIONAL-SKIP>
+ %% Skippable = [{unix, [linux]}],
+ %% Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ %% ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_send_segmented_msg_plain2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(ssmp2, Pre, Case, Post).
+
+do_send_segmented_msg_plain2([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -1389,26 +1406,31 @@ ssmp2_mg_notify_reply_ar(Cid, Tid) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
send_segmented_msg_plain3(suite) ->
[];
send_segmented_msg_plain3(doc) ->
"Third plain test that it is possible to send segmented messages. "
"Send window = 1. ";
send_segmented_msg_plain3(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, ssmp3),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_send_segmented_msg_plain3/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(ssmp3, Pre, Case, Post).
+
+do_send_segmented_msg_plain3([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -2076,32 +2098,38 @@ ssmp3_mg_notify_reply_ar(Cid, Tid) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
send_segmented_msg_plain4(suite) ->
[];
send_segmented_msg_plain4(doc) ->
"Forth plain test that it is possible to send segmented messages. "
"Send window = 3. ";
send_segmented_msg_plain4(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, ssmp4),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Factor = ?config(megaco_factor, Config),
+ ct:timetrap(Factor * ?SECS(60)),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun(X) -> do_send_segmented_msg_plain4(Factor, X) end,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(ssmp4, Pre, Case, Post).
+
+do_send_segmented_msg_plain4(Factor, [MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
d("[MGC] create the event sequence"),
- MgcEvSeq = ssmp4_mgc_event_sequence(text, tcp),
+ MgcEvSeq = ssmp4_mgc_event_sequence(Factor, text, tcp),
i("wait some time before starting the MGC simulation"),
sleep(1000),
@@ -2116,7 +2144,7 @@ send_segmented_msg_plain4(Config) when is_list(Config) ->
{ok, Mg} = megaco_test_megaco_generator:start_link("MG", MgNode),
d("[MG] create the event sequence"),
- MgEvSeq = ssmp4_mg_event_sequence(text, tcp),
+ MgEvSeq = ssmp4_mg_event_sequence(Factor, text, tcp),
i("wait some time before starting the MG simulation"),
sleep(1000),
@@ -2144,7 +2172,7 @@ send_segmented_msg_plain4(Config) when is_list(Config) ->
%% MGC generator stuff
%%
-ssmp4_mgc_event_sequence(text, tcp) ->
+ssmp4_mgc_event_sequence(Factor, text, tcp) ->
DecodeFun = ssmp4_mgc_decode_msg_fun(megaco_pretty_text_encoder, []),
EncodeFun = ssmp4_mgc_encode_msg_fun(megaco_pretty_text_encoder, []),
Mid = {deviceName,"mgc"},
@@ -2213,33 +2241,38 @@ ssmp4_mgc_event_sequence(text, tcp) ->
SegmentRep7 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 7, false),
SegmentRep8 = ssmp4_mgc_segment_reply_msg(Mid, TransId, 8, true),
TransAck = ssmp4_mgc_trans_ack_msg(Mid, TransId),
+ TO = fun(T) -> Factor*T end,
EvSeq = [{debug, true},
+ {trigger, "verbosity",
+ fun() ->
+ put(verbosity, ?TEST_VERBOSITY)
+ end},
{decode, DecodeFun},
{encode, EncodeFun},
{listen, 2944},
{expect_accept, any},
- {expect_receive, "service-change-request", {ScrVerifyFun, 5000}},
+ {expect_receive, "service-change-request", {ScrVerifyFun, TO(5000)}},
{send, "service-change-reply", ServiceChangeRep},
{expect_nothing, 1000},
{send, "notify request", NotifyReq},
- {expect_receive, "notify reply: segment 1", {NrVerifyFun1, 1000}},
- {expect_receive, "notify reply: segment 2", {NrVerifyFun2, 1000}},
- {expect_receive, "notify reply: segment 3", {NrVerifyFun3, 1000}},
+ {expect_receive, "notify reply: segment 1", {NrVerifyFun1, TO(1000)}},
+ {expect_receive, "notify reply: segment 2", {NrVerifyFun2, TO(1000)}},
+ {expect_receive, "notify reply: segment 3", {NrVerifyFun3, TO(1000)}},
{expect_nothing, 1000},
{send, "segment reply 1", SegmentRep1},
- {expect_receive, "notify reply: segment 4", {NrVerifyFun4, 1000}},
+ {expect_receive, "notify reply: segment 4", {NrVerifyFun4, TO(1000)}},
{expect_nothing, 1000},
{send, "segment reply 2", SegmentRep2},
- {expect_receive, "notify reply: segment 5", {NrVerifyFun5, 1000}},
+ {expect_receive, "notify reply: segment 5", {NrVerifyFun5, TO(1000)}},
{expect_nothing, 1000},
{send, "segment reply 3", SegmentRep3},
- {expect_receive, "notify reply: segment 6", {NrVerifyFun6, 1000}},
+ {expect_receive, "notify reply: segment 6", {NrVerifyFun6, TO(1000)}},
{expect_nothing, 1000},
{send, "segment reply 4", SegmentRep4},
- {expect_receive, "notify reply: segment 7", {NrVerifyFun7, 1000}},
+ {expect_receive, "notify reply: segment 7", {NrVerifyFun7, TO(1000)}},
{expect_nothing, 1000},
{send, "segment reply 5", SegmentRep5},
- {expect_receive, "notify reply: segment 8", {NrVerifyFun8, 1000}},
+ {expect_receive, "notify reply: segment 8", {NrVerifyFun8, TO(1000)}},
{expect_nothing, 1000},
{send, "segment reply 6", SegmentRep6},
{expect_nothing, 1000},
@@ -2506,7 +2539,7 @@ ssmp4_mgc_trans_ack_msg(Mid, TransId) ->
%%
%% MG generator stuff
%%
-ssmp4_mg_event_sequence(text, tcp) ->
+ssmp4_mg_event_sequence(Factor, text, tcp) ->
Mid = {deviceName,"mg"},
RI = [
{port, 2944},
@@ -2527,7 +2560,8 @@ ssmp4_mg_event_sequence(text, tcp) ->
Tid8 = #megaco_term_id{id = ["00000000","00000000","00000008"]},
Tids = [Tid1, Tid2, Tid3, Tid4, Tid5, Tid6, Tid7, Tid8],
NotifyReqVerify = ssmp4_mg_verify_notify_request_fun(Tids),
- AckVerify = ssmp4_mg_verify_ack_fun(),
+ AckVerify = ssmp4_mg_verify_ack_fun(),
+ TO = fun(T) -> Factor*T end,
EvSeq = [
{debug, true},
{megaco_trace, disable},
@@ -2548,7 +2582,7 @@ ssmp4_mg_event_sequence(text, tcp) ->
{megaco_update_conn_info, max_pdu_size, 128},
{sleep, 1000},
{megaco_callback, handle_trans_request, NotifyReqVerify},
- {megaco_callback, handle_trans_ack, AckVerify, 15000},
+ {megaco_callback, handle_trans_ack, AckVerify, TO(15000)},
megaco_stop_user,
megaco_stop,
{sleep, 1000}
@@ -2636,30 +2670,34 @@ ssmp4_mg_verify_notify_request_fun(Tids) ->
ssmp4_mg_verify_notify_request(
{handle_trans_request, _CH, ?VERSION, ARs}, Tids)
- when length(ARs) == length(Tids) ->
+ when length(ARs) =:= length(Tids) ->
(catch ssmp4_mg_do_verify_notify_request(Tids, ARs));
ssmp4_mg_verify_notify_request(
{handle_trans_request, _CH, ?VERSION, ARs}, _Tids) ->
+ e("MG Notify Request verification failed: invalid action requests"
+ "~n ARs: ~p", [ARs]),
{error, {invalid_action_requests, ARs}, ok};
ssmp4_mg_verify_notify_request(
{handle_trans_request, CH, V, ARs}, _Tids) ->
+ e("MG Notify Request verification failed: invalid trans request"
+ "~n CH: ~p"
+ "~n V: ~p"
+ "~n ARs: ~p", [CH, V, ARs]),
{error, {invalid_trans_request, {CH, V, ARs}}, ok};
ssmp4_mg_verify_notify_request(Crap, _Tids) ->
- io:format("ssmp4_mg_verify_notify_request -> unknown request"
- "~n Crap: ~p"
- "~n Tids: ~p"
- "~n", [Crap, _Tids]),
+ e("MG Notify Request verification failed: unknown request"
+ "~n Crap: ~p"
+ "~n Tids: ~p", [Crap, _Tids]),
{error, {unexpected_event, Crap}, ok}.
ssmp4_mg_do_verify_notify_request(Tids, ARs) ->
- io:format("ssmp4_mg_do_verify_notify_request -> ok"
- "~n Tids: ~p"
- "~n ARs: ~p"
- "~n", [Tids, ARs]),
+ p("MG Notify Request verification - attempt verify action request(s):"
+ "~n Tids: ~p"
+ "~n ARs: ~p", [Tids, ARs]),
ActionReplies = ssmp4_mg_do_verify_notify_request_ars(Tids, ARs),
- io:format("ssmp4_mg_do_verify_notify_request -> ok"
- "~n ActionReplies: ~p"
- "~n", [ActionReplies]),
+ p("MG Notify Request verification - ok"
+ "~n ActionReplies: ~p"
+ "~n", [ActionReplies]),
Reply = {{handle_ack, ssmp4}, ActionReplies},
{ok, ARs, Reply}.
@@ -2673,10 +2711,9 @@ ssmp4_mg_do_verify_notify_request_ars([Tid|Tids], [AR|ARs], Acc) ->
ssmp4_mg_do_verify_notify_request_ars(Tids, ARs, [ActionReply|Acc]).
ssmp4_mg_do_verify_notify_request_ar(Tid, AR) ->
- io:format("ssmp4_mg_do_verify_notify_request_ar -> ok"
- "~n Tid: ~p"
- "~n AR: ~p"
- "~n", [Tid, AR]),
+ p("ssmp4_mg_do_verify_notify_request_ar -> ok"
+ "~n Tid: ~p"
+ "~n AR: ~p", [Tid, AR]),
{Cid, CR} =
case AR of
#'ActionRequest'{contextId = CtxId,
@@ -2755,8 +2792,6 @@ ssmp4_mg_notify_reply_ar(Cid, Tid) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
send_segmented_msg_ooo1(suite) ->
[];
send_segmented_msg_ooo1(doc) ->
@@ -2765,20 +2800,27 @@ send_segmented_msg_ooo1(doc) ->
"segment reply is sent out-of-order. "
"Send window = 3. ";
send_segmented_msg_ooo1(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, ssmo1),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
- d("[MGC] start the simulator "),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_send_segmented_msg_ooo1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(ssmo1, Pre, Case, Post).
+
+do_send_segmented_msg_ooo1([MgcNode, MgNode]) ->
+
+ d("[MGC] start the simulator"),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
d("[MGC] create the event sequence"),
@@ -3436,8 +3478,6 @@ ssmo1_mg_notify_reply_ar(Cid, Tid) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
send_segmented_msg_missing_seg_reply1(suite) ->
[];
send_segmented_msg_missing_seg_reply1(doc) ->
@@ -3446,18 +3486,25 @@ send_segmented_msg_missing_seg_reply1(doc) ->
"when a segment reply goes missing. Ack expected. "
"Send window = 3. ";
send_segmented_msg_missing_seg_reply1(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, ssmmsr1),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_send_segmented_msg_missing_seg_reply1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(ssmmsr1, Pre, Case, Post).
+
+do_send_segmented_msg_missing_seg_reply1([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -3613,6 +3660,10 @@ ssmmsr1_mgc_event_sequence(text, tcp) ->
TransAck = ssmmsr1_mgc_trans_ack_msg(Mid, TransId),
ReadyForSegments = ssmmsr1_mgc_ready_for_segments_fun(),
EvSeq = [{debug, true},
+ {trigger, "verbosity",
+ fun() ->
+ put(verbosity, ?TEST_VERBOSITY)
+ end},
{decode, DecodeFun},
{encode, EncodeFun},
{listen, 2944},
@@ -3942,6 +3993,10 @@ ssmmsr1_mg_event_sequence(text, tcp) ->
ReadyForSegments = ssmmsr1_mg_ready_for_segments_fun(),
EvSeq = [
{debug, true},
+ {trigger,
+ fun() ->
+ put(verbosity, ?TEST_VERBOSITY)
+ end},
{megaco_trace, disable},
%% {megaco_trace, max},
megaco_start,
@@ -4202,8 +4257,6 @@ ssmmsr1_mg_notify_reply_ar(Cid, Tid) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-
send_segmented_msg_missing_seg_reply2(suite) ->
[];
send_segmented_msg_missing_seg_reply2(doc) ->
@@ -4212,18 +4265,25 @@ send_segmented_msg_missing_seg_reply2(doc) ->
"when a segment reply goes missing. Ack expected. "
"Send window = 1. ";
send_segmented_msg_missing_seg_reply2(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, ssmmsr2),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_send_segmented_msg_missing_seg_reply2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(ssmmsr2, Pre, Case, Post).
+
+do_send_segmented_msg_missing_seg_reply2([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -4353,6 +4413,10 @@ ssmmsr2_mgc_event_sequence(text, tcp) ->
SegmentRep1 = ssmmsr2_mgc_segment_reply_msg(Mid, TransId, 1, false),
ReadyForSegments = ssmmsr2_mgc_ready_for_segments_fun(),
EvSeq = [{debug, true},
+ {trigger, "verbosity",
+ fun() ->
+ put(verbosity, ?TEST_VERBOSITY)
+ end},
{decode, DecodeFun},
{encode, EncodeFun},
{listen, 2944},
@@ -4661,6 +4725,10 @@ ssmmsr2_mg_event_sequence(text, tcp) ->
ReadyForSegments = ssmmsr2_mg_ready_for_segments_fun(),
EvSeq = [
{debug, true},
+ {trigger,
+ fun() ->
+ put(verbosity, ?TEST_VERBOSITY)
+ end},
{megaco_trace, disable},
%% {megaco_trace, max},
megaco_start,
@@ -4952,18 +5020,25 @@ recv_segmented_msg_plain(suite) ->
recv_segmented_msg_plain(doc) ->
"Received segmented megaco message [plain]";
recv_segmented_msg_plain(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rsmp),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_recv_segmented_msg_plain/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rsmp, Pre, Case, Post).
+
+do_recv_segmented_msg_plain([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -5621,18 +5696,25 @@ recv_segmented_msg_ooo_seg(suite) ->
recv_segmented_msg_ooo_seg(doc) ->
"Received segmented megaco message [out-of-order segments]";
recv_segmented_msg_ooo_seg(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rsmos),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_recv_segmented_msg_ooo_seg/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rsmos, Pre, Case, Post).
+
+do_recv_segmented_msg_ooo_seg([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -6288,18 +6370,25 @@ recv_segmented_msg_missing_seg1(doc) ->
"Received segmented megaco message with one segment missing "
"using plain integer recv segment timer";
recv_segmented_msg_missing_seg1(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rsmms1),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_recv_segmented_msg_missing_seg1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rsmms1, Pre, Case, Post).
+
+do_recv_segmented_msg_missing_seg1([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -6956,18 +7045,25 @@ recv_segmented_msg_missing_seg2(doc) ->
"Received segmented megaco message with one segment missing "
"using incremental recv segment timer";
recv_segmented_msg_missing_seg2(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, rsmms2),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MgcNode: ~p"
- "~n MgNode: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MgcNode: ~p"
+ "~n MgNode: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_recv_segmented_msg_missing_seg2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rsmms2, Pre, Case, Post).
+
+do_recv_segmented_msg_missing_seg2([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_tcp_generator:start_link("MGC", MgcNode),
@@ -7828,40 +7924,65 @@ sleep(X) -> receive after X -> ok end.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try_tc(TCName, Pre, Case, Post) ->
+ try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
+
+try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
+ ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
p(F, A) ->
io:format("*** [~s] ~p ***"
"~n " ++ F ++ "~n",
[?FTS(), self() | A]).
+%% e(F) ->
+%% e(F, []).
+
+e(F, A) ->
+ print(error, get(verbosity), "ERROR", get(tc), F, A).
+
+
i(F) ->
i(F, []).
i(F, A) ->
- print(info, get(verbosity), get(tc), "INF", F, A).
+ print(info, get(verbosity), "INFO", get(tc), F, A).
d(F) ->
d(F, []).
d(F, A) ->
- print(debug, get(verbosity), get(tc), "DBG", F, A).
+ print(debug, get(verbosity), "DBG", get(tc), F, A).
printable(_, debug) -> true;
printable(info, info) -> true;
+printable(error, _) -> true;
printable(_,_) -> false.
-print(Severity, Verbosity, Tc, P, F, A) ->
- print(printable(Severity, Verbosity), Tc, P, F, A).
+print(Severity, Verbosity, P, TC, F, A) ->
+ print(printable(Severity, Verbosity), P, TC, F, A).
-print(true, Tc, P, F, A) ->
- io:format("*** [~s] ~s ~p ~s:~w ***"
- "~n " ++ F ++ "~n",
- [?FTS(), P, self(), get(sname), Tc | A]);
+print(true, P, TC, F, A) when (TC =:= undefined) ->
+ print(P, "", F, A);
+print(true, P, TC, F, A) when is_atom(TC) ->
+ print(P, ":" ++ atom_to_list(TC), F, A);
+print(true, P, TC, F, A) when is_list(TC) ->
+ print(P, TC, F, A);
print(_, _, _, _, _) ->
ok.
+print(P, TCStr, F, A) ->
+ io:format("*** [~s] ~s ~p ~s~s ***"
+ "~n " ++ F ++ "~n",
+ [?FTS(), P, self(), get(sname), TCStr | A]).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
diff --git a/lib/megaco/test/megaco_tcp_SUITE.erl b/lib/megaco/test/megaco_tcp_SUITE.erl
index 5981e34f19..5792c6b380 100644
--- a/lib/megaco/test/megaco_tcp_SUITE.erl
+++ b/lib/megaco/test/megaco_tcp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -30,8 +30,6 @@
-include_lib("megaco/src/tcp/megaco_tcp.hrl").
-include("megaco_test_lib.hrl").
-%% -compile(export_all).
-
%%----------------------------------------------------------------------
%% External exports
@@ -69,14 +67,14 @@
%% Macros
%%----------------------------------------------------------------------
+-define(CH, megaco_test_command_handler).
+-define(TEST_VERBOSITY, debug).
+
+
%%----------------------------------------------------------------------
%% Records
%%----------------------------------------------------------------------
--record(command, {id, desc, cmd}).
--record(server, {parent, transport_ref, control_pid, handle}).
--record(client, {parent, transport_ref, control_pid, handle}).
-
%%======================================================================
%% Common Test interface functions
@@ -248,17 +246,22 @@ start_and_stop(doc) ->
["This test case sets up a connection and then cloises it. "
"No data is sent. "];
start_and_stop(Config) when is_list(Config) ->
- put(sname, "start_and_stop"),
- p("BEGIN TEST-CASE"),
-
- process_flag(trap_exit, true),
-
- p("create nodes"),
- ServerNode = make_node_name(server),
- ClientNode = make_node_name(client),
- Nodes = [ServerNode, ClientNode],
- ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
-
+ Pre = fun() ->
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_start_and_stop/1,
+ Post = fun(Nodes) ->
+ p("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(start_and_stop, Pre, Case, Post).
+
+do_start_and_stop([ServerNode, ClientNode]) ->
%% Create command sequences
p("create command sequences"),
ServerPort = 2944,
@@ -275,7 +278,7 @@ start_and_stop(Config) when is_list(Config) ->
await_server_listening(Server, Client),
- await_command_handler_completion([Server, Client], timer:seconds(20)),
+ ok = await_command_handler_completion([Server, Client], ?SECS(20)),
p("done"),
ok.
@@ -284,41 +287,41 @@ start_and_stop_server_commands(Port) ->
Opts = [{port, Port}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#server{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- server_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Listen",
- cmd = fun(State) ->
- server_listen(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Notify listening",
- cmd = fun(State) ->
- server_notify_listening(State)
- end},
-
- #command{id = 5,
- desc = "Await nothing",
- cmd = fun(State) ->
- server_await_nothing(State, 6000)
- end},
-
- #command{id = 6,
- desc = "Stop",
- cmd = fun(State) ->
- server_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Listen",
+ cmd => fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Notify listening",
+ cmd => fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #{id => 5,
+ desc => "Await nothing",
+ cmd => fun(State) ->
+ server_await_nothing(State, 6000)
+ end},
+
+ #{id => 6,
+ desc => "Stop",
+ cmd => fun(State) ->
+ server_stop_transport(State)
+ end}
].
@@ -327,47 +330,47 @@ start_and_stop_client_commands(ServerPort, ServerHost) ->
Opts = [{port, ServerPort}, {host, ServerHost}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#client{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- client_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Await continue",
- cmd = fun(State) ->
- client_await_continue_signal(State, 5000)
- end},
-
- #command{id = 4,
- desc = "Connect",
- cmd = fun(State) ->
- client_connect(State, Opts)
- end},
-
- #command{id = 5,
- desc = "Await nothing",
- cmd = fun(State) ->
- client_await_nothing(State, 5000)
- end},
-
- #command{id = 6,
- desc = "Disconnect",
- cmd = fun(State) ->
- client_disconnect(State)
- end},
-
- #command{id = 7,
- desc = "Stop transport",
- cmd = fun(State) ->
- client_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Await continue",
+ cmd => fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #{id => 4,
+ desc => "Connect",
+ cmd => fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #{id => 5,
+ desc => "Await nothing",
+ cmd => fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #{id => 6,
+ desc => "Disconnect",
+ cmd => fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #{id => 7,
+ desc => "Stop transport",
+ cmd => fun(State) ->
+ client_stop_transport(State)
+ end}
].
@@ -378,17 +381,22 @@ start_and_stop_client_commands(ServerPort, ServerHost) ->
sendreceive(suite) ->
[];
sendreceive(Config) when is_list(Config) ->
- put(sname, "sendreceive"),
- p("BEGIN TEST-CASE"),
-
- process_flag(trap_exit, true),
-
- p("create nodes"),
- ServerNode = make_node_name(server),
- ClientNode = make_node_name(client),
- Nodes = [ServerNode, ClientNode],
- ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
-
+ Pre = fun() ->
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_sendreceive/1,
+ Post = fun(Nodes) ->
+ p("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(sendreceive, Pre, Case, Post).
+
+do_sendreceive([ServerNode, ClientNode]) ->
%% Create command sequences
p("create command sequences"),
ServerPort = 2944,
@@ -405,7 +413,7 @@ sendreceive(Config) when is_list(Config) ->
await_server_listening(Server, Client),
- await_command_handler_completion([Server, Client], timer:seconds(20)),
+ ok = await_command_handler_completion([Server, Client], ?SECS(20)),
p("done"),
ok.
@@ -414,83 +422,83 @@ sendreceive_server_commands(Port) ->
Opts = [{port, Port}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#server{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- server_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Listen",
- cmd = fun(State) ->
- server_listen(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Notify listening",
- cmd = fun(State) ->
- server_notify_listening(State)
- end},
-
- #command{id = 5,
- desc = "Await initial message (ping)",
- cmd = fun(State) ->
- server_await_initial_message(State, "ping", 5000)
- end},
-
- #command{id = 6,
- desc = "Send reply (pong) to initial message",
- cmd = fun(State) ->
- server_send_message(State, "pong")
- end},
-
- #command{id = 7,
- desc = "Await nothing before sending a message (hejsan)",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 8,
- desc = "Send message (hejsan)",
- cmd = fun(State) ->
- server_send_message(State, "hejsan")
- end},
-
- #command{id = 9,
- desc = "Await reply (hoppsan) to message",
- cmd = fun(State) ->
- server_await_message(State, "hoppsan", 1000)
- end},
-
- #command{id = 10,
- desc = "Await nothing before disconnecting",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 11,
- desc = "Disconnect",
- cmd = fun(State) ->
- server_disconnect(State)
- end},
-
- #command{id = 12,
- desc = "Await nothing before stopping transport",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 13,
- desc = "Stop",
- cmd = fun(State) ->
- server_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Listen",
+ cmd => fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Notify listening",
+ cmd => fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #{id => 5,
+ desc => "Await initial message (ping)",
+ cmd => fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #{id => 6,
+ desc => "Send reply (pong) to initial message",
+ cmd => fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #{id => 7,
+ desc => "Await nothing before sending a message (hejsan)",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 8,
+ desc => "Send message (hejsan)",
+ cmd => fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #{id => 9,
+ desc => "Await reply (hoppsan) to message",
+ cmd => fun(State) ->
+ server_await_message(State, "hoppsan", 1000)
+ end},
+
+ #{id => 10,
+ desc => "Await nothing before disconnecting",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 11,
+ desc => "Disconnect",
+ cmd => fun(State) ->
+ server_disconnect(State)
+ end},
+
+ #{id => 12,
+ desc => "Await nothing before stopping transport",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 13,
+ desc => "Stop",
+ cmd => fun(State) ->
+ server_stop_transport(State)
+ end}
].
@@ -498,77 +506,77 @@ sendreceive_client_commands(ServerPort, ServerHost) ->
Opts = [{port, ServerPort}, {host, ServerHost}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#client{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- client_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Await continue",
- cmd = fun(State) ->
- client_await_continue_signal(State, 5000)
- end},
-
- #command{id = 4,
- desc = "Connect",
- cmd = fun(State) ->
- client_connect(State, Opts)
- end},
-
- #command{id = 5,
- desc = "Send initial message (ping)",
- cmd = fun(State) ->
- client_send_message(State, "ping")
- end},
-
- #command{id = 6,
- desc = "Await reply (pong) to initial message",
- cmd = fun(State) ->
- client_await_message(State, "pong", 1000)
- end},
-
- #command{id = 7,
- desc = "Await message (hejsan)",
- cmd = fun(State) ->
- client_await_message(State, "hejsan", 5000)
- end},
-
- #command{id = 8,
- desc = "Send reply (hoppsan) to message",
- cmd = fun(State) ->
- client_send_message(State, "hoppsan")
- end},
-
- #command{id = 9,
- desc = "Await nothing before disconnecting",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 10,
- desc = "Disconnect",
- cmd = fun(State) ->
- client_disconnect(State)
- end},
-
- #command{id = 11,
- desc = "Await nothing before stopping transport",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 12,
- desc = "Stop transport",
- cmd = fun(State) ->
- client_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Await continue",
+ cmd => fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #{id => 4,
+ desc => "Connect",
+ cmd => fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #{id => 5,
+ desc => "Send initial message (ping)",
+ cmd => fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #{id => 6,
+ desc => "Await reply (pong) to initial message",
+ cmd => fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #{id => 7,
+ desc => "Await message (hejsan)",
+ cmd => fun(State) ->
+ client_await_message(State, "hejsan", 5000)
+ end},
+
+ #{id => 8,
+ desc => "Send reply (hoppsan) to message",
+ cmd => fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #{id => 9,
+ desc => "Await nothing before disconnecting",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 10,
+ desc => "Disconnect",
+ cmd => fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #{id => 11,
+ desc => "Await nothing before stopping transport",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 12,
+ desc => "Stop transport",
+ cmd => fun(State) ->
+ client_stop_transport(State)
+ end}
].
@@ -578,17 +586,22 @@ sendreceive_client_commands(ServerPort, ServerHost) ->
block_unblock(suite) ->
[];
block_unblock(Config) when is_list(Config) ->
- put(sname, "block_unblock"),
- p("BEGIN TEST-CASE"),
-
- process_flag(trap_exit, true),
-
- p("create nodes"),
- ServerNode = make_node_name(server),
- ClientNode = make_node_name(client),
- Nodes = [ServerNode, ClientNode],
- ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
-
+ Pre = fun() ->
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_block_unblock/1,
+ Post = fun(Nodes) ->
+ p("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(block_unblock, Pre, Case, Post).
+
+do_block_unblock([ServerNode, ClientNode]) ->
%% Create command sequences
p("create command sequences"),
ServerPort = 2944,
@@ -607,7 +620,7 @@ block_unblock(Config) when is_list(Config) ->
await_client_blocked(Server, Client),
- await_command_handler_completion([Server, Client], timer:seconds(30)),
+ ok = await_command_handler_completion([Server, Client], ?SECS(30)),
p("done"),
ok.
@@ -616,89 +629,89 @@ block_unblock_server_commands(Port) ->
Opts = [{port, Port}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#server{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- server_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Listen",
- cmd = fun(State) ->
- server_listen(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Notify listening",
- cmd = fun(State) ->
- server_notify_listening(State)
- end},
-
- #command{id = 5,
- desc = "Await initial message (ping)",
- cmd = fun(State) ->
- server_await_initial_message(State, "ping", 5000)
- end},
-
- #command{id = 6,
- desc = "Send reply (pong) to initial message",
- cmd = fun(State) ->
- server_send_message(State, "pong")
- end},
-
- #command{id = 7,
- desc = "Await continue",
- cmd = fun(State) ->
- server_await_continue_signal(State, 5000)
- end},
-
- #command{id = 9,
- desc = "Await nothing before sending a message (hejsan)",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 10,
- desc = "Send message (hejsan)",
- cmd = fun(State) ->
- server_send_message(State, "hejsan")
- end},
-
- #command{id = 11,
- desc = "Await reply (hoppsan) to message",
- cmd = fun(State) ->
- server_await_message(State, "hoppsan", 10000)
- end},
-
- #command{id = 12,
- desc = "Await nothing before disconnecting",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 13,
- desc = "Disconnect",
- cmd = fun(State) ->
- server_disconnect(State)
- end},
-
- #command{id = 14,
- desc = "Await nothing before stopping transport",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 15,
- desc = "Stop",
- cmd = fun(State) ->
- server_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Listen",
+ cmd => fun(State) ->
+ server_listen(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Notify listening",
+ cmd => fun(State) ->
+ server_notify_listening(State)
+ end},
+
+ #{id => 5,
+ desc => "Await initial message (ping)",
+ cmd => fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #{id => 6,
+ desc => "Send reply (pong) to initial message",
+ cmd => fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #{id => 7,
+ desc => "Await continue",
+ cmd => fun(State) ->
+ server_await_continue_signal(State, 5000)
+ end},
+
+ #{id => 9,
+ desc => "Await nothing before sending a message (hejsan)",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 10,
+ desc => "Send message (hejsan)",
+ cmd => fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #{id => 11,
+ desc => "Await reply (hoppsan) to message",
+ cmd => fun(State) ->
+ server_await_message(State, "hoppsan", 10000)
+ end},
+
+ #{id => 12,
+ desc => "Await nothing before disconnecting",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 13,
+ desc => "Disconnect",
+ cmd => fun(State) ->
+ server_disconnect(State)
+ end},
+
+ #{id => 14,
+ desc => "Await nothing before stopping transport",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 15,
+ desc => "Stop",
+ cmd => fun(State) ->
+ server_stop_transport(State)
+ end}
].
@@ -706,107 +719,107 @@ block_unblock_client_commands(ServerPort, ServerHost) ->
Opts = [{port, ServerPort}, {host, ServerHost}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#client{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- client_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Await continue",
- cmd = fun(State) ->
- client_await_continue_signal(State, 5000)
- end},
-
- #command{id = 4,
- desc = "Connect",
- cmd = fun(State) ->
- client_connect(State, Opts)
- end},
-
- #command{id = 5,
- desc = "Send initial message (ping)",
- cmd = fun(State) ->
- client_send_message(State, "ping")
- end},
-
- #command{id = 6,
- desc = "Await reply (pong) to initial message",
- cmd = fun(State) ->
- client_await_message(State, "pong", 1000)
- end},
-
- #command{id = 7,
- desc = "Await nothing before blocking",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 8,
- desc = "Block",
- cmd = fun(State) ->
- client_block(State)
- end},
-
- #command{id = 9,
- desc = "Notify blocked",
- cmd = fun(State) ->
- client_notify_blocked(State)
- end},
-
- #command{id = 10,
- desc = "Await nothing before unblocking",
- cmd = fun(State) ->
- client_await_nothing(State, 5000)
- end},
-
- #command{id = 11,
- desc = "Unblock",
- cmd = fun(State) ->
- client_unblock(State)
- end},
-
- #command{id = 12,
- desc = "Await message (hejsan)",
- cmd = fun(State) ->
- client_await_message(State, "hejsan", 100)
- end},
-
- #command{id = 13,
- desc = "Send reply (hoppsan) to message",
- cmd = fun(State) ->
- client_send_message(State, "hoppsan")
- end},
-
- #command{id = 14,
- desc = "Await nothing before disconnecting",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 15,
- desc = "Disconnect",
- cmd = fun(State) ->
- client_disconnect(State)
- end},
-
- #command{id = 16,
- desc = "Await nothing before stopping transport",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 17,
- desc = "Stop transport",
- cmd = fun(State) ->
- client_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Await continue",
+ cmd => fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #{id => 4,
+ desc => "Connect",
+ cmd => fun(State) ->
+ client_connect(State, Opts)
+ end},
+
+ #{id => 5,
+ desc => "Send initial message (ping)",
+ cmd => fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #{id => 6,
+ desc => "Await reply (pong) to initial message",
+ cmd => fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #{id => 7,
+ desc => "Await nothing before blocking",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 8,
+ desc => "Block",
+ cmd => fun(State) ->
+ client_block(State)
+ end},
+
+ #{id => 9,
+ desc => "Notify blocked",
+ cmd => fun(State) ->
+ client_notify_blocked(State)
+ end},
+
+ #{id => 10,
+ desc => "Await nothing before unblocking",
+ cmd => fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #{id => 11,
+ desc => "Unblock",
+ cmd => fun(State) ->
+ client_unblock(State)
+ end},
+
+ #{id => 12,
+ desc => "Await message (hejsan)",
+ cmd => fun(State) ->
+ client_await_message(State, "hejsan", 100)
+ end},
+
+ #{id => 13,
+ desc => "Send reply (hoppsan) to message",
+ cmd => fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #{id => 14,
+ desc => "Await nothing before disconnecting",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 15,
+ desc => "Disconnect",
+ cmd => fun(State) ->
+ client_disconnect(State)
+ end},
+
+ #{id => 16,
+ desc => "Await nothing before stopping transport",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 17,
+ desc => "Stop transport",
+ cmd => fun(State) ->
+ client_stop_transport(State)
+ end}
].
@@ -956,7 +969,11 @@ await_server_listening(Server, Client) ->
"send continue to client [~p]"
"~n", [Server, Client]),
Client ! {continue, self()},
- ok
+ ok;
+ {'EXIT', Server, SReason} ->
+ exit({server_crash, SReason});
+ {'EXIT', Client, CReason} ->
+ exit({client_crash, CReason})
after 5000 ->
%% There is no normal reason why this should take any time.
%% Normally, this takes a few milli seconds. So, if we are not
@@ -973,7 +990,11 @@ await_client_blocked(Server, Client) ->
p("received blocked message from client [~p] => "
"send continue to server [~p]~n", [Client, Server]),
Server ! {continue, self()},
- ok
+ ok;
+ {'EXIT', Client, CReason} ->
+ exit({client_crash, CReason});
+ {'EXIT', Server, SReason} ->
+ exit({server_crash, SReason})
after 5000 ->
%% There is no normal reason why this should take any time.
%% Normally, this takes a few milli seconds. So, if we are not
@@ -988,18 +1009,18 @@ await_client_blocked(Server, Client) ->
%% ------- Server command handler and utility functions ----------
server_start_command_handler(Node, Commands) ->
- start_command_handler(Node, Commands, #server{}, "server").
+ start_command_handler(Node, Commands, #{}, "server").
-server_start_transport(State) when is_record(State, server) ->
+server_start_transport(State) when is_map(State) ->
case (catch megaco_tcp:start_transport()) of
{ok, Ref} ->
- {ok, State#server{transport_ref = Ref}};
+ {ok, State#{transport_ref => Ref}};
Error ->
Error
end.
-server_listen(#server{transport_ref = Ref} = State, Options)
- when is_record(State, server) andalso is_list(Options) ->
+server_listen(#{transport_ref := Ref} = State, Options)
+ when is_list(Options) ->
Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
case (catch megaco_tcp:listen(Ref, Opts)) of
ok ->
@@ -1008,12 +1029,11 @@ server_listen(#server{transport_ref = Ref} = State, Options)
Error
end.
-server_notify_listening(#server{parent = Parent} = State)
- when is_record(State, server) ->
+server_notify_listening(#{parent := Parent} = State) ->
Parent ! {listening, self()},
{ok, State}.
-server_await_continue_signal(#server{parent = Parent} = State, Timeout) ->
+server_await_continue_signal(#{parent := Parent} = State, Timeout) ->
receive
{continue, Parent} ->
{ok, State}
@@ -1022,11 +1042,11 @@ server_await_continue_signal(#server{parent = Parent} = State, Timeout) ->
end.
server_await_initial_message(State, InitialMessage, Timeout)
- when is_record(State, server) ->
+ when is_map(State) ->
receive
{receive_message, {ControlPid, Handle, InitialMessage}} ->
- NewState = State#server{control_pid = ControlPid,
- handle = Handle},
+ NewState = State#{control_pid => ControlPid,
+ handle => Handle},
{ok, NewState};
Any ->
@@ -1037,12 +1057,12 @@ server_await_initial_message(State, InitialMessage, Timeout)
{error, timeout}
end.
-server_send_message(#server{handle = Handle} = State, Message) ->
+server_send_message(#{handle := Handle} = State, Message) ->
megaco_tcp:send_message(Handle, Message),
{ok, State}.
server_await_nothing(State, Timeout)
- when is_record(State, server) ->
+ when is_map(State) ->
receive
Any ->
p("received unexpected event: ~p", [Any]),
@@ -1052,9 +1072,8 @@ server_await_nothing(State, Timeout)
{ok, State}
end.
-
server_await_message(State, ExpectMessage, Timeout)
- when is_record(State, server) ->
+ when is_map(State) ->
receive
{receive_message, {_, _, ExpectMessage}} ->
{ok, State};
@@ -1067,22 +1086,12 @@ server_await_message(State, ExpectMessage, Timeout)
{error, timeout}
end.
-server_disconnect(#server{handle = Handle} = State)
+server_disconnect(#{handle := Handle} = State)
when (Handle =/= undefined) ->
megaco_tcp:close(Handle),
- {ok, State#server{handle = undefined}}.
-
-%% server_block(#server{handle = Handle} = State)
-%% when (Handle =/= undefined) ->
-%% megaco_tcp:block(Handle),
-%% {ok, State}.
+ {ok, State#{handle => undefined}}.
-%% server_unblock(#server{handle = Handle} = State)
-%% when (Handle =/= undefined) ->
-%% megaco_tcp:unblock(Handle),
-%% {ok, State}.
-
-server_stop_transport(#server{transport_ref = Ref} = State)
+server_stop_transport(#{transport_ref := Ref} = State)
when (Ref =/= undefined) ->
megaco_tcp:stop_transport(Ref),
{ok, State}.
@@ -1091,28 +1100,28 @@ server_stop_transport(#server{transport_ref = Ref} = State)
%% ------- Client command handler and utility functions ----------
client_start_command_handler(Node, Commands) ->
- start_command_handler(Node, Commands, #client{}, "client").
+ start_command_handler(Node, Commands, #{}, "client").
-client_start_transport(State) when is_record(State, client) ->
+client_start_transport(State) when is_map(State) ->
case (catch megaco_tcp:start_transport()) of
{ok, Ref} ->
- {ok, State#client{transport_ref = Ref}};
+ {ok, State#{transport_ref => Ref}};
Error ->
Error
end.
-client_connect(#client{transport_ref = Ref} = State, Options)
- when is_record(State, client) andalso is_list(Options) ->
+client_connect(#{transport_ref := Ref} = State, Options)
+ when is_list(Options) ->
Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
case (catch megaco_tcp:connect(Ref, Opts)) of
{ok, Handle, ControlPid} ->
- {ok, State#client{control_pid = ControlPid,
- handle = Handle}};
+ {ok, State#{control_pid => ControlPid,
+ handle => Handle}};
Error ->
Error
end.
-client_await_continue_signal(#client{parent = Parent} = State, Timeout) ->
+client_await_continue_signal(#{parent := Parent} = State, Timeout) ->
receive
{continue, Parent} ->
{ok, State}
@@ -1120,12 +1129,12 @@ client_await_continue_signal(#client{parent = Parent} = State, Timeout) ->
{error, timeout}
end.
-client_notify_blocked(#client{parent = Parent} = State) ->
+client_notify_blocked(#{parent := Parent} = State) ->
Parent ! {blocked, self()},
{ok, State}.
client_await_nothing(State, Timeout)
- when is_record(State, client) ->
+ when is_map(State) ->
receive
Any ->
p("received unexpected event: ~p", [Any]),
@@ -1134,12 +1143,12 @@ client_await_nothing(State, Timeout)
{ok, State}
end.
-client_send_message(#client{handle = Handle} = State, Message) ->
+client_send_message(#{handle := Handle} = State, Message) ->
megaco_tcp:send_message(Handle, Message),
{ok, State}.
client_await_message(State, ExpectMessage, Timeout)
- when is_record(State, client) ->
+ when is_map(State) ->
receive
{receive_message, {_, _, ExpectMessage}} ->
{ok, State};
@@ -1152,22 +1161,22 @@ client_await_message(State, ExpectMessage, Timeout)
{error, timeout}
end.
-client_block(#client{handle = Handle} = State)
+client_block(#{handle := Handle} = State)
when (Handle =/= undefined) ->
megaco_tcp:block(Handle),
{ok, State}.
-client_unblock(#client{handle = Handle} = State)
+client_unblock(#{handle := Handle} = State)
when (Handle =/= undefined) ->
megaco_tcp:unblock(Handle),
{ok, State}.
-client_disconnect(#client{handle = Handle} = State)
+client_disconnect(#{handle := Handle} = State)
when (Handle =/= undefined) ->
megaco_tcp:close(Handle),
- {ok, State#client{handle = undefined, control_pid = undefined}}.
+ {ok, State#{handle => undefined, control_pid => undefined}}.
-client_stop_transport(#client{transport_ref = Ref} = State)
+client_stop_transport(#{transport_ref := Ref} = State)
when (Ref =/= undefined) ->
megaco_tcp:stop_transport(Ref),
{ok, State}.
@@ -1176,100 +1185,22 @@ client_stop_transport(#client{transport_ref = Ref} = State)
%% -------- Command handler ---------
start_command_handler(Node, Commands, State, ShortName) ->
- Fun = fun() ->
- put(sname, ShortName),
- process_flag(trap_exit, true),
- Result = (catch command_handler(Commands, State)),
- p("command handler terminated with: "
- "~n Result: ~p", [Result]),
- exit(Result)
- end,
- erlang:spawn_link(Node, Fun).
+ ?CH:start(Node, Commands, State, ShortName).
-command_handler([], State) ->
- p("command_handler -> entry when done with"
- "~n State: ~p", [State]),
- {ok, State};
-command_handler([#command{id = Id,
- desc = Desc,
- cmd = Cmd}|Commands], State) ->
- p("command_handler -> entry with"
- "~n Id: ~p"
- "~n Desc: ~p", [Id, Desc]),
- case (catch Cmd(State)) of
- {ok, NewState} ->
- p("command_handler -> cmd ~w ok", [Id]),
- command_handler(Commands, NewState);
- {error, Reason} ->
- p("command_handler -> cmd ~w error: "
- "~n Reason: ~p", [Id, Reason]),
- {error, {cmd_error, Reason}};
- {'EXIT', Reason} ->
- p("command_handler -> cmv ~w exit: "
- "~n Reason: ~p", [Id, Reason]),
- {error, {cmd_exit, Reason}};
- Error ->
- p("command_handler -> cmd ~w failure: "
- "~n Error: ~p", [Id, Error]),
- {error, {cmd_failure, Error}}
- end.
+await_command_handler_completion(Pids, Timeout) ->
+ ?CH:await_completion(Pids, Timeout).
-await_command_handler_completion(Pids, Timeout) ->
- await_command_handler_completion(Pids, [], [], Timeout).
-
-await_command_handler_completion([], [], _Good, _Timeout) ->
- p("await_command_handler_completion -> entry when done"),
- ok;
-await_command_handler_completion([], Bad, Good, _Timeout) ->
- p("await_command_handler_completion -> entry when done with bad result: "
- "~n Bad: ~p"
- "~n Good: ~p", [Bad, Good]),
- ok;
-await_command_handler_completion(Pids, Bad, Good, Timeout) ->
- p("await_command_handler_completion -> entry when waiting for"
- "~n Pids: ~p"
- "~n Bad: ~p"
- "~n Good: ~p"
- "~n Timeout: ~p", [Pids, Bad, Good, Timeout]),
- Begin = ms(),
- receive
- {'EXIT', Pid, {ok, FinalState}} ->
- p("await_command_handler_completion -> "
- "received ok EXIT signal from ~p", [Pid]),
- case lists:delete(Pid, Pids) of
- Pids ->
- await_command_handler_completion(Pids, Bad, Good,
- Timeout - (ms() - Begin));
- Pids2 ->
- p("await_command_handler_completion -> ~p done", [Pid]),
- await_command_handler_completion(Pids2,
- Bad,
- [{Pid, FinalState}|Good],
- Timeout - (ms() - Begin))
- end;
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
- {'EXIT', Pid, {error, Reason}} ->
- p("await_command_handler_completion -> "
- "received error EXIT signal from ~p", [Pid]),
- case lists:delete(Pid, Pids) of
- Pids ->
- await_command_handler_completion(Pids, Bad, Good,
- Timeout - (ms() - Begin));
- Pids2 ->
- p("await_command_handler_completion -> ~p done", [Pid]),
- await_command_handler_completion(Pids2,
- [{Pid, Reason}|Bad],
- Good,
- Timeout - (ms() - Begin))
- end
+try_tc(TCName, Pre, Case, Post) ->
+ try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
- after Timeout ->
- p("await_command_handler_completion -> timeout"),
- exit({timeout, Pids})
- end.
+try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
+ ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% ------- Misc functions --------
@@ -1298,7 +1229,3 @@ p(_S, F, A) ->
[?FTS(), self() | A]).
-ms() ->
- erlang:monotonic_time(milli_seconds).
-
-
diff --git a/lib/megaco/test/megaco_test_command_handler.erl b/lib/megaco/test/megaco_test_command_handler.erl
new file mode 100644
index 0000000000..93d6f86e55
--- /dev/null
+++ b/lib/megaco/test/megaco_test_command_handler.erl
@@ -0,0 +1,193 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(megaco_test_command_handler).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("megaco_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ start/4,
+ await_completion/2,
+
+ print/1, print/2
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Exported functions
+%%----------------------------------------------------------------------
+
+start(Node, Commands, InitialState, ShortName)
+ when is_atom(Node) andalso
+ is_list(Commands) andalso
+ is_map(InitialState) andalso
+ is_list(ShortName) ->
+ Fun = fun() ->
+ put(sname, ShortName),
+ process_flag(trap_exit, true),
+ Result = command_handler(Commands, InitialState),
+ print("command handler terminated with: "
+ "~n ~p", [Result]),
+ exit(Result)
+ end,
+ erlang:spawn_link(Node, Fun).
+
+command_handler([], State) ->
+ print("command_handler -> entry when done with"
+ "~n State: ~p", [State]),
+ {ok, State};
+command_handler([#{id := Id,
+ desc := Desc,
+ cmd := Cmd}|Commands], State)
+ when is_list(Desc) andalso is_function(Cmd, 1) ->
+ print("command_handler -> [~w] ~s", [Id, Desc]),
+ try Cmd(State) of
+ {ok, NewState} ->
+ print("command_handler -> [~w] cmd ok", [Id]),
+ command_handler(Commands, NewState);
+ {skip, _} = SKIP ->
+ print("command_handler -> [~w] cmd skip (returned)", [Id]),
+ SKIP;
+ {error, Reason} ->
+ print("command_handler -> [~w] cmd error: "
+ "~n Reason: ~p", [Id, Reason]),
+ {error, {cmd_error, Reason}}
+
+ catch
+ throw:{skip, _} = SKIP:_ ->
+ print("command_handler -> [~w] cmd skip (throw)", [Id]),
+ SKIP;
+ exit:{skip, _} = SKIP:_ ->
+ print("command_handler -> [~w] cmd skip (exit)", [Id]),
+ SKIP;
+ C:E:S ->
+ print("command_handler -> [~w] cmd failure:"
+ "~n C: ~p"
+ "~n E: ~p"
+ "~n S: ~p", [Id, C, E, S]),
+ {error, {cmd_failure, {C, E, S}}}
+ end.
+
+
+%% --- Await completion of one or more command handler(s)
+
+await_completion(Pids, Timeout) ->
+ await_completion(Pids, [], [], Timeout).
+
+await_completion([], [], _Good, _Timeout) ->
+ print("await_completion -> entry when done (success)"),
+ ok;
+await_completion([], Bad, Good, _Timeout) ->
+ print("await_completion -> entry when done with bad result: "
+ "~n Bad: ~p"
+ "~n Good: ~p", [Bad, Good]),
+ {error, Bad, Good};
+await_completion(Pids, Bad, Good, Timeout) ->
+ print("await_completion -> entry when waiting for"
+ "~n Pids: ~p"
+ "~n Bad: ~p"
+ "~n Good: ~p"
+ "~n Timeout: ~p", [Pids, Bad, Good, Timeout]),
+ Begin = ms(),
+ receive
+ {'EXIT', Pid, {ok, FinalState}} ->
+ case lists:delete(Pid, Pids) of
+ Pids ->
+ print("await_completion -> "
+ "received ok EXIT signal from unknown ~p", [Pid]),
+ await_completion(Pids, Bad, Good,
+ Timeout - (ms() - Begin));
+ Pids2 ->
+ print("await_completion -> success from ~p", [Pid]),
+ await_completion(Pids2,
+ Bad,
+ [{Pid, FinalState}|Good],
+ Timeout - (ms() - Begin))
+ end;
+
+ {'EXIT', Pid, {error, Reason}} ->
+ case lists:delete(Pid, Pids) of
+ Pids ->
+ print("await_completion -> "
+ "received error EXIT signal from unknown ~p", [Pid]),
+ await_completion(Pids, Bad, Good,
+ Timeout - (ms() - Begin));
+ Pids2 ->
+ print("await_completion -> failure from ~p", [Pid]),
+ await_completion(Pids2,
+ [{Pid, Reason}|Bad],
+ Good,
+ Timeout - (ms() - Begin))
+ end;
+
+ {'EXIT', Pid, {skip, Reason}} ->
+ print("await_completion -> skip (exit) from ~p:"
+ " ~p", [Pid, Reason]),
+ ?SKIP(Reason)
+
+ after Timeout ->
+ print("await_completion -> timeout"),
+ exit({timeout, Pids})
+ end.
+
+
+
+%% ------- Misc functions --------
+
+print(F) ->
+ print(F, []).
+
+print(F, A) ->
+ print(get(sname), F, A).
+
+print(N, F, A) when is_list(N) ->
+ io:format("*** [~s] ~p ~s ***"
+ "~n " ++ F ++ "~n",
+ [?FTS(), self(), N | A]);
+print(_N, F, A) ->
+ io:format("*** [~s] ~p *** "
+ "~n " ++ F ++ "~n",
+ [?FTS(), self() | A]).
+
+
+ms() ->
+ erlang:monotonic_time(milli_seconds).
+
+
diff --git a/lib/megaco/test/megaco_test_generator.erl b/lib/megaco/test/megaco_test_generator.erl
index 8ea7f5ddf7..a7920e7f9e 100644
--- a/lib/megaco/test/megaco_test_generator.erl
+++ b/lib/megaco/test/megaco_test_generator.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -423,7 +423,7 @@ handler_main(Parent, Mod, State, []) ->
handler_main(Parent, Mod, State, [Instruction|Instructions]) ->
d("handler_main -> entry with"
- "~n Instruction: ~p", [Instruction]),
+ "~n Instruction: ~p", [Instruction]),
receive
{stop, Parent} ->
d("handler_main -> premature stop requested"),
@@ -435,6 +435,8 @@ handler_main(Parent, Mod, State, [Instruction|Instructions]) ->
Result = (catch Mod:terminate({parent_died, Reason}, State)),
exit({parent_died, Reason, Result})
after 0 ->
+ d("handler_main -> exec: "
+ "~n Instruction: ~p", [Instruction]),
case (catch handler_callback_exec(Mod, State, Instruction)) of
{ok, NewState} ->
handler_main(Parent, Mod, NewState, Instructions);
@@ -535,28 +537,38 @@ debug(F, A) ->
debug(get(debug), F, A).
debug(true, F, A) ->
- print(" DBG", F, A);
-debug(_, _F, _A) ->
+ print(false, " DBG", F, A);
+debug(_, _, _) ->
ok.
+print(Pre, F, A) ->
+ print(true, Pre, F, A).
+
+
error(F, A) ->
- print(" ERROR", F, A).
-
-
-print(P, F, A) ->
- print(P, get(name), F, A).
-
-print([], undefined, F, A) ->
- io:format("*** [~s] ~p *** " ++
- "~n " ++ F ++ "~n",
- [?FTS(), self() | A]);
-print(P, undefined, F, A) ->
- io:format("*** [~s] ~p ~s *** " ++
- "~n " ++ F ++ "~n",
- [?FTS(), self(), P | A]);
-print(P, N, F, A) ->
- io:format("*** [~s] ~p ~s~s *** " ++
- "~n " ++ F ++ "~n",
- [?FTS(), self(), N, P | A]).
+ print(true, " ERROR", F, A).
+
+
+print(true = _Verbose, Pre, F, A) ->
+ FStr = ?F("*** [~s] ~p ~s~s *** " ++
+ "~n " ++ F ++ "~n~n",
+ [?FTS(), self(), string_name(), Pre | A]),
+ io:format(user, FStr, []),
+ io:format(standard_io, FStr, []);
+print(false = _Verbose, Pre, F, A) ->
+ FStr = ?F("*** [~s] ~p ~s~s *** " ++
+ "~n " ++ F ++ "~n~n",
+ [?FTS(), self(), string_name(), Pre | A]),
+ io:format(FStr, []).
+
+string_name() ->
+ case get(name) of
+ N when is_list(N) ->
+ N;
+ undefined ->
+ "";
+ N when is_atom(N) ->
+ atom_to_list(N)
+ end.
diff --git a/lib/megaco/test/megaco_test_generator_lib.erl b/lib/megaco/test/megaco_test_generator_lib.erl
index d19728e009..555302d9ea 100644
--- a/lib/megaco/test/megaco_test_generator_lib.erl
+++ b/lib/megaco/test/megaco_test_generator_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -51,14 +51,24 @@ await_completion(TmrRef, [], OK, ERROR) ->
await_completion(TmrRef, Tags, OK, ERROR) ->
receive
exec_complete_timeout ->
+ error_msg("Exec complete timeout:"
+ "~n Tags: ~p"
+ "~n OK: ~p"
+ "~n ERROR: ~p", [Tags, OK, ERROR]),
{error, {timeout, Tags, OK, ERROR}};
{exec_complete, Tag, ok, Result} ->
case lists:delete(Tag, Tags) of
Tags ->
%% Unknown => ignore
+ warning_msg("Exec unknown complete with success:"
+ "~n Tag: ~p"
+ "~n Result: ~p", [Tag, Result]),
await_completion(TmrRef, Tags, OK, ERROR);
Tags2 ->
+ info_msg("Exec complete with success:"
+ "~n Tag: ~p"
+ "~n Result: ~p", [Tag, Result]),
await_completion(TmrRef, Tags2, [{Tag, Result}|OK], ERROR)
end;
@@ -66,8 +76,14 @@ await_completion(TmrRef, Tags, OK, ERROR) ->
case lists:delete(Tag, Tags) of
Tags ->
%% Unknown => ignore
+ warning_msg("Exec unknown complete with failure:"
+ "~n Tag: ~p"
+ "~n Reason: ~p", [Tag, Reason]),
await_completion(TmrRef, Tags, OK, ERROR);
Tags2 ->
+ error_msg("Exec complete with failure:"
+ "~n Tag: ~p"
+ "~n Reason: ~p", [Tag, Reason]),
await_completion(TmrRef, Tags2, OK, [{Tag, Reason}|ERROR])
end
end.
@@ -82,3 +98,14 @@ stop_timer(undefined) ->
ok;
stop_timer(TmrRef) ->
erlang:cancel_timer(TmrRef).
+
+
+info_msg(F, A) ->
+ error_logger:info_msg(F ++ "~n", A).
+
+warning_msg(F, A) ->
+ error_logger:warning_msg(F ++ "~n", A).
+
+error_msg(F, A) ->
+ error_logger:error_msg(F ++ "~n", A).
+
diff --git a/lib/megaco/test/megaco_test_lib.erl b/lib/megaco/test/megaco_test_lib.erl
index f45d499199..1e4b7841ee 100644
--- a/lib/megaco/test/megaco_test_lib.erl
+++ b/lib/megaco/test/megaco_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1999-2019. All Rights Reserved.
+%% Copyright Ericsson AB 1999-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -46,13 +46,18 @@
display_alloc_info/0,
display_system_info/1, display_system_info/2, display_system_info/3,
+ try_tc/6,
+
prepare_test_case/5,
proxy_start/1, proxy_start/2,
mk_nodes/1,
- start_nodes/3,
- start_node/3
+ start_nodes/3, start_nodes/4,
+ start_node/3, start_node/4,
+
+ stop_nodes/3,
+ stop_node/3
]).
-export([init_per_suite/1, end_per_suite/1,
@@ -438,18 +443,6 @@ pprint(F, A) ->
init_per_suite(Config) ->
- io:format("Host info:"
- "~n OS Type: ~p"
- "~n OS Version: ~s"
- "~n",
- [os:type(),
- case os:version() of
- {Major, Minor, Release} ->
- ?F("~w.~w.~w", [Major, Minor, Release]);
- Str when is_list(Str) ->
- Str
- end]),
-
%% We have some crap machines that causes random test case failures
%% for no obvious reason. So, attempt to identify those without actually
%% checking for the host name...
@@ -485,13 +478,36 @@ init_per_suite(Config) ->
%% This version is *not* ok: Skip
true
end,
- COND = [{unix, [{linux, LinuxVersionVerify}, {darwin, DarwinVersionVerify}]}],
+ %% We are "looking" for a specific machine (a VM)
+ %% which are *old and crappy" and slow, because it
+ %% causes a bunch of test cases to fail randomly.
+ %% But we don not want to test for the host name...
+ WinVersionVerify =
+ fun(V) when (V =:= {6,2,9200}) ->
+ try erlang:system_info(schedulers) of
+ 2 ->
+ true;
+ _ ->
+ false
+ catch
+ _:_:_ ->
+ true
+ end;
+ (_) ->
+ false
+ end,
+ COND = [
+ {unix, [{linux, LinuxVersionVerify},
+ {darwin, DarwinVersionVerify}]}%% ,
+ %% {win32, [{nt, WinVersionVerify}]}
+ ],
case os_based_skip(COND) of
true ->
{skip, "Unstable host and/or os (or combo thererof)"};
false ->
+ Factor = analyze_and_print_host_info(),
maybe_start_global_sys_monitor(Config),
- Config
+ [{megaco_factor, Factor} | Config]
end.
%% We start the global system monitor unless explicitly disabled
@@ -547,6 +563,671 @@ end_per_testcase(_Case, Config) ->
reset_kill_timer(Config).
+%% This function prints various host info, which might be usefull
+%% when analyzing the test suite (results).
+%% It also returns a "factor" that can be used when deciding
+%% the load for some test cases. Such as run time or number of
+%% iteraions. This only works for some OSes.
+%%
+%% We make some calculations on Linux, OpenBSD and FreeBSD.
+%% On SunOS we always set the factor to 2 (just to be on the safe side)
+%% On all other os:es (mostly windows) we check the number of schedulers,
+%% but at least the factor will be 2.
+analyze_and_print_host_info() ->
+ {OsFam, OsName} = os:type(),
+ Version =
+ case os:version() of
+ {Maj, Min, Rel} ->
+ f("~w.~w.~w", [Maj, Min, Rel]);
+ VStr ->
+ VStr
+ end,
+ case {OsFam, OsName} of
+ {unix, linux} ->
+ analyze_and_print_linux_host_info(Version);
+ {unix, openbsd} ->
+ analyze_and_print_openbsd_host_info(Version);
+ {unix, freebsd} ->
+ analyze_and_print_freebsd_host_info(Version);
+ {unix, sunos} ->
+ analyze_and_print_solaris_host_info(Version);
+ {win32, nt} ->
+ analyze_and_print_win_host_info(Version);
+ _ ->
+ io:format("OS Family: ~p"
+ "~n OS Type: ~p"
+ "~n Version: ~p"
+ "~n Num Schedulers: ~s"
+ "~n", [OsFam, OsName, Version, str_num_schedulers()]),
+ try erlang:system_info(schedulers) of
+ 1 ->
+ 10;
+ 2 ->
+ 5;
+ N when (N =< 6) ->
+ 2;
+ _ ->
+ 1
+ catch
+ _:_:_ ->
+ 10
+ end
+ end.
+
+str_num_schedulers() ->
+ try erlang:system_info(schedulers) of
+ N -> f("~w", [N])
+ catch
+ _:_:_ -> "-"
+ end.
+
+
+analyze_and_print_linux_host_info(Version) ->
+ case file:read_file_info("/etc/issue") of
+ {ok, _} ->
+ io:format("Linux: ~s"
+ "~n ~s"
+ "~n",
+ [Version, string:trim(os:cmd("cat /etc/issue"))]);
+ _ ->
+ io:format("Linux: ~s"
+ "~n", [Version])
+ end,
+ Factor =
+ case (catch linux_which_cpuinfo()) of
+ {ok, {CPU, BogoMIPS}} ->
+ io:format("CPU: "
+ "~n Model: ~s"
+ "~n BogoMIPS: ~s"
+ "~n Num Schedulers: ~s"
+ "~n", [CPU, BogoMIPS, str_num_schedulers()]),
+ %% We first assume its a float, and if not try integer
+ try list_to_float(string:trim(BogoMIPS)) of
+ F when F > 4000 ->
+ 1;
+ F when F > 1000 ->
+ 2;
+ F when F > 500 ->
+ 3;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ try list_to_integer(string:trim(BogoMIPS)) of
+ I when I > 4000 ->
+ 1;
+ I when I > 1000 ->
+ 2;
+ I when I > 500 ->
+ 3;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 5 % Be a "bit" conservative...
+ end
+ end;
+ {ok, CPU} ->
+ io:format("CPU: "
+ "~n Model: ~s"
+ "~n Num Schedulers: ~s"
+ "~n", [CPU, str_num_schedulers()]),
+ 2; % Be a "bit" conservative...
+ _ ->
+ 5 % Be a "bit" (more) conservative...
+ end,
+ %% Check if we need to adjust the factor because of the memory
+ try linux_which_meminfo() of
+ AddFactor ->
+ Factor + AddFactor
+ catch
+ _:_:_ ->
+ Factor
+ end.
+
+linux_which_cpuinfo() ->
+ %% Check for x86 (Intel or AMD)
+ CPU =
+ try [string:trim(S) || S <- string:tokens(os:cmd("grep \"model name\" /proc/cpuinfo"), [$:,$\n])] of
+ ["model name", ModelName | _] ->
+ ModelName;
+ _ ->
+ %% ARM (at least some distros...)
+ try [string:trim(S) || S <- string:tokens(os:cmd("grep \"Processor\" /proc/cpuinfo"), [$:,$\n])] of
+ ["Processor", Proc | _] ->
+ Proc;
+ _ ->
+ %% Ok, we give up
+ throw(noinfo)
+ catch
+ _:_:_ ->
+ throw(noinfo)
+ end
+ catch
+ _:_:_ ->
+ throw(noinfo)
+ end,
+ try [string:trim(S) || S <- string:tokens(os:cmd("grep -i \"bogomips\" /proc/cpuinfo"), [$:,$\n])] of
+ [_, BMips | _] ->
+ {ok, {CPU, BMips}};
+ _ ->
+ {ok, CPU}
+ catch
+ _:_:_ ->
+ {ok, CPU}
+ end.
+
+%% We *add* the value this return to the Factor.
+linux_which_meminfo() ->
+ try [string:trim(S) || S <- string:tokens(os:cmd("grep MemTotal /proc/meminfo"), [$:])] of
+ [_, MemTotal] ->
+ io:format("Memory:"
+ "~n ~s"
+ "~n", [MemTotal]),
+ case string:tokens(MemTotal, [$ ]) of
+ [MemSzStr, MemUnit] ->
+ MemSz2 = list_to_integer(MemSzStr),
+ MemSz3 =
+ case string:to_lower(MemUnit) of
+ "kb" ->
+ MemSz2;
+ "mb" ->
+ MemSz2*1024;
+ "gb" ->
+ MemSz2*1024*1024;
+ _ ->
+ throw(noinfo)
+ end,
+ if
+ (MemSz3 >= 8388608) ->
+ 0;
+ (MemSz3 >= 4194304) ->
+ 1;
+ (MemSz3 >= 2097152) ->
+ 3;
+ true ->
+ 5
+ end;
+ _X ->
+ 0
+ end;
+ _ ->
+ 0
+ catch
+ _:_:_ ->
+ 0
+ end.
+
+
+%% Just to be clear: This is ***not*** scientific...
+analyze_and_print_openbsd_host_info(Version) ->
+ io:format("OpenBSD:"
+ "~n Version: ~p"
+ "~n", [Version]),
+ Extract =
+ fun(Key) ->
+ string:tokens(string:trim(os:cmd("sysctl " ++ Key)), [$=])
+ end,
+ try
+ begin
+ CPU =
+ case Extract("hw.model") of
+ ["hw.model", Model] ->
+ string:trim(Model);
+ _ ->
+ "-"
+ end,
+ CPUSpeed =
+ case Extract("hw.cpuspeed") of
+ ["hw.cpuspeed", Speed] ->
+ list_to_integer(Speed);
+ _ ->
+ -1
+ end,
+ NCPU =
+ case Extract("hw.ncpufound") of
+ ["hw.ncpufound", N] ->
+ list_to_integer(N);
+ _ ->
+ -1
+ end,
+ Memory =
+ case Extract("hw.physmem") of
+ ["hw.physmem", PhysMem] ->
+ list_to_integer(PhysMem) div 1024;
+ _ ->
+ -1
+ end,
+ io:format("CPU:"
+ "~n Model: ~s"
+ "~n Speed: ~w"
+ "~n N: ~w"
+ "~nMemory:"
+ "~n ~w KB"
+ "~n", [CPU, CPUSpeed, NCPU, Memory]),
+ CPUFactor =
+ if
+ (CPUSpeed =:= -1) ->
+ 1;
+ (CPUSpeed >= 2000) ->
+ if
+ (NCPU >= 4) ->
+ 1;
+ (NCPU >= 2) ->
+ 2;
+ true ->
+ 3
+ end;
+ true ->
+ if
+ (NCPU >= 4) ->
+ 2;
+ (NCPU >= 2) ->
+ 3;
+ true ->
+ 4
+ end
+ end,
+ MemAddFactor =
+ if
+ (Memory =:= -1) ->
+ 0;
+ (Memory >= 8388608) ->
+ 0;
+ (Memory >= 4194304) ->
+ 1;
+ (Memory >= 2097152) ->
+ 2;
+ true ->
+ 3
+ end,
+ CPUFactor + MemAddFactor
+ end
+ catch
+ _:_:_ ->
+ 1
+ end.
+
+
+analyze_and_print_freebsd_host_info(Version) ->
+ io:format("FreeBSD:"
+ "~n Version: ~p"
+ "~n", [Version]),
+ %% This test require that the program 'sysctl' is in the path.
+ %% First test with 'which sysctl', if that does not work
+ %% try with 'which /sbin/sysctl'. If that does not work either,
+ %% we skip the test...
+ try
+ begin
+ SysCtl =
+ case string:trim(os:cmd("which sysctl")) of
+ [] ->
+ case string:trim(os:cmd("which /sbin/sysctl")) of
+ [] ->
+ throw(sysctl);
+ SC2 ->
+ SC2
+ end;
+ SC1 ->
+ SC1
+ end,
+ Extract =
+ fun(Key) ->
+ string:tokens(string:trim(os:cmd(SysCtl ++ " " ++ Key)),
+ [$:])
+ end,
+ CPU = analyze_freebsd_cpu(Extract),
+ CPUSpeed = analyze_freebsd_cpu_speed(Extract),
+ NCPU = analyze_freebsd_ncpu(Extract),
+ Memory = analyze_freebsd_memory(Extract),
+ io:format("CPU:"
+ "~n Model: ~s"
+ "~n Speed: ~w"
+ "~n N: ~w"
+ "~n Num Schedulers: ~w"
+ "~nMemory:"
+ "~n ~w KB"
+ "~n",
+ [CPU, CPUSpeed, NCPU,
+ erlang:system_info(schedulers), Memory]),
+ CPUFactor =
+ if
+ (CPUSpeed =:= -1) ->
+ 1;
+ (CPUSpeed >= 2000) ->
+ if
+ (NCPU >= 4) ->
+ 1;
+ (NCPU >= 2) ->
+ 2;
+ true ->
+ 3
+ end;
+ true ->
+ if
+ (NCPU =:= -1) ->
+ 1;
+ (NCPU >= 4) ->
+ 2;
+ (NCPU >= 2) ->
+ 3;
+ true ->
+ 4
+ end
+ end,
+ MemAddFactor =
+ if
+ (Memory =:= -1) ->
+ 0;
+ (Memory >= 8388608) ->
+ 0;
+ (Memory >= 4194304) ->
+ 1;
+ (Memory >= 2097152) ->
+ 2;
+ true ->
+ 3
+ end,
+ CPUFactor + MemAddFactor
+ end
+ catch
+ _:_:_ ->
+ io:format("CPU:"
+ "~n Num Schedulers: ~w"
+ "~n", [erlang:system_info(schedulers)]),
+ case erlang:system_info(schedulers) of
+ 1 ->
+ 10;
+ 2 ->
+ 5;
+ _ ->
+ 2
+ end
+ end.
+
+analyze_freebsd_cpu(Extract) ->
+ analyze_freebsd_item(Extract, "hw.model", fun(X) -> X end, "-").
+
+analyze_freebsd_cpu_speed(Extract) ->
+ analyze_freebsd_item(Extract,
+ "hw.clockrate",
+ fun(X) -> list_to_integer(X) end,
+ -1).
+
+analyze_freebsd_ncpu(Extract) ->
+ analyze_freebsd_item(Extract,
+ "hw.ncpu",
+ fun(X) -> list_to_integer(X) end,
+ -1).
+
+analyze_freebsd_memory(Extract) ->
+ analyze_freebsd_item(Extract,
+ "hw.physmem",
+ fun(X) -> list_to_integer(X) div 1024 end,
+ -1).
+
+analyze_freebsd_item(Extract, Key, Process, Default) ->
+ try
+ begin
+ case Extract(Key) of
+ [Key, Model] ->
+ Process(string:trim(Model));
+ _ ->
+ Default
+ end
+ end
+ catch
+ _:_:_ ->
+ Default
+ end.
+
+
+analyze_and_print_solaris_host_info(Version) ->
+ Release =
+ case file:read_file_info("/etc/release") of
+ {ok, _} ->
+ case [string:trim(S) || S <- string:tokens(os:cmd("cat /etc/release"), [$\n])] of
+ [Rel | _] ->
+ Rel;
+ _ ->
+ "-"
+ end;
+ _ ->
+ "-"
+ end,
+ %% Display the firmware device tree root properties (prtconf -b)
+ Props = [list_to_tuple([string:trim(PS) || PS <- Prop]) ||
+ Prop <- [string:tokens(S, [$:]) ||
+ S <- string:tokens(os:cmd("prtconf -b"), [$\n])]],
+ BannerName = case lists:keysearch("banner-name", 1, Props) of
+ {value, {_, BN}} ->
+ string:trim(BN);
+ _ ->
+ "-"
+ end,
+ InstructionSet =
+ case string:trim(os:cmd("isainfo -k")) of
+ "Pseudo-terminal will not" ++ _ ->
+ "-";
+ IS ->
+ IS
+ end,
+ PtrConf = [list_to_tuple([string:trim(S) || S <- Items]) || Items <- [string:tokens(S, [$:]) || S <- string:tokens(os:cmd("prtconf"), [$\n])], length(Items) > 1],
+ SysConf =
+ case lists:keysearch("System Configuration", 1, PtrConf) of
+ {value, {_, SC}} ->
+ SC;
+ _ ->
+ "-"
+ end,
+ NumPhysProc =
+ begin
+ NPPStr = string:trim(os:cmd("psrinfo -p")),
+ try list_to_integer(NPPStr) of
+ _ ->
+ NPPStr
+ catch
+ _:_:_ ->
+ "-"
+ end
+ end,
+ NumProc = try integer_to_list(length(string:tokens(os:cmd("psrinfo"), [$\n]))) of
+ NPStr ->
+ NPStr
+ catch
+ _:_:_ ->
+ "-"
+ end,
+ MemSz =
+ case lists:keysearch("Memory size", 1, PtrConf) of
+ {value, {_, MS}} ->
+ MS;
+ _ ->
+ "-"
+ end,
+ io:format("Solaris: ~s"
+ "~n Release: ~s"
+ "~n Banner Name: ~s"
+ "~n Instruction Set: ~s"
+ "~n CPUs: ~s (~s)"
+ "~n System Config: ~s"
+ "~n Memory Size: ~s"
+ "~n Num Schedulers: ~s"
+ "~n~n", [Version, Release, BannerName, InstructionSet,
+ NumPhysProc, NumProc,
+ SysConf, MemSz,
+ str_num_schedulers()]),
+ MemFactor =
+ try string:tokens(MemSz, [$ ]) of
+ [SzStr, "Mega" ++ _] ->
+ try list_to_integer(SzStr) of
+ Sz when Sz > 8192 ->
+ 0;
+ Sz when Sz > 4096 ->
+ 1;
+ Sz when Sz > 2048 ->
+ 2;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 10
+ end;
+ [SzStr, "Giga" ++ _] ->
+ try list_to_integer(SzStr) of
+ Sz when Sz > 8 ->
+ 0;
+ Sz when Sz > 4 ->
+ 1;
+ Sz when Sz > 2 ->
+ 2;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 10
+ end;
+ _ ->
+ 10
+ catch
+ _:_:_ ->
+ 10
+ end,
+ try erlang:system_info(schedulers) of
+ 1 ->
+ 10;
+ 2 ->
+ 5;
+ N when (N =< 6) ->
+ 2;
+ _ ->
+ 1
+ catch
+ _:_:_ ->
+ 10
+ end + MemFactor.
+
+
+analyze_and_print_win_host_info(Version) ->
+ SysInfo = which_win_system_info(),
+ OsName = win_sys_info_lookup(os_name, SysInfo),
+ OsVersion = win_sys_info_lookup(os_version, SysInfo),
+ SysMan = win_sys_info_lookup(system_manufacturer, SysInfo),
+ NumProcs = win_sys_info_lookup(num_processors, SysInfo),
+ TotPhysMem = win_sys_info_lookup(total_phys_memory, SysInfo),
+ io:format("Windows: ~s"
+ "~n OS Version: ~s (~p)"
+ "~n System Manufacturer: ~s"
+ "~n Number of Processor(s): ~s"
+ "~n Total Physical Memory: ~s"
+ "~n", [OsName, OsVersion, Version, SysMan, NumProcs, TotPhysMem]),
+ MemFactor =
+ try
+ begin
+ [MStr, MUnit|_] =
+ string:tokens(lists:delete($,, TotPhysMem), [$\ ]),
+ case string:to_lower(MUnit) of
+ "gb" ->
+ try list_to_integer(MStr) of
+ M when M > 8 ->
+ 0;
+ M when M > 4 ->
+ 1;
+ M when M > 2 ->
+ 2;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 10
+ end;
+ "mb" ->
+ try list_to_integer(MStr) of
+ M when M > 8192 ->
+ 0;
+ M when M > 4096 ->
+ 1;
+ M when M > 2048 ->
+ 2;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 10
+ end;
+ _ ->
+ 10
+ end
+ end
+ catch
+ _:_:_ ->
+ 10
+ end,
+ CPUFactor =
+ case erlang:system_info(schedulers) of
+ 1 ->
+ 10;
+ 2 ->
+ 5;
+ _ ->
+ 2
+ end,
+ CPUFactor + MemFactor.
+
+win_sys_info_lookup(Key, SysInfo) ->
+ win_sys_info_lookup(Key, SysInfo, "-").
+
+win_sys_info_lookup(Key, SysInfo, Def) ->
+ case lists:keysearch(Key, 1, SysInfo) of
+ {value, {Key, Value}} ->
+ Value;
+ false ->
+ Def
+ end.
+
+%% This function only extracts the prop we actually care about!
+which_win_system_info() ->
+ SysInfo = os:cmd("systeminfo"),
+ try process_win_system_info(string:tokens(SysInfo, [$\r, $\n]), [])
+ catch
+ _:_:_ ->
+ io:format("Failed process System info: "
+ "~s~n", [SysInfo]),
+ []
+ end.
+
+process_win_system_info([], Acc) ->
+ Acc;
+process_win_system_info([H|T], Acc) ->
+ case string:tokens(H, [$:]) of
+ [Key, Value] ->
+ case string:to_lower(Key) of
+ "os name" ->
+ process_win_system_info(T,
+ [{os_name, string:trim(Value)}|Acc]);
+ "os version" ->
+ process_win_system_info(T,
+ [{os_version, string:trim(Value)}|Acc]);
+ "system manufacturer" ->
+ process_win_system_info(T,
+ [{system_manufacturer, string:trim(Value)}|Acc]);
+ "processor(s)" ->
+ [NumProcStr|_] = string:tokens(Value, [$\ ]),
+ T2 = lists:nthtail(list_to_integer(NumProcStr), T),
+ process_win_system_info(T2,
+ [{num_processors, NumProcStr}|Acc]);
+ "total physical memory" ->
+ process_win_system_info(T,
+ [{total_phys_memory, string:trim(Value)}|Acc]);
+ _ ->
+ process_win_system_info(T, Acc)
+ end;
+ _ ->
+ process_win_system_info(T, Acc)
+ end.
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% Set kill timer
@@ -578,6 +1259,71 @@ reset_kill_timer(Config) ->
end.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+try_tc(TCName, Name, Verbosity, Pre, Case, Post)
+ when is_function(Pre, 0) andalso
+ is_function(Case, 1) andalso
+ is_function(Post, 1) ->
+ process_flag(trap_exit, true),
+ put(verbosity, Verbosity),
+ put(sname, Name),
+ put(tc, TCName),
+ p("try_tc -> starting: try pre"),
+ try Pre() of
+ State ->
+ p("try_tc -> pre done: try test case"),
+ try Case(State) of
+ Res ->
+ p("try_tc -> test case done: try post"),
+ (catch Post(State)),
+ p("try_tc -> done"),
+ Res
+ catch
+ throw:{skip, _} = SKIP:_ ->
+ p("try_tc -> test case (throw) skip: try post"),
+ (catch Post(State)),
+ p("try_tc -> test case (throw) skip: done"),
+ SKIP;
+ exit:{skip, _} = SKIP:_ ->
+ p("try_tc -> test case (exit) skip: try post"),
+ (catch Post(State)),
+ p("try_tc -> test case (exit) skip: done"),
+ SKIP;
+ C:E:S ->
+ p("try_tc -> test case failed: try post"),
+ (catch Post(State)),
+ case megaco_test_global_sys_monitor:events() of
+ [] ->
+ p("try_tc -> test case failed: done"),
+ exit({case_catched, C, E, S});
+ SysEvs ->
+ p("try_tc -> test case failed with system event(s): "
+ "~n ~p", [SysEvs]),
+ {skip, "TC failure with system events"}
+ end
+ end
+ catch
+ throw:{skip, _} = SKIP:_ ->
+ p("try_tc -> pre (throw) skip"),
+ SKIP;
+ exit:{skip, _} = SKIP:_ ->
+ p("try_tc -> pre (exit) skip"),
+ SKIP;
+ C:E:S ->
+ case megaco_test_global_sys_monitor:events() of
+ [] ->
+ p("try_tc -> pre failed: done"),
+ exit({pre_catched, C, E, S});
+ SysEvs ->
+ p("try_tc -> pre failed with system event(s): "
+ "~n ~p", [SysEvs]),
+ {skip, "TC pre failure with system events"}
+ end
+ end.
+
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
prepare_test_case(Actions, N, Config, File, Line) ->
@@ -637,14 +1383,59 @@ node_to_name_and_host(Node) ->
start_nodes(Nodes, File, Line) when is_list(Nodes) ->
- lists:foreach(fun(N) -> start_node(N, File, Line) end, Nodes).
+ start_nodes(Nodes, false, File, Line).
+
+start_nodes(Nodes, Force, File, Line)
+ when is_list(Nodes) andalso is_boolean(Force) ->
+ start_nodes(Nodes, Force, File, Line, []).
+
+start_nodes([], _Force, _File, _Line, _Started) ->
+ ok;
+start_nodes([Node|Nodes], Force, File, Line, Started) ->
+ try start_node(Node, Force, true, File, Line) of
+ ok ->
+ start_nodes(Nodes, Force, File, Line, [Node|Started])
+ catch
+ exit:{skip, _} = SKIP:_ ->
+ (catch stop_nodes(lists:reverse(Started), File, Line)),
+ exit(SKIP);
+ C:E:S ->
+ (catch stop_nodes(lists:reverse(Started), File, Line)),
+ erlang:raise(C, E, S)
+ end.
start_node(Node, File, Line) ->
+ start_node(Node, false, false, File, Line).
+
+start_node(Node, Force, File, Line)
+ when is_atom(Node) andalso is_boolean(Force) ->
+ start_node(Node, Force, false, File, Line).
+
+start_node(Node, Force, Retry, File, Line) ->
case net_adm:ping(Node) of
- pong ->
+ %% Do not require a *new* node
+ pong when (Force =:= false) ->
p("node ~p already running", [Node]),
ok;
- pang ->
+
+ %% Do require a *new* node, so kill this one and try again
+ pong when ((Force =:= true) andalso (Retry =:= true)) ->
+ e("node ~p already running - kill and retry", [Node]),
+ case stop_node(Node) of
+ ok ->
+ start_node(Node, Force, false, File, Line);
+ error ->
+ e("node ~p already running - failed kill (no retry)", [Node]),
+ fatal_skip({node_already_running, Node}, File, Line)
+ end;
+
+ %% Do require a *new* node, but no retry so give up and fail
+ pong when (Force =:= true) ->
+ e("node ~p already running", [Node]),
+ fatal_skip({node_already_running, Node}, File, Line);
+
+ % Not (yet) running
+ pang ->
[Name, Host] = node_to_name_and_host(Node),
Pa = filename:dirname(code:which(?MODULE)),
Args = " -pa " ++ Pa ++
@@ -662,17 +1453,67 @@ start_node(Node, File, Line) ->
{_, []} = rpc:multicall(global, sync, []),
ok;
Other ->
- p("failed starting node ~p: ~p", [Node, Other]),
+ e("failed starting node ~p: ~p", [Node, Other]),
fatal_skip({cannot_start_node, Node, Other}, File, Line)
end
end.
+
+
+stop_nodes(Nodes, File, Line) when is_list(Nodes) ->
+ stop_nodes(Nodes, [], File, Line).
+
+stop_nodes([], [], _File, _Line) ->
+ ok;
+stop_nodes([], StillRunning, File, Line) ->
+ e("Failed stopping nodes: "
+ "~n ~p", [StillRunning]),
+ fatal_skip({failed_stop_nodes, lists:reverse(StillRunning)}, File, Line);
+stop_nodes([Node|Nodes], Acc, File, Line) ->
+ case stop_node(Node) of
+ ok ->
+ stop_nodes(Nodes, Acc, File, Line);
+ error ->
+ stop_nodes(Nodes, [Node|Acc], File, Line)
+ end.
+stop_node(Node, File, Line) when is_atom(Node) ->
+ p("try stop node ~p", [Node]),
+ case stop_node(Node) of
+ ok ->
+ ok;
+ error ->
+ fatal_skip({failed_stop_node, Node}, File, Line)
+ end.
+
+stop_node(Node) ->
+ p("try stop node ~p", [Node]),
+ erlang:monitor_node(Node, true),
+ rpc:call(Node, erlang, halt, []),
+ receive
+ {nodedown, Node} ->
+ ok
+ after 10000 ->
+ e("failed stop node ~p", [Node]),
+ error
+ end.
+
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
f(F, A) ->
lists:flatten(io_lib:format(F, A)).
+e(F, A) ->
+ print("ERROR", F, A).
+
+p(F) ->
+ p(F, []).
+
p(F, A) ->
- io:format("~s ~p " ++ F ++ "~n", [?FTS(), self() | A]).
+ print("INFO", F, A).
+
+print(Pre, F, A) ->
+ io:format("*** [~s] [~s] ~p " ++ F ++ "~n", [?FTS(), Pre, self() | A]).
+
diff --git a/lib/megaco/test/megaco_test_lib.hrl b/lib/megaco/test/megaco_test_lib.hrl
index 4c49f89a8e..2ff887178e 100644
--- a/lib/megaco/test/megaco_test_lib.hrl
+++ b/lib/megaco/test/megaco_test_lib.hrl
@@ -80,12 +80,19 @@
-define(MULTI_RECEIVE(Expected),
?VERIFY(lists:sort(Expected), lists:sort(?LIB:flush()))).
+-define(TRY_TC(TCN, N, V, PRE, CASE, POST),
+ ?LIB:try_tc(TCN, N, V, PRE, CASE, POST)).
+
-define(ACQUIRE_NODES(N, Config),
?LIB:prepare_test_case([init, {stop_app, megaco}],
N, Config, ?FILE, ?LINE)).
--define(START_NODE(Node), ?LIB:start_node(Node, ?FILE, ?LINE)).
--define(START_NODES(Nodes), ?LIB:start_nodes(Nodes, ?FILE, ?LINE)).
+-define(START_NODE(Node, Force), ?LIB:start_node(Node, Force, ?FILE, ?LINE)).
+-define(START_NODE(Node), ?START_NODE(Node, false)).
+-define(START_NODES(Nodes, Force), ?LIB:start_nodes(Nodes, Force, ?FILE, ?LINE)).
+-define(START_NODES(Nodes), ?START_NODES(Nodes, false)).
+-define(STOP_NODE(Node), ?LIB:stop_node(Node, ?FILE, ?LINE)).
+-define(STOP_NODES(Nodes), ?LIB:stop_nodes(Nodes, ?FILE, ?LINE)).
-define(SLEEP(MSEC), ?LIB:sleep(MSEC)).
-define(HOURS(T), ?LIB:hours(T)).
diff --git a/lib/megaco/test/megaco_test_megaco_generator.erl b/lib/megaco/test/megaco_test_megaco_generator.erl
index 4e0f2e334c..4eedd8d731 100644
--- a/lib/megaco/test/megaco_test_megaco_generator.erl
+++ b/lib/megaco/test/megaco_test_megaco_generator.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -370,12 +370,15 @@ handle_exec({debug, Debug}, State) ->
{ok, State};
handle_exec({expect_nothing, To}, State) ->
- p("expect_nothing: ~p", [To]),
+ p("expect nothing: ~p", [To]),
receive
Any ->
+ e("received unexpected: "
+ "~n ~p", [Any]),
error({expect_nothing, Any})
after To ->
- {ok, State}
+ p("go nothing (~p) as expected", [To]),
+ {ok, State}
end;
handle_exec({megaco_trace, disable}, State) ->
@@ -388,17 +391,17 @@ handle_exec({megaco_trace, Level}, State) ->
{ok, State};
handle_exec(megaco_start, State) ->
- p("megaco_start"),
+ p("start megaco"),
ok = megaco:start(),
{ok, State};
handle_exec(megaco_stop, State) ->
- p("megaco_stop"),
+ p("stop megaco"),
ok = megaco:stop(),
{ok, State};
handle_exec({megaco_start_user, Mid, RecvInfo, Conf}, State) ->
- p("megaco_start_user: ~p", [Mid]),
+ p("start megaco user: ~p", [Mid]),
d("megaco_start_user -> start user"),
ok = megaco:start_user(Mid, Conf),
@@ -424,16 +427,17 @@ handle_exec({megaco_start_user, Mid, RecvInfo, Conf}, State) ->
handle_exec(megaco_stop_user, #state{mid = Mid} = State)
when Mid /= undefined ->
+ p("stop megaco user: ~p", [Mid]),
megaco_cleanup(State),
ok = megaco:stop_user(Mid),
{ok, State#state{mid = undefined}};
-handle_exec(start_transport, #state{recv_handle = RH} = State) ->
- p("start_transport"),
- #megaco_receive_handle{send_mod = TM} = RH,
+handle_exec(start_transport,
+ #state{recv_handle = #megaco_receive_handle{send_mod = TM}} = State) ->
+ p("start transport ~p", [TM]),
case (catch TM:start_transport()) of
{ok, Sup} ->
- d("start_transport -> Sup: ~p", [Sup]),
+ d("transport started: Sup: ~p", [Sup]),
{ok, State#state{transport_sup = Sup}};
{error, Reason} ->
e("failed starting transport (~w): "
@@ -448,7 +452,7 @@ handle_exec(start_transport, #state{recv_handle = RH} = State) ->
handle_exec({listen, Opts0, MaybeRetry},
#state{recv_handle = RH, port = Port, transport_sup = Pid} = State)
when RH#megaco_receive_handle.send_mod =:= megaco_tcp ->
- p("listen(tcp)", []),
+ p("listen(tcp)"),
Opts = [{module, ?DELIVER_MOD},
{port, Port},
{receive_handle, RH},
@@ -471,7 +475,7 @@ handle_exec({listen, Opts0, _MaybeRetry},
error({udp_open, Opts0, Else})
end;
handle_exec({listen, Opts0, _MaybeRetry},
- #state{recv_handle = RH, port = Port, transport_sup = Pid} = State)
+ #state{recv_handle = RH, port = Port, transport_sup = Pid} = State)
when RH#megaco_receive_handle.send_mod =:= megaco_test_generic_transport ->
p("listen(generic)"),
Opts = [{module, ?DELIVER_MOD}, {port, Port}, {receive_handle, RH}|Opts0],
@@ -487,7 +491,7 @@ handle_exec({connect, Host, Opts0, MaybeRetry},
recv_handle = RH,
port = Port} = State)
when RH#megaco_receive_handle.send_mod =:= megaco_tcp ->
- p("connect[megaco_tcp] to ~p:~p", [Host, Port]),
+ p("connect(tcp) to ~p:~p", [Host, Port]),
PrelMid = preliminary_mid,
Opts = [{host, Host},
{port, Port},
@@ -495,7 +499,7 @@ handle_exec({connect, Host, Opts0, MaybeRetry},
{tcp_options, [{nodelay, true}]} | Opts0],
case (catch handle_exec_connect_tcp(Host, Opts, Sup, MaybeRetry)) of
{ok, SH, ControlPid} ->
- d("tcp connected: ~p, ~p", [SH, ControlPid]),
+ d("connected(tcp): ~p, ~p", [SH, ControlPid]),
megaco_connector_start(RH, PrelMid, SH, ControlPid),
{ok, State#state{send_handle = SH,
ctrl_pid = ControlPid}};
@@ -508,13 +512,13 @@ handle_exec({connect, Host, Opts0, _MaybeRetry},
recv_handle = RH,
port = Port} = State)
when RH#megaco_receive_handle.send_mod =:= megaco_udp ->
- p("connect[megaco_udp] to ~p", [Host]),
+ p("connect(udp) to ~p", [Host]),
PrelMid = preliminary_mid,
Opts = [{port, 0}, {receive_handle, RH}|Opts0],
d("udp open", []),
case (catch megaco_udp:open(Sup, Opts)) of
{ok, Handle, ControlPid} ->
- d("udp opened: ~p, ~p", [Handle, ControlPid]),
+ d("opened(udp): ~p, ~p", [Handle, ControlPid]),
SH = megaco_udp:create_send_handle(Handle, Host, Port),
megaco_connector_start(RH, PrelMid, SH, ControlPid),
{ok, State#state{send_handle = SH,
@@ -528,12 +532,12 @@ handle_exec({connect, Host, Opts0, _MaybeRetry},
recv_handle = RH,
port = Port} = State)
when RH#megaco_receive_handle.send_mod =:= megaco_test_generic_transport ->
- p("connect[megaco_test_generic_transport] to ~p", [Host]),
+ p("connect(generic) to ~p", [Host]),
PrelMid = preliminary_mid,
Opts = [{host, Host}, {port, Port}, {receive_handle, RH}|Opts0],
case (catch megaco_test_generic_transport:connect(Sup, Opts)) of
{ok, SH, ControlPid} ->
- d("generic connected: ~p, ~p", [SH, ControlPid]),
+ d("connected(generic): ~p, ~p", [SH, ControlPid]),
megaco_connector_start(RH, PrelMid, SH, ControlPid),
{ok, State#state{send_handle = SH,
ctrl_pid = ControlPid}};
@@ -542,13 +546,13 @@ handle_exec({connect, Host, Opts0, _MaybeRetry},
end;
handle_exec(megaco_connect, State) ->
- p("megaco_connect"),
+ p("expect megaco_connect"),
receive
{megaco_connect_result, {ok, CH}} ->
- p("megaco connect succeeded: ~p", [CH]),
+ p("received successful megaco_connect: ~p", [CH]),
{ok, State#state{conn_handle = CH}};
{megaco_connect_result, Error} ->
- p("megaco connect failed: ~p", [Error]),
+ p("received failed megaco_connect: ~p", [Error]),
#state{result = Res} = State,
{ok, State#state{result = [Error|Res]}}
end;
@@ -557,27 +561,27 @@ handle_exec({megaco_connect, Mid},
#state{recv_handle = RH,
send_handle = SH,
ctrl_pid = ControlPid} = State) ->
- p("megaco_connect: ~p", [Mid]),
+ p("megaco connect: ~p", [Mid]),
megaco_connector_start(RH, Mid, SH, ControlPid),
{ok, State};
handle_exec({megaco_user_info, Tag}, #state{mid = Mid, result = Res} = State)
when Mid /= undefined ->
- p("megaco_user_info: ~w", [Tag]),
+ p("megaco user-info: ~w", [Tag]),
Val = (catch megaco:user_info(Mid, Tag)),
d("megaco_user_info: ~p", [Val]),
{ok, State#state{result = [Val|Res]}};
handle_exec({megaco_update_user_info, Tag, Val}, #state{mid = Mid} = State)
when Mid /= undefined ->
- p("megaco_update_user_info: ~w -> ~p", [Tag, Val]),
+ p("update megaco user-info: ~w -> ~p", [Tag, Val]),
ok = megaco:update_user_info(Mid, Tag, Val),
{ok, State};
handle_exec({megaco_conn_info, Tag},
#state{conn_handle = CH, result = Res} = State)
when CH /= undefined ->
- p("megaco_conn_info: ~w", [Tag]),
+ p("megaco conn-info: ~w", [Tag]),
Val = (catch megaco:conn_info(CH, Tag)),
d("megaco_conn_info: ~p", [Val]),
{ok, State#state{result = [Val|Res]}};
@@ -585,7 +589,7 @@ handle_exec({megaco_conn_info, Tag},
handle_exec({megaco_update_conn_info, Tag, Val},
#state{conn_handle = CH} = State)
when CH /= undefined ->
- p("megaco_update_conn_info: ~w -> ~p", [Tag, Val]),
+ p("update megaco conn-info: ~w -> ~p", [Tag, Val]),
case megaco:update_conn_info(CH, Tag, Val) of
ok ->
{ok, State};
@@ -594,15 +598,15 @@ handle_exec({megaco_update_conn_info, Tag, Val},
end;
handle_exec(megaco_info, #state{result = Res} = State) ->
- p("megaco_info", []),
+ p("megaco info", []),
Val = (catch megaco:info()),
d("megaco_info: ~p", [Val]),
{ok, State#state{result = [Val|Res]}};
handle_exec({megaco_system_info, Tag, Verify}, #state{result = Res} = State) ->
- p("megaco_system_info: ~w", [Tag]),
+ p("megaco system-info: ~w", [Tag]),
Val = (catch megaco:system_info(Tag)),
- d("megaco_system_info: ~p", [Val]),
+ d("megaco system-info: ~p", [Val]),
case Verify(Val) of
ok ->
{ok, State#state{result = [Val|Res]}};
@@ -613,7 +617,10 @@ handle_exec({megaco_system_info, Tag, Verify}, #state{result = Res} = State) ->
%% This is either a MG or a MGC which is only connected to one MG
handle_exec({megaco_call, ARs, Opts}, #state{conn_handle = CH} = State)
when CH /= undefined ->
- p("megaco_call"),
+ p("megaco_call: "
+ "~n CH: ~p"
+ "~n ARs: ~p"
+ "~n Opts: ~p", [CH, ARs, Opts]),
{_PV, UserReply} = megaco:call(CH, ARs, Opts),
d("megaco_call -> UserReply: ~n~p", [UserReply]),
{ok, State};
@@ -624,6 +631,10 @@ handle_exec({megaco_call, RemoteMid, ARs, Opts}, #state{mid = Mid} = State) ->
Conns = megaco:user_info(Mid, connections),
{value, {_, CH}} =
lists:keysearch(RemoteMid, #megaco_conn_handle.remote_mid, Conns),
+ p("megaco_call: "
+ "~n CH: ~p"
+ "~n ARs: ~p"
+ "~n Opts: ~p", [CH, ARs, Opts]),
{_PV, UserReply} = megaco:call(CH, ARs, Opts),
d("megaco_call -> UserReply: ~n~p", [UserReply]),
{ok, State};
@@ -631,56 +642,65 @@ handle_exec({megaco_call, RemoteMid, ARs, Opts}, #state{mid = Mid} = State) ->
%% This is either a MG or a MGC which is only connected to one MG
handle_exec({megaco_cast, ARs, Opts}, #state{conn_handle = CH} = State)
when CH =/= undefined ->
- p("megaco_cast"),
+ p("megaco_cast: "
+ "~n CH: ~p"
+ "~n ARs: ~p", [CH, ARs]),
case megaco:cast(CH, ARs, Opts) of
ok ->
{ok, State};
Error ->
- d("failed sending (cast) message: ~n~p", [Error]),
+ e("failed sending (cast) message: ~n~p", [Error]),
#state{result = Acc} = State,
{error, State#state{result = [Error|Acc]}}
end;
handle_exec({megaco_cast, RemoteMid, ARs, Opts}, #state{mid = Mid} = State) ->
- p("megaco_cast: ~p", [RemoteMid]),
+ p("megaco_cast with ~p", [RemoteMid]),
%% First we have to find the CH for this Mid
Conns = megaco:user_info(Mid, connections),
{value, {_, CH}} =
lists:keysearch(RemoteMid, #megaco_conn_handle.remote_mid, Conns),
+ p("megaco_cast: "
+ "~n CH: ~p"
+ "~n ARs: ~p"
+ "~n Opts: ~p", [CH, ARs, Opts]),
case megaco:cast(CH, ARs, Opts) of
ok ->
{ok, State};
Error ->
- d("failed sending (cast) message: ~n~p", [Error]),
+ e("failed sending (cast) message: "
+ "~n ~p", [Error]),
#state{result = Acc} = State,
{error, State#state{result = [Error|Acc]}}
end;
%% Nothing shall happen for atleast Timeout time
handle_exec({megaco_callback, nocall, Timeout}, State) ->
- p("megaco_callback [~w,~w]", [nocall, Timeout]),
+ p("expect no megaco_callback for ~w", [Timeout]),
receive
{handle_megaco_callback, Type, Msg, Pid} ->
- d("received unexpected megaco callback: ~n~p", [Msg]),
+ e("received unexpected megaco callback: ~n~p", [Msg]),
#state{result = Res} = State,
Err = {unexpected_callback, Type, Msg, Pid},
{error, State#state{result = [Err|Res]}}
after Timeout ->
+ p("got no callback (~p) as expected", [Timeout]),
{ok, State}
end;
handle_exec({megaco_callback, Tag, Verify}, State) when is_function(Verify) ->
- p("megaco_callback [~w]", [Tag]),
+ p("expect megaco_callback ~w", [Tag]),
receive
{handle_megaco_callback, Type, Msg, Pid} ->
- d("received megaco callback: ~n~p", [Msg]),
+ d("received megaco callback:"
+ "~n ~p", [Msg]),
case Verify(Msg) of
{VRes, Res, Reply} ->
- d("megaco_callback [~w] ~w",[Tag, VRes]),
+ d("megaco_callback [~w] ~w", [Tag, VRes]),
handle_megaco_callback_reply(Pid, Type, Reply),
validate(VRes, Tag, Res, State);
{VRes, Delay, Res, Reply} ->
- d("megaco_callback [~w] ~w, ~w",[Tag,Delay,VRes]),
+ d("megaco_callback [~w] ~w, ~w", [Tag,Delay,VRes]),
handle_megaco_callback_reply(Pid, Type, Delay, Reply),
validate(VRes, Tag, Res, State)
end
@@ -688,7 +708,7 @@ handle_exec({megaco_callback, Tag, Verify}, State) when is_function(Verify) ->
handle_exec({megaco_callback, Tag, {VMod, VFunc, VArgs}}, State)
when is_atom(VMod) andalso is_atom(VFunc) andalso is_list(VArgs) ->
- p("megaco_callback [~w]", [Tag]),
+ p("expect megaco_callback ~w", [Tag]),
receive
{handle_megaco_callback, Type, Msg, Pid} ->
d("received megaco callback: ~n~p"
@@ -710,7 +730,7 @@ handle_exec({megaco_callback, Tag, {VMod, VFunc, VArgs}}, State)
handle_exec({megaco_callback, Tag, Verify, Timeout}, State)
when (is_function(Verify) andalso
(is_integer(Timeout) andalso (Timeout > 0))) ->
- p("megaco_callback [~w]", [Tag]),
+ p("expect megaco_callback ~w (with ~w)", [Tag, Timeout]),
receive
{handle_megaco_callback, Type, Msg, Pid} ->
d("received megaco callback: ~n~p", [Msg]),
@@ -725,22 +745,23 @@ handle_exec({megaco_callback, Tag, Verify, Timeout}, State)
validate(VRes, Tag, Res, State)
end
after Timeout ->
+ e("megaco_callback ~w timeout", [Tag]),
#state{result = Res} = State,
Err = {callback_timeout, Tag, Timeout},
{error, State#state{result = [Err|Res]}}
end;
handle_exec({megaco_callback, Verifiers}, State) ->
- p("megaco_callback"),
+ p("expect megaco_callback(s)"),
megaco_callback_verify(Verifiers, State);
handle_exec({megaco_cancel, Reason}, #state{conn_handle = CH} = State) ->
- p("megaco_cancel [~w]", [Reason]),
+ p("megaco_cancel: ~w", [Reason]),
case megaco:cancel(CH, Reason) of
ok ->
{ok, State};
Error ->
- d("failed cancel: ~n~p", [Error]),
+ e("failed cancel: ~n~p", [Error]),
#state{result = Acc} = State,
{error, State#state{result = [Error|Acc]}}
end;
@@ -1050,32 +1071,37 @@ handle_trans_request_abort(RH, PV, TransNo, Pid, Extra, P) ->
handle_megaco_callback_cast(P, Msg, Reply).
handle_megaco_callback_cast(P, Msg, Reply) ->
- p("handle_megaco_callback_cast -> entry with Msg: ~n~p", [Msg]),
+ d("handle_megaco_callback_cast -> entry with Msg: ~n~p", [Msg]),
P ! {handle_megaco_callback, cast, Msg, self()},
Reply.
handle_megaco_callback_call(P, Msg) ->
- p("handle_megaco_callback_call -> entry with"
+ d("handle_megaco_callback_call -> entry with"
"~n P: ~p"
"~n Msg: ~p", [P, Msg]),
P ! {handle_megaco_callback, call, Msg, self()},
receive
{handle_megaco_callback_reply, Reply} ->
- p("handle_megaco_callback_call -> received reply: ~n~p", [Reply]),
+ d("handle_megaco_callback_call -> received reply: ~n~p", [Reply]),
Reply;
{handle_megaco_callback_reply, Delay, Reply} when is_integer(Delay) ->
- p("handle_megaco_callback_call -> "
+ d("handle_megaco_callback_call -> "
"received reply [~w]: "
"~n ~p", [Delay, Reply]),
sleep(Delay),
- p("handle_megaco_callback_call -> deliver reply after delay [~w]",
+ d("handle_megaco_callback_call -> deliver reply after delay [~w]",
[Delay]),
Reply;
+ {'EXIT', Pid, Reason} when (Pid =:= P) ->
+ d("handle_megaco_callback_call -> "
+ "received unexpected EXIT signal (from ~p): "
+ "~n Reason: ~p", [Pid, Reason]),
+ exit({unexpected_EXIT_signal, Pid, Reason});
{'EXIT', SomePid, SomeReason} ->
- p("handle_megaco_callback_call -> "
- "received unexpected EXIT signal: "
- "~n SomePid: ~p"
- "~n SomeReason: ~p", [SomePid, SomeReason]),
+ d("handle_megaco_callback_call -> "
+ "received unexpected EXIT signal from unknown process: "
+ "~n Pid: ~p"
+ "~n Reason: ~p", [SomePid, SomeReason]),
exit({unexpected_EXIT_signal, SomePid, SomeReason})
end.
diff --git a/lib/megaco/test/megaco_test_mg.erl b/lib/megaco/test/megaco_test_mg.erl
index 38883c94f0..5979466785 100644
--- a/lib/megaco/test/megaco_test_mg.erl
+++ b/lib/megaco/test/megaco_test_mg.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -95,9 +95,9 @@ start(Node, Mid, Encoding, Transport, Verbosity) ->
start(Node, Mid, Encoding, Transport, Conf, Verbosity) ->
d("start mg[~p]: ~p"
- "~n Encoding: ~p"
- "~n Transport: ~p"
- "~n Conf: ~p", [Node, Mid, Encoding, Transport, Conf]),
+ "~n Encoding: ~p"
+ "~n Transport: ~p"
+ "~n Conf: ~p", [Node, Mid, Encoding, Transport, Conf]),
RI1 = encoding_config(Encoding),
RI2 = transport_config(Transport),
{RI3, Conf1} = transport_opts(Conf),
@@ -106,17 +106,15 @@ start(Node, Mid, Encoding, Transport, Conf, Verbosity) ->
Self = self(),
Fun =
fun() ->
- io:format("LOADER(~p,~p) started~n", [self(),node()]),
+ i("LOADER(~p,~p) started", [self(),node()]),
case (catch mg(Self, Verbosity, Config)) of
{'EXIT', Reason} ->
- io:format("LOADER(~p,~p) terminating with exit"
- "~n~p"
- "~n", [self(), node(), Reason]),
+ e("LOADER(~p,~p) terminating with exit"
+ "~n ~p", [self(), node(), Reason]),
exit(Reason);
Else ->
- io:format("LOADER(~p,~p) terminating with"
- "~n~p"
- "~n", [self(), node(), Else]),
+ i("LOADER(~p,~p) terminating with"
+ "~n ~p", [self(), node(), Else]),
Else
end
end,
@@ -127,12 +125,12 @@ start(Node, Mid, Encoding, Transport, Conf, Verbosity) ->
NodePing = net_adm:ping(Node),
ProcInfo = (catch proc_info(Pid)),
i("start -> "
- "~n self(): ~p"
- "~n node(): ~p"
- "~n net_adm:ping(~p): ~p"
- "~n Loader: ~p"
- "~n Monitor ref: ~p"
- "~n Process info: ~p",
+ "~n self(): ~p"
+ "~n node(): ~p"
+ "~n net_adm:ping(~p): ~p"
+ "~n Loader: ~p"
+ "~n Monitor ref: ~p"
+ "~n Process info: ~p",
[self(), node(),
Node, NodePing,
Pid,
@@ -195,12 +193,12 @@ transport_opts(Config) ->
await_started(Node, MonRef, Pid) ->
i("await_started -> entry with"
- "~n MonRef: ~p"
- "~n Pid: ~p", [MonRef, Pid]),
+ "~n MonRef: ~p"
+ "~n Pid: ~p", [MonRef, Pid]),
receive
{started, Pid} ->
d("await_started ~p - started"
- "~n Process info: ~p", [Pid, (catch proc_info(Pid))]),
+ "~n Process Info: ~p", [Pid, (catch proc_info(Pid))]),
true = erlang:monitor_node(Node, false),
erlang:demonitor(MonRef),
{ok, Pid};
@@ -210,13 +208,13 @@ await_started(Node, MonRef, Pid) ->
exit({node_down, Node});
{'DOWN', MonRef, process, Pid, Info} ->
- i("await_started ~p - received down signal: ~p",
+ e("await_started ~p - received down signal: ~p",
[Pid, Info]),
true = erlang:monitor_node(Node, false),
exit({failed_starting, Pid, Info});
{'EXIT', Pid, Reason} ->
- i("await_started ~p - received exit signal: ~p", [Pid, Reason]),
+ e("await_started ~p - received exit signal: ~p", [Pid, Reason]),
true = erlang:monitor_node(Node, false),
exit({failed_starting, Pid, Reason})
@@ -226,10 +224,10 @@ await_started(Node, MonRef, Pid) ->
NodePing = net_adm:ping(Node),
ProcInfo = (catch proc_info(Pid)),
FlushQ = megaco_test_lib:flush(),
- i("await_started ~p - timeout: "
- "~n net_adm:ping(~p): ~p"
- "~n Process info: ~p"
- "~n Messages in my queue: ~p",
+ e("await_started ~p - timeout: "
+ "~n net_adm:ping(~p): ~p"
+ "~n Process info: ~p"
+ "~n Messages in my queue: ~p",
[Pid, Node, NodePing, ProcInfo, FlushQ]),
true = erlang:monitor_node(Node, false),
exit({error, timeout})
@@ -371,19 +369,21 @@ mg(Parent, Verbosity, Config) ->
{'EXIT', normal} ->
exit(normal);
{'EXIT', Reason} ->
- i("mg failed with reason:~n ~p", [Reason]),
+ e("mg failed with reason:"
+ "~n ~p", [Reason]),
exit(Reason);
Else ->
- i("mg terminated: ~n ~p", [Else]),
+ e("mg terminated:"
+ "~n ~p", [Else]),
exit({unexpected, Else})
end
end.
init(Config) ->
d("init -> entry with"
- "~n Config: ~p", [Config]),
+ "~n Config: ~p", [Config]),
random_init(),
- d("init -> random initiated", []),
+ d("init -> random initiated"),
Mid = get_conf(local_mid, Config),
d("init -> Mid: ~p", [Mid]),
RI = get_conf(receive_info, Config),
@@ -462,8 +462,8 @@ loop(#mg{parent = Parent, mid = Mid} = S) ->
i("loop -> enable_test_code: ~p, ~p", [Tag, Fun]),
Reply = (catch ets:insert(megaco_test_data, {Tag, Fun})),
d("loop -> enable_test_code -> "
- "~n Reply: ~p"
- "~n ets:tab2list(megaco_test_data): ~p",
+ "~n Reply: ~p"
+ "~n ets:tab2list(megaco_test_data): ~p",
[Reply,ets:tab2list(megaco_test_data)]),
server_reply(Parent, enable_test_code_reply, Reply),
loop(evs(S, {enable_test_code, Tag}));
@@ -476,13 +476,13 @@ loop(#mg{parent = Parent, mid = Mid} = S) ->
%% Give me statistics
{statistics, Parent} ->
- i("loop -> got request for statistics", []),
+ i("loop -> got request for statistics"),
Stats = do_get_statistics(Mid),
server_reply(Parent, statistics_reply, {ok, Stats}),
loop(evs(S, stats));
{reset_stats, Parent} ->
- i("loop -> got request to reset stats counters", []),
+ i("loop -> got request to reset stats counters"),
do_reset_stats(Mid),
server_reply(Parent, reset_stats_ack, ok),
loop(evs(S, rst_stats));
@@ -518,11 +518,11 @@ loop(#mg{parent = Parent, mid = Mid} = S) ->
%% No server-reply here. Since the service change is
%% async, the reply (from the MGC) will come later.
{service_change, Parent} ->
- i("loop -> received request to perform service change", []),
+ i("loop -> received request to perform service change"),
S1 =
case (catch do_service_change(S)) of
{ok, MG} ->
- d("loop -> service change initiated", []),
+ d("loop -> service change initiated"),
MG;
Error ->
d("loop -> service change failed: ~p", [Error]),
@@ -538,16 +538,16 @@ loop(#mg{parent = Parent, mid = Mid} = S) ->
loop(evs(S#mg{group_size = N}, {grp_reqs, N}));
{{ack_info, To}, Parent} ->
- i("loop -> received request to inform about received ack's ", []),
+ i("loop -> received request to inform about received ack's"),
loop(evs(S#mg{ack_info = To}, {acki, To}));
{{rep_info, To}, Parent} ->
- i("loop -> received request to inform about received rep's ", []),
+ i("loop -> received request to inform about received rep's "),
loop(evs(S#mg{rep_info = To}, {repi, To}));
%% Make a sync-call
{notify_request, Parent} ->
- i("loop -> received request to send notify request ", []),
+ i("loop -> received request to send notify request "),
{Res, S1} = do_handle_notify_request(S),
d("loop -> notify request result: ~p", [Res]),
loop(evs(S1, not_req));
@@ -564,7 +564,7 @@ loop(#mg{parent = Parent, mid = Mid} = S) ->
%% cancel requests
{cancel_request, Reason, Parent} ->
- i("loop -> received request to cancel (all) megaco requests ", []),
+ i("loop -> received request to cancel (all) megaco requests"),
Res = do_cancel_requests(Mid, Reason),
server_reply(Parent, cancel_request_reply, Res),
loop(evs(S, {creq, Reason}));
@@ -600,25 +600,28 @@ loop(#mg{parent = Parent, mid = Mid} = S) ->
%% Megaco callback messages
{request, Request, Mid, From} ->
- d("loop -> received megaco request: ~n ~p"
- "~n Mid: ~p"
- "~n From: ~p",
+ d("loop -> received megaco request: "
+ "~n ~p"
+ "~n Mid: ~p"
+ "~n From: ~p",
[Request, Mid, From]),
{Reply, S1} = handle_megaco_request(S, Request),
- d("loop -> send (megaco callback) request reply: ~n~p", [Reply]),
+ d("loop -> send (megaco callback) request reply:"
+ "~n ~p", [Reply]),
From ! {reply, Reply, self()},
loop(evs(S1, {req, {Request, Mid, From}}));
{'EXIT', Pid, Reason} ->
i("loop -> received exit signal from ~p: "
- "~n ~p", [Pid, Reason]),
+ "~n ~p", [Pid, Reason]),
S1 = handle_exit(S, Pid, Reason),
loop(evs(S1, {exit, {Pid, Reason}}));
Invalid ->
- error_msg("received invalid request: ~n~p", [Invalid]),
+ error_msg("received invalid request: "
+ "~n ~p", [Invalid]),
loop(evs(S, {invalid, Invalid}))
end.
@@ -793,10 +796,10 @@ do_service_change(#mg{state = State} = MG) ->
do_service_change(ConnHandle, Method, EAF, Reason) ->
d("send service change using:"
- "~n ConnHandle: ~p"
- "~n Method: ~p"
- "~n EAF: ~p"
- "~n Reason: ~p", [ConnHandle, Method, EAF, Reason]),
+ "~n ConnHandle: ~p"
+ "~n Method: ~p"
+ "~n EAF: ~p"
+ "~n Reason: ~p", [ConnHandle, Method, EAF, Reason]),
SCP = cre_serviceChangeParm(Method, [Reason]),
TermId = [?megaco_root_termination_id],
SCR = cre_serviceChangeReq(TermId, SCP),
@@ -816,7 +819,7 @@ do_handle_notify_request(#mg{mid = Mid,
{ok, MG#mg{req_handler = Pid}};
do_handle_notify_request(#mg{state = State} = MG) ->
d("do_handle_notify_request -> entry with"
- "~n State: ~p", [State]),
+ "~n State: ~p", [State]),
{{error, {invalid_state, State}}, MG}.
@@ -867,7 +870,7 @@ handle_exit(#mg{parent = Pid} = S, Pid, Reason) ->
handle_exit(#mg{parent = Parent, req_handler = Pid} = MG, Pid, Reason) ->
error_msg("received unexpected exit from the request handler:"
- "~n ~p", [Reason]),
+ "~n ~p", [Reason]),
server_reply(Parent, notify_request_reply,
{error, {request_handler_exit, Reason}}),
MG#mg{req_handler = undefined};
@@ -875,14 +878,14 @@ handle_exit(#mg{parent = Parent, req_handler = Pid} = MG, Pid, Reason) ->
handle_exit(#mg{parent = Parent, mload_info = {Loaders0, Ok, Err}} = MG,
Pid, loader_done) ->
d("handle_exit(loader_done) -> entry when"
- "~n Loaders0: ~p"
- "~n Ok: ~p"
- "~n Err: ~p", [Loaders0, Ok, Err]),
+ "~n Loaders0: ~p"
+ "~n Ok: ~p"
+ "~n Err: ~p", [Loaders0, Ok, Err]),
Loaders = lists:delete(Pid, Loaders0),
LoadInfo =
case Loaders of
[] ->
- d("handle_exit -> multi load done", []),
+ d("handle_exit -> multi load done"),
server_reply(Parent, apply_multi_load_ack, {ok, Ok+1, Err}),
undefined;
_ ->
@@ -895,10 +898,10 @@ handle_exit(#mg{parent = Parent, mload_info = {Loaders, Ok, Err}} = MG,
Pid, Reason)
when length(Loaders) > 0 ->
d("handle_exit -> entry when"
- "~n Reason: ~p"
- "~n Loaders: ~p"
- "~n Ok: ~p"
- "~n Err: ~p", [Reason, Loaders, Ok, Err]),
+ "~n Reason: ~p"
+ "~n Loaders: ~p"
+ "~n Ok: ~p"
+ "~n Err: ~p", [Reason, Loaders, Ok, Err]),
case lists:delete(Pid, Loaders) of
[] ->
%% since we cannot be empty prior the delete,
@@ -907,15 +910,15 @@ handle_exit(#mg{parent = Parent, mload_info = {Loaders, Ok, Err}} = MG,
MG#mg{mload_info = undefined};
Loaders ->
%% Could not be this MG, so go on to the next
- error_msg("received unexpected exit signal from ~p:~n~p",
- [Pid, Reason]);
+ error_msg("received unexpected exit signal from ~p:"
+ "~n ~p", [Pid, Reason]);
Loaders1 ->
%% Not empty, but we removed one
MG#mg{mload_info = {Loaders1,Ok,Err+1}}
end;
handle_exit(_MG, Pid, Reason) ->
- error_msg("received unexpected exit signal from ~p:~n~p",
- [Pid, Reason]).
+ error_msg("received unexpected exit signal from ~p:"
+ "~n ~p", [Pid, Reason]).
parse_receive_info(RI, RH) ->
@@ -949,10 +952,10 @@ start_transport(_, _, #megaco_receive_handle{send_mod = Mod}, _TO) ->
start_tcp(MgcPort, MgcHost, RH, TO) ->
d("start tcp transport: "
- "~n MGC Port: ~p"
- "~n MGC Host: ~p"
- "~n Receive handle: ~p"
- "~n Transport options: ~p", [MgcPort, MgcHost, RH, TO]),
+ "~n MGC Port: ~p"
+ "~n MGC Host: ~p"
+ "~n Receive handle: ~p"
+ "~n Transport options: ~p", [MgcPort, MgcHost, RH, TO]),
case megaco_tcp:start_transport() of
{ok, Sup} ->
d("tcp transport started: ~p", [Sup]),
@@ -1026,11 +1029,11 @@ megaco_udp_connect(MgcPort, MgcHost, RH, Handle, ControlPid) ->
update_load_times(#mg{load_counter = 0} = MG, Times) ->
d("update_load_times(0) -> entry with"
- "~n Times: ~p", [Times]),
+ "~n Times: ~p", [Times]),
{ok, MG#mg{load_counter = Times}};
update_load_times(#mg{load_counter = N}, Times) ->
d("update_load_times(~p) -> entry with"
- "~n Times: ~p", [N, Times]),
+ "~n Times: ~p", [N, Times]),
{error, {already_counting, N}}.
@@ -1050,14 +1053,14 @@ do_apply_load(#mg{parent = Parent,
group_size = Sz,
load_counter = N0} = MG, CH) ->
d("do_apply_load -> entry with"
- "~n Mode: ~p"
- "~n Sz: ~p"
- "~n N0: ~p", [Mode, Sz, N0]),
+ "~n Mode: ~p"
+ "~n Sz: ~p"
+ "~n N0: ~p", [Mode, Sz, N0]),
{NofSent, Actions, ReplyData} = make_notify_request(N0, Sz),
d("do_apply_load -> notifications constructed:"
- "~n NofSent: ~p"
- "~n Actions: ~p"
- "~n ReplyData: ~p", [NofSent, Actions, ReplyData]),
+ "~n NofSent: ~p"
+ "~n Actions: ~p"
+ "~n ReplyData: ~p", [NofSent, Actions, ReplyData]),
N = N0 - NofSent,
case Mode of
sync ->
@@ -1084,9 +1087,9 @@ do_apply_load(#mg{parent = Parent,
start_notify_request_handler(EAF, CH, N) ->
d("start_notify_request_handler -> entry with"
- "~n EAF: ~p"
- "~n CH: ~p"
- "~n N: ~p", [EAF, CH, N]),
+ "~n EAF: ~p"
+ "~n CH: ~p"
+ "~n N: ~p", [EAF, CH, N]),
Env = get(),
spawn_link(?MODULE, notify_request_handler_main, [self(), Env, EAF, CH, N]).
@@ -1094,13 +1097,13 @@ notify_request_handler_main(Parent, Env, EAF, CH, N) ->
F = fun({Tag, Val}) -> put(Tag, Val) end,
lists:foreach(F, Env),
d("notify_request_handler_main -> entry with"
- "~n Parent: ~p"
- "~n EAF: ~p"
- "~n CH: ~p"
- "~n N: ~p", [Parent, EAF, CH, N]),
+ "~n Parent: ~p"
+ "~n EAF: ~p"
+ "~n CH: ~p"
+ "~n N: ~p", [Parent, EAF, CH, N]),
Res = do_notify_request(EAF, CH, N),
d("notify_request_handler_main -> notify complete:"
- "~n Res: ~p", [Res]),
+ "~n Res: ~p", [Res]),
Parent ! {notify_request_complete, {ok, Res}, self()},
unlink(Parent),
exit(normal).
@@ -1220,7 +1223,7 @@ handle_megaco_request(#mg{req_handler = Pid} = MG,
{handle_disconnect, _CH, _PV, R})
when is_pid(Pid) ->
d("handle_megaco_request(handle_disconnect) -> entry with"
- "~n Pid: ~p", [Pid]),
+ "~n Pid: ~p", [Pid]),
Error = {error, {disconnected, R}},
self() ! {notify_request_complete, Error, Pid},
unlink(Pid),
@@ -1238,19 +1241,19 @@ handle_megaco_request(#mg{req_handler = Pid} = MG,
{handle_message_error, CH, PV, ED})
when is_pid(Pid) ->
d("handle_megaco_request(handle_message_error) -> entry with"
- "~n Pid: ~p"
- "~n CH: ~p"
- "~n PV: ~p"
- "~n ED: ~p", [Pid, CH, PV, ED]),
+ "~n Pid: ~p"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n ED: ~p", [Pid, CH, PV, ED]),
self() ! {notify_request_complete, ED, Pid},
unlink(Pid),
exit(Pid, kill),
{no_reply, MG#mg{req_handler = undefined}};
handle_megaco_request(MG, {handle_message_error, CH, PV, ED}) ->
d("handle_megaco_request(handle_message_error) -> entry with"
- "~n CH: ~p"
- "~n PV: ~p"
- "~n ED: ~p", [CH, PV, ED]),
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n ED: ~p", [CH, PV, ED]),
{no_reply, MG};
handle_megaco_request(MG, {handle_trans_request, _CH, _PV, _AR}) ->
@@ -1283,31 +1286,31 @@ handle_megaco_request(MG, {handle_trans_ack, _CH, _PV, _AS, _AD}) ->
do_handle_trans_reply(#mg{parent = Parent, state = connecting} = MG,
CH, _PV, {ok, Rep}, _RD) ->
d("do_handle_trans_reply(connecting) -> entry with"
- "~n CH: ~p"
- "~n Rep: ~p", [CH, Rep]),
+ "~n CH: ~p"
+ "~n Rep: ~p", [CH, Rep]),
server_reply(Parent, service_change_reply, ok),
{ok, MG#mg{state = connected}};
do_handle_trans_reply(#mg{parent = Parent, load_counter = 0} = MG,
CH, _PV, {ok, Rep}, _RD) ->
d("do_handle_trans_reply(load_counter = 0) -> entry with"
- "~n CH: ~p"
- "~n Rep: ~p", [CH, Rep, Parent]),
+ "~n CH: ~p"
+ "~n Rep: ~p", [CH, Rep, Parent]),
handle_trans_reply_verify_act(Rep),
server_reply(Parent, load_complete, ok),
{ok, MG#mg{reply_counter = 0}};
do_handle_trans_reply(#mg{reply_counter = 0} = MG,
CH, _PV, {ok, Rep}, _RD) ->
d("do_handle_trans_reply(reply_counter = 0) -> entry with"
- "~n CH: ~p"
- "~n Rep: ~p", [CH, Rep]),
+ "~n CH: ~p"
+ "~n Rep: ~p", [CH, Rep]),
handle_trans_reply_verify_act(Rep),
apply_load_timer(),
{ok, MG};
do_handle_trans_reply(#mg{reply_counter = N} = MG,
CH, _PV, {ok, Rep}, _RD) ->
d("do_handle_trans_reply(reply_counter = ~p) -> entry with"
- "~n CH: ~p"
- "~n Rep: ~p", [N, CH, Rep]),
+ "~n CH: ~p"
+ "~n Rep: ~p", [N, CH, Rep]),
handle_trans_reply_verify_act(Rep),
apply_load_timer(),
{ok, MG#mg{reply_counter = N-1}};
@@ -1529,11 +1532,18 @@ num2str(N, Val) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% e(F) ->
+%% i(F, []).
+
+e(F, A) ->
+ print(error, get(verbosity), "ERROR", F, A).
+
+
i(F) ->
i(F, []).
i(F, A) ->
- print(info, get(verbosity), "", F, A).
+ print(info, get(verbosity), "INFO", F, A).
d(F) ->
@@ -1543,15 +1553,16 @@ d(F, A) ->
print(debug, get(verbosity), "DBG", F, A).
+printable(error, _) -> true;
printable(_, debug) -> true;
printable(info, info) -> true;
printable(_,_) -> false.
print(Severity, Verbosity, P, F, A) ->
- print(printable(Severity,Verbosity), P, F, A).
+ print(printable(Severity, Verbosity), P, F, A).
print(true, P, F, A) ->
- io:format("*** [~s] ~s ~p ~s ***"
+ io:format("*** [~s] [~s] ~p ~s ***"
"~n " ++ F ++ "~n~n",
[?FTS(), P, self(), get(sname) | A]);
print(_, _, _, _) ->
diff --git a/lib/megaco/test/megaco_test_mgc.erl b/lib/megaco/test/megaco_test_mgc.erl
index a9027ca68e..8a9b182368 100644
--- a/lib/megaco/test/megaco_test_mgc.erl
+++ b/lib/megaco/test/megaco_test_mgc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -90,7 +90,9 @@ start(Node, Mid, ET, Verbosity) ->
start(Node, Mid, ET, Conf, Verbosity).
start(Node, Mid, ET, Conf, Verbosity) ->
- d("start mgc[~p]: ~p", [Node, Mid]),
+ d("start mgc[~p]: ~p"
+ "~n ET: ~p"
+ "~n Conf: ~p", [Node, Mid, ET, Conf]),
RI = {receive_info, mk_recv_info(ET)},
Config = [{local_mid, Mid}, RI] ++ Conf,
Pid = spawn_link(Node, ?MODULE, mgc, [self(), Verbosity, Config]),
@@ -160,13 +162,13 @@ await_started(Pid) ->
{ok, Pid};
{'EXIT', Pid,
{failed_starting_tcp_listen, {could_not_start_listener, {gen_tcp_listen, eaddrinuse}}}} ->
- i("await_started ~p: address already in use", [Pid]),
+ e("await_started ~p: address already in use", [Pid]),
?SKIP(eaddrinuse);
{'EXIT', Pid, Reason} ->
- i("await_started ~p: received exit signal: ~p", [Pid, Reason]),
+ e("await_started ~p: received exit signal: ~p", [Pid, Reason]),
exit({failed_starting, Pid, Reason})
after 10000 ->
- i("await_started ~p: timeout", [Pid]),
+ e("await_started ~p: timeout", [Pid]),
exit({error, timeout})
end.
@@ -365,19 +367,19 @@ loop(S) ->
loop(evs(S#mgc{dsi_timer = NewTimer}, {dsi, Time}));
{stop, Parent} when S#mgc.parent =:= Parent ->
- i("loop -> stopping", []),
+ i("loop -> stopping"),
display_system_info(S#mgc.mid, "at finish "),
cancel_timer(S#mgc.dsi_timer),
Mid = S#mgc.mid,
(catch close_conns(Mid)),
megaco:stop_user(Mid),
application:stop(megaco),
- i("loop -> stopped", []),
+ i("loop -> stopped"),
server_reply(Parent, stopped, ok),
done(evs(S, stop), normal);
{{disconnect, Reason}, Parent} when S#mgc.parent == Parent ->
- i("loop -> disconnecting", []),
+ i("loop -> disconnecting"),
Mid = S#mgc.mid,
[Conn|_] = megaco:user_info(Mid, connections),
Res = megaco:disconnect(Conn, {self(), Reason}),
@@ -485,8 +487,8 @@ loop(S) ->
%% Megaco callback messages
{request, Request, From} ->
- d("loop -> received megaco request from ~p:~n~p",
- [From, Request]),
+ d("loop -> received megaco request from ~p:"
+ "~n ~p", [From, Request]),
{Reply, S1} = handle_megaco_request(Request, S),
d("loop -> send request reply: ~n~p", [Reply]),
reply(From, Reply),
@@ -494,17 +496,17 @@ loop(S) ->
{ack_info, To, Parent} when S#mgc.parent == Parent ->
- i("loop -> received request to inform about received ack's ", []),
+ i("loop -> received request to inform about received ack's "),
loop(evs(S#mgc{ack_info = To}, {acki, To}));
{abort_info, To, Parent} when S#mgc.parent == Parent ->
- i("loop -> received request to inform about received aborts ", []),
+ i("loop -> received request to inform about received aborts "),
loop(evs(S#mgc{abort_info = To}, {abi, To}));
{req_info, To, Parent} when S#mgc.parent == Parent ->
- i("loop -> received request to inform about received req's ", []),
+ i("loop -> received request to inform about received req's "),
loop(evs(S#mgc{req_info = To}, {reqi, To}));
@@ -516,16 +518,16 @@ loop(S) ->
{'EXIT', Pid, Reason} when S#mgc.tcp_sup =:= Pid ->
error_msg("MGC received unexpected exit "
- "from TCP transport supervisor (~p):~n~p",
- [Pid, Reason]),
- i("loop -> [tcp] exiting", []),
+ "from TCP transport supervisor (~p):"
+ "~n ~p", [Pid, Reason]),
+ i("loop -> [tcp] exiting"),
display_system_info(S#mgc.mid, "at bad finish (tcp) "),
cancel_timer(S#mgc.dsi_timer),
Mid = S#mgc.mid,
(catch close_conns(Mid)),
megaco:stop_user(Mid),
application:stop(megaco),
- i("loop -> stopped", []),
+ i("loop -> stopped"),
StopReason = {error, {tcp_terminated, Pid, Reason}},
server_reply(S#mgc.parent, stopped, StopReason),
done(evs(S, {tcp_sup_exit, Reason}), StopReason);
@@ -533,16 +535,16 @@ loop(S) ->
{'EXIT', Pid, Reason} when S#mgc.udp_sup =:= Pid ->
error_msg("MGC received unexpected exit "
- "from UDP transport supervisor (~p):~n~p",
- [Pid, Reason]),
- i("loop -> [udp] exiting", []),
+ "from UDP transport supervisor (~p):"
+ "~n ~p", [Pid, Reason]),
+ i("loop -> [udp] exiting"),
display_system_info(S#mgc.mid, "at bad finish (udp) "),
cancel_timer(S#mgc.dsi_timer),
Mid = S#mgc.mid,
(catch close_conns(Mid)),
megaco:stop_user(Mid),
application:stop(megaco),
- i("loop -> stopped", []),
+ i("loop -> stopped"),
StopReason = {error, {udp_terminated, Pid, Reason}},
server_reply(S#mgc.parent, stopped, StopReason),
done(evs(S, {udp_sup_exit, Reason}), StopReason);
@@ -619,13 +621,13 @@ parse_receive_info(RI, RH) ->
parse_receive_info([], _RH, Transports) ->
d("parse_receive_info -> done when"
- "~n Transports: ~p", [Transports]),
+ "~n Transports: ~p", [Transports]),
Transports;
parse_receive_info([RI|RIs], RH, Transports) ->
d("parse_receive_info -> parse receive info"),
case (catch parse_receive_info1(RI, RH)) of
{error, Reason} ->
- i("failed parsing receive info: ~p~n~p", [RI, Reason]),
+ e("failed parsing receive info: ~p~n~p", [RI, Reason]),
exit({failed_parsing_recv_info, RI, Reason});
RH1 ->
parse_receive_info(RIs, RH, [RH1|Transports])
@@ -646,9 +648,9 @@ parse_receive_info1(RI, RH) ->
encoding_mod = EM,
encoding_config = EC},
d("parse_receive_info1 -> "
- "~n Transport Opts: ~p"
- "~n Port: ~p"
- "~n Receive handle: ~p", [TO, TP, RH1]),
+ "~n Transport Opts: ~p"
+ "~n Port: ~p"
+ "~n Receive handle: ~p", [TO, TP, RH1]),
{TO, TP, RH1}.
@@ -675,19 +677,27 @@ start_transports1([], Tcp, Udp) ->
start_transports1([{_TO, _Port, RH}|Transports], Tcp, Udp)
when ((RH#megaco_receive_handle.send_mod =:= megaco_tcp) andalso
(not is_pid(Tcp))) ->
+ d("try start tcp transport service"),
case megaco_tcp:start_transport() of
{ok, Sup} ->
+ d("tcp transport service started: ~p", [Sup]),
start_transports1(Transports, Sup, Udp);
Else ->
+ e("Failed starting TCP transport service:"
+ "~n ~p", [Else]),
throw({error, {failed_starting_tcp_transport, Else}})
end;
start_transports1([{_TO, _Port, RH}|Transports], Tcp, Udp)
when ((RH#megaco_receive_handle.send_mod =:= megaco_udp) andalso
(not is_pid(Udp))) ->
+ d("try start udp transport servuice"),
case megaco_udp:start_transport() of
{ok, Sup} ->
+ d("udp transport started: ~p", [Sup]),
start_transports1(Transports, Tcp, Sup);
Else ->
+ e("Failed starting UDP transport service:"
+ "~n ~p", [Else]),
throw({error, {failed_starting_udp_transport, Else}})
end;
start_transports1([_|Transports], Tcp, Udp) ->
@@ -831,34 +841,34 @@ handle_megaco_request({handle_trans_reply, _CH, _PV, _AR, _RD}, S) ->
handle_megaco_request({handle_trans_ack, CH, PV, AS, AD},
#mgc{ack_info = P} = S) when is_pid(P) ->
d("handle_megaco_request(handle_trans_ack,~p) -> entry when"
- "~n CH: ~p"
- "~n PV: ~p"
- "~n AS: ~p"
- "~n AD: ~p", [P, CH, PV, AS, AD]),
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n AS: ~p"
+ "~n AD: ~p", [P, CH, PV, AS, AD]),
P ! {ack_received, self(), AS},
{ok, S};
handle_megaco_request({handle_trans_ack, CH, PV, AS, AD}, S) ->
d("handle_megaco_request(handle_trans_ack) -> entry with"
- "~n Conn Handle: ~p"
- "~n Prot Version: ~p"
- "~n Ack Status: ~p"
- "~n Ack Data: ~p", [CH, PV, AS, AD]),
+ "~n Conn Handle: ~p"
+ "~n Prot Version: ~p"
+ "~n Ack Status: ~p"
+ "~n Ack Data: ~p", [CH, PV, AS, AD]),
{ok, S};
handle_megaco_request({handle_unexpected_trans, CH, PV, TR}, S) ->
d("handle_megaco_request(handle_unexpected_trans) -> entry with"
- "~n CH: ~p"
- "~n PV: ~p"
- "~n TR: ~p", [CH, PV, TR]),
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n TR: ~p", [CH, PV, TR]),
{ok, S};
handle_megaco_request({handle_trans_request_abort, CH, PV, TI, Handler}, S) ->
d("handle_megaco_request(handle_trans_request_abort) -> entry with"
- "~n CH: ~p"
- "~n PV: ~p"
- "~n TI: ~p"
- "~n Handler: ~p", [CH, PV, TI, Handler]),
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n TI: ~p"
+ "~n Handler: ~p", [CH, PV, TI, Handler]),
Reply =
case S#mgc.abort_info of
P when is_pid(P) ->
@@ -873,8 +883,8 @@ handle_megaco_request({handle_trans_request_abort, CH, PV, TI, Handler}, S) ->
do_handle_trans_request(CH, PV, ARs,
#mgc{req_action = Action, req_timeout = To} = S) ->
d("do_handle_megaco_request(handle_trans_request) -> entry with"
- "~n Action: ~p"
- "~n To: ~p", [Action, To]),
+ "~n Action: ~p"
+ "~n To: ~p", [Action, To]),
case handle_act_requests(CH, PV, ARs, Action) of
{pending_ignore, ActReqs} ->
{{pending, ActReqs}, S#mgc{req_action = ignore}};
@@ -950,8 +960,8 @@ handle_notify_req(CH, PV, CtxId,
handle_event(_CH, _PV, _Cid, Tid, EvDesc) ->
d("handle_event -> received"
- "~n EvDesc: ~p"
- "~n Tid: ~p", [EvDesc, Tid]),
+ "~n EvDesc: ~p"
+ "~n Tid: ~p", [EvDesc, Tid]),
{notifyReply, cre_notifyRep(Tid)}.
@@ -1195,20 +1205,24 @@ cancel_timer(Ref) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+e(F, A) ->
+ print(error, get(verbosity), "ERROR", F, A).
+
i(F) ->
i(F, []).
i(F, A) ->
- print(info, get(verbosity), "", F, A).
+ print(info, get(verbosity), "INFO", F, A).
d(F) ->
d(F, []).
d(F, A) ->
- print(debug, get(verbosity), "DBG: ", F, A).
+ print(debug, get(verbosity), "DBG", F, A).
+printable(error, _) -> true;
printable(_, debug) -> true;
printable(info, info) -> true;
printable(_,_) -> false.
@@ -1222,7 +1236,7 @@ print(_, _, _, _) ->
ok.
print(P, F, A) ->
- io:format("*** [~s] ~s ~p ~s ***"
+ io:format("*** [~s] [~s] ~p ~s ***"
"~n " ++ F ++ "~n~n",
[?FTS(), P, self(), get(sname) | A]).
diff --git a/lib/megaco/test/megaco_test_tcp_generator.erl b/lib/megaco/test/megaco_test_tcp_generator.erl
index ec256f7a87..0edeac6733 100644
--- a/lib/megaco/test/megaco_test_tcp_generator.erl
+++ b/lib/megaco/test/megaco_test_tcp_generator.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -404,6 +404,7 @@ handle_exec({expect_receive, Desc, {Verify, To}},
e("received unknown message: ~p", [Else]),
{error, {expect_receive, {unexpected_message, Else}}}
after To ->
+ e("(expect) receive timeout: ~w", [To]),
{error, {expect_receive, timeout}}
end;
@@ -412,14 +413,14 @@ handle_exec({expect_closed, To},
result = Acc} = State) ->
p("expect_closed ~w", [To]),
inet:setopts(Sock, [{active, once}]),
- p("expect_closed - await closed", []),
+ d("expect_closed - await closed", []),
receive
{tcp_closed, Sock} ->
p("expect_closed - received closed"),
{ok, State#state{connection = undefined,
result = [closed|Acc]}}
after To ->
- e("expect_closed timeout after ~w", [To]),
+ e("(expect) closed timeout after ~w", [To]),
{error, {expect_closed, timeout}}
end;
@@ -428,13 +429,13 @@ handle_exec({expect_nothing, To},
result = Acc} = State) ->
p("expect_nothing ~w", [To]),
inet:setopts(Sock, [{active, once}]),
- p("expect_nothing - await anything", []),
+ d("expect_nothing - await anything", []),
receive
Any ->
e("expect_nothing - received: ~p", [Any]),
{error, {expect_nothing, Any}}
after To ->
- p("expect_nothing timeout after ~w", [To]),
+ p("got nothing (~w) as expected", [To]),
{ok, State#state{result = [{nothing, To}|Acc]}}
end;
@@ -502,6 +503,6 @@ e(F, A) -> megaco_test_generator:error(F, A).
p(F ) -> p("", F, []).
p(F, A) -> p("", F, A).
-p(P, F, A) -> megaco_test_generator:print(P, F, A).
+p(P, F, A) -> megaco_test_generator:print(P, F, A).
diff --git a/lib/megaco/test/megaco_trans_SUITE.erl b/lib/megaco/test/megaco_trans_SUITE.erl
index c1c333a305..1e281987b8 100644
--- a/lib/megaco/test/megaco_trans_SUITE.erl
+++ b/lib/megaco/test/megaco_trans_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -308,19 +308,25 @@ single_ack(suite) ->
single_ack(doc) ->
[];
single_ack(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, single_ack),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_single_ack/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(rsingle_ack, Pre, Case, Post).
+
+do_single_ack([MgcNode, MgNode]) ->
%% Start the MGC and MGs
i("[MGC] start"),
ET = [{text,tcp}, {text,udp}, {binary,tcp}, {binary,udp}],
@@ -375,26 +381,33 @@ multi_ack_timeout(suite) ->
multi_ack_timeout(doc) ->
[];
multi_ack_timeout(Config) when is_list(Config) ->
- %% <CONDITIONAL-SKIP>
- Skippable = [win32, {unix, [darwin, linux, sunos]}], % Is there any left?
- Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
- ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
- %% </CONDITIONAL-SKIP>
-
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_ack_timeout),
- i("starting"),
+ Pre = fun() ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [win32, {unix, [darwin, linux, sunos]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_ack_timeout/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_ack_timeout, Pre, Case, Post).
+do_multi_ack_timeout([MgcNode, MgNode]) ->
MaxCount = 20,
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -459,19 +472,26 @@ multi_ack_maxcount(suite) ->
multi_ack_maxcount(doc) ->
[];
multi_ack_maxcount(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_ack_maxcount),
- i("starting"),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_ack_maxcount/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_ack_maxcount, Pre, Case, Post).
+
+do_multi_ack_maxcount([MgcNode, MgNode]) ->
MaxCount = 10,
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
%% Start the MGC and MGs
i("[MGC] start"),
@@ -523,7 +543,6 @@ multi_ack_maxcount(Config) when is_list(Config) ->
i("wait some time before closing down"),
sleep(5000),
-
%% Tell MG to stop
i("[MG] stop"),
?MG_STOP(Mg),
@@ -544,20 +563,25 @@ single_trans_req(suite) ->
single_trans_req(doc) ->
[];
single_trans_req(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, single_trans_req),
- process_flag(trap_exit, true),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_single_trans_req/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(single_trans_req, Pre, Case, Post).
+do_single_trans_req([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -984,19 +1008,25 @@ multi_trans_req_timeout(suite) ->
multi_trans_req_timeout(doc) ->
[];
multi_trans_req_timeout(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_timeout),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_timeout/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(request_and_no_reply, Pre, Case, Post).
+do_multi_trans_req_timeout([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -1438,20 +1468,25 @@ multi_trans_req_maxcount1(suite) ->
multi_trans_req_maxcount1(doc) ->
"Test that a message is sent when req_maxcount is reached";
multi_trans_req_maxcount1(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_maxcount1),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_maxcount1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_maxcount1, Pre, Case, Post).
+
+do_multi_trans_req_maxcount1([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -1895,19 +1930,25 @@ multi_trans_req_maxcount2(doc) ->
"Test that the message is sent when req_maxcount is reached "
"with a request bigger then maxsize limit";
multi_trans_req_maxcount2(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_maxcount2),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_maxcount2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_maxcount2, Pre, Case, Post).
+do_multi_trans_req_maxcount2([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -2404,19 +2445,30 @@ multi_trans_req_maxsize1(suite) ->
multi_trans_req_maxsize1(doc) ->
"Test that the message is sent when req_maxsize is reached";
multi_trans_req_maxsize1(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_maxsize1),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ put(verbosity, ?TEST_VERBOSITY),
+ put(sname, "TEST"),
+ put(tc, multi_trans_req_maxsize1),
+ i("starting"),
+
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_maxsize1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_maxsize1, Pre, Case, Post).
+do_multi_trans_req_maxsize1([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -2859,19 +2911,25 @@ multi_trans_req_maxsize2(doc) ->
"Test that the message is sent when req_maxsize is reached, "
"when the 'last' message is bigger then req_maxsize itself";
multi_trans_req_maxsize2(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_maxsize2),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_maxsize2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_maxsize2, Pre, Case, Post).
+do_multi_trans_req_maxsize2([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -3356,19 +3414,25 @@ single_trans_req_and_ack(suite) ->
single_trans_req_and_ack(doc) ->
[];
single_trans_req_and_ack(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, single_trans_req_and_ack),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_single_trans_req_and_ack/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(single_trans_req_and_ack, Pre, Case, Post).
+do_single_trans_req_and_ack([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -3839,19 +3903,25 @@ multi_trans_req_and_ack_timeout(suite) ->
multi_trans_req_and_ack_timeout(doc) ->
[];
multi_trans_req_and_ack_timeout(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_and_ack_timeout),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_and_ack_timeout/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_and_ack_timeout, Pre, Case, Post).
+do_multi_trans_req_and_ack_timeout([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -4327,24 +4397,34 @@ mtrtaat_err_desc(T) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Transaction Sender
+%%
+%%
+
multi_trans_req_and_ack_ackmaxcount(suite) ->
[];
multi_trans_req_and_ack_ackmaxcount(doc) ->
[];
multi_trans_req_and_ack_ackmaxcount(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_and_ack_ackmaxcount),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_and_ack_ackmaxcount/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_and_ack_ackmaxcount, Pre, Case, Post).
+do_multi_trans_req_and_ack_ackmaxcount([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -4438,6 +4518,9 @@ mtrtaaamc_mgc_event_sequence(text, tcp) ->
DiscoVerify = ?mtrtaaamc_mgc_verify_handle_disconnect_fun(),
EvSeq = [
{debug, true},
+ {trigger, fun() ->
+ put(verbosity, ?TEST_VERBOSITY)
+ end},
{megaco_trace, disable},
megaco_start,
{megaco_start_user, Mid, RI, []},
@@ -4469,12 +4552,12 @@ mtrtaaamc_mgc_event_sequence(text, tcp) ->
mtrtaaamc_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
- io:format("mtrtaaamc_mgc_verify_handle_connect -> ok"
- "~n CH: ~p~n", [CH]),
+ i("MGC Connect verification ok"
+ "~n ~p~n", [CH]),
{ok, CH, ok};
mtrtaaamc_mgc_verify_handle_connect(Else) ->
- io:format("mtrtaaamc_mgc_verify_handle_connect -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MGC Connect verification failed: unknown"
+ "~n ~p~n", [Else]),
{error, Else, ok}.
mtrtaaamc_mgc_verify_service_change_req_fun(Mid) ->
@@ -4484,8 +4567,9 @@ mtrtaaamc_mgc_verify_service_change_req_fun(Mid) ->
mtrtaaamc_mgc_verify_service_change_req(
{handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
- io:format("mtrtaaamc_mgc_verify_service_change_req -> ok"
- "~n AR: ~p~n", [AR]),
+ i("MGC Service Change Request verification: begin"
+ "~n AR: ~p"
+ "~n", [AR]),
case AR of
#'ActionRequest'{commandRequests = [CR]} ->
case CR of
@@ -4501,11 +4585,17 @@ mtrtaaamc_mgc_verify_service_change_req(
#'ServiceChangeParm'{
serviceChangeMethod = restart,
serviceChangeReason = [[$9,$0,$1|_]]} ->
+ i("MGC Service Change Request "
+ "verification ok"),
Reply =
{discard_ack,
[mtrtaaamc_mgc_service_change_reply_ar(Mid, 1)]},
{ok, AR, Reply};
_ ->
+ e("MGC Service Change Request "
+ "verification failed: invalid SCP"
+ "~n ~p"
+ "~n", [Parms]),
Err = {invalid_SCP, Parms},
ED = mtrtaaamc_err_desc(Parms),
ErrReply = {discard_ack,
@@ -4513,32 +4603,50 @@ mtrtaaamc_mgc_verify_service_change_req(
{error, Err, ErrReply}
end;
_ ->
+ e("MGC Service Change Request "
+ "verification failed: "
+ "invalid termination id"
+ "~n ~p"
+ "~n", [Tid]),
Err = {invalid_termination_id, Tid},
ED = mtrtaaamc_err_desc(Tid),
ErrReply = {discard_ack, ED},
{error, Err, ErrReply}
end;
_ ->
+ e("MGC Service Change Request verification failed: "
+ "invalid command"
+ "~n ~p"
+ "~n", [Cmd]),
Err = {invalid_command, Cmd},
ED = mtrtaaamc_err_desc(Cmd),
ErrReply = {discard_ack, ED},
{error, Err, ErrReply}
end;
_ ->
+ e("MGC Service Change Request verification failed: "
+ "invalid command request"
+ "~n ~p"
+ "~n", [CR]),
Err = {invalid_command_request, CR},
ED = mtrtaaamc_err_desc(CR),
ErrReply = {discard_ack, ED},
{error, Err, ErrReply}
end;
_ ->
+ e("MGC Service Change Request verification failed: "
+ "invalid action request"
+ "~n ~p"
+ "~n", [AR]),
Err = {invalid_action_request, AR},
ED = mtrtaaamc_err_desc(AR),
ErrReply = {discard_ack, ED},
{error, Err, ErrReply}
end;
mtrtaaamc_mgc_verify_service_change_req(Else, _Mid) ->
- io:format("mtrtaaamc_mgc_verify_service_change_req -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MGC Service Change Request verification failed: unknown"
+ "~n ~p"
+ "~n", [Else]),
ED = mtrtaaamc_err_desc(Else),
ErrReply = {discard_ack, ED},
{error, Else, ErrReply}.
@@ -4550,9 +4658,11 @@ mtrtaaamc_mgc_verify_notify_request_fun() ->
mtrtaaamc_mgc_verify_notify_request(
{handle_trans_request, _, ?VERSION, [AR]}) ->
- io:format("mtrtaaamc_mgc_verify_notify_request:fun -> ok"
- "~n AR: ~p~n", [AR]),
+ i("MGC Notify Request verification: begin"
+ "~n AR: ~p"
+ "~n", [AR]),
case AR of
+ %% *** SLOPPY ACK ***
#'ActionRequest'{contextId = 1 = Cid,
commandRequests = [CR]} ->
#'CommandRequest'{command = Cmd} = CR,
@@ -4564,9 +4674,15 @@ mtrtaaamc_mgc_verify_notify_request(
observedEventLst = [OE]} = OED,
#'ObservedEvent'{eventName = "al/of"} = OE,
HandleAck = {handle_sloppy_ack, {kalle, Rid}},
+ i("MGC Notify Request verification ok: sloppy ack"
+ "~n Cid: ~p"
+ "~n Tid: ~p"
+ "~n Rid: ~p", [Cid, Tid, Rid]),
Reply = {HandleAck,
[mtrtaaamc_mgc_notify_reply_ar(Cid, Tid)]},
{ok, AR, Reply};
+
+ %% *** PROPER ACK ***
#'ActionRequest'{contextId = 2 = Cid,
commandRequests = [CR]} ->
#'CommandRequest'{command = Cmd} = CR,
@@ -4574,43 +4690,54 @@ mtrtaaamc_mgc_verify_notify_request(
#'NotifyRequest'{terminationID = [Tid],
observedEventsDescriptor = OED,
errorDescriptor = asn1_NOVALUE} = NR,
- #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
+ #'ObservedEventsDescriptor'{requestId = _Rid,
+ observedEventLst = [OE]} = OED,
#'ObservedEvent'{eventName = "al/of"} = OE,
+ i("MGC Notify Request verification ok: discard ack"
+ "~n Cid: ~p"
+ "~n Tid: ~p"
+ "~n Rid: ~p", [Cid, Tid, _Rid]),
Reply = {discard_ack, [mtrtaaamc_mgc_notify_reply_ar(Cid, Tid)]},
{ok, AR, Reply};
+
_ ->
+ e("MGC Notify Request verification failed: unexpected AR"
+ "~n ~p"
+ "~n", [AR]),
ED = mtrtaaamc_err_desc(AR),
ErrReply = {discard_ack, ED},
{error, AR, ErrReply}
end;
mtrtaaamc_mgc_verify_notify_request(Else) ->
- io:format("mtrtaaamc_mgc_verify_notify_request:fun -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MGC Notify Request verification failed: unexpected callback"
+ "~n ~p"
+ "~n", [Else]),
ED = mtrtaaamc_err_desc(Else),
ErrReply = {discard_ack, ED},
{error, Else, ErrReply}.
mtrtaaamc_mgc_verify_ack({handle_trans_ack, CH, ?VERSION, ok,
{kalle, Rid}}) ->
- io:format("mtrtaaamc_mgc_verify_ack -> ok"
- "~n CH: ~p"
- "~n Rid: ~p"
- "~n", [CH, Rid]),
+ i("MGC Ack verification: ok (kalle)"
+ "~n CH: ~p"
+ "~n Rid: ~p"
+ "~n", [CH, Rid]),
{ok, CH, ok};
mtrtaaamc_mgc_verify_ack(Else) ->
- io:format("mtrtaaamc_mgc_verify_ack -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MGC Ack verification failed: unknown"
+ "~n ~p~n", [Else]),
{error, Else, ok}.
mtrtaaamc_mgc_verify_handle_disconnect({handle_disconnect, CH, ?VERSION, R}) ->
- io:format("mtrtaaamc_mgc_verify_handle_disconnect -> ok"
- "~n CH: ~p"
- "~n R: ~p"
- "~n", [CH, R]),
+ i("MGC Disconnect verification: ok"
+ "~n CH: ~p"
+ "~n R: ~p"
+ "~n", [CH, R]),
{ok, CH, ok};
mtrtaaamc_mgc_verify_handle_disconnect(Else) ->
- io:format("mtrtaaamc_mgc_verify_handle_disconnect -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MGC Disconnect verification failed: unknown"
+ "~n ~p"
+ "~n", [Else]),
{error, Else, ok}.
@@ -4622,26 +4749,11 @@ mtrtaaamc_mgc_service_change_reply_ar(Mid, Cid) ->
CR = cre_cmdReply(SCR),
cre_actionReply(Cid, [CR]).
-%% mtrtaaamc_mgc_service_change_reply_msg(Mid, TransId, Cid) ->
-%% AR = mtrtaaamc_mgc_service_change_reply_ar(Mid, Cid),
-%% TRes = cre_transResult([AR]),
-%% TR = cre_transReply(TransId, TRes),
-%% Trans = cre_transaction(TR),
-%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
-%% cre_megacoMessage(Mess).
-
mtrtaaamc_mgc_notify_reply_ar(Cid, TermId) ->
NR = cre_notifyReply([TermId]),
CR = cre_cmdReply(NR),
cre_actionReply(Cid, [CR]).
-%% mtrtaaamc_mgc_notify_reply(Mid, TransId, Cid, TermId) ->
-%% AR = mtrtaaamc_mgc_notify_reply_ar(Cid, TermId),
-%% TRes = cre_transResult([AR]),
-%% TR = cre_transReply(TransId, TRes),
-%% Trans = cre_transaction(TR),
-%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
-%% cre_megacoMessage(Mess).
%%
@@ -4681,6 +4793,9 @@ mtrtaaamc_mg_event_sequence(text, tcp) ->
NotifyReplyVerify = ?mtrtaaamc_mg_verify_notify_reply_fun(),
EvSeq = [
{debug, true},
+ {trigger, fun() ->
+ put(verbosity, ?TEST_VERBOSITY)
+ end},
megaco_start,
{megaco_start_user, Mid, RI, []},
start_transport,
@@ -4704,20 +4819,35 @@ mtrtaaamc_mg_event_sequence(text, tcp) ->
{megaco_update_conn_info, trans_ack, true},
{megaco_update_conn_info, trans_req, true},
{megaco_conn_info, all},
+ {megaco_conn_info, requests},
{megaco_cast, NR(1,1), []},
+ {megaco_conn_info, requests},
{megaco_cast, NR(1,2), []},
+ {megaco_conn_info, requests},
{megaco_cast, NR(1,3), []},
+ {megaco_conn_info, requests},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_conn_info, requests},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_conn_info, requests},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_conn_info, requests},
{megaco_cast, NR(2,1), []},
+ {megaco_conn_info, requests},
{megaco_cast, NR(2,2), []},
+ {megaco_conn_info, requests},
{megaco_cast, NR(2,3), []},
+ {megaco_conn_info, requests},
{megaco_cast, NR(1,4), [{trans_req,false}]},
+ {megaco_conn_info, requests},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_conn_info, requests},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_conn_info, requests},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_conn_info, requests},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_conn_info, requests},
{sleep, 3000},
megaco_stop_user,
megaco_stop,
@@ -4726,18 +4856,21 @@ mtrtaaamc_mg_event_sequence(text, tcp) ->
EvSeq.
mtrtaaamc_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
- io:format("mtrtaaamc_mg_verify_handle_connect -> ok"
- "~n CH: ~p~n", [CH]),
+ i("MG Connect verification: ok"
+ "~n CH: ~p"
+ "~n", [CH]),
{ok, CH, ok};
mtrtaaamc_mg_verify_handle_connect(Else) ->
- io:format("mtrtaaamc_mg_verify_handle_connect -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MG Connect verification failed: unknown"
+ "~n ~p"
+ "~n", [Else]),
{error, Else, ok}.
mtrtaaamc_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
{ok, [AR]}, _}) ->
- io:format("mtrtaaamc_mg_verify_service_change_reply -> ok"
- "~n AR: ~p~n", [AR]),
+ i("MG Service Change Reply verification: begin"
+ "~n AR: ~p"
+ "~n", [AR]),
case AR of
#'ActionReply'{commandReply = [SCR]} ->
case SCR of
@@ -4751,37 +4884,73 @@ mtrtaaamc_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
{serviceChangeResParms,
#'ServiceChangeResParm'{
serviceChangeMgcId = _RemoteMid}} ->
+ i("MG Service Change Reply verification ok"),
{ok, AR, ok};
{Tag, Val} ->
+ e("MG Service Change Reply "
+ "verification failed: "
+ "invalid service change result"
+ "~n Tag: ~p"
+ "~n Val: ~p"
+ "~n", [Tag, Val]),
Err = {invalid_service_change_result,
Tag, Val},
{error, Err, ok}
end;
_ ->
+ e("MG Service Change Reply verification failed: "
+ "invalid termination id"
+ "~n ~p"
+ "~n", [Tid]),
Err = {invalid_termination_id, Tid},
{error, Err, ok}
end;
{Tag, Val} ->
+ e("MG Service Change Reply verification failed: "
+ "invalid command reply"
+ "~n Tag: ~p"
+ "~n Val: ~p"
+ "~n", [Tag, Val]),
Err = {invalid_command_reply, Tag, Val},
{error, Err, ok}
end;
_ ->
+ e("MG Service Change Reply verification failed: invalid action reply"
+ "~n ~p"
+ "~n", [AR]),
Err = {invalid_action_reply, AR},
{error, Err, ok}
end;
mtrtaaamc_mg_verify_service_change_reply(Else) ->
- io:format("mtrtaaamc_mg_verify_service_change_reply -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MG Service Change Reply verification failed -> unknown"
+ "~n ~p"
+ "~n", [Else]),
{error, Else, ok}.
mtrtaaamc_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
{ok, [AR]}, _}) ->
- io:format("mtrtaaamc_mg_verify_notify_reply -> ok"
- "~n AR: ~p~n", [AR]),
+ i("MG Notify Reply verification ok:"
+ "~n ~p~n", [AR]),
{ok, AR, ok};
+mtrtaaamc_mg_verify_notify_reply({handle_unexpected_trans, CH, PV, T} = Else) ->
+ e("MG Notify Reply verification failed: unexpected transaction"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n T: ~p"
+ "~n", [CH, PV, T]),
+ {error, Else, ok};
+mtrtaaamc_mg_verify_notify_reply({handle_unexpected_trans, CH, PV, E, T} = Else) ->
+ e("MG Notify Reply failed: unexpected transaction"
+ "~n CH: ~p"
+ "~n PV: ~p"
+ "~n E: ~p"
+ "~n T: ~p"
+ "~n", [CH, PV, E, T]),
+ {error, Else, ok};
mtrtaaamc_mg_verify_notify_reply(Else) ->
- io:format("mtrtaaamc_mg_verify_notify_reply -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MG Notify Reply failed -> unknown"
+ "~n ~p"
+ "~n", [Else]),
{error, Else, ok}.
mtrtaaamc_mg_service_change_request_ar(_Mid, Cid) ->
@@ -4793,13 +4962,6 @@ mtrtaaamc_mg_service_change_request_ar(_Mid, Cid) ->
CR = cre_cmdReq(CMD),
cre_actionReq(Cid, [CR]).
-%% mtrtaaamc_mg_service_change_request_msg(Mid, TransId, Cid) ->
-%% AR = mtrtaaamc_mg_service_change_request_ar(Mid, Cid),
-%% TR = cre_transReq(TransId, [AR]),
-%% Trans = cre_transaction(TR),
-%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
-%% cre_megacoMessage(Mess).
-
mtrtaaamc_mg_notify_request_ar(Rid, Tid, Cid) ->
TT = cre_timeNotation("19990729", "22000000"),
Ev = cre_obsEvent("al/of", TT),
@@ -4809,13 +4971,6 @@ mtrtaaamc_mg_notify_request_ar(Rid, Tid, Cid) ->
CR = cre_cmdReq(CMD),
cre_actionReq(Cid, [CR]).
-%% mtrtaaamc_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
-%% AR = mtrtaaamc_mg_notify_request_ar(Rid, TermId, Cid),
-%% TR = cre_transReq(TransId, [AR]),
-%% Trans = cre_transaction(TR),
-%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
-%% cre_megacoMessage(Mess).
-
%%
%% Common functions for the multi_trans_req_timeout test case
@@ -4832,19 +4987,25 @@ multi_trans_req_and_ack_reqmaxcount(suite) ->
multi_trans_req_and_ack_reqmaxcount(doc) ->
[];
multi_trans_req_and_ack_reqmaxcount(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_and_ack_reqmaxcount),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_and_ack_reqmaxcount/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_and_ack_reqmaxcount, Pre, Case, Post).
+do_multi_trans_req_and_ack_reqmaxcount([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -5235,8 +5396,6 @@ mtrtaarac_mg_verify_handle_connect(Else) ->
mtrtaarac_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
{ok, [AR]}, _}) ->
- io:format("mtrtaarac_mg_verify_service_change_reply -> ok"
- "~n AR: ~p~n", [AR]),
case AR of
#'ActionReply'{commandReply = [SCR]} ->
case SCR of
@@ -5250,37 +5409,55 @@ mtrtaarac_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
{serviceChangeResParms,
#'ServiceChangeResParm'{
serviceChangeMgcId = _RemoteMid}} ->
+ i("received expected handle_trans_reply "
+ "(service change) with ok"
+ "~n AR: ~p", [AR]),
{ok, AR, ok};
{Tag, Val} ->
+ e("received expected handle_trans_reply "
+ "(service change) with error"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
Err = {invalid_service_change_result,
Tag, Val},
{error, Err, ok}
end;
_ ->
+ e("received expected handle_trans_reply "
+ "(service change) with error"
+ "~n Tid: ~p", [Tid]),
Err = {invalid_termination_id, Tid},
{error, Err, ok}
end;
{Tag, Val} ->
+ e("received expected handle_trans_reply "
+ "(action reply) with error"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
Err = {invalid_command_reply, Tag, Val},
{error, Err, ok}
end;
_ ->
+ e("received expected handle_trans_reply with error"
+ "~n AR: ~p", [AR]),
Err = {invalid_action_reply, AR},
{error, Err, ok}
end;
mtrtaarac_mg_verify_service_change_reply(Else) ->
- io:format("mtrtaarac_mg_verify_service_change_reply -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("mtrtaarac_mg_verify_service_change_reply -> invalid service change reply"
+ "~n Expected: handle_trans_reply (service change) with ok"
+ "~n Received; ~p", [Else]),
{error, Else, ok}.
mtrtaarac_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
{ok, [AR]}, _}) ->
- io:format("mtrtaarac_mg_verify_notify_reply -> ok"
- "~n AR: ~p~n", [AR]),
+ i("received expected handle_notify_reply with ok"
+ "~n AR: ~p~n", [AR]),
{ok, AR, ok};
mtrtaarac_mg_verify_notify_reply(Else) ->
- io:format("mtrtaarac_mg_verify_notify_reply -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("MG Notify Reply verification failed: invalid notify reply"
+ "~n Expected: handle_trans_reply with ok"
+ "~n Received: ~p", [Else]),
{error, Else, ok}.
mtrtaarac_mg_service_change_request_ar(_Mid, Cid) ->
@@ -5292,13 +5469,6 @@ mtrtaarac_mg_service_change_request_ar(_Mid, Cid) ->
CR = cre_cmdReq(CMD),
cre_actionReq(Cid, [CR]).
-%% mtrtaarac_mg_service_change_request_msg(Mid, TransId, Cid) ->
-%% AR = mtrtaarac_mg_service_change_request_ar(Mid, Cid),
-%% TR = cre_transReq(TransId, [AR]),
-%% Trans = cre_transaction(TR),
-%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
-%% cre_megacoMessage(Mess).
-
mtrtaarac_mg_notify_request_ar(Rid, Tid, Cid) ->
TT = cre_timeNotation("19990729", "22000000"),
Ev = cre_obsEvent("al/of", TT),
@@ -5308,13 +5478,6 @@ mtrtaarac_mg_notify_request_ar(Rid, Tid, Cid) ->
CR = cre_cmdReq(CMD),
cre_actionReq(Cid, [CR]).
-%% mtrtaarac_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
-%% AR = mtrtaarac_mg_notify_request_ar(Rid, TermId, Cid),
-%% TR = cre_transReq(TransId, [AR]),
-%% Trans = cre_transaction(TR),
-%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
-%% cre_megacoMessage(Mess).
-
%%
%% Common functions for the multi_trans_req_timeout test case
@@ -5333,19 +5496,25 @@ multi_trans_req_and_ack_maxsize1(suite) ->
multi_trans_req_and_ack_maxsize1(doc) ->
[];
multi_trans_req_and_ack_maxsize1(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_and_ack_maxsize1),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_and_ack_maxsize1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_and_ack_maxsize1, Pre, Case, Post).
+do_multi_trans_req_and_ack_maxsize1([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -5831,19 +6000,25 @@ multi_trans_req_and_ack_maxsize2(suite) ->
multi_trans_req_and_ack_maxsize2(doc) ->
[];
multi_trans_req_and_ack_maxsize2(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_and_ack_maxsize2),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_and_ack_maxsize2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_and_ack_maxsize2, Pre, Case, Post).
+do_multi_trans_req_and_ack_maxsize2([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -6372,19 +6547,25 @@ multi_trans_req_and_ack_and_pending(suite) ->
multi_trans_req_and_ack_and_pending(doc) ->
[];
multi_trans_req_and_ack_and_pending(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, mtraaap),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_and_ack_and_pending/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(mtraaap, Pre, Case, Post).
+do_multi_trans_req_and_ack_and_pending([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -6844,38 +7025,6 @@ mtraaap_mg_verify_service_change_reply(Else) ->
"~n Else: ~p~n", [Else]),
{error, Else, ok}.
-%% mtraaap_mg_verify_notify_request_fun() ->
-%% fun(Ev) ->
-%% mtraaap_mg_verify_notify_request(Ev)
-%% end.
-
-%% mtraaap_mg_verify_notify_request(
-%% {handle_trans_request, _, ?VERSION, [AR]}) ->
-%% io:format("mtraaap_mg_verify_notify_request -> ok"
-%% "~n AR: ~p~n", [AR]),
-%% case AR of
-%% #'ActionRequest'{contextId = 1 = Cid,
-%% commandRequests = [CR]} ->
-%% #'CommandRequest'{command = Cmd} = CR,
-%% {notifyReq, NR} = Cmd,
-%% #'NotifyRequest'{terminationID = [Tid],
-%% observedEventsDescriptor = OED,
-%% errorDescriptor = asn1_NOVALUE} = NR,
-%% #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
-%% #'ObservedEvent'{eventName = "al/of"} = OE,
-%% Reply = {discard_ack, [mtraaap_mg_notify_reply_ar(Cid, Tid)]},
-%% {ok, 3000, AR, Reply};
-%% _ ->
-%% ED = mtraaap_err_desc(AR),
-%% ErrReply = {discard_ack, ED},
-%% {error, AR, ErrReply}
-%% end;
-%% mtraaap_mg_verify_notify_request(Else) ->
-%% io:format("mtraaap_mg_verify_notify_request:fun -> unknown"
-%% "~n Else: ~p~n", [Else]),
-%% ED = mtraaap_err_desc(Else),
-%% ErrReply = {discard_ack, ED},
-%% {error, Else, ErrReply}.
mtraaap_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
{ok, [AR]}, _}) ->
@@ -6960,19 +7109,25 @@ multi_trans_req_and_ack_and_reply(suite) ->
multi_trans_req_and_ack_and_reply(doc) ->
[];
multi_trans_req_and_ack_and_reply(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, multi_trans_req_and_ack_and_reply),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_multi_trans_req_and_ack_and_reply/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(multi_trans_req_and_ack_and_reply, Pre, Case, Post).
+do_multi_trans_req_and_ack_and_reply([MgcNode, MgNode]) ->
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -7537,23 +7692,27 @@ otp_7192_1(suite) ->
otp_7192_1(doc) ->
[""];
otp_7192_1(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_7192_1),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
-
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_otp_7192_1/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_7192_1, Pre, Case, Post).
+
+do_otp_7192_1([MgcNode, MgNode]) ->
MgMid = {deviceName,"mg"},
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
-
-
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -8109,22 +8268,27 @@ otp_7192_2(suite) ->
otp_7192_2(doc) ->
[];
otp_7192_2(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_7192_2),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
-
- MgMid = {deviceName,"mg"},
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_otp_7192_2/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_7192_2, Pre, Case, Post).
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+do_otp_7192_2([MgcNode, MgNode]) ->
+ MgMid = {deviceName,"mg"},
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -8208,7 +8372,7 @@ otp71922_mgc_event_sequence(text, tcp, MgMid) ->
{encoding_config, []},
{transport_module, megaco_tcp}
],
- Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
+ Tid = #megaco_term_id{id = ["00000000","00000100","01101101"]},
NR = fun(Cid, Rid) ->
[otp71922_mgc_notify_request_ar(Rid, Tid, Cid)]
end,
@@ -8251,12 +8415,14 @@ otp71922_mgc_event_sequence(text, tcp, MgMid) ->
otp71922_mgc_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
- io:format("otp71922_mgc_verify_handle_connect -> ok"
- "~n CH: ~p~n", [CH]),
+ i("received expected handle_connect with"
+ "~n CH: ~p"
+ "~n => force a 2 second sleep before return", [CH]),
{ok, timer:seconds(2), CH, ok};
otp71922_mgc_verify_handle_connect(Else) ->
- io:format("otp71922_mgc_verify_handle_connect -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("otp71922_mgc_verify_handle_connect -> invalid handle-connect: "
+ "~n Extected: handle_connect"
+ "~n Received: ~p", [Else]),
{error, Else, ok}.
otp71922_mgc_verify_service_change_req_fun(Mid) ->
@@ -8266,8 +8432,8 @@ otp71922_mgc_verify_service_change_req_fun(Mid) ->
otp71922_mgc_verify_service_change_req(
{handle_trans_request, _, ?VERSION, [AR]}, Mid) ->
- io:format("otp71922_mgc_verify_service_change_req -> ok"
- "~n AR: ~p~n", [AR]),
+ i("otp71922_mgc_verify_service_change_req -> ok"
+ "~n AR: ~p", [AR]),
case AR of
#'ActionRequest'{commandRequests = [CR]} ->
case CR of
@@ -8478,8 +8644,11 @@ otp71922_mg_event_sequence(text, tcp, Mid) ->
{transport_module, megaco_tcp}
],
ServiceChangeReq = [otp71922_mg_service_change_request_ar(Mid, 1)],
- Tid = #megaco_term_id{id = ["00000000","00000000","01101101"]},
- NR = fun(Cid, Rid) ->
+ %% This is so that we can match notify request and reply
+ Tid1 = #megaco_term_id{id = ["00000000","00000001","01101101"]},
+ Tid2 = #megaco_term_id{id = ["00000000","00000010","01101101"]},
+ Tid3 = #megaco_term_id{id = ["00000000","00000011","01101101"]},
+ NR = fun(Cid, Rid, Tid) ->
[otp71922_mg_notify_request_ar(Rid, Tid, Cid)]
end,
ConnectVerify = ?otp71922_mg_verify_handle_connect_fun(),
@@ -8512,20 +8681,20 @@ otp71922_mg_event_sequence(text, tcp, Mid) ->
{megaco_update_conn_info, trans_ack, true},
{megaco_update_conn_info, trans_req, true},
{megaco_conn_info, all},
- {megaco_cast, NR(1,1), []},
- {megaco_cast, NR(1,2), []},
- {megaco_cast, NR(1,3), []},
+ {megaco_cast, NR(1,1,Tid1), []},
+ {megaco_cast, NR(1,2,Tid2), []},
+ {megaco_cast, NR(1,3,Tid3), []},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
{megaco_callback, handle_trans_reply, NotifyReplyVerify},
{megaco_update_conn_info, trans_timer, 120000},
- {megaco_cast, NR(2,1), []},
- {megaco_cast, NR(2,2), []},
- {megaco_cast, NR(2,3), []},
+ {megaco_cast, NR(2,1,Tid1), []},
+ {megaco_cast, NR(2,2,Tid2), []},
+ {megaco_cast, NR(2,3,Tid3), []},
{megaco_callback, handle_trans_request, NotifyReqVerify},
- {megaco_callback, handle_trans_reply, NotifyReplyVerify},
- {megaco_callback, handle_trans_reply, NotifyReplyVerify},
- {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
+ {megaco_callback, handle_trans_reply, NotifyReplyVerify},
{sleep, 3000},
megaco_stop_user,
megaco_stop,
@@ -8534,18 +8703,17 @@ otp71922_mg_event_sequence(text, tcp, Mid) ->
EvSeq.
otp71922_mg_verify_handle_connect({handle_connect, CH, ?VERSION}) ->
- io:format("otp71922_mg_verify_handle_connect -> ok"
- "~n CH: ~p~n", [CH]),
+ i("received expected handle_connect:"
+ "~n CH: ~p", [CH]),
{ok, CH, ok};
otp71922_mg_verify_handle_connect(Else) ->
- io:format("otp71922_mg_verify_handle_connect -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("otp71922_mg_verify_handle_connect -> received unexpected:"
+ "~n Expected: handle_connect"
+ "~n Received: ~p", [Else]),
{error, Else, ok}.
otp71922_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
{ok, [AR]}, _}) ->
- io:format("otp71922_mg_verify_service_change_reply -> ok"
- "~n AR: ~p~n", [AR]),
case AR of
#'ActionReply'{commandReply = [SCR]} ->
case SCR of
@@ -8559,70 +8727,55 @@ otp71922_mg_verify_service_change_reply({handle_trans_reply, _CH, ?VERSION,
{serviceChangeResParms,
#'ServiceChangeResParm'{
serviceChangeMgcId = _RemoteMid}} ->
+ i("received expected handle_trans_reply "
+ "(service change) with ok"
+ "~n AR: ~p", [AR]),
{ok, AR, ok};
{Tag, Val} ->
+ e("received expected handle_trans_reply "
+ "(service change) with error"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
Err = {invalid_service_change_result,
Tag, Val},
{error, Err, ok}
end;
_ ->
+ e("received expected handle_trans_reply "
+ "(service change) with error"
+ "~n Tid: ~p", [Tid]),
Err = {invalid_termination_id, Tid},
{error, Err, ok}
end;
{Tag, Val} ->
+ e("received expected handle_trans_reply "
+ "(action reply) with error"
+ "~n Tag: ~p"
+ "~n Val: ~p", [Tag, Val]),
Err = {invalid_command_reply, Tag, Val},
{error, Err, ok}
end;
_ ->
+ e("received expected handle_trans_reply with error"
+ "~n AR: ~p", [AR]),
Err = {invalid_action_reply, AR},
{error, Err, ok}
end;
otp71922_mg_verify_service_change_reply(Else) ->
- io:format("otp71922_mg_verify_service_change_reply -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("invalid service change reply:"
+ "~n Expected: handle_trans_reply"
+ "~n Received: ~p", [Else]),
{error, Else, ok}.
-%% otp71922_mg_verify_notify_request_fun() ->
-%% fun(Ev) ->
-%% otp71922_mg_verify_notify_request(Ev)
-%% end.
-
-%% otp71922_mg_verify_notify_request(
-%% {handle_trans_request, _, ?VERSION, [AR]}) ->
-%% io:format("otp71922_mg_verify_notify_request -> ok"
-%% "~n AR: ~p~n", [AR]),
-%% case AR of
-%% #'ActionRequest'{contextId = 1 = Cid,
-%% commandRequests = [CR]} ->
-%% #'CommandRequest'{command = Cmd} = CR,
-%% {notifyReq, NR} = Cmd,
-%% #'NotifyRequest'{terminationID = [Tid],
-%% observedEventsDescriptor = OED,
-%% errorDescriptor = asn1_NOVALUE} = NR,
-%% #'ObservedEventsDescriptor'{observedEventLst = [OE]} = OED,
-%% #'ObservedEvent'{eventName = "al/of"} = OE,
-%% Reply = {discard_ack, [otp71922_mg_notify_reply_ar(Cid, Tid)]},
-%% {ok, AR, Reply};
-%% _ ->
-%% ED = otp71922_err_desc(AR),
-%% ErrReply = {discard_ack, ED},
-%% {error, AR, ErrReply}
-%% end;
-%% otp71922_mg_verify_notify_request(Else) ->
-%% io:format("otp71922_mg_verify_notify_request -> unknown"
-%% "~n Else: ~p~n", [Else]),
-%% ED = otp71922_err_desc(Else),
-%% ErrReply = {discard_ack, ED},
-%% {error, Else, ErrReply}.
-
otp71922_mg_verify_notify_reply({handle_trans_reply, _CH, ?VERSION,
{ok, [AR]}, _}) ->
- io:format("otp71922_mg_verify_notify_reply -> ok"
- "~n AR: ~p~n", [AR]),
+ i("received expected handle_notify_reply -> ok"
+ "~n AR: ~p", [AR]),
{ok, AR, ok};
otp71922_mg_verify_notify_reply(Else) ->
- io:format("otp71922_mg_verify_notify_reply -> unknown"
- "~n Else: ~p~n", [Else]),
+ e("otp71922_mg_verify_notify_reply -> invalid notify reply"
+ "~n Expected: handle_trans_reply with ok"
+ "~n Received: ~p", [Else]),
{error, Else, ok}.
otp71922_mg_service_change_request_ar(_Mid, Cid) ->
@@ -8634,18 +8787,6 @@ otp71922_mg_service_change_request_ar(_Mid, Cid) ->
CR = cre_cmdReq(CMD),
cre_actionReq(Cid, [CR]).
-%% otp71922_mg_service_change_request_msg(Mid, TransId, Cid) ->
-%% AR = otp71922_mg_service_change_request_ar(Mid, Cid),
-%% TR = cre_transReq(TransId, [AR]),
-%% Trans = cre_transaction(TR),
-%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
-%% cre_megacoMessage(Mess).
-
-%% otp71922_mg_notify_reply_ar(Cid, TermId) ->
-%% NR = cre_notifyReply([TermId]),
-%% CR = cre_cmdReply(NR),
-%% cre_actionReply(Cid, [CR]).
-
otp71922_mg_notify_request_ar(Rid, Tid, Cid) ->
TT = cre_timeNotation("19990729", "22000000"),
Ev = cre_obsEvent("al/of", TT),
@@ -8655,13 +8796,6 @@ otp71922_mg_notify_request_ar(Rid, Tid, Cid) ->
CR = cre_cmdReq(CMD),
cre_actionReq(Cid, [CR]).
-%% otp71922_notify_request_msg(Mid, TransId, Rid, TermId, Cid) ->
-%% AR = otp71922_mg_notify_request_ar(Rid, TermId, Cid),
-%% TR = cre_transReq(TransId, [AR]),
-%% Trans = cre_transaction(TR),
-%% Mess = cre_message(?VERSION, Mid, cre_transactions([Trans])),
-%% cre_megacoMessage(Mess).
-
%%
%% Common functions for the multi_trans_req_timeout test case
@@ -8678,22 +8812,27 @@ otp_7192_3(suite) ->
otp_7192_3(doc) ->
["Same as otp_7192_2 but transport is UDP instead of TCP"];
otp_7192_3(Config) when is_list(Config) ->
- put(verbosity, ?TEST_VERBOSITY),
- put(sname, "TEST"),
- put(tc, otp_7192_3),
- i("starting"),
-
- MgcNode = make_node_name(mgc),
- MgNode = make_node_name(mg),
- d("start nodes: "
- "~n MGC Node: ~p"
- "~n MG Node: ~p",
- [MgcNode, MgNode]),
-
- MgMid = {deviceName,"mg"},
+ Pre = fun() ->
+ MgcNode = make_node_name(mgc),
+ MgNode = make_node_name(mg),
+ d("start nodes: "
+ "~n MGC Node: ~p"
+ "~n MG Node: ~p",
+ [MgcNode, MgNode]),
+ Nodes = [MgcNode, MgNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_otp_7192_3/1,
+ Post = fun(Nodes) ->
+ d("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(otp_7192_3, Pre, Case, Post).
- ok = megaco_test_lib:start_nodes([MgcNode, MgNode], ?FILE, ?LINE),
+do_otp_7192_3([MgcNode, MgNode]) ->
+ MgMid = {deviceName,"mg"},
d("[MGC] start the simulator "),
{ok, Mgc} = megaco_test_megaco_generator:start_link("MGC", MgcNode),
@@ -9456,6 +9595,16 @@ await_completion(Ids, Timeout) ->
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+try_tc(TCName, Pre, Case, Post) ->
+ try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
+
+try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
+ ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
sleep(X) -> receive after X -> ok end.
%% error_msg(F,A) -> error_logger:error_msg(F ++ "~n",A).
@@ -9472,14 +9621,14 @@ p(F, A) ->
%% e(F, []).
e(F, A) ->
- print(error, "ERR", F, A).
+ print(error, "ERROR", F, A).
i(F) ->
i(F, []).
i(F, A) ->
- print(info, "INF", F, A).
+ print(info, "INFO", F, A).
d(F) ->
@@ -9500,11 +9649,13 @@ printable(info, info) -> true;
printable(error, _) -> true;
printable(_,_) -> false.
-
print2(true, P, F, A) ->
- S = ?F("*** [~s] ~s ~p ~w ***"
+ S = ?F("*** [~s] ~s ~p~s ***"
"~n " ++ F ++ "~n"
- "~n", [?FTS(), P, self(), get(tc) | A]),
+ "~n", [?FTS(), P, self(), case get(tc) of
+ undefined -> "";
+ TC -> " " ++ atom_to_list(TC)
+ end | A]),
io:format("~s", [S]);
print2(_, _, _, _) ->
ok.
diff --git a/lib/megaco/test/megaco_udp_SUITE.erl b/lib/megaco/test/megaco_udp_SUITE.erl
index 26783d5faf..05910e50a9 100644
--- a/lib/megaco/test/megaco_udp_SUITE.erl
+++ b/lib/megaco/test/megaco_udp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2000-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2000-2020 All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -63,14 +63,14 @@
%% Macros
%%----------------------------------------------------------------------
+-define(CH, megaco_test_command_handler).
+-define(TEST_VERBOSITY, debug).
+
+
%%----------------------------------------------------------------------
%% Records
%%----------------------------------------------------------------------
--record(command, {id, desc, cmd}).
--record(server, {parent, transport_ref, control_pid, handle, remote}).
--record(client, {parent, transport_ref, control_pid, handle, remote}).
-
%%======================================================================
%% Common Test interface functions
@@ -239,17 +239,22 @@ start_and_stop(doc) ->
["This test case sets up a connection and then cloises it. "
"No data is sent. "];
start_and_stop(Config) when is_list(Config) ->
- put(sname, "start_and_stop"),
- p("BEGIN TEST-CASE"),
-
- process_flag(trap_exit, true),
-
- p("create nodes"),
- ServerNode = make_node_name(server),
- ClientNode = make_node_name(client),
- Nodes = [ServerNode, ClientNode],
- ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
-
+ Pre = fun() ->
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_start_and_stop/1,
+ Post = fun(Nodes) ->
+ p("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(start_and_stop, Pre, Case, Post).
+
+do_start_and_stop([ServerNode, ClientNode]) ->
%% Create command sequences
p("create command sequences"),
ServerPort = 2944,
@@ -279,7 +284,7 @@ start_and_stop(Config) when is_list(Config) ->
{error, server_timeout}
end,
- ok = await_command_handler_completion([Server, Client], timer:seconds(20)),
+ ok = await_command_handler_completion([Server, Client], ?SECS(20)),
p("done"),
ok.
@@ -288,47 +293,47 @@ start_and_stop_server_commands(Port) ->
Opts = [{port, Port}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#server{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- server_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Open",
- cmd = fun(State) ->
- server_open(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Notify operational",
- cmd = fun(State) ->
- server_notify_operational(State)
- end},
-
- #command{id = 5,
- desc = "Await nothing",
- cmd = fun(State) ->
- server_await_nothing(State, 5000)
- end},
-
- #command{id = 6,
- desc = "Close",
- cmd = fun(State) ->
- server_close(State)
- end},
-
- #command{id = 7,
- desc = "Stop",
- cmd = fun(State) ->
- server_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Open",
+ cmd => fun(State) ->
+ server_open(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Notify operational",
+ cmd => fun(State) ->
+ server_notify_operational(State)
+ end},
+
+ #{id => 5,
+ desc => "Await nothing",
+ cmd => fun(State) ->
+ server_await_nothing(State, 5000)
+ end},
+
+ #{id => 6,
+ desc => "Close",
+ cmd => fun(State) ->
+ server_close(State)
+ end},
+
+ #{id => 7,
+ desc => "Stop",
+ cmd => fun(State) ->
+ server_stop_transport(State)
+ end}
].
@@ -336,47 +341,47 @@ start_and_stop_client_commands(ServerPort, _ServerHost) ->
Opts = [{port, ServerPort}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#client{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- client_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Open",
- cmd = fun(State) ->
- client_open(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Await continue",
- cmd = fun(State) ->
- client_await_continue_signal(State, 5000)
- end},
-
- #command{id = 5,
- desc = "Await nothing",
- cmd = fun(State) ->
- client_await_nothing(State, 5000)
- end},
-
- #command{id = 6,
- desc = "Close",
- cmd = fun(State) ->
- client_close(State)
- end},
-
- #command{id = 7,
- desc = "Stop transport",
- cmd = fun(State) ->
- client_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Open",
+ cmd => fun(State) ->
+ client_open(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Await continue",
+ cmd => fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #{id => 5,
+ desc => "Await nothing",
+ cmd => fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #{id => 6,
+ desc => "Close",
+ cmd => fun(State) ->
+ client_close(State)
+ end},
+
+ #{id => 7,
+ desc => "Stop transport",
+ cmd => fun(State) ->
+ client_stop_transport(State)
+ end}
].
@@ -394,17 +399,22 @@ sendreceive(suite) ->
sendreceive(doc) ->
["Test send and receive with the UDP transport. "];
sendreceive(Config) when is_list(Config) ->
- put(sname, "sendreceive"),
- p("BEGIN TEST-CASE"),
-
- process_flag(trap_exit, true),
-
- p("create nodes"),
- ServerNode = make_node_name(server),
- ClientNode = make_node_name(client),
- Nodes = [ServerNode, ClientNode],
- ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
-
+ Pre = fun() ->
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_sendreceive/1,
+ Post = fun(Nodes) ->
+ p("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(sendreceive, Pre, Case, Post).
+
+do_sendreceive([ServerNode, ClientNode]) ->
%% Create command sequences
p("create command sequences"),
ServerPort = 2944,
@@ -434,7 +444,7 @@ sendreceive(Config) when is_list(Config) ->
{error, server_timeout}
end,
- ok = await_command_handler_completion([Server, Client], timer:seconds(20)),
+ ok = await_command_handler_completion([Server, Client], ?SECS(20)),
p("done"),
ok.
@@ -443,168 +453,167 @@ sendreceive_server_commands(Port) ->
Opts = [{port, Port}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#server{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- server_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Open",
- cmd = fun(State) ->
- server_open(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Notify operational",
- cmd = fun(State) ->
- server_notify_operational(State)
- end},
-
- #command{id = 5,
- desc = "Await initial message (ping)",
- cmd = fun(State) ->
- server_await_initial_message(State, "ping", 5000)
- end},
-
- #command{id = 6,
- desc = "Send reply (pong) to initial message",
- cmd = fun(State) ->
- server_send_message(State, "pong")
- end},
-
- #command{id = 7,
- desc = "Await nothing before sending a message (hejsan)",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 8,
- desc = "Send message (hejsan)",
- cmd = fun(State) ->
- server_send_message(State, "hejsan")
- end},
-
- #command{id = 9,
- desc = "Await reply (hoppsan) to message",
- cmd = fun(State) ->
- server_await_message(State, "hoppsan", 1000)
- end},
-
- #command{id = 10,
- desc = "Await nothing before closing",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 11,
- desc = "Close",
- cmd = fun(State) ->
- server_close(State)
- end},
-
- #command{id = 12,
- desc = "Await nothing before stopping transport",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 13,
- desc = "Stop",
- cmd = fun(State) ->
- server_stop_transport(State)
- end}
-
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Open",
+ cmd => fun(State) ->
+ server_open(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Notify operational",
+ cmd => fun(State) ->
+ server_notify_operational(State)
+ end},
+
+ #{id => 5,
+ desc => "Await initial message (ping)",
+ cmd => fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #{id => 6,
+ desc => "Send reply (pong) to initial message",
+ cmd => fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #{id => 7,
+ desc => "Await nothing before sending a message (hejsan)",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 8,
+ desc => "Send message (hejsan)",
+ cmd => fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #{id => 9,
+ desc => "Await reply (hoppsan) to message",
+ cmd => fun(State) ->
+ server_await_message(State, "hoppsan", 1000)
+ end},
+
+ #{id => 10,
+ desc => "Await nothing before closing",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 11,
+ desc => "Close",
+ cmd => fun(State) ->
+ server_close(State)
+ end},
+
+ #{id => 12,
+ desc => "Await nothing before stopping transport",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 13,
+ desc => "Stop",
+ cmd => fun(State) ->
+ server_stop_transport(State)
+ end}
].
sendreceive_client_commands(ServerPort, ServerHost) ->
OwnPort = ServerPort+1,
- Opts = [{port, OwnPort}],
- Self = self(),
+ Opts = [{port, OwnPort}],
+ Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#client{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- client_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Open",
- cmd = fun(State) ->
- client_open(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Await continue",
- cmd = fun(State) ->
- client_await_continue_signal(State, 5000)
- end},
-
- #command{id = 5,
- desc = "Connect",
- cmd = fun(State) ->
- client_connect(State, ServerHost, ServerPort)
- end},
-
- #command{id = 6,
- desc = "Send initial message (ping)",
- cmd = fun(State) ->
- client_send_message(State, "ping")
- end},
-
- #command{id = 7,
- desc = "Await reply (pong) to initial message",
- cmd = fun(State) ->
- client_await_message(State, "pong", 1000)
- end},
-
- #command{id = 8,
- desc = "Await message (hejsan)",
- cmd = fun(State) ->
- client_await_message(State, "hejsan", 5000)
- end},
-
- #command{id = 9,
- desc = "Send reply (hoppsan) to message",
- cmd = fun(State) ->
- client_send_message(State, "hoppsan")
- end},
-
- #command{id = 10,
- desc = "Await nothing before closing",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 11,
- desc = "Close",
- cmd = fun(State) ->
- client_close(State)
- end},
-
- #command{id = 12,
- desc = "Await nothing before stopping transport",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 13,
- desc = "Stop transport",
- cmd = fun(State) ->
- client_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Open",
+ cmd => fun(State) ->
+ client_open(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Await continue",
+ cmd => fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #{id => 5,
+ desc => "Connect",
+ cmd => fun(State) ->
+ client_connect(State, ServerHost, ServerPort)
+ end},
+
+ #{id => 6,
+ desc => "Send initial message (ping)",
+ cmd => fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #{id => 7,
+ desc => "Await reply (pong) to initial message",
+ cmd => fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #{id => 8,
+ desc => "Await message (hejsan)",
+ cmd => fun(State) ->
+ client_await_message(State, "hejsan", 5000)
+ end},
+
+ #{id => 9,
+ desc => "Send reply (hoppsan) to message",
+ cmd => fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #{id => 10,
+ desc => "Await nothing before closing",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 11,
+ desc => "Close",
+ cmd => fun(State) ->
+ client_close(State)
+ end},
+
+ #{id => 12,
+ desc => "Await nothing before stopping transport",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 13,
+ desc => "Stop transport",
+ cmd => fun(State) ->
+ client_stop_transport(State)
+ end}
].
@@ -615,17 +624,22 @@ block_unblock(suite) ->
block_unblock(doc) ->
["Test the block/unblock functions of the UDP transport. "];
block_unblock(Config) when is_list(Config) ->
- put(sname, "block_unblock"),
- p("BEGIN TEST-CASE"),
-
- process_flag(trap_exit, true),
-
- p("create nodes"),
- ServerNode = make_node_name(server),
- ClientNode = make_node_name(client),
- Nodes = [ServerNode, ClientNode],
- ok = megaco_test_lib:start_nodes(Nodes, ?FILE, ?LINE),
-
+ Pre = fun() ->
+ p("create nodes"),
+ ServerNode = make_node_name(server),
+ ClientNode = make_node_name(client),
+ Nodes = [ServerNode, ClientNode],
+ ok = ?START_NODES(Nodes),
+ Nodes
+ end,
+ Case = fun do_block_unblock/1,
+ Post = fun(Nodes) ->
+ p("stop nodes"),
+ ?STOP_NODES(lists:reverse(Nodes))
+ end,
+ try_tc(block_unblock, Pre, Case, Post).
+
+do_block_unblock([ServerNode, ClientNode]) ->
%% Create command sequences
p("create command sequences"),
ServerPort = 2944,
@@ -674,7 +688,7 @@ block_unblock(Config) when is_list(Config) ->
{error, timeout}
end,
- ok = await_command_handler_completion([Server, Client], timer:seconds(20)),
+ ok = await_command_handler_completion([Server, Client], ?SECS(20)),
p("done"),
ok.
@@ -683,198 +697,198 @@ block_unblock_server_commands(Port) ->
Opts = [{port, Port}],
Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#server{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- server_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Open",
- cmd = fun(State) ->
- server_open(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Notify operational",
- cmd = fun(State) ->
- server_notify_operational(State)
- end},
-
- #command{id = 5,
- desc = "Await initial message (ping)",
- cmd = fun(State) ->
- server_await_initial_message(State, "ping", 5000)
- end},
-
- #command{id = 6,
- desc = "Send reply (pong) to initial message",
- cmd = fun(State) ->
- server_send_message(State, "pong")
- end},
-
- #command{id = 7,
- desc = "Await continue",
- cmd = fun(State) ->
- server_await_continue_signal(State, 5000)
- end},
-
- #command{id = 8,
- desc = "Send message (hejsan)",
- cmd = fun(State) ->
- server_send_message(State, "hejsan")
- end},
-
- #command{id = 9,
- desc = "Await nothing before receiving (hoppsan) reply",
- cmd = fun(State) ->
- server_await_nothing(State, 4000)
- end},
-
- #command{id = 10,
- desc = "Await reply (hoppsan) to message",
- cmd = fun(State) ->
- server_await_message(State, "hoppsan", 2000)
- end},
-
- #command{id = 11,
- desc = "Await nothing before closing",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 12,
- desc = "Close",
- cmd = fun(State) ->
- server_close(State)
- end},
-
- #command{id = 13,
- desc = "Await nothing before stopping transport",
- cmd = fun(State) ->
- server_await_nothing(State, 1000)
- end},
-
- #command{id = 14,
- desc = "Stop",
- cmd = fun(State) ->
- server_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ server_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Open",
+ cmd => fun(State) ->
+ server_open(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Notify operational",
+ cmd => fun(State) ->
+ server_notify_operational(State)
+ end},
+
+ #{id => 5,
+ desc => "Await initial message (ping)",
+ cmd => fun(State) ->
+ server_await_initial_message(State, "ping", 5000)
+ end},
+
+ #{id => 6,
+ desc => "Send reply (pong) to initial message",
+ cmd => fun(State) ->
+ server_send_message(State, "pong")
+ end},
+
+ #{id => 7,
+ desc => "Await continue",
+ cmd => fun(State) ->
+ server_await_continue_signal(State, 5000)
+ end},
+
+ #{id => 8,
+ desc => "Send message (hejsan)",
+ cmd => fun(State) ->
+ server_send_message(State, "hejsan")
+ end},
+
+ #{id => 9,
+ desc => "Await nothing before receiving (hoppsan) reply",
+ cmd => fun(State) ->
+ server_await_nothing(State, 4000)
+ end},
+
+ #{id => 10,
+ desc => "Await reply (hoppsan) to message",
+ cmd => fun(State) ->
+ server_await_message(State, "hoppsan", 2000)
+ end},
+
+ #{id => 11,
+ desc => "Await nothing before closing",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 12,
+ desc => "Close",
+ cmd => fun(State) ->
+ server_close(State)
+ end},
+
+ #{id => 13,
+ desc => "Await nothing before stopping transport",
+ cmd => fun(State) ->
+ server_await_nothing(State, 1000)
+ end},
+
+ #{id => 14,
+ desc => "Stop",
+ cmd => fun(State) ->
+ server_stop_transport(State)
+ end}
].
block_unblock_client_commands(ServerPort, ServerHost) ->
OwnPort = ServerPort+1,
- Opts = [{port, OwnPort}],
- Self = self(),
+ Opts = [{port, OwnPort}],
+ Self = self(),
[
- #command{id = 1,
- desc = "Command sequence init",
- cmd = fun(State) ->
- {ok, State#client{parent = Self}}
- end},
-
- #command{id = 2,
- desc = "Start transport",
- cmd = fun(State) ->
- client_start_transport(State)
- end},
-
- #command{id = 3,
- desc = "Open",
- cmd = fun(State) ->
- client_open(State, Opts)
- end},
-
- #command{id = 4,
- desc = "Await continue",
- cmd = fun(State) ->
- client_await_continue_signal(State, 5000)
- end},
-
- #command{id = 5,
- desc = "[pseudo] Connect",
- cmd = fun(State) ->
- client_connect(State, ServerHost, ServerPort)
- end},
-
- #command{id = 6,
- desc = "Send initial message (ping)",
- cmd = fun(State) ->
- client_send_message(State, "ping")
- end},
-
- #command{id = 7,
- desc = "Await reply (pong) to initial message",
- cmd = fun(State) ->
- client_await_message(State, "pong", 1000)
- end},
-
- #command{id = 8,
- desc = "Block",
- cmd = fun(State) ->
- client_block(State)
- end},
-
- #command{id = 9,
- desc = "Notify blocked",
- cmd = fun(State) ->
- client_notify_blocked(State)
- end},
-
- #command{id = 10,
- desc = "Await nothing before unblocking",
- cmd = fun(State) ->
- client_await_nothing(State, 5000)
- end},
-
- #command{id = 11,
- desc = "Unblock",
- cmd = fun(State) ->
- client_unblock(State)
- end},
-
- #command{id = 8,
- desc = "Await message (hejsan)",
- cmd = fun(State) ->
- client_await_message(State, "hejsan", 5000)
- end},
-
- #command{id = 9,
- desc = "Send reply (hoppsan) to message",
- cmd = fun(State) ->
- client_send_message(State, "hoppsan")
- end},
-
- #command{id = 10,
- desc = "Await nothing before closing",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 11,
- desc = "Close",
- cmd = fun(State) ->
- client_close(State)
- end},
-
- #command{id = 12,
- desc = "Await nothing before stopping transport",
- cmd = fun(State) ->
- client_await_nothing(State, 1000)
- end},
-
- #command{id = 13,
- desc = "Stop transport",
- cmd = fun(State) ->
- client_stop_transport(State)
- end}
+ #{id => 1,
+ desc => "Command sequence init",
+ cmd => fun(State) ->
+ {ok, State#{parent => Self}}
+ end},
+
+ #{id => 2,
+ desc => "Start transport",
+ cmd => fun(State) ->
+ client_start_transport(State)
+ end},
+
+ #{id => 3,
+ desc => "Open",
+ cmd => fun(State) ->
+ client_open(State, Opts)
+ end},
+
+ #{id => 4,
+ desc => "Await continue",
+ cmd => fun(State) ->
+ client_await_continue_signal(State, 5000)
+ end},
+
+ #{id => 5,
+ desc => "[pseudo] Connect",
+ cmd => fun(State) ->
+ client_connect(State, ServerHost, ServerPort)
+ end},
+
+ #{id => 6,
+ desc => "Send initial message (ping)",
+ cmd => fun(State) ->
+ client_send_message(State, "ping")
+ end},
+
+ #{id => 7,
+ desc => "Await reply (pong) to initial message",
+ cmd => fun(State) ->
+ client_await_message(State, "pong", 1000)
+ end},
+
+ #{id => 8,
+ desc => "Block",
+ cmd => fun(State) ->
+ client_block(State)
+ end},
+
+ #{id => 9,
+ desc => "Notify blocked",
+ cmd => fun(State) ->
+ client_notify_blocked(State)
+ end},
+
+ #{id => 10,
+ desc => "Await nothing before unblocking",
+ cmd => fun(State) ->
+ client_await_nothing(State, 5000)
+ end},
+
+ #{id => 11,
+ desc => "Unblock",
+ cmd => fun(State) ->
+ client_unblock(State)
+ end},
+
+ #{id => 8,
+ desc => "Await message (hejsan)",
+ cmd => fun(State) ->
+ client_await_message(State, "hejsan", 5000)
+ end},
+
+ #{id => 9,
+ desc => "Send reply (hoppsan) to message",
+ cmd => fun(State) ->
+ client_send_message(State, "hoppsan")
+ end},
+
+ #{id => 10,
+ desc => "Await nothing before closing",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 11,
+ desc => "Close",
+ cmd => fun(State) ->
+ client_close(State)
+ end},
+
+ #{id => 12,
+ desc => "Await nothing before stopping transport",
+ cmd => fun(State) ->
+ client_await_nothing(State, 1000)
+ end},
+
+ #{id => 13,
+ desc => "Stop transport",
+ cmd => fun(State) ->
+ client_stop_transport(State)
+ end}
].
@@ -947,35 +961,34 @@ process_received_message(ReceiveHandle, ControlPid, SendHandle, BinMsg)
%% ------- Server command handler and utility functions ----------
server_start_command_handler(Node, Commands) ->
- start_command_handler(Node, Commands, #server{}, "server").
+ start_command_handler(Node, Commands, #{}, "server").
-server_start_transport(State) when is_record(State, server) ->
+server_start_transport(State) when is_map(State) ->
case (catch megaco_udp:start_transport()) of
{ok, Ref} ->
- {ok, State#server{transport_ref = Ref}};
+ {ok, State#{transport_ref => Ref}};
Error ->
Error
end.
-server_open(#server{transport_ref = Ref} = State, Options)
- when is_record(State, server) andalso is_list(Options) ->
+server_open(#{transport_ref := Ref} = State, Options)
+ when is_list(Options) ->
Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
case (catch megaco_udp:open(Ref, Opts)) of
{ok, Socket, ControlPid} ->
- {ok, State#server{handle = {socket, Socket}, % Temporary
- control_pid = ControlPid}};
+ {ok, State#{handle => {socket, Socket}, % Temporary
+ control_pid => ControlPid}};
{error, {could_not_open_udp_port, eaddrinuse}} ->
{skip, {server, eaddrinuse}};
Error ->
Error
end.
-server_notify_operational(#server{parent = Parent} = State)
- when is_record(State, server) ->
+server_notify_operational(#{parent := Parent} = State) ->
Parent ! {operational, self()},
{ok, State}.
-server_await_continue_signal(#server{parent = Parent} = State, Timeout) ->
+server_await_continue_signal(#{parent := Parent} = State, Timeout) ->
receive
{continue, Parent} ->
{ok, State}
@@ -984,13 +997,13 @@ server_await_continue_signal(#server{parent = Parent} = State, Timeout) ->
end.
server_await_initial_message(State, InitialMessage, Timeout)
- when is_record(State, server) ->
+ when is_map(State) ->
receive
{receive_message, {ControlPid, Handle, InitialMessage}} ->
p("received expected event with: "
"~n ControlPid: ~p"
"~n Handle: ~p", [ControlPid, Handle]),
- NewState = State#server{handle = Handle},
+ NewState = State#{handle => Handle},
{ok, NewState};
Any ->
@@ -1001,7 +1014,7 @@ server_await_initial_message(State, InitialMessage, Timeout)
{error, timeout}
end.
-server_send_message(#server{handle = Handle} = State, Message) ->
+server_send_message(#{handle := Handle} = State, Message) ->
Bin = if
is_list(Message) ->
list_to_binary(Message);
@@ -1012,7 +1025,7 @@ server_send_message(#server{handle = Handle} = State, Message) ->
{ok, State}.
server_await_nothing(State, Timeout)
- when is_record(State, server) ->
+ when is_map(State) ->
receive
Any ->
p("received unexpected event: ~p", [Any]),
@@ -1022,9 +1035,8 @@ server_await_nothing(State, Timeout)
{ok, State}
end.
-
server_await_message(State, ExpectMessage, Timeout)
- when is_record(State, server) ->
+ when is_map(State) ->
receive
{receive_message, {_, _, ExpectMessage}} ->
p("received expected message [~p]", [ExpectMessage]),
@@ -1038,57 +1050,47 @@ server_await_message(State, ExpectMessage, Timeout)
{error, timeout}
end.
-server_close(#server{handle = {socket, Socket}} = State) ->
+server_close(#{handle := {socket, Socket}} = State) ->
megaco_udp:close(Socket),
- {ok, State#server{handle = undefined, control_pid = undefined}};
-server_close(#server{handle = Handle} = State)
+ {ok, State#{handle => undefined, control_pid => undefined}};
+server_close(#{handle := Handle} = State)
when (Handle =/= undefined) ->
megaco_udp:close(Handle),
- {ok, State#server{handle = undefined, control_pid = undefined}}.
-
-%% server_block(#server{handle = Handle} = State)
-%% when (Handle =/= undefined) ->
-%% megaco_udp:block(Handle),
-%% {ok, State}.
+ {ok, State#{handle => undefined, control_pid => undefined}}.
-%% server_unblock(#server{handle = Handle} = State)
-%% when (Handle =/= undefined) ->
-%% megaco_udp:unblock(Handle),
-%% {ok, State}.
-
-server_stop_transport(#server{transport_ref = Ref} = State)
+server_stop_transport(#{transport_ref := Ref} = State)
when (Ref =/= undefined) ->
megaco_udp:stop_transport(Ref),
- {ok, State#server{transport_ref = undefined}}.
+ {ok, State#{transport_ref => undefined}}.
%% ------- Client command handler and utility functions ----------
client_start_command_handler(Node, Commands) ->
- start_command_handler(Node, Commands, #client{}, "client").
+ start_command_handler(Node, Commands, #{}, "client").
-client_start_transport(State) when is_record(State, client) ->
+client_start_transport(State) when is_map(State) ->
case (catch megaco_udp:start_transport()) of
{ok, Ref} ->
- {ok, State#client{transport_ref = Ref}};
+ {ok, State#{transport_ref => Ref}};
Error ->
Error
end.
-client_open(#client{transport_ref = Ref} = State, Options)
- when is_record(State, client) andalso is_list(Options) ->
+client_open(#{transport_ref := Ref} = State, Options)
+ when is_list(Options) ->
Opts = [{receive_handle, self()}, {module, ?MODULE} | Options],
case (catch megaco_udp:open(Ref, Opts)) of
{ok, Socket, ControlPid} ->
- {ok, State#client{handle = {socket, Socket},
- control_pid = ControlPid}};
+ {ok, State#{handle => {socket, Socket},
+ control_pid => ControlPid}};
{error, {could_not_open_udp_port, eaddrinuse}} ->
{skip, {client, eaddrinuse}};
Error ->
Error
end.
-client_await_continue_signal(#client{parent = Parent} = State, Timeout) ->
+client_await_continue_signal(#{parent := Parent} = State, Timeout) ->
receive
{continue, Parent} ->
{ok, State}
@@ -1096,12 +1098,12 @@ client_await_continue_signal(#client{parent = Parent} = State, Timeout) ->
{error, timeout}
end.
-client_notify_blocked(#client{parent = Parent} = State) ->
+client_notify_blocked(#{parent := Parent} = State) ->
Parent ! {blocked, self()},
{ok, State}.
client_await_nothing(State, Timeout)
- when is_record(State, client) ->
+ when is_map(State) ->
receive
Any ->
p("received unexpected event: ~p", [Any]),
@@ -1110,11 +1112,11 @@ client_await_nothing(State, Timeout)
{ok, State}
end.
-client_connect(#client{handle = {socket, Socket}} = State, Host, Port) ->
+client_connect(#{handle := {socket, Socket}} = State, Host, Port) ->
Handle = megaco_udp:create_send_handle(Socket, Host, Port),
- {ok, State#client{handle = Handle}}.
+ {ok, State#{handle => Handle}}.
-client_send_message(#client{handle = Handle} = State, Message) ->
+client_send_message(#{handle := Handle} = State, Message) ->
Bin = if
is_list(Message) ->
list_to_binary(Message);
@@ -1125,7 +1127,7 @@ client_send_message(#client{handle = Handle} = State, Message) ->
{ok, State}.
client_await_message(State, ExpectMessage, Timeout)
- when is_record(State, client) ->
+ when is_map(State) ->
receive
{receive_message, {_, _, ExpectMessage}} ->
{ok, State};
@@ -1138,137 +1140,50 @@ client_await_message(State, ExpectMessage, Timeout)
{error, timeout}
end.
-client_block(#client{handle = Handle} = State)
+client_block(#{handle := Handle} = State)
when (Handle =/= undefined) ->
- megaco_udp:block(Handle),
+ ok = megaco_udp:block(Handle),
{ok, State}.
-client_unblock(#client{handle = Handle} = State)
+client_unblock(#{handle := Handle} = State)
when (Handle =/= undefined) ->
- megaco_udp:unblock(Handle),
+ ok = megaco_udp:unblock(Handle),
{ok, State}.
-client_close(#client{handle = {socket, Socket}} = State) ->
+client_close(#{handle := {socket, Socket}} = State) ->
megaco_udp:close(Socket),
- {ok, State#client{handle = undefined, control_pid = undefined}};
-client_close(#client{handle = Handle} = State)
+ {ok, State#{handle => undefined, control_pid => undefined}};
+client_close(#{handle := Handle} = State)
when (Handle =/= undefined) ->
megaco_udp:close(Handle),
- {ok, State#client{handle = undefined, control_pid = undefined}}.
+ {ok, State#{handle => undefined, control_pid => undefined}}.
-client_stop_transport(#client{transport_ref = Ref} = State)
+client_stop_transport(#{transport_ref := Ref} = State)
when (Ref =/= undefined) ->
megaco_udp:stop_transport(Ref),
- {ok, State#client{transport_ref = undefined}}.
+ {ok, State#{transport_ref => undefined}}.
-%% -------- Command handler ---------
+%% -------- Command handler interface ---------
start_command_handler(Node, Commands, State, ShortName) ->
- Fun = fun() ->
- put(sname, ShortName),
- process_flag(trap_exit, true),
- Result = (catch command_handler(Commands, State)),
- p("command handler terminated with: "
- "~n Result: ~p", [Result]),
- exit(Result)
- end,
- erlang:spawn_link(Node, Fun).
-
-command_handler([], State) ->
- p("command_handler -> entry when done with"
- "~n State: ~p", [State]),
- {ok, State};
-command_handler([#command{id = Id,
- desc = Desc,
- cmd = Cmd}|Commands], State) ->
- p("command_handler -> entry with"
- "~n Id: ~p"
- "~n Desc: ~p", [Id, Desc]),
- case (catch Cmd(State)) of
- {ok, NewState} ->
- p("command_handler -> cmd ~w ok", [Id]),
- command_handler(Commands, NewState);
- {skip, _} = SKIP ->
- p("command_handler -> cmd ~w skip", [Id]),
- SKIP;
- {error, Reason} ->
- p("command_handler -> cmd ~w error: "
- "~n Reason: ~p", [Id, Reason]),
- {error, {cmd_error, Reason}};
- {'EXIT', Reason} ->
- p("command_handler -> cmv ~w exit: "
- "~n Reason: ~p", [Id, Reason]),
- {error, {cmd_exit, Reason}};
- Error ->
- p("command_handler -> cmd ~w failure: "
- "~n Error: ~p", [Id, Error]),
- {error, {cmd_failure, Error}}
- end.
+ ?CH:start(Node, Commands, State, ShortName).
await_command_handler_completion(Pids, Timeout) ->
- await_command_handler_completion(Pids, [], [], Timeout).
-
-await_command_handler_completion([], [], _Good, _Timeout) ->
- p("await_command_handler_completion -> entry when done"),
- ok;
-await_command_handler_completion([], Bad, Good, _Timeout) ->
- p("await_command_handler_completion -> entry when done with bad result: "
- "~n Bad: ~p"
- "~n Good: ~p", [Bad, Good]),
- {error, Bad, Good};
-await_command_handler_completion(Pids, Bad, Good, Timeout) ->
- p("await_command_handler_completion -> entry when waiting for"
- "~n Pids: ~p"
- "~n Bad: ~p"
- "~n Good: ~p"
- "~n Timeout: ~p", [Pids, Bad, Good, Timeout]),
- Begin = ms(),
- receive
- {'EXIT', Pid, {ok, FinalState}} ->
- p("await_command_handler_completion -> "
- "received ok EXIT signal from ~p", [Pid]),
- case lists:delete(Pid, Pids) of
- Pids ->
- await_command_handler_completion(Pids, Bad, Good,
- Timeout - (ms() - Begin));
- Pids2 ->
- p("await_command_handler_completion -> ~p done", [Pid]),
- await_command_handler_completion(Pids2,
- Bad,
- [{Pid, FinalState}|Good],
- Timeout - (ms() - Begin))
- end;
+ ?CH:await_completion(Pids, Timeout).
- {'EXIT', Pid, {error, Reason}} ->
- p("await_command_handler_completion -> "
- "received error EXIT signal from ~p", [Pid]),
- case lists:delete(Pid, Pids) of
- Pids ->
- await_command_handler_completion(Pids, Bad, Good,
- Timeout - (ms() - Begin));
- Pids2 ->
- p("await_command_handler_completion -> ~p done with"
- "~n ~p", [Pid, Reason]),
- await_command_handler_completion(Pids2,
- [{Pid, Reason}|Bad],
- Good,
- Timeout - (ms() - Begin))
- end;
- {'EXIT', Pid, {skip, Reason}} ->
- p("await_command_handler_completion -> "
- "received skip EXIT signal from ~p with"
- "~p", [Pid, Reason]),
- ?SKIP(Reason)
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+try_tc(TCName, Pre, Case, Post) ->
+ try_tc(TCName, "TEST", ?TEST_VERBOSITY, Pre, Case, Post).
- after Timeout ->
- p("await_command_handler_completion -> timeout"),
- exit({timeout, Pids})
- end.
+try_tc(TCName, Name, Verbosity, Pre, Case, Post) ->
+ ?TRY_TC(TCName, Name, Verbosity, Pre, Case, Post).
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%% ------- Misc functions --------
@@ -1297,7 +1212,7 @@ p(_S, F, A) ->
[?FTS(), self() | A]).
-ms() ->
- erlang:monotonic_time(milli_seconds).
+%% ms() ->
+%% erlang:monotonic_time(milli_seconds).
diff --git a/lib/megaco/test/modules.mk b/lib/megaco/test/modules.mk
index 3ec3ce7368..55b3003d6d 100644
--- a/lib/megaco/test/modules.mk
+++ b/lib/megaco/test/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2001-2019. All Rights Reserved.
+# Copyright Ericsson AB 2001-2020. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -33,6 +33,7 @@ TEST_UTIL_MODULES = \
megaco_mess_otp8212_test \
megaco_profile \
megaco_tc_controller \
+ megaco_test_command_handler \
megaco_test_global_sys_monitor \
megaco_test_sys_monitor \
megaco_test_generator_lib \
diff --git a/lib/mnesia/src/mnesia_bup.erl b/lib/mnesia/src/mnesia_bup.erl
index e57fc5199d..2111c1ce17 100644
--- a/lib/mnesia/src/mnesia_bup.erl
+++ b/lib/mnesia/src/mnesia_bup.erl
@@ -1121,6 +1121,7 @@ local_uninstall_fallback(Master, FA) ->
Bup = FA2#fallback_args.fallback_bup,
file:delete(Tmp),
Res = file:delete(Bup),
+ unregister(mnesia_fallback),
?eval_debug_fun({?MODULE, uninstall_fallback2, post_delete}, []),
Master ! {self(), Res},
unlink(Master),
diff --git a/lib/public_key/asn1/PKIX1Algorithms88.asn1 b/lib/public_key/asn1/PKIX1Algorithms88.asn1
index 6cc6745af6..207ab005a9 100644
--- a/lib/public_key/asn1/PKIX1Algorithms88.asn1
+++ b/lib/public_key/asn1/PKIX1Algorithms88.asn1
@@ -283,4 +283,12 @@
sect571k1 OBJECT IDENTIFIER ::= { ellipticCurve 38 }
sect571r1 OBJECT IDENTIFIER ::= { ellipticCurve 39 }
+
+ id-edwards-curve-algs OBJECT IDENTIFIER ::= { 1 3 101 }
+
+ id-X25519 OBJECT IDENTIFIER ::= { id-edwards-curve-algs 110 }
+ id-X448 OBJECT IDENTIFIER ::= { id-edwards-curve-algs 111 }
+ id-Ed25519 OBJECT IDENTIFIER ::= { id-edwards-curve-algs 112 }
+ id-Ed448 OBJECT IDENTIFIER ::= { id-edwards-curve-algs 113 }
+
END
diff --git a/lib/public_key/src/pubkey_cert_records.erl b/lib/public_key/src/pubkey_cert_records.erl
index 6a80874df8..1c79f904f3 100644
--- a/lib/public_key/src/pubkey_cert_records.erl
+++ b/lib/public_key/src/pubkey_cert_records.erl
@@ -113,7 +113,8 @@ supportedPublicKeyAlgorithms(?'id-keyExchangeAlgorithm') -> 'KEA-PublicKey';
supportedPublicKeyAlgorithms(?'id-ecPublicKey') -> 'ECPoint'.
supportedCurvesTypes(?'characteristic-two-field') -> characteristic_two_field;
-supportedCurvesTypes(?'prime-field') -> prime_field.
+supportedCurvesTypes(?'prime-field') -> prime_field;
+supportedCurvesTypes(?'id-edwards-curve-algs') -> edwards_curve.
namedCurves(?'sect571r1') -> sect571r1;
namedCurves(?'sect571k1') -> sect571k1;
@@ -148,6 +149,8 @@ namedCurves(?'sect163r1') -> sect163r1;
namedCurves(?'sect163k1') -> sect163k1;
namedCurves(?'secp256r1') -> secp256r1;
namedCurves(?'secp192r1') -> secp192r1;
+namedCurves(?'id-X25519') -> x25519;
+namedCurves(?'id-X448') -> x448;
namedCurves(?'brainpoolP160r1') -> brainpoolP160r1;
namedCurves(?'brainpoolP160t1') -> brainpoolP160t1;
namedCurves(?'brainpoolP192r1') -> brainpoolP192r1;
@@ -162,7 +165,6 @@ namedCurves(?'brainpoolP384r1') -> brainpoolP384r1;
namedCurves(?'brainpoolP384t1') -> brainpoolP384t1;
namedCurves(?'brainpoolP512r1') -> brainpoolP512r1;
namedCurves(?'brainpoolP512t1') -> brainpoolP512t1;
-
namedCurves(sect571r1) -> ?'sect571r1';
namedCurves(sect571k1) -> ?'sect571k1';
namedCurves(sect409r1) -> ?'sect409r1';
@@ -196,6 +198,8 @@ namedCurves(sect163r1) -> ?'sect163r1';
namedCurves(sect163k1) -> ?'sect163k1';
namedCurves(secp256r1) -> ?'secp256r1';
namedCurves(secp192r1) -> ?'secp192r1';
+namedCurves(x25519) -> ?'id-X25519';
+namedCurves(x448) -> ?'id-X448';
namedCurves(brainpoolP160r1) -> ?'brainpoolP160r1';
namedCurves(brainpoolP160t1) -> ?'brainpoolP160t1';
namedCurves(brainpoolP192r1) -> ?'brainpoolP192r1';
diff --git a/lib/public_key/src/public_key.erl b/lib/public_key/src/public_key.erl
index 47266c514c..ce5151750d 100644
--- a/lib/public_key/src/public_key.erl
+++ b/lib/public_key/src/public_key.erl
@@ -1536,6 +1536,10 @@ ec_curve_spec({ecParameters, ECParams}) ->
ec_curve_spec(ECParams);
ec_curve_spec({namedCurve, OID}) when is_tuple(OID), is_integer(element(1,OID)) ->
ec_curve_spec({namedCurve, pubkey_cert_records:namedCurves(OID)});
+ec_curve_spec({namedCurve, x25519 = Name}) ->
+ Name;
+ec_curve_spec({namedCurve, x448 = Name}) ->
+ Name;
ec_curve_spec({namedCurve, Name}) when is_atom(Name) ->
crypto:ec_curve(Name).
diff --git a/lib/public_key/test/Makefile b/lib/public_key/test/Makefile
index b9beb6d3b9..1ee3b24e3a 100644
--- a/lib/public_key/test/Makefile
+++ b/lib/public_key/test/Makefile
@@ -32,7 +32,8 @@ MODULES= \
erl_make_certs \
public_key_SUITE \
pbe_SUITE \
- pkits_SUITE
+ pkits_SUITE \
+ pubkey_ssh_SUITE
ERL_FILES= $(MODULES:%=%.erl)
diff --git a/lib/public_key/test/pubkey_ssh_SUITE.erl b/lib/public_key/test/pubkey_ssh_SUITE.erl
new file mode 100644
index 0000000000..afa3741346
--- /dev/null
+++ b/lib/public_key/test/pubkey_ssh_SUITE.erl
@@ -0,0 +1,417 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+%%
+-module(pubkey_ssh_SUITE).
+
+-include_lib("common_test/include/ct.hrl").
+-include_lib("public_key/include/public_key.hrl").
+
+%% Note: This directive should only be used in test suites.
+-compile(export_all).
+
+-define(TIMEOUT, 120000). % 2 min
+
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+
+suite() ->
+ [].
+
+all() ->
+ [{group, ssh_public_key_decode_encode},
+ {group, ssh_hostkey_fingerprint}
+ ].
+
+groups() ->
+ [{ssh_public_key_decode_encode, [],
+ [ssh_rsa_public_key, ssh_dsa_public_key, ssh_ecdsa_public_key,
+ ssh_rfc4716_rsa_comment, ssh_rfc4716_dsa_comment,
+ ssh_rfc4716_rsa_subject,
+ ssh_known_hosts,
+ ssh_auth_keys, ssh1_known_hosts, ssh1_auth_keys, ssh_openssh_public_key_with_comment,
+ ssh_openssh_public_key_long_header]},
+
+ {ssh_hostkey_fingerprint, [],
+ [ssh_hostkey_fingerprint_md5_implicit,
+ ssh_hostkey_fingerprint_md5,
+ ssh_hostkey_fingerprint_sha,
+ ssh_hostkey_fingerprint_sha256,
+ ssh_hostkey_fingerprint_sha384,
+ ssh_hostkey_fingerprint_sha512,
+ ssh_hostkey_fingerprint_list]}
+ ].
+%%-------------------------------------------------------------------
+init_per_suite(Config) ->
+ application:stop(crypto),
+ try crypto:start() of
+ ok ->
+ application:start(asn1),
+ Config
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ application:stop(asn1),
+ application:stop(crypto).
+
+%%-------------------------------------------------------------------
+init_per_group(_GroupName, Config) ->
+ Config.
+
+end_per_group(_GroupName, Config) ->
+ Config.
+%%-------------------------------------------------------------------
+init_per_testcase(ssh_hostkey_fingerprint_md5_implicit, Config) ->
+ init_fingerprint_testcase([md5], Config);
+
+init_per_testcase(ssh_hostkey_fingerprint_md5, Config) ->
+ init_fingerprint_testcase([md5], Config);
+
+init_per_testcase(ssh_hostkey_fingerprint_sha, Config) ->
+ init_fingerprint_testcase([sha], Config);
+
+init_per_testcase(ssh_hostkey_fingerprint_sha256, Config) ->
+ init_fingerprint_testcase([sha256], Config);
+
+init_per_testcase(ssh_hostkey_fingerprint_sha384, Config) ->
+ init_fingerprint_testcase([sha384], Config);
+
+init_per_testcase(ssh_hostkey_fingerprint_sha512, Config) ->
+ init_fingerprint_testcase([sha512], Config);
+
+init_per_testcase(ssh_hostkey_fingerprint_list , Config) ->
+ init_fingerprint_testcase([sha,md5], Config);
+
+init_per_testcase(_, Config) ->
+ init_common_per_testcase(Config).
+
+
+init_fingerprint_testcase(Algs, Config) ->
+ Hashs = proplists:get_value(hashs, crypto:supports(), []),
+ case Algs -- Hashs of
+ [] -> init_common_per_testcase(Config);
+ UnsupportedAlgs -> {skip,{UnsupportedAlgs,not_supported}}
+ end.
+
+init_common_per_testcase(Config0) ->
+ Config = lists:keydelete(watchdog, 1, Config0),
+ Dog = ct:timetrap(?TIMEOUT),
+ [{watchdog, Dog} | Config].
+
+
+end_per_testcase(_TestCase, _Config) ->
+ ok.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+ssh_rsa_public_key(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_pub")),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, public_key),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, rfc4716_public_key),
+
+ {ok, RSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_rsa_pub")),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, public_key),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, openssh_public_key),
+
+ %% Can not check EncodedSSh == RSARawSsh2 and EncodedOpenSsh
+ %% = RSARawOpenSsh as line breakpoints may differ
+
+ EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
+ EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
+
+ [{PubKey, Attributes1}] =
+ public_key:ssh_decode(EncodedSSh, public_key),
+ [{PubKey, Attributes2}] =
+ public_key:ssh_decode(EncodedOpenSsh, public_key).
+
+%%--------------------------------------------------------------------
+ssh_dsa_public_key(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_pub")),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, public_key),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, rfc4716_public_key),
+
+ {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_pub")),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, public_key),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key),
+
+ %% Can not check EncodedSSh == DSARawSsh2 and EncodedOpenSsh
+ %% = DSARawOpenSsh as line breakpoints may differ
+
+ EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
+ EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
+
+ [{PubKey, Attributes1}] =
+ public_key:ssh_decode(EncodedSSh, public_key),
+ [{PubKey, Attributes2}] =
+ public_key:ssh_decode(EncodedOpenSsh, public_key).
+
+%%--------------------------------------------------------------------
+ssh_ecdsa_public_key(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, ECDSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_ecdsa_pub")),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, public_key),
+ [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, rfc4716_public_key),
+
+ {ok, ECDSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_ecdsa_pub")),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(ECDSARawOpenSsh, public_key),
+ [{PubKey, Attributes2}] = public_key:ssh_decode(ECDSARawOpenSsh, openssh_public_key),
+
+ %% Can not check EncodedSSh == ECDSARawSsh2 and EncodedOpenSsh
+ %% = ECDSARawOpenSsh as line breakpoints may differ
+
+ EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
+ EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
+
+ [{PubKey, Attributes1}] =
+ public_key:ssh_decode(EncodedSSh, public_key),
+ [{PubKey, Attributes2}] =
+ public_key:ssh_decode(EncodedOpenSsh, public_key).
+
+%%--------------------------------------------------------------------
+ssh_rfc4716_rsa_comment(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_comment_pub")),
+ [{#'RSAPublicKey'{} = PubKey, Attributes}] =
+ public_key:ssh_decode(RSARawSsh2, public_key),
+
+ Headers = proplists:get_value(headers, Attributes),
+
+ Value = proplists:get_value("Comment", Headers, undefined),
+ true = Value =/= undefined,
+ RSARawSsh2 = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key).
+
+%%--------------------------------------------------------------------
+ssh_rfc4716_dsa_comment(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_comment_pub")),
+ [{{_, #'Dss-Parms'{}} = PubKey, Attributes}] =
+ public_key:ssh_decode(DSARawSsh2, public_key),
+
+ Headers = proplists:get_value(headers, Attributes),
+
+ Value = proplists:get_value("Comment", Headers, undefined),
+ true = Value =/= undefined,
+
+ %% Can not check Encoded == DSARawSsh2 as line continuation breakpoints may differ
+ Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key),
+ [{PubKey, Attributes}] =
+ public_key:ssh_decode(Encoded, public_key).
+
+%%--------------------------------------------------------------------
+ssh_rfc4716_rsa_subject(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_subject_pub")),
+ [{#'RSAPublicKey'{} = PubKey, Attributes}] =
+ public_key:ssh_decode(RSARawSsh2, public_key),
+
+ Headers = proplists:get_value(headers, Attributes),
+
+ Value = proplists:get_value("Subject", Headers, undefined),
+ true = Value =/= undefined,
+
+ %% Can not check Encoded == RSARawSsh2 as line continuation breakpoints may differ
+ Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key),
+ [{PubKey, Attributes}] =
+ public_key:ssh_decode(Encoded, public_key).
+
+%%--------------------------------------------------------------------
+ssh_known_hosts(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "known_hosts")),
+ [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},
+ {#'RSAPublicKey'{}, Attributes3}, {#'RSAPublicKey'{}, Attributes4}] = Decoded =
+ public_key:ssh_decode(SshKnownHosts, known_hosts),
+
+ Comment1 = undefined,
+ Comment2 = "foo@bar.com",
+ Comment3 = "Comment with whitespaces",
+ Comment4 = "foo@bar.com Comment with whitespaces",
+
+ Comment1 = proplists:get_value(comment, Attributes1, undefined),
+ Comment2 = proplists:get_value(comment, Attributes2),
+ Comment3 = proplists:get_value(comment, Attributes3),
+ Comment4 = proplists:get_value(comment, Attributes4),
+
+ Value1 = proplists:get_value(hostnames, Attributes1, undefined),
+ Value2 = proplists:get_value(hostnames, Attributes2, undefined),
+ true = (Value1 =/= undefined) and (Value2 =/= undefined),
+
+ Encoded = public_key:ssh_encode(Decoded, known_hosts),
+ Decoded = public_key:ssh_decode(Encoded, known_hosts).
+
+%%--------------------------------------------------------------------
+ssh1_known_hosts(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "ssh1_known_hosts")),
+ [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},{#'RSAPublicKey'{}, Attributes3}]
+ = Decoded = public_key:ssh_decode(SshKnownHosts, known_hosts),
+
+ Value1 = proplists:get_value(hostnames, Attributes1, undefined),
+ Value2 = proplists:get_value(hostnames, Attributes2, undefined),
+ true = (Value1 =/= undefined) and (Value2 =/= undefined),
+
+ Comment ="dhopson@VMUbuntu-DSH comment with whitespaces",
+ Comment = proplists:get_value(comment, Attributes3),
+
+ Encoded = public_key:ssh_encode(Decoded, known_hosts),
+ Decoded = public_key:ssh_decode(Encoded, known_hosts).
+
+%%--------------------------------------------------------------------
+ssh_auth_keys(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "auth_keys")),
+ [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, Attributes2},
+ {#'RSAPublicKey'{}, Attributes3}, {{_, #'Dss-Parms'{}}, Attributes4}
+ ] = Decoded =
+ public_key:ssh_decode(SshAuthKeys, auth_keys),
+
+ Value1 = proplists:get_value(options, Attributes1, undefined),
+ true = Value1 =/= undefined,
+
+ Comment1 = Comment2 = "dhopson@VMUbuntu-DSH",
+ Comment3 = Comment4 ="dhopson@VMUbuntu-DSH comment with whitespaces",
+
+ Comment1 = proplists:get_value(comment, Attributes1),
+ Comment2 = proplists:get_value(comment, Attributes2),
+ Comment3 = proplists:get_value(comment, Attributes3),
+ Comment4 = proplists:get_value(comment, Attributes4),
+
+ Encoded = public_key:ssh_encode(Decoded, auth_keys),
+ Decoded = public_key:ssh_decode(Encoded, auth_keys).
+
+%%--------------------------------------------------------------------
+ssh1_auth_keys(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "ssh1_auth_keys")),
+ [{#'RSAPublicKey'{}, Attributes1},
+ {#'RSAPublicKey'{}, Attributes2}, {#'RSAPublicKey'{}, Attributes3},
+ {#'RSAPublicKey'{}, Attributes4}, {#'RSAPublicKey'{}, Attributes5}] = Decoded =
+ public_key:ssh_decode(SshAuthKeys, auth_keys),
+
+ Value1 = proplists:get_value(bits, Attributes2, undefined),
+ Value2 = proplists:get_value(bits, Attributes3, undefined),
+ true = (Value1 =/= undefined) and (Value2 =/= undefined),
+
+ Comment2 = Comment3 = "dhopson@VMUbuntu-DSH",
+ Comment4 = Comment5 ="dhopson@VMUbuntu-DSH comment with whitespaces",
+
+ undefined = proplists:get_value(comment, Attributes1, undefined),
+ Comment2 = proplists:get_value(comment, Attributes2),
+ Comment3 = proplists:get_value(comment, Attributes3),
+ Comment4 = proplists:get_value(comment, Attributes4),
+ Comment5 = proplists:get_value(comment, Attributes5),
+
+ Encoded = public_key:ssh_encode(Decoded, auth_keys),
+ Decoded = public_key:ssh_decode(Encoded, auth_keys).
+
+%%--------------------------------------------------------------------
+ssh_openssh_public_key_with_comment(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_with_comment_pub")),
+ [{{_, #'Dss-Parms'{}}, _}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key).
+
+%%--------------------------------------------------------------------
+ssh_openssh_public_key_long_header(Config) when is_list(Config) ->
+ Datadir = proplists:get_value(data_dir, Config),
+
+ {ok,RSARawOpenSsh} = file:read_file(filename:join(Datadir, "ssh_rsa_long_header_pub")),
+ [{#'RSAPublicKey'{}, _}] = Decoded = public_key:ssh_decode(RSARawOpenSsh, public_key),
+
+ Encoded = public_key:ssh_encode(Decoded, rfc4716_public_key),
+ Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key).
+
+%%--------------------------------------------------------------------
+%% Check of different host keys left to later
+ssh_hostkey_fingerprint_md5_implicit(_Config) ->
+ Expected = "4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a",
+ Expected = public_key:ssh_hostkey_fingerprint(ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Check of different host keys left to later
+ssh_hostkey_fingerprint_md5(_Config) ->
+ Expected = "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a",
+ Expected = public_key:ssh_hostkey_fingerprint(md5, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead. The Expected is generated with:
+%% $ openssh-7.3p1/ssh-keygen -E sha1 -lf <file>
+%% 2048 SHA1:Soammnaqg06jrm2jivMSnzQGlmk none@example.org (RSA)
+ssh_hostkey_fingerprint_sha(_Config) ->
+ Expected = "SHA1:Soammnaqg06jrm2jivMSnzQGlmk",
+ Expected = public_key:ssh_hostkey_fingerprint(sha, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha256(_Config) ->
+ Expected = "SHA256:T7F1BahkJWR7iJO8+rpzWOPbp7LZP4MlNrDExdNYOvY",
+ Expected = public_key:ssh_hostkey_fingerprint(sha256, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha384(_Config) ->
+ Expected = "SHA384:QhkLoGNI4KXdPvC//HxxSCP3uTQVADqxdajbgm+Gkx9zqz8N94HyP1JmH8C4/aEl",
+ Expected = public_key:ssh_hostkey_fingerprint(sha384, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_sha512(_Config) ->
+ Expected = "SHA512:ezUismvm3ADQQb6Nm0c1DwQ6ydInlJNfsnSQejFkXNmABg1Aenk9oi45CXeBOoTnlfTsGG8nFDm0smP10PBEeA",
+ Expected = public_key:ssh_hostkey_fingerprint(sha512, ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Since this kind of fingerprint is not available yet on standard
+%% distros, we do like this instead.
+ssh_hostkey_fingerprint_list(_Config) ->
+ Expected = ["SHA1:Soammnaqg06jrm2jivMSnzQGlmk",
+ "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a"],
+ Expected = public_key:ssh_hostkey_fingerprint([sha,md5], ssh_hostkey(rsa)).
+
+%%--------------------------------------------------------------------
+%% Internal functions ------------------------------------------------
+%%--------------------------------------------------------------------
+ssh_hostkey(rsa) ->
+ [{PKdecoded,_}] =
+ public_key:ssh_decode(
+ <<"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYXcYmsyJBstl4EfFYzfQJmSiUE162zvSGSoMYybShYOI6rnnyvvihfw8Aml+2gZ716F2tqG48FQ/yPZEGWNPMrCejPpJctaPWhpNdNMJ8KFXSEgr5bY2mEpa19DHmuDeXKzeJJ+X7s3fVdYc4FMk5731KIW6Huf019ZnTxbx0VKG6b1KAJBg3vpNsDxEMwQ4LFMB0JHVklOTzbxmpaeULuIxvl65A+eGeFVeo2Q+YI9UnwY1vSgmc9Azwy8Ie9Z0HpQBN5I7Uc5xnknT8V6xDhgNfXEfzsgsRdDfZLECt1WO/1gP9wkosvAGZWt5oG8pbNQWiQdFq536ck8WQD9WD none@example.org">>,
+ public_key),
+ PKdecoded.
+
diff --git a/lib/public_key/test/public_key_SUITE_data/auth_keys b/lib/public_key/test/pubkey_ssh_SUITE_data/auth_keys
index 8be7357a06..8be7357a06 100644
--- a/lib/public_key/test/public_key_SUITE_data/auth_keys
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/auth_keys
diff --git a/lib/public_key/test/public_key_SUITE_data/known_hosts b/lib/public_key/test/pubkey_ssh_SUITE_data/known_hosts
index 3c3af68178..3c3af68178 100644
--- a/lib/public_key/test/public_key_SUITE_data/known_hosts
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/known_hosts
diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_pub
index a765ba8189..a765ba8189 100644
--- a/lib/public_key/test/public_key_SUITE_data/openssh_dsa_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_with_comment_pub
index d5a34a3f78..d5a34a3f78 100644
--- a/lib/public_key/test/public_key_SUITE_data/openssh_dsa_with_comment_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_dsa_with_comment_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_ecdsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_ecdsa_pub
index a49b4264b8..a49b4264b8 100644
--- a/lib/public_key/test/public_key_SUITE_data/openssh_ecdsa_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_ecdsa_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_rsa_pub
index 0a0838db40..0a0838db40 100644
--- a/lib/public_key/test/public_key_SUITE_data/openssh_rsa_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/openssh_rsa_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_auth_keys
index ac3d61b4c7..ac3d61b4c7 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh1_auth_keys
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_auth_keys
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_known_hosts
index 835b16ab67..835b16ab67 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh1_known_hosts
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh1_known_hosts
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_comment_pub
index ca5089dbd7..ca5089dbd7 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_comment_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_comment_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_pub
index a5e38be81a..a5e38be81a 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh2_dsa_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_dsa_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_ecdsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_ecdsa_pub
index 702e5c4fde..702e5c4fde 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh2_ecdsa_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_ecdsa_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_comment_pub
index e4d446147c..e4d446147c 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_comment_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_comment_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_pub
index 761088b517..761088b517 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh2_rsa_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_rsa_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_subject_pub
index 8b8ccda8ba..8b8ccda8ba 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh2_subject_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh2_subject_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_comment_pub
index 7b42ced93e..7b42ced93e 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_comment_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_comment_pub
diff --git a/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_header_pub
index 7b42ced93e..7b42ced93e 100644
--- a/lib/public_key/test/public_key_SUITE_data/ssh_rsa_long_header_pub
+++ b/lib/public_key/test/pubkey_ssh_SUITE_data/ssh_rsa_long_header_pub
diff --git a/lib/public_key/test/public_key_SUITE.erl b/lib/public_key/test/public_key_SUITE.erl
index 878489eb0f..5acb61575e 100644
--- a/lib/public_key/test/public_key_SUITE.erl
+++ b/lib/public_key/test/public_key_SUITE.erl
@@ -40,7 +40,6 @@ suite() ->
all() ->
[app, appup,
{group, pem_decode_encode},
- {group, ssh_public_key_decode_encode},
encrypt_decrypt,
{group, sign_verify},
pkix, pkix_countryname, pkix_emailaddress, pkix_path_validation,
@@ -53,14 +52,7 @@ all() ->
pkix_verify_hostname_options,
pkix_test_data_all_default,
pkix_test_data,
- short_cert_issuer_hash, short_crl_issuer_hash,
- ssh_hostkey_fingerprint_md5_implicit,
- ssh_hostkey_fingerprint_md5,
- ssh_hostkey_fingerprint_sha,
- ssh_hostkey_fingerprint_sha256,
- ssh_hostkey_fingerprint_sha384,
- ssh_hostkey_fingerprint_sha512,
- ssh_hostkey_fingerprint_list
+ short_cert_issuer_hash, short_crl_issuer_hash
].
groups() ->
@@ -70,13 +62,6 @@ groups() ->
ec_pem_encode_generated,
gen_ec_param_prime_field, gen_ec_param_char_2_field
]},
- {ssh_public_key_decode_encode, [],
- [ssh_rsa_public_key, ssh_dsa_public_key, ssh_ecdsa_public_key,
- ssh_rfc4716_rsa_comment, ssh_rfc4716_dsa_comment,
- ssh_rfc4716_rsa_subject,
- ssh_known_hosts,
- ssh_auth_keys, ssh1_known_hosts, ssh1_auth_keys, ssh_openssh_public_key_with_comment,
- ssh_openssh_public_key_long_header]},
{sign_verify, [], [rsa_sign_verify, dsa_sign_verify]}
].
%%-------------------------------------------------------------------
@@ -118,24 +103,11 @@ init_per_testcase(gen_ec_param_char_2_field=TC, Config) ->
init_per_testcase(TestCase, Config) ->
case TestCase of
- ssh_hostkey_fingerprint_md5_implicit -> init_fingerprint_testcase([md5], Config);
- ssh_hostkey_fingerprint_md5 -> init_fingerprint_testcase([md5], Config);
- ssh_hostkey_fingerprint_sha -> init_fingerprint_testcase([sha], Config);
- ssh_hostkey_fingerprint_sha256 -> init_fingerprint_testcase([sha256], Config);
- ssh_hostkey_fingerprint_sha384 -> init_fingerprint_testcase([sha384], Config);
- ssh_hostkey_fingerprint_sha512 -> init_fingerprint_testcase([sha512], Config);
- ssh_hostkey_fingerprint_list -> init_fingerprint_testcase([sha,md5], Config);
- ec_pem_encode_generated -> init_ec_pem_encode_generated(Config);
+ ec_pem_encode_generated ->
+ init_ec_pem_encode_generated(Config);
_ -> init_common_per_testcase(Config)
end.
-init_fingerprint_testcase(Algs, Config) ->
- Hashs = proplists:get_value(hashs, crypto:supports(), []),
- case Algs -- Hashs of
- [] -> init_common_per_testcase(Config);
- UnsupportedAlgs -> {skip,{UnsupportedAlgs,not_supported}}
- end.
-
init_common_per_testcase(Config0) ->
Config = lists:keydelete(watchdog, 1, Config0),
Dog = ct:timetrap(?TIMEOUT),
@@ -404,313 +376,6 @@ cert_pem(Config) when is_list(Config) ->
asn1_encode_decode(Entry2).
%%--------------------------------------------------------------------
-ssh_rsa_public_key() ->
- [{doc, "ssh rsa public key decode/encode"}].
-ssh_rsa_public_key(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_pub")),
- [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, public_key),
- [{PubKey, Attributes1}] = public_key:ssh_decode(RSARawSsh2, rfc4716_public_key),
-
- {ok, RSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_rsa_pub")),
- [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, public_key),
- [{PubKey, Attributes2}] = public_key:ssh_decode(RSARawOpenSsh, openssh_public_key),
-
- %% Can not check EncodedSSh == RSARawSsh2 and EncodedOpenSsh
- %% = RSARawOpenSsh as line breakpoints may differ
-
- EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
- EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
-
- [{PubKey, Attributes1}] =
- public_key:ssh_decode(EncodedSSh, public_key),
- [{PubKey, Attributes2}] =
- public_key:ssh_decode(EncodedOpenSsh, public_key).
-
-%%--------------------------------------------------------------------
-
-ssh_dsa_public_key() ->
- [{doc, "ssh dsa public key decode/encode"}].
-ssh_dsa_public_key(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_pub")),
- [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, public_key),
- [{PubKey, Attributes1}] = public_key:ssh_decode(DSARawSsh2, rfc4716_public_key),
-
- {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_pub")),
- [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, public_key),
- [{PubKey, Attributes2}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key),
-
- %% Can not check EncodedSSh == DSARawSsh2 and EncodedOpenSsh
- %% = DSARawOpenSsh as line breakpoints may differ
-
- EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
- EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
-
- [{PubKey, Attributes1}] =
- public_key:ssh_decode(EncodedSSh, public_key),
- [{PubKey, Attributes2}] =
- public_key:ssh_decode(EncodedOpenSsh, public_key).
-
-%%--------------------------------------------------------------------
-
-ssh_ecdsa_public_key() ->
- [{doc, "ssh ecdsa public key decode/encode"}].
-ssh_ecdsa_public_key(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, ECDSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_ecdsa_pub")),
- [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, public_key),
- [{PubKey, Attributes1}] = public_key:ssh_decode(ECDSARawSsh2, rfc4716_public_key),
-
- {ok, ECDSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_ecdsa_pub")),
- [{PubKey, Attributes2}] = public_key:ssh_decode(ECDSARawOpenSsh, public_key),
- [{PubKey, Attributes2}] = public_key:ssh_decode(ECDSARawOpenSsh, openssh_public_key),
-
- %% Can not check EncodedSSh == ECDSARawSsh2 and EncodedOpenSsh
- %% = ECDSARawOpenSsh as line breakpoints may differ
-
- EncodedSSh = public_key:ssh_encode([{PubKey, Attributes1}], rfc4716_public_key),
- EncodedOpenSsh = public_key:ssh_encode([{PubKey, Attributes2}], openssh_public_key),
-
- [{PubKey, Attributes1}] =
- public_key:ssh_decode(EncodedSSh, public_key),
- [{PubKey, Attributes2}] =
- public_key:ssh_decode(EncodedOpenSsh, public_key).
-
-%%--------------------------------------------------------------------
-ssh_rfc4716_rsa_comment() ->
- [{doc, "Test comment header and rsa key"}].
-ssh_rfc4716_rsa_comment(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_rsa_comment_pub")),
- [{#'RSAPublicKey'{} = PubKey, Attributes}] =
- public_key:ssh_decode(RSARawSsh2, public_key),
-
- Headers = proplists:get_value(headers, Attributes),
-
- Value = proplists:get_value("Comment", Headers, undefined),
- true = Value =/= undefined,
- RSARawSsh2 = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key).
-
-%%--------------------------------------------------------------------
-ssh_rfc4716_dsa_comment() ->
- [{doc, "Test comment header and dsa key"}].
-ssh_rfc4716_dsa_comment(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, DSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_dsa_comment_pub")),
- [{{_, #'Dss-Parms'{}} = PubKey, Attributes}] =
- public_key:ssh_decode(DSARawSsh2, public_key),
-
- Headers = proplists:get_value(headers, Attributes),
-
- Value = proplists:get_value("Comment", Headers, undefined),
- true = Value =/= undefined,
-
- %% Can not check Encoded == DSARawSsh2 as line continuation breakpoints may differ
- Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key),
- [{PubKey, Attributes}] =
- public_key:ssh_decode(Encoded, public_key).
-
-%%--------------------------------------------------------------------
-ssh_rfc4716_rsa_subject() ->
- [{doc, "Test another header value than comment"}].
-ssh_rfc4716_rsa_subject(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, RSARawSsh2} = file:read_file(filename:join(Datadir, "ssh2_subject_pub")),
- [{#'RSAPublicKey'{} = PubKey, Attributes}] =
- public_key:ssh_decode(RSARawSsh2, public_key),
-
- Headers = proplists:get_value(headers, Attributes),
-
- Value = proplists:get_value("Subject", Headers, undefined),
- true = Value =/= undefined,
-
- %% Can not check Encoded == RSARawSsh2 as line continuation breakpoints may differ
- Encoded = public_key:ssh_encode([{PubKey, Attributes}], rfc4716_public_key),
- [{PubKey, Attributes}] =
- public_key:ssh_decode(Encoded, public_key).
-
-%%--------------------------------------------------------------------
-ssh_known_hosts() ->
- [{doc, "ssh known hosts file encode/decode"}].
-ssh_known_hosts(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "known_hosts")),
- [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},
- {#'RSAPublicKey'{}, Attributes3}, {#'RSAPublicKey'{}, Attributes4}] = Decoded =
- public_key:ssh_decode(SshKnownHosts, known_hosts),
-
- Comment1 = undefined,
- Comment2 = "foo@bar.com",
- Comment3 = "Comment with whitespaces",
- Comment4 = "foo@bar.com Comment with whitespaces",
-
- Comment1 = proplists:get_value(comment, Attributes1, undefined),
- Comment2 = proplists:get_value(comment, Attributes2),
- Comment3 = proplists:get_value(comment, Attributes3),
- Comment4 = proplists:get_value(comment, Attributes4),
-
- Value1 = proplists:get_value(hostnames, Attributes1, undefined),
- Value2 = proplists:get_value(hostnames, Attributes2, undefined),
- true = (Value1 =/= undefined) and (Value2 =/= undefined),
-
- Encoded = public_key:ssh_encode(Decoded, known_hosts),
- Decoded = public_key:ssh_decode(Encoded, known_hosts).
-
-%%--------------------------------------------------------------------
-
-ssh1_known_hosts() ->
- [{doc, "ssh (ver 1) known hosts file encode/decode"}].
-ssh1_known_hosts(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, SshKnownHosts} = file:read_file(filename:join(Datadir, "ssh1_known_hosts")),
- [{#'RSAPublicKey'{}, Attributes1}, {#'RSAPublicKey'{}, Attributes2},{#'RSAPublicKey'{}, Attributes3}]
- = Decoded = public_key:ssh_decode(SshKnownHosts, known_hosts),
-
- Value1 = proplists:get_value(hostnames, Attributes1, undefined),
- Value2 = proplists:get_value(hostnames, Attributes2, undefined),
- true = (Value1 =/= undefined) and (Value2 =/= undefined),
-
- Comment ="dhopson@VMUbuntu-DSH comment with whitespaces",
- Comment = proplists:get_value(comment, Attributes3),
-
- Encoded = public_key:ssh_encode(Decoded, known_hosts),
- Decoded = public_key:ssh_decode(Encoded, known_hosts).
-
-%%--------------------------------------------------------------------
-ssh_auth_keys() ->
- [{doc, "ssh authorized keys file encode/decode"}].
-ssh_auth_keys(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "auth_keys")),
- [{#'RSAPublicKey'{}, Attributes1}, {{_, #'Dss-Parms'{}}, Attributes2},
- {#'RSAPublicKey'{}, Attributes3}, {{_, #'Dss-Parms'{}}, Attributes4}
- ] = Decoded =
- public_key:ssh_decode(SshAuthKeys, auth_keys),
-
- Value1 = proplists:get_value(options, Attributes1, undefined),
- true = Value1 =/= undefined,
-
- Comment1 = Comment2 = "dhopson@VMUbuntu-DSH",
- Comment3 = Comment4 ="dhopson@VMUbuntu-DSH comment with whitespaces",
-
- Comment1 = proplists:get_value(comment, Attributes1),
- Comment2 = proplists:get_value(comment, Attributes2),
- Comment3 = proplists:get_value(comment, Attributes3),
- Comment4 = proplists:get_value(comment, Attributes4),
-
- Encoded = public_key:ssh_encode(Decoded, auth_keys),
- Decoded = public_key:ssh_decode(Encoded, auth_keys).
-
-%%--------------------------------------------------------------------
-ssh1_auth_keys() ->
- [{doc, "ssh (ver 1) authorized keys file encode/decode"}].
-ssh1_auth_keys(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, SshAuthKeys} = file:read_file(filename:join(Datadir, "ssh1_auth_keys")),
- [{#'RSAPublicKey'{}, Attributes1},
- {#'RSAPublicKey'{}, Attributes2}, {#'RSAPublicKey'{}, Attributes3},
- {#'RSAPublicKey'{}, Attributes4}, {#'RSAPublicKey'{}, Attributes5}] = Decoded =
- public_key:ssh_decode(SshAuthKeys, auth_keys),
-
- Value1 = proplists:get_value(bits, Attributes2, undefined),
- Value2 = proplists:get_value(bits, Attributes3, undefined),
- true = (Value1 =/= undefined) and (Value2 =/= undefined),
-
- Comment2 = Comment3 = "dhopson@VMUbuntu-DSH",
- Comment4 = Comment5 ="dhopson@VMUbuntu-DSH comment with whitespaces",
-
- undefined = proplists:get_value(comment, Attributes1, undefined),
- Comment2 = proplists:get_value(comment, Attributes2),
- Comment3 = proplists:get_value(comment, Attributes3),
- Comment4 = proplists:get_value(comment, Attributes4),
- Comment5 = proplists:get_value(comment, Attributes5),
-
- Encoded = public_key:ssh_encode(Decoded, auth_keys),
- Decoded = public_key:ssh_decode(Encoded, auth_keys).
-
-%%--------------------------------------------------------------------
-ssh_openssh_public_key_with_comment() ->
- [{doc, "Test that emty lines and lines starting with # are ignored"}].
-ssh_openssh_public_key_with_comment(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok, DSARawOpenSsh} = file:read_file(filename:join(Datadir, "openssh_dsa_with_comment_pub")),
- [{{_, #'Dss-Parms'{}}, _}] = public_key:ssh_decode(DSARawOpenSsh, openssh_public_key).
-
-%%--------------------------------------------------------------------
-ssh_openssh_public_key_long_header() ->
- [{doc, "Test that long headers are handled"}].
-ssh_openssh_public_key_long_header(Config) when is_list(Config) ->
- Datadir = proplists:get_value(data_dir, Config),
-
- {ok,RSARawOpenSsh} = file:read_file(filename:join(Datadir, "ssh_rsa_long_header_pub")),
- [{#'RSAPublicKey'{}, _}] = Decoded = public_key:ssh_decode(RSARawOpenSsh, public_key),
-
- Encoded = public_key:ssh_encode(Decoded, rfc4716_public_key),
- Decoded = public_key:ssh_decode(Encoded, rfc4716_public_key).
-
-%%--------------------------------------------------------------------
-%% Check of different host keys left to later
-ssh_hostkey_fingerprint_md5_implicit(_Config) ->
- Expected = "4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a",
- Expected = public_key:ssh_hostkey_fingerprint(ssh_hostkey(rsa)).
-
-%%--------------------------------------------------------------------
-%% Check of different host keys left to later
-ssh_hostkey_fingerprint_md5(_Config) ->
- Expected = "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a",
- Expected = public_key:ssh_hostkey_fingerprint(md5, ssh_hostkey(rsa)).
-
-%%--------------------------------------------------------------------
-%% Since this kind of fingerprint is not available yet on standard
-%% distros, we do like this instead. The Expected is generated with:
-%% $ openssh-7.3p1/ssh-keygen -E sha1 -lf <file>
-%% 2048 SHA1:Soammnaqg06jrm2jivMSnzQGlmk none@example.org (RSA)
-ssh_hostkey_fingerprint_sha(_Config) ->
- Expected = "SHA1:Soammnaqg06jrm2jivMSnzQGlmk",
- Expected = public_key:ssh_hostkey_fingerprint(sha, ssh_hostkey(rsa)).
-
-%%--------------------------------------------------------------------
-%% Since this kind of fingerprint is not available yet on standard
-%% distros, we do like this instead.
-ssh_hostkey_fingerprint_sha256(_Config) ->
- Expected = "SHA256:T7F1BahkJWR7iJO8+rpzWOPbp7LZP4MlNrDExdNYOvY",
- Expected = public_key:ssh_hostkey_fingerprint(sha256, ssh_hostkey(rsa)).
-
-%%--------------------------------------------------------------------
-%% Since this kind of fingerprint is not available yet on standard
-%% distros, we do like this instead.
-ssh_hostkey_fingerprint_sha384(_Config) ->
- Expected = "SHA384:QhkLoGNI4KXdPvC//HxxSCP3uTQVADqxdajbgm+Gkx9zqz8N94HyP1JmH8C4/aEl",
- Expected = public_key:ssh_hostkey_fingerprint(sha384, ssh_hostkey(rsa)).
-
-%%--------------------------------------------------------------------
-%% Since this kind of fingerprint is not available yet on standard
-%% distros, we do like this instead.
-ssh_hostkey_fingerprint_sha512(_Config) ->
- Expected = "SHA512:ezUismvm3ADQQb6Nm0c1DwQ6ydInlJNfsnSQejFkXNmABg1Aenk9oi45CXeBOoTnlfTsGG8nFDm0smP10PBEeA",
- Expected = public_key:ssh_hostkey_fingerprint(sha512, ssh_hostkey(rsa)).
-
-%%--------------------------------------------------------------------
-%% Since this kind of fingerprint is not available yet on standard
-%% distros, we do like this instead.
-ssh_hostkey_fingerprint_list(_Config) ->
- Expected = ["SHA1:Soammnaqg06jrm2jivMSnzQGlmk",
- "MD5:4b:0b:63:de:0f:a7:3a:ab:2c:cc:2d:d1:21:37:1d:3a"],
- Expected = public_key:ssh_hostkey_fingerprint([sha,md5], ssh_hostkey(rsa)).
-
-%%--------------------------------------------------------------------
encrypt_decrypt() ->
[{doc, "Test public_key:encrypt_private and public_key:decrypt_public"}].
encrypt_decrypt(Config) when is_list(Config) ->
@@ -1413,13 +1078,6 @@ incorrect_emailaddress_pkix_cert() ->
-ssh_hostkey(rsa) ->
- [{PKdecoded,_}] =
- public_key:ssh_decode(
- <<"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDYXcYmsyJBstl4EfFYzfQJmSiUE162zvSGSoMYybShYOI6rnnyvvihfw8Aml+2gZ716F2tqG48FQ/yPZEGWNPMrCejPpJctaPWhpNdNMJ8KFXSEgr5bY2mEpa19DHmuDeXKzeJJ+X7s3fVdYc4FMk5731KIW6Huf019ZnTxbx0VKG6b1KAJBg3vpNsDxEMwQ4LFMB0JHVklOTzbxmpaeULuIxvl65A+eGeFVeo2Q+YI9UnwY1vSgmc9Azwy8Ie9Z0HpQBN5I7Uc5xnknT8V6xDhgNfXEfzsgsRdDfZLECt1WO/1gP9wkosvAGZWt5oG8pbNQWiQdFq536ck8WQD9WD none@example.org">>,
- public_key),
- PKdecoded.
-
hardcode_rsa_key() ->
#'RSAPrivateKey'{
version = 'two-prime',
diff --git a/lib/sasl/src/systools_make.erl b/lib/sasl/src/systools_make.erl
index c5d4b9bef3..99b796e24a 100644
--- a/lib/sasl/src/systools_make.erl
+++ b/lib/sasl/src/systools_make.erl
@@ -47,7 +47,7 @@
-compile({inline,[{badarg,2}]}).
-ifdef(USE_ESOCK).
--define(ESOCK_SOCKET_MODS, [socket]).
+-define(ESOCK_SOCKET_MODS, [socket, socket_registry]).
-define(ESOCK_NET_MODS, [prim_net]).
-else.
-define(ESOCK_SOCKET_MODS, []).
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
index e376330809..dd1c535d01 100644
--- a/lib/snmp/doc/src/notes.xml
+++ b/lib/snmp/doc/src/notes.xml
@@ -80,6 +80,32 @@
</section>
+ <section><title>SNMP 5.4.3.1</title>
+
+ <section><title>Improvements and New Features</title>
+ <list>
+ <item>
+ <p>
+ Its now possible to remove selected varbinds (from the
+ final message) when sending a notification. This is done
+ by setting the 'value' (in the varbind(s) of the varbinds
+ list) to '?NOTIFICATION_IGNORE_VB_VALUE'.</p>
+ <p>
+ Own Id: OTP-16349 Aux Id: ERIERL-444 </p>
+ </item>
+ <item>
+ <p>
+ Its now possible to specify that an oid shall be
+ "truncated" (trailing ".0" to be removed) when sending an
+ notification.</p>
+ <p>
+ Own Id: OTP-16360 Aux Id: ERIERL-451 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SNMP 5.4.3</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/snmp/doc/src/snmp_agent_netif.xml b/lib/snmp/doc/src/snmp_agent_netif.xml
index a8dea5ab7b..66a1bd900f 100644
--- a/lib/snmp/doc/src/snmp_agent_netif.xml
+++ b/lib/snmp/doc/src/snmp_agent_netif.xml
@@ -36,7 +36,7 @@
<image file="snmp_agent_netif_1.gif">
<icaption>The Purpose of Agent Net if</icaption>
</image>
- <p>The Network Interface (Net if) process delivers SNMP PDUs to a
+ <p>The Network Interface (Net If) process delivers SNMP PDUs to a
master agent, and receives SNMP PDUs from the master agent. The most
common behaviour of a Net if process is that is receives bytes from
a network, decodes them into an SNMP PDU, which it sends to a master
@@ -70,7 +70,7 @@
<marker id="messages"></marker>
<title>Messages</title>
<p>The section <em>Messages</em> describes mandatory messages, which
- Net if must send and be able to receive.
+ Net If must send and be able to receive.
</p>
<p>In this section an <c>Address</c> field is a
<c>{Domain, Addr}</c> tuple where <c>Domain</c> is
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml
index 54a7eafe76..978aff59b1 100644
--- a/lib/snmp/doc/src/snmp_app.xml
+++ b/lib/snmp/doc/src/snmp_app.xml
@@ -4,7 +4,7 @@
<appref>
<header>
<copyright>
- <year>1997</year><year>2019</year>
+ <year>1997</year><year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -594,7 +594,7 @@ in the snmp_config file!
<tag><marker id="manager_server"></marker>
<c><![CDATA[server() = [server_opt()] <optional>]]></c></tag>
<item>
- <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()} | {cbproxy, server_cbproxy()}</c></p>
+ <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()} | {cbproxy, server_cbproxy()} | {netif_sup, server_nis()}</c></p>
<p>Specifies the options for the manager server process.</p>
<p>Default is <c>silence</c>.</p>
</item>
@@ -641,6 +641,36 @@ in the snmp_config file!
<p>Default is <c>temporary</c>.</p>
</item>
+ <tag><marker id="manager_server_nis"></marker>
+ <c><![CDATA[server_nis() = none (default) | {PingTO, PongTO} <optional>]]></c></tag>
+ <item>
+ <p>This option specifies if the server should actively supervise the
+ net-if process.
+ Note that this will only work if the used net-if process actually supports
+ the protocol. See
+ <seealso marker="snmpm_network_interface">snmpm_network_interface</seealso> behaviour for more info. </p>
+ <taglist>
+ <tag><marker id="manager_server_nis_none"></marker>
+ <c><![CDATA[none (default)]]></c></tag>
+ <item>
+ <p>No active supervision of the net-if process. </p>
+ </item>
+
+ <tag><marker id="manager_server_nis_active"></marker>
+ <c><![CDATA[{PingTO :: pos_integer(), PongTO :: pos_integer()}]]></c></tag>
+ <item>
+ <p>The <c>PingTO</c> time specifies the between a successful ping
+ (or start) and the time when a ping message is to be sent to the net-if
+ process (basically the time between ping). </p>
+ <p>The <c>PongTO</c> time specifies how long time the net-if process
+ has to respond to a ping message, with a <em>pong</em> message.
+ Its starts counting when the ping message has been sent.</p>
+ <p>Both times are in milli seconds.</p>
+ </item>
+ </taglist>
+ <p>Default is <c>none</c>.</p>
+ </item>
+
<tag><marker id="manager_config"></marker>
<c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag>
<item>
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
index d615edcec0..79c6703c94 100644
--- a/lib/snmp/doc/src/snmp_config.xml
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>1997</year><year>2016</year>
+ <year>1997</year><year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -612,7 +612,7 @@ in so far as it will be converted to the new format if found.
<tag><marker id="manager_server"></marker>
<c><![CDATA[server() = [server_opt()] <optional>]]></c></tag>
<item>
- <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()} | {cbproxy, server_cbproxy()}</c></p>
+ <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()} | {cbproxy, server_cbproxy()} | {netif_sup, server_nis()}</c></p>
<p>Specifies the options for the manager server process.</p>
<p>Default is <c>silence</c>.</p>
</item>
@@ -659,6 +659,40 @@ in so far as it will be converted to the new format if found.
<p>Default is <c>temporary</c>.</p>
</item>
+ <tag><marker id="manager_server_nis"></marker>
+ <c><![CDATA[server_nis() = none (default) | {PingTO, PongTO} <optional>]]></c></tag>
+ <item>
+ <p>This option specifies if the server should actively supervise the
+ net-if process.
+ Note that this will only work if the used net-if process actually supports
+ the protocol. See
+ <seealso marker="snmpm_network_interface">snmpm_network_interface</seealso> behaviour for more info. </p>
+ <taglist>
+ <tag><marker id="manager_server_nis_none"></marker>
+ <c><![CDATA[none (default)]]></c></tag>
+ <item>
+ <p>No active supervision of the net-if process. </p>
+ </item>
+
+ <tag><marker id="manager_server_nis_active"></marker>
+ <c><![CDATA[{PingTO :: pos_integer(), PongTO :: pos_integer()}]]></c></tag>
+ <item>
+ <p>The <c>PingTO</c> time specifies the between a successful ping
+ (or start) and the time when a
+ <seealso marker="snmp_manager_netif#im_ping">ping</seealso>
+ message is to be sent to the net-if
+ process (basically the time between ping:s). </p>
+ <p>The <c>PongTO</c> time specifies how long time the net-if process
+ has to respond to a ping message, with a
+ <seealso marker="snmp_manager_netif#om_pong">pong</seealso>
+ message.
+ It starts counting when the ping message has been sent.</p>
+ <p>Both times are in milli seconds.</p>
+ </item>
+ </taglist>
+ <p>Default is <c>none</c>.</p>
+ </item>
+
<tag><marker id="manager_config"></marker>
<c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag>
<item>
diff --git a/lib/snmp/doc/src/snmp_manager_netif.xml b/lib/snmp/doc/src/snmp_manager_netif.xml
index 0dfcdbda0d..9825f3f3bd 100644
--- a/lib/snmp/doc/src/snmp_manager_netif.xml
+++ b/lib/snmp/doc/src/snmp_manager_netif.xml
@@ -37,7 +37,7 @@
<icaption>The Purpose of Manager Net if</icaption>
</image>
- <p>The Network Interface (Net if) process delivers SNMP PDUs to the
+ <p>The Network Interface (Net If) process delivers SNMP PDUs to the
manager server, and receives SNMP PDUs from the manager server.
The most common behaviour of a Net if process is that is receives
request PDU from the manager server, encodes the PDU into bytes
@@ -54,131 +54,186 @@
both uses UDP as the transport protocol i.e the transport domains
<c>transportDomainUdpIpv4</c> and/or <c>transportDomainUdpIpv6</c>.
The difference between the two modules is that the latter is
- "multi-threaded", i.e. for each message/request a new process
+ "multi-threaded", i.e. for each message/request a new process
is created that processes the message/request and then exits. </p>
+ <p>There is a <c>server</c> config option,
+ <seealso marker="snmp_config#manager_server_nis">netif_sup</seealso>
+ that enables "active" Net If supervision. This is very simple mechanism.
+ The (supervising) process simply sends a
+ <seealso marker="#im_ping">ping</seealso> message and expects a
+ <seealso marker="#om_pong">pong</seealso> message response
+ (withing a specific time).
+ The interval between each <c>ping/pong</c> exhange is user configurable.
+ As is the time that is allowed for the
+ <seealso marker="#om_pong">pong</seealso>
+ message to arrive.
+ Both the NetIf module(s) provided with the app supports active supervision.
+ If a NetIf module/process is used which do not implement this, then
+ the server cannot be configured with active supervision. </p>
+
<p>It is also possible to write your own Net if process and
this section describes how to do that.</p>
<section>
<marker id="mandatory_functions"></marker>
<title>Mandatory Functions</title>
- <p>A Net if process must implement the SNMP manager
+ <p>A Net If process must implement the SNMP manager
<seealso marker="snmpm_network_interface">network interface behaviour</seealso>. </p>
</section>
<section>
<title>Messages</title>
- <p>The section <em>Messages</em> describes mandatory messages, which
- Net if must send to the manager server process.
- </p>
+ <p>The section <em>Messages</em> describes mandatory (with exception
+ for the ping/pong messages) messages,
+ which Net If must send to the manager server process. </p>
<p>In this section a <c>Domain</c> field is the transport domain i.e
one of <c>transportDomainUdpIpv4</c> or <c>transportDomainUdpIpv6</c>,
and an <c>Addr</c> field is an
<c>{</c><seealso marker="kernel:inet#type-ip_address"><c>IpAddr</c></seealso><c>,IpPort}</c> tuple.</p>
- <p>Net if must send the following message when it receives an
- SNMP PDU from the network that is aimed for the MasterAgent:
- </p>
- <pre>
+ <section>
+ <marker id="outgoing_messages"></marker>
+ <title>Outgoing Messages</title>
+
+ <p>Net if must send the following message when it receives an
+ SNMP PDU from the network that is aimed for the MasterAgent: </p>
+ <pre>
Server ! {snmp_pdu, Pdu, Domain, Addr}
- </pre>
- <list type="bulleted">
- <item>
- <p><c>Pdu</c> is an SNMP PDU record, as defined in
- <c>snmp_types.hrl</c>, with the SNMP request.</p>
- </item>
- <item>
- <p><c>Domain</c> is the source transport domain. </p>
- </item>
- <item>
- <p><c>Addr</c> is the source address. </p>
- </item>
- </list>
- <pre>
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Pdu</c> is an SNMP PDU record, as defined in
+ <c>snmp_types.hrl</c>, with the SNMP request.</p>
+ </item>
+ <item>
+ <p><c>Domain</c> is the source transport domain. </p>
+ </item>
+ <item>
+ <p><c>Addr</c> is the source address. </p>
+ </item>
+ </list>
+
+ <pre>
Server ! {snmp_trap, Trap, Domain, Addr}
- </pre>
- <list type="bulleted">
- <item>
- <p><c>Trap</c> is either an SNMP pdu record or an trappdu record,
- as defined in <c>snmp_types.hrl</c>, with the SNMP request.</p>
- </item>
- <item>
- <p><c>Domain</c> is the source transport domain. </p>
- </item>
- <item>
- <p><c>Addr</c> is the source address. </p>
- </item>
- </list>
- <pre>
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Trap</c> is either an SNMP pdu record or an trappdu record,
+ as defined in <c>snmp_types.hrl</c>, with the SNMP request.</p>
+ </item>
+ <item>
+ <p><c>Domain</c> is the source transport domain. </p>
+ </item>
+ <item>
+ <p><c>Addr</c> is the source address. </p>
+ </item>
+ </list>
+
+ <pre>
Server ! {snmp_inform, Ref, Pdu, PduMS, Domain, Addr}
- </pre>
- <list type="bulleted">
- <item>
- <p><c>Ref</c> is either the atom <c>ignore</c> or something
- that can be used to identify the inform-request (e.g. request-id).
- <c>ignore</c> is used if the response (acknowledgment) to the
- inform-request has already been sent (this means that the server
- will not make the call to the
- <seealso marker="snmpm_network_interface#inform_response">inform_response</seealso>
- function). See the
- <seealso marker="snmp_config#manager_irb">inform request behaviour</seealso>
- configuration option for more info.</p>
- </item>
- <item>
- <p><c>Pdu</c> is an SNMP PDU record, as defined in
- <c>snmp_types.hrl</c>, with the SNMP request.</p>
- </item>
- <item>
- <p><c>Domain</c> is the source transport domain. </p>
- </item>
- <item>
- <p><c>Addr</c> is the source address. </p>
- </item>
- </list>
- <pre>
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Ref</c> is either the atom <c>ignore</c> or something
+ that can be used to identify the inform-request (e.g. request-id).
+ <c>ignore</c> is used if the response (acknowledgment) to the
+ inform-request has already been sent (this means that the server
+ will not make the call to the
+ <seealso marker="snmpm_network_interface#inform_response">inform_response</seealso>
+ function). See the
+ <seealso marker="snmp_config#manager_irb">inform request behaviour</seealso>
+ configuration option for more info.</p>
+ </item>
+ <item>
+ <p><c>Pdu</c> is an SNMP PDU record, as defined in
+ <c>snmp_types.hrl</c>, with the SNMP request.</p>
+ </item>
+ <item>
+ <p><c>Domain</c> is the source transport domain. </p>
+ </item>
+ <item>
+ <p><c>Addr</c> is the source address. </p>
+ </item>
+ </list>
+
+ <pre>
Server ! {snmp_report, Data, Domain, Addr}
- </pre>
- <list type="bulleted">
- <item>
- <p><c>Data</c> is either <c>{ok, Pdu}</c> or
- <c>{error, ReqId, ReasonInfo, Pdu}</c>. Which one is used depends
- on the return value from the MPD
- <seealso marker="snmpm_mpd#process_msg">process_msg</seealso> function. If the MsgData is <c>ok</c>,
- the first is used, and if it is <c>{error, ReqId, Reason}</c>
- the latter is used.</p>
- </item>
- <item>
- <p><c>Pdu</c> is an SNMP PDU record, as defined in
- <c>snmp_types.hrl</c>, with the SNMP request.</p>
- </item>
- <item>
- <p><c>ReqId</c> is an integer.</p>
- </item>
- <item>
- <p><c>ReasonInfo</c> is a term().</p>
- </item>
- <item>
- <p><c>Domain</c> is the source transport domain. </p>
- </item>
- <item>
- <p><c>Addr</c> is the source address. </p>
- </item>
- </list>
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Data</c> is either <c>{ok, Pdu}</c> or
+ <c>{error, ReqId, ReasonInfo, Pdu}</c>. Which one is used depends
+ on the return value from the MPD
+ <seealso marker="snmpm_mpd#process_msg">process_msg</seealso> function. If the MsgData is <c>ok</c>,
+ the first is used, and if it is <c>{error, ReqId, Reason}</c>
+ the latter is used.</p>
+ </item>
+ <item>
+ <p><c>Pdu</c> is an SNMP PDU record, as defined in
+ <c>snmp_types.hrl</c>, with the SNMP request.</p>
+ </item>
+ <item>
+ <p><c>ReqId</c> is an integer.</p>
+ </item>
+ <item>
+ <p><c>ReasonInfo</c> is a term().</p>
+ </item>
+ <item>
+ <p><c>Domain</c> is the source transport domain. </p>
+ </item>
+ <item>
+ <p><c>Addr</c> is the source address. </p>
+ </item>
+ </list>
+
+ <marker id="om_pong"></marker>
+ <pre>
+Supervisor ! {pong, self()}
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Supervisor</c> is the process that sent the
+ <seealso marker="#im_ping">ping</seealso> message (see below). </p>
+ </item>
+ </list>
+ </section>
<section>
- <title>Notes</title>
- <p>Since the Net if process is responsible for encoding and
- decoding of SNMP messages, it must also update the relevant
- counters in the SNMP group in MIB-II. It can use the functions
- in the module <c>snmpm_mpd</c> for this purpose (refer to the
- Reference Manual, section <c>snmp</c>, module <c>snmpm_mpd</c>
- for more details).
- </p>
- <p>There are also some useful functions for encoding and
- decoding of SNMP messages in the module <c>snmp_pdus</c>.
- </p>
+ <marker id="incoming_messages"></marker>
+ <title>Incoming Messages</title>
+ <p>This section describes the incoming messages which a Net If
+ process may choose to respond to. </p>
+
+ <list type="bulleted">
+ <item>
+ <marker id="im_ping"></marker>
+ <p><c>{ping, Supervisor}</c></p>
+ <p>This message is sent to the Net If process by a process that
+ has been configured to perfor "active supervision" of the Net If
+ process. The Net If process should respond immediately with
+ a <seealso marker="#om_pong">pong</seealso> message. </p>
+ <list type="bulleted">
+ <item>
+ <p><c>Supervisor</c> is a <c>pid()</c>. </p>
+ </item>
+ </list>
+ </item>
+ </list>
</section>
</section>
+
+ <section>
+ <title>Notes</title>
+ <p>Since the Net if process is responsible for encoding and
+ decoding of SNMP messages, it must also update the relevant
+ counters in the SNMP group in MIB-II. It can use the functions
+ in the module <c>snmpm_mpd</c> for this purpose (refer to the
+ Reference Manual, section <c>snmp</c>, module <c>snmpm_mpd</c>
+ for more details). </p>
+
+ <p>There are also some useful functions for encoding and
+ decoding of SNMP messages in the module <c>snmp_pdus</c>. </p>
+ </section>
</chapter>
diff --git a/lib/snmp/doc/src/snmp_pdus.xml b/lib/snmp/doc/src/snmp_pdus.xml
index f403b6edf4..4b00dcb7f0 100644
--- a/lib/snmp/doc/src/snmp_pdus.xml
+++ b/lib/snmp/doc/src/snmp_pdus.xml
@@ -125,22 +125,7 @@
<p>Decodes a list of bytes into an SNMP UsmSecurityParameters</p>
</desc>
</func>
- <func>
- <name since="">enc_encrypted_scoped_pdu(EncryptedScopedPdu) -> [byte()]</name>
- <fsummary>Encode an encrypted SNMP scopedPDU</fsummary>
- <type>
- <v>EncryptedScopedPdu = [byte()]</v>
- </type>
- <desc>
- <p>Encodes an encrypted SNMP ScopedPdu into an OCTET STRING
- that can be used as the <c>data</c> field in a
- <c>message</c> record, that later can be encoded with a call
- to <c>enc_message_only/1</c>.
- </p>
- <p>This function should be used whenever the <c>ScopedPDU</c>
- is encrypted.</p>
- </desc>
- </func>
+
<func>
<name since="">enc_message(Message) -> [byte()]</name>
<fsummary>Encode an SNMP Message</fsummary>
diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml
index c45df98ee0..71308dcf80 100644
--- a/lib/snmp/doc/src/snmpm.xml
+++ b/lib/snmp/doc/src/snmpm.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2018</year>
+ <year>2004</year><year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -1487,6 +1487,21 @@ priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb1
verbosity <c>silence</c>, nothing is printed. The higher the
verbosity, the more is printed.</p>
+ <marker id="restart"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name since="">restart(Ref) -> void()</name>
+ <fsummary>Restart the indicated process</fsummary>
+ <type>
+ <v>Ref = net_if</v>
+ </type>
+ <desc>
+ <p>Restart the indicated process (<c>Ref</c>). Note that its not
+ without risk to restart a process, and should therefor be used
+ with care. </p>
+
<marker id="format_reason"></marker>
</desc>
</func>
diff --git a/lib/snmp/doc/src/snmpm_mpd.xml b/lib/snmp/doc/src/snmpm_mpd.xml
index b024f8d294..721e579470 100644
--- a/lib/snmp/doc/src/snmpm_mpd.xml
+++ b/lib/snmp/doc/src/snmpm_mpd.xml
@@ -48,7 +48,7 @@
<funcs>
<func>
- <name since="">init_mpd(Vsns) -> mpd_state()</name>
+ <name since="">init(Vsns) -> mpd_state()</name>
<fsummary>Initialize the MPD module</fsummary>
<type>
<v>Vsns = [Vsn]</v>
diff --git a/lib/snmp/doc/src/snmpm_user.xml b/lib/snmp/doc/src/snmpm_user.xml
index c961300490..fe0ac0b0d2 100644
--- a/lib/snmp/doc/src/snmpm_user.xml
+++ b/lib/snmp/doc/src/snmpm_user.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2004</year><year>2016</year>
+ <year>2004</year><year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -96,7 +96,7 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
<name since="">handle_error(ReqId, Reason, UserData) -> void()</name>
<fsummary>Handle error</fsummary>
<type>
- <v>ReqId = integer()</v>
+ <v>ReqId = netif | integer()</v>
<v>Reason = {unexpected_pdu, SnmpInfo} | {invalid_sec_info, SecInfo, SnmpInfo} | {empty_message, Addr, Port} | term()</v>
<v>SnmpInfo = snmp_gen_info()</v>
<v>SecInfo = term()</v>
@@ -115,7 +115,11 @@ snmp_v1_trap_info() :: {Enteprise :: snmp:oid(),
<p>If <c>ReqId</c> is less then 0, it means that this
information was not available to the manager (that info was
never retrieved before the message was discarded). </p>
- <p>For <c>SnmpInfo</c> see handle_agent below.</p>
+ <p>For <c>SnmpInfo</c> see handle_agent below.</p>
+ <p>Note that there is a special case when the value of <c>ReqId</c>
+ has the value of the atom <c>netif</c>. This means that the NetIF
+ process has suffered a "fatal" error and been restarted.
+ With possible loss of traffic! </p>
<marker id="handle_agent"></marker>
</desc>
diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
index 8e60cecaf9..c0859f6fd8 100644
--- a/lib/snmp/src/manager/snmpm.erl
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -89,8 +89,9 @@
system_start_time/0,
sys_up_time/0,
- info/0,
- verbosity/2
+ info/0, info/1,
+ verbosity/2,
+ restart/1
]).
-export([format_reason/1, format_reason/2]).
@@ -297,6 +298,9 @@ oid_to_type(Oid) ->
info() ->
snmpm_server:info().
+info(Key) ->
+ proplists:get_value(Key, info(), {error, not_found}).
+
%% -- Verbosity --
@@ -316,6 +320,16 @@ verbosity(all, V) ->
snmpm_server:verbosity(note_store, V).
+%% -- Restart --
+
+%% Restart various component processes in the manager
+%% Note that the effects of this is diffiult to
+%% predict, so it should be use with *caution*!
+
+restart(net_if = What) ->
+ snmpm_server:restart(What).
+
+
%% -- Users --
%% Register the 'user'.
diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl
index fc6ddc5738..decda09022 100644
--- a/lib/snmp/src/manager/snmpm_config.erl
+++ b/lib/snmp/src/manager/snmpm_config.erl
@@ -151,6 +151,7 @@
-define(SERVER_OPT_GCT_DEFAULT, 30000).
-define(SERVER_OPT_MT_DEFAULT, true).
-define(SERVER_OPT_CBP_DEFAULT, temporary). % permanent
+-define(SERVER_OPT_NIS_DEFAULT, none).
%% -define(DEF_ADDR_TAG, default_addr_tag).
-define(DEFAULT_TARGETNAME, default_agent).
@@ -1115,15 +1116,17 @@ do_init(Opts) ->
end,
%% -- Server (optional) --
- ServerOpts = get_opt(server, Opts, []),
+ ServerOpts = get_opt(server, Opts, []),
ServerVerb = get_opt(verbosity, ServerOpts, ?SERVER_OPT_VERB_DEFAULT),
ServerGct = get_opt(timeout, ServerOpts, ?SERVER_OPT_GCT_DEFAULT),
ServerMt = get_opt(multi_threaded, ServerOpts, ?SERVER_OPT_MT_DEFAULT),
ServerCBP = get_opt(cbproxy, ServerOpts, ?SERVER_OPT_CBP_DEFAULT),
+ ServerNIS = get_opt(netif_sup, ServerOpts, ?SERVER_OPT_NIS_DEFAULT),
ets:insert(snmpm_config_table, {server_verbosity, ServerVerb}),
ets:insert(snmpm_config_table, {server_timeout, ServerGct}),
ets:insert(snmpm_config_table, {server_multi_threaded, ServerMt}),
ets:insert(snmpm_config_table, {server_cbproxy, ServerCBP}),
+ ets:insert(snmpm_config_table, {server_nis, ServerNIS}),
%% -- Mibs (optional) --
?vdebug("initiate mini mib", []),
@@ -1132,7 +1135,7 @@ do_init(Opts) ->
init_mini_mib(Mibs),
%% -- Net-if (optional) --
- ?vdebug("net_if options", []),
+ ?vdebug("net-if options", []),
NetIfIrb =
case get_opt(inform_request_behaviour, Opts, ?IRB_DEFAULT) of
user ->
@@ -1421,6 +1424,9 @@ verify_server_opts([{multi_threaded, MT}|Opts]) when is_boolean(MT) ->
verify_server_opts([{cbproxy, CBP}|Opts]) ->
verify_server_cbproxy(CBP),
verify_server_opts(Opts);
+verify_server_opts([{netif_sup, NIS}|Opts]) ->
+ verify_server_nis(NIS),
+ verify_server_opts(Opts);
verify_server_opts([Opt|_]) ->
error({invalid_server_option, Opt}).
@@ -1436,6 +1442,17 @@ verify_server_cbproxy(permanent) ->
verify_server_cbproxy(CBP) ->
error({invalid_server_cbproxy, CBP}).
+verify_server_nis(none) ->
+ ok;
+verify_server_nis({PingTo, PongTo} = V) when is_integer(PingTo) andalso
+ (PingTo > 0) andalso
+ is_integer(PongTo) andalso
+ (PongTo > 0) ->
+ ok;
+verify_server_nis(NIS) ->
+ error({invalid_server_netif_sup, NIS}).
+
+
verify_net_if_opts([]) ->
ok;
verify_net_if_opts([{module, Mod}|Opts]) ->
diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl
index c2e5c6d2f0..0d57bc944a 100644
--- a/lib/snmp/src/manager/snmpm_net_if.erl
+++ b/lib/snmp/src/manager/snmpm_net_if.erl
@@ -58,6 +58,14 @@
%% -define(VMODULE,"NET_IF").
-include("snmp_verbosity.hrl").
+%% This is for debugging!!
+-ifdef(snmp_debug).
+-define(allow_exec, true).
+-else.
+-define(allow_exec, false).
+-endif.
+
+
-record(state,
{
server,
@@ -67,7 +75,8 @@
log,
irb = auto, % auto | {user, integer()}
irgc,
- filter
+ filter,
+ allow_exec = ?allow_exec
}).
-record(transport,
@@ -92,6 +101,7 @@
-define(ATL_SEQNO_MAX, 2147483647).
+
%%%-------------------------------------------------------------------
%%% API
%%%-------------------------------------------------------------------
@@ -520,6 +530,13 @@ handle_call(info, _From, State) ->
Reply = get_info(State),
{reply, Reply, State};
+%% This is for debugging!!
+handle_call({exec, F}, _From, #state{allow_exec = true} = State)
+ when is_function(F, 0) ->
+ ?vlog("[call] exec", []),
+ {reply, F(), State};
+
+
handle_call(Req, From, State) ->
warning_msg("received unknown request (from ~p): ~n~p", [Req, From]),
{reply, {error, {invalid_request, Req}}, State}.
@@ -556,6 +573,13 @@ handle_cast(filter_reset, State) ->
reset_counters(),
{noreply, State};
+%% This is for debugging!!
+handle_cast({exec, F}, #state{allow_exec = true} = State) when is_function(F, 0) ->
+ ?vlog("[cast] exec", []),
+ F(),
+ {noreply, State};
+
+
handle_cast(Msg, State) ->
warning_msg("received unknown message: ~n~p", [Msg]),
{noreply, State}.
@@ -597,6 +621,20 @@ handle_info({disk_log, _Node, Log, Info}, State) ->
handle_info({'DOWN', _, _, _, _} = Info, State) ->
handle_info_down(Info, State);
+
+handle_info({ping, Pid}, State) ->
+ ?vdebug("received ping message from ~p", [Pid]),
+ Pid ! {pong, self()},
+ {noreply, State};
+
+
+%% This is for debugging!!
+handle_info({exec, F}, #state{allow_exec = true} = State) when is_function(F, 0) ->
+ ?vlog("[info] exec", []),
+ F(),
+ {noreply, State};
+
+
handle_info(Info, State) ->
handle_info_unknown(Info, State).
diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl
index fe2c22d9ba..1a8d09ab9b 100644
--- a/lib/snmp/src/manager/snmpm_server.erl
+++ b/lib/snmp/src/manager/snmpm_server.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -45,13 +45,13 @@
%% discovery/2, discovery/3, discovery/4, discovery/5, discovery/6,
- %% system_info_updated/2,
get_log_type/0, set_log_type/1,
reconfigure/0,
info/0,
- verbosity/1, verbosity/2
+ verbosity/1, verbosity/2,
+ restart/1
]).
@@ -77,6 +77,9 @@
%% GCT exports
-export([gct_init/1, gct/2]).
+%% NIS exports
+-export([nis_init/2, nis_loop/1]).
+
%% CallBack Proxy exports
-export([cbproxy_loop/1,
do_handle_error/4,
@@ -157,6 +160,24 @@
net_if,
net_if_mod,
net_if_ref,
+
+ %% NetIF supervision
+ %% This (config) option defines if/how the "server"
+ %% shall supervise the net-if process.
+ %% And by "supervise" we don't meant in the way a
+ %% *supervisor" supervisor. This is "active" supervision
+ %% (basically, send ping and expect pong back).
+ %% There are two alternatives:
+ %% none - No supervision (default)
+ %% {PingInterval, PongTimeout}
+ %% PingInterval :: pos_integer()
+ %% Time between a successful test and the next.
+ %% PongInterval :: pos_integer()
+ %% Time the NetIF process has to answer a ping
+ %%
+ nis :: none | {pos_integer(), pos_integer()},
+ nis_pid :: undefined | pid(), % Pid of the process doing the actual sup
+
req, %% ???? Last request id in outgoing message
oid, %% ???? Last oid in request outgoing message
mini_mib,
@@ -492,6 +513,9 @@ cancel_async_request(UserId, ReqId) ->
call({cancel_async_request, UserId, ReqId}).
+info() ->
+ call(info).
+
verbosity(Verbosity) ->
case ?vvalidate(Verbosity) of
Verbosity ->
@@ -500,9 +524,6 @@ verbosity(Verbosity) ->
{error, {invalid_verbosity, Verbosity}}
end.
-info() ->
- call(info).
-
verbosity(net_if = Ref, Verbosity) ->
verbosity2(Ref, Verbosity);
verbosity(note_store = Ref, Verbosity) ->
@@ -516,9 +537,10 @@ verbosity2(Ref, Verbosity) ->
{error, {invalid_verbosity, Verbosity}}
end.
-%% Target -> all | server | net_if
-%% system_info_updated(Target, What) ->
-%% call({system_info_updated, Target, What}).
+
+restart(net_if = What) ->
+ cast({restart, What}).
+
get_log_type() ->
call(get_log_type).
@@ -590,6 +612,15 @@ do_init() ->
{NoteStore, NoteStoreRef} = do_init_note_store(Prio),
{NetIf, NetIfModule, NetIfRef} = do_init_net_if(NoteStore),
+ %% -- (maybe) Start the NetIF "supervisor" --
+ {NIS, NISPid} =
+ case snmpm_config:system_info(server_nis) of
+ {ok, none = V} ->
+ {V, undefined};
+ {ok, {PingTO, PongTO} = V} ->
+ {V, nis_start(NetIf, PingTO, PongTO)}
+ end,
+
MiniMIB = snmpm_config:make_mini_mib(),
State = #state{mini_mib = MiniMIB,
gct = GCT,
@@ -598,6 +629,8 @@ do_init() ->
net_if = NetIf,
net_if_mod = NetIfModule,
net_if_ref = NetIfRef,
+ nis = NIS,
+ nis_pid = NISPid,
cbproxy = CBProxy,
cbproxy_pid = CBPPid},
?vlog("started", []),
@@ -624,7 +657,7 @@ do_init_note_store(Prio) ->
end.
do_init_net_if(NoteStore) ->
- ?vdebug("try start net if", []),
+ ?vdebug("try start net-if", []),
{ok, NetIfModule} = snmpm_config:system_info(net_if_module),
case snmpm_misc_sup:start_net_if(NetIfModule, NoteStore) of
{ok, Pid} ->
@@ -638,6 +671,7 @@ do_init_net_if(NoteStore) ->
throw({error, {failed_starting_net_if, Reason}})
end.
+
%% ---------------------------------------------------------------------
%% ---------------------------------------------------------------------
@@ -1017,6 +1051,13 @@ handle_call(Req, _From, State) ->
{reply, {error, unknown_request}, State}.
+handle_cast({restart, net_if},
+ #state{net_if = Pid} = State) ->
+ ?vlog("received net_if (~p) restart message", [Pid]),
+ %% We will get an exit signel/message, which will trigger a (re-)start
+ exit(Pid, kill),
+ {noreply, State};
+
handle_cast(Msg, State) ->
warning_msg("received unknown message: ~n~p", [Msg]),
{noreply, State}.
@@ -1077,19 +1118,18 @@ handle_info(gc_timeout, #state{gct = GCT} = State) ->
{noreply, State};
-handle_info({'DOWN', _MonRef, process, Pid, _Reason},
- #state{note_store = NoteStore,
- net_if = Pid} = State) ->
- ?vlog("received 'DOWN' message regarding net_if", []),
- {NetIf, _, Ref} = do_init_net_if(NoteStore),
- {noreply, State#state{net_if = NetIf, net_if_ref = Ref}};
+handle_info({'DOWN', _MonRef, process, Pid, Reason},
+ #state{net_if = Pid} = State) ->
+ ?vlog("received 'DOWN' message regarding net_if (~p)", [Pid]),
+ NewState = handle_netif_down(State, Reason),
+ {noreply, NewState};
handle_info({'DOWN', _MonRef, process, Pid, _Reason},
#state{note_store = Pid,
net_if = NetIf,
net_if_mod = Mod} = State) ->
- ?vlog("received 'DOWN' message regarding note_store", []),
+ ?vlog("received 'DOWN' message regarding note_store (~p)", [Pid]),
{ok, Prio} = snmpm_config:system_info(prio),
{NoteStore, Ref} = do_init_note_store(Prio),
Mod:note_store(NetIf, NoteStore),
@@ -1118,8 +1158,17 @@ handle_info({'EXIT', Pid, Reason}, #state{cbproxy_pid = Pid} = State) ->
{noreply, State#state{cbproxy_pid = NewCBP}};
+handle_info({'EXIT', Pid, Reason}, #state{net_if = NetIF,
+ nis = {PingTO, PongTO},
+ nis_pid = Pid} = State) ->
+ warning_msg("NetIF (active) supervisor (~w) process crashed: "
+ "~n ~p", [Pid, Reason]),
+ NewNIS = nis_start(NetIF, PingTO, PongTO),
+ {noreply, State#state{nis_pid = NewNIS}};
+
+
handle_info(Info, State) ->
- warning_msg("received unknown info: ~n~p", [Info]),
+ warning_msg("received unknown info: ~n ~p", [Info]),
{noreply, State}.
@@ -1146,8 +1195,9 @@ code_change(_Vsn, #state{gct = Pid} = State0, _Extra) ->
%% Terminate
%%----------------------------------------------------------
-terminate(Reason, #state{gct = GCT, cbproxy = CBP}) ->
+terminate(Reason, #state{nis_pid = NIS, gct = GCT, cbproxy = CBP}) ->
?vdebug("terminate: ~p",[Reason]),
+ nis_stop(NIS),
cbproxy_stop(CBP),
gct_stop(GCT),
snmpm_misc_sup:stop_note_store(),
@@ -3119,7 +3169,17 @@ handle_invalid_result(Func, Args, InvalidResult) ->
"~n Invalid result: ~p",
[Func, Args, InvalidResult]).
-
+
+handle_netif_down(#state{note_store = NoteStore,
+ nis_pid = NIS} = State,
+ Reason) ->
+ %% Srart a new NetIF
+ {NetIF, _, Ref} = do_init_net_if(NoteStore),
+ %% Inform the (active) supervisor
+ nis_netif(NIS, NetIF),
+ netif_down_inform_users(Reason),
+ State#state{net_if = NetIF, net_if_ref = Ref}.
+
handle_down(MonRef) ->
(catch do_handle_down(MonRef)).
@@ -3608,6 +3668,258 @@ new_timeout(T1, T2) ->
%%----------------------------------------------------------------------
+%% NetIF Supervisor
+%%
+%% The NIS process "supervises" the NetIF process. That does *not* mean
+%% that it takes on the role of a standard erlang 'supervisor' process.
+%% The NIS is instead a process that "actively" supervises by means
+%% of "ping" messages, which the supervised process must respond to
+%% (with a pong message) *in time*.
+%% If it does not, NIS assumes that it has hung, and kills it.
+%% The server process then restarts the NetIF process and informs NIS.
+%%----------------------------------------------------------------------
+
+nis_start(NetIF, PingTO, PongTO) ->
+ ?vdebug("start nis process (~w, ~w)", [PingTO, PongTO]),
+ State = #{parent => self(),
+ netif_pid => NetIF,
+ ping_to => PingTO,
+ ping_tref => undefined,
+ ping_start => undefined, % Time when ping sent
+ ping_max => undefined, % Max roundtrip time
+ pong_to => PongTO,
+ pong_tref => undefined,
+ kill_cnt => 0},
+ proc_lib:start_link(?MODULE, nis_init, [State, get(verbosity)]).
+
+nis_stop(NIS) when is_pid(NIS) ->
+ NIS ! {?MODULE, self(), stop};
+nis_stop(_) ->
+ ok.
+
+
+nis_info(NIS) when is_pid(NIS) ->
+ NIS ! {?MODULE, self(), info},
+ receive
+ {?MODULE, NIS, {info, Info}} ->
+ Info
+ after 1000 ->
+ []
+ end;
+nis_info(_) ->
+ [].
+
+
+nis_netif(NIS, NetIF) when is_pid(NIS) andalso is_pid(NetIF) ->
+ NIS ! {?MODULE, self(), {netif, NetIF}};
+nis_netif(_, _) ->
+ ok.
+
+
+nis_init(#{parent := Parent,
+ netif_pid := NetIF,
+ ping_to := PingTO} = State,
+ Verbosity) ->
+ put(verbosity, Verbosity),
+ put(sname, mnis),
+ ?vlog("starting"),
+ MRef = erlang:monitor(process, NetIF),
+ TRef = erlang:start_timer(PingTO, self(), ping_timeout),
+ erlang:register(snmpm_server_nis, self()),
+ proc_lib:init_ack(Parent, self()),
+ ?vlog("started"),
+ nis_loop(State#{netif_mref => MRef,
+ ping_tref => TRef}).
+
+%% The NetIF is dead. Its up to the server to restart it and inform us
+nis_loop(#{parent := Parent,
+ netif_pid := undefined,
+ ping_tref := undefined,
+ pong_tref := undefined} = State) ->
+ receive
+ {?MODULE, Parent, stop} ->
+ ?vlog("[idle] stop received"),
+ nis_handle_stop(State),
+ exit(normal);
+
+ {?MODULE, Pid, info} ->
+ ?vtrace("[idle] info received"),
+ Info = nis_handle_info(State),
+ Pid ! {?MODULE, self(), {info, Info}},
+ ?MODULE:nis_loop(State);
+
+ {?MODULE, Parent, {netif, NetIF}} ->
+ ?vlog("[idle] (new) netif started: ~p => start ping timer", [NetIF]),
+ MRef = erlang:monitor(process, NetIF),
+ PingTO = maps:get(ping_to, State),
+ TRef = erlang:start_timer(PingTO, self(), ping_timeout),
+ ?MODULE:nis_loop(State#{netif_pid => NetIF,
+ netif_mref => MRef,
+ ping_max => undefined,
+ ping_tref => TRef});
+
+ _Any ->
+ ?MODULE:nis_loop(State)
+
+ after 5000 ->
+ %% This is for code upgrade
+ ?MODULE:nis_loop(State)
+ end;
+
+%% PING timer running (waiting for ping-timeout)
+nis_loop(#{parent := Parent,
+ netif_pid := NetIF,
+ netif_mref := MRef,
+ ping_tref := PingTRef,
+ pong_tref := undefined} = State) when is_pid(NetIF) andalso
+ (PingTRef =/= undefined) ->
+ receive
+ {'DOWN', MRef, process, NetIF, _} ->
+ ?vlog("[ping] netif died => cancel ping timer"),
+ erlang:cancel_timer(PingTRef),
+ ?MODULE:nis_loop(State#{netif_pid => undefined,
+ netif_mref => undefined,
+ ping_tref => undefined});
+
+ {?MODULE, Parent, stop} ->
+ ?vlog("[ping] stop received"),
+ nis_handle_stop(State),
+ exit(normal);
+
+ {?MODULE, Pid, info} ->
+ ?vtrace("[ping] info received"),
+ Info = nis_handle_info(State),
+ Pid ! {?MODULE, self(), {info, Info}},
+ ?MODULE:nis_loop(State);
+
+ %% Time to ping NetIF
+ {timeout, PingTRef, ping_timeout} ->
+ ?vlog("[ping] (ping-) timer timeout => send ping and start pong timer"),
+ NetIF ! {ping, self()},
+ PongTO = maps:get(pong_to, State),
+ TRef = erlang:start_timer(PongTO, self(), pong_timeout),
+ ?MODULE:nis_loop(State#{ping_tref => undefined,
+ ping_start => us(),
+ pong_tref => TRef});
+
+ _Any ->
+ ?MODULE:nis_loop(State)
+
+ after 5000 ->
+ %% This is for code upgrade
+ ?MODULE:nis_loop(State)
+ end;
+
+%% PONG timer running (waiting for pong message)
+nis_loop(#{parent := Parent,
+ netif_pid := NetIF,
+ netif_mref := MRef,
+ ping_tref := undefined,
+ pong_tref := PongTRef} = State) when is_pid(NetIF) andalso
+ (PongTRef =/= undefined) ->
+ receive
+ {'DOWN', MRef, process, NetIF, _} ->
+ ?vlog("[pong] netif died => cancel pong timer"),
+ erlang:cancel_timer(PongTRef),
+ ?MODULE:nis_loop(State#{netif_pid => undefined,
+ netif_mref => undefined,
+ pong_tref => undefined});
+
+ {?MODULE, Parent, stop} ->
+ ?vlog("[pong] stop received"),
+ nis_handle_stop(State),
+ exit(normal);
+
+ {?MODULE, Pid, info} ->
+ ?vlog("[pong] info received"),
+ Info = nis_handle_info(State),
+ Pid ! {?MODULE, self(), {info, Info}},
+ ?MODULE:nis_loop(State);
+
+ {pong, NetIF} ->
+ ?vlog("[pong] received pong => cancel pong timer, start ping timer"),
+ T = us(),
+ erlang:cancel_timer(PongTRef),
+ Start = maps:get(ping_start, State),
+ Max = maps:get(ping_max, State),
+ RT = T - Start,
+ NewMax =
+ if
+ (Max =:= undefined) ->
+ ?vtrace("[pong] Max: ~w", [RT]),
+ RT;
+ (RT > Max) ->
+ ?vtrace("[pong] New Max: ~w", [RT]),
+ RT;
+ true ->
+ Max
+ end,
+ PingTO = maps:get(ping_to, State),
+ PingTRef = erlang:start_timer(PingTO, self(), ping_timeout),
+ ?MODULE:nis_loop(State#{ping_tref => PingTRef,
+ ping_start => undefined,
+ ping_max => NewMax,
+ pong_tref => undefined});
+
+ %% Time to kill NetIF
+ {timeout, PongTRef, pong_timeout} ->
+ ?vinfo("[pong] (pong-) timer timeout => kill NetIF (~p)", [NetIF]),
+ nis_handle_pong_timeout(NetIF, MRef),
+ KCnt = maps:get(kill_cnt, State),
+ ?MODULE:nis_loop(State#{netif_pid => undefined,
+ netif_mref => undefined,
+ pong_tref => undefined,
+ kill_cnt => KCnt + 1});
+
+ _Any ->
+ ?MODULE:nis_loop(State)
+
+ after 5000 ->
+ %% This is for code upgrade
+ ?MODULE:nis_loop(State)
+ end.
+
+
+nis_handle_info(#{ping_max := undefined, kill_cnt := KCnt}) ->
+ [{kcnt, KCnt}];
+nis_handle_info(#{ping_max := Max, kill_cnt := KCnt}) ->
+ [{max, Max}, {kcnt, KCnt}].
+
+
+nis_handle_stop(#{pong_tref := PongTRef,
+ ping_tref := PingTRef}) ->
+ cancel_timer(PongTRef),
+ cancel_timer(PingTRef).
+
+%% Inform all users that the netif process has been killed
+nis_handle_pong_timeout(NetIF, MRef) ->
+ erlang:demonitor(MRef, [flush]),
+ exit(NetIF, kill),
+ netif_down_inform_users({pong, killed}),
+ ok.
+
+
+%%----------------------------------------------------------------------
+
+%% Inform all users that "something" fatal happened to the NetIF process.
+netif_down_inform_users(Reason) ->
+ InformUser = fun(UserId) ->
+ spawn(fun() ->
+ case snmpm_config:user_info(UserId) of
+ {ok, UserMod, UserData} ->
+ UserMod:handle_error(netif,
+ Reason,
+ UserData);
+ {error, _} ->
+ ok
+ end,
+ exit(normal)
+ end)
+ end,
+ lists:foreach(InformUser, snmpm_config:which_users()).
+
+
+%%----------------------------------------------------------------------
maybe_delete(false, ReqId) ->
ets:delete(snmpm_request_table, ReqId);
@@ -3651,6 +3963,9 @@ is_started(#state{net_if = _Pid, net_if_mod = _Mod}) ->
%%----------------------------------------------------------------------
+cast(Req) ->
+ gen_server:cast(?SERVER, Req).
+
call(Req) ->
call(Req, infinity).
@@ -3672,15 +3987,16 @@ get_info(#state{gct = GCT,
net_if = NI,
net_if_mod = NIMod,
note_store = NS,
+ nis_pid = NIS,
cbproxy = CBP}) ->
- Info = [{server, server_info(GCT, CBP)},
+ Info = [{server, server_info(GCT, CBP, NIS)},
{config, config_info()},
{net_if, net_if_info(NI, NIMod)},
{note_store, note_store_info(NS)},
{stats_counters, get_stats_counters()}],
Info.
-server_info(GCT, CBP) ->
+server_info(GCT, CBP, NIS) ->
{CBPInfo, CBPSz} =
if
(CBP =:= permanent) ->
@@ -3689,12 +4005,20 @@ server_info(GCT, CBP) ->
true ->
{[], []}
end,
+ {NISInfo, NISSz} =
+ case NIS of
+ undefined ->
+ {[], []};
+ _ ->
+ {[{nis, nis_info(NIS)}],
+ [{nis, proc_mem(NIS)}]}
+ end,
ProcSize = proc_mem(self()),
GCTSz = proc_mem(GCT),
RTSz = tab_size(snmpm_request_table),
MTSz = tab_size(snmpm_monitor_table),
- [{process_memory, [{server, ProcSize}, {gct, GCTSz}] ++ CBPSz},
- {db_memory, [{request, RTSz}, {monitor, MTSz}]}] ++ CBPInfo.
+ [{process_memory, [{server, ProcSize}, {gct, GCTSz}] ++ CBPSz ++ NISSz},
+ {db_memory, [{request, RTSz}, {monitor, MTSz}]}] ++ CBPInfo ++ NISInfo.
proc_mem(P) when is_pid(P) ->
case (catch erlang:process_info(P, memory)) of
@@ -3744,3 +4068,6 @@ note_store_info(Pid) ->
%%----------------------------------------------------------------------
+
+us() ->
+ erlang:monotonic_time(micro_seconds).
diff --git a/lib/snmp/src/manager/snmpm_user.erl b/lib/snmp/src/manager/snmpm_user.erl
index c0100d372f..9d0077449a 100644
--- a/lib/snmp/src/manager/snmpm_user.erl
+++ b/lib/snmp/src/manager/snmpm_user.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2016. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -41,7 +41,7 @@
%% An "asynchronous" error has been detected
-callback handle_error(
- ReqId :: integer(),
+ ReqId :: netif | integer(),
Reason :: {unexpected_pdu, SnmpInfo :: snmp_gen_info()} |
{invalid_sec_info,
SecInfo :: term(),
diff --git a/lib/snmp/src/misc/snmp_verbosity.erl b/lib/snmp/src/misc/snmp_verbosity.erl
index 9b2676d048..a42a1acb3a 100644
--- a/lib/snmp/src/misc/snmp_verbosity.erl
+++ b/lib/snmp/src/misc/snmp_verbosity.erl
@@ -138,6 +138,7 @@ image_of_sname(mns) -> "M-NOTE-STORE";
image_of_sname(mnif) -> "M-NET-IF";
image_of_sname(mnifl) -> "M-NET-IF-LOGGER";
image_of_sname(mnifw) -> io_lib:format("M-NET-IF-worker(~p)", [self()]);
+image_of_sname(mnis) -> "M-NIS";
image_of_sname(mconf) -> "M-CONF";
image_of_sname(lc) -> io_lib:format("LOG-CONVERTER(~p)", [self()]);
diff --git a/lib/snmp/src/misc/snmp_verbosity.hrl b/lib/snmp/src/misc/snmp_verbosity.hrl
index c79f4c3e88..6aef28a854 100644
--- a/lib/snmp/src/misc/snmp_verbosity.hrl
+++ b/lib/snmp/src/misc/snmp_verbosity.hrl
@@ -24,39 +24,59 @@
-ifdef(VMODULE).
+-define(vinfo(F), ?vinfo(F, [])).
-define(vinfo(F,A), snmp_verbosity:print(get(verbosity),info, ?VMODULE,F,A)).
+-define(vlog(F), ?vlog(F, [])).
-define(vlog(F,A), snmp_verbosity:print(get(verbosity),log, ?VMODULE,F,A)).
+-define(vdebug(F), ?vdebug(F, [])).
-define(vdebug(F,A),snmp_verbosity:print(get(verbosity),debug,?VMODULE,F,A)).
+-define(vtrace(F), ?vtrace(F, [])).
-define(vtrace(F,A),snmp_verbosity:print(get(verbosity),trace,?VMODULE,F,A)).
-else.
+-define(vinfo(F), ?vinfo(F, [])).
-define(vinfo(F,A), snmp_verbosity:print(get(verbosity),info, F,A)).
+-define(vlog(F), ?vlog(F, [])).
-define(vlog(F,A), snmp_verbosity:print(get(verbosity),log, F,A)).
+-define(vdebug(F), ?vdebug(F, [])).
-define(vdebug(F,A),snmp_verbosity:print(get(verbosity),debug,F,A)).
+-define(vtrace(F), ?vtrace(F, [])).
-define(vtrace(F,A),snmp_verbosity:print(get(verbosity),trace,F,A)).
-endif.
-define(vvalidate(V), snmp_verbosity:validate(V)).
+-define(vinfoc(F), ?vinfoc(F, [])).
-define(vinfoc(F,A), snmp_verbosity:printc(get(verbosity),info, F,A)).
+-define(vlogc(F), ?vlogc(F, [])).
-define(vlogc(F,A), snmp_verbosity:printc(get(verbosity),log, F,A)).
+-define(vdebugc(F), ?vdebug(F, [])).
-define(vdebugc(F,A),snmp_verbosity:printc(get(verbosity),debug,F,A)).
+-define(vtracec(F), ?vtracec(F, [])).
-define(vtracec(F,A),snmp_verbosity:printc(get(verbosity),trace,F,A)).
-else.
-define(vvalidate(V),ok).
--define(vinfo(F,A),ok).
--define(vlog(F,A),ok).
--define(vdebug(F,A),ok).
--define(vtrace(F,A),ok).
-
--define(vinfoc(F,A),ok).
--define(vlogc(F,A),ok).
+-define(vinfo(F), ok).
+-define(vinfo(F,A), ok).
+-define(vlog(F), ok).
+-define(vlog(F,A), ok).
+-define(vdebug(F), ok).
+-define(vdebug(F,A), ok).
+-define(vtrace(F), ok).
+-define(vtrace(F,A), ok).
+
+-define(vinfoc(F), ok).
+-define(vinfoc(F,A), ok).
+-define(vlogc(F), ok).
+-define(vlogc(F,A), ok).
+-define(vdebugc(F), ok).
-define(vdebugc(F,A),ok).
+-define(vtracec(F), ok).
-define(vtracec(F,A),ok).
-endif.
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
index a9a88ccbfa..0e24506c5d 100644
--- a/lib/snmp/test/Makefile
+++ b/lib/snmp/test/Makefile
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2016. All Rights Reserved.
+# Copyright Ericsson AB 1997-2020. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -89,14 +89,8 @@ ifeq ($(SNMP_DEBUG),)
# SNMP_DEBUG = d
endif
-ifeq ($(SNMP_DEBUG),e)
- SNMP_FLAGS += -Dsnmp_error
-endif
-ifeq ($(SNMP_DEBUG),l)
- SNMP_FLAGS += -Dsnmp_error -Dsnmp_log
-endif
ifeq ($(SNMP_DEBUG),d)
- SNMP_FLAGS += -Dsnmp_error -Dsnmp_log -Dsnmp_debug
+ SNMP_FLAGS += -Dsnmp_debug
endif
ifeq ($(DONT_USE_TS),true)
@@ -175,7 +169,7 @@ emakebuild: $(EMAKEFILE)
targets: mib $(EMAKEFILE)
erl -make
-old_targets: mib $(TARGET_FILES) $(TEST_SERVER_TARGETS)
+old_targets: mib $(TARGET_FILES)
$(EMAKEFILE): Makefile
$(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' > $(EMAKEFILE)
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
index a1554815d9..ba0aea21dd 100644
--- a/lib/snmp/test/modules.mk
+++ b/lib/snmp/test/modules.mk
@@ -2,7 +2,7 @@
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2004-2019. All Rights Reserved.
+# Copyright Ericsson AB 2004-2020. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -35,14 +35,14 @@ SUITE_MODULES = \
snmp_to_snmpnet_SUITE
TEST_UTIL_MODULES = \
- snmp_agent_test_get \
+ snmp_test_lib \
snmp_agent_test_lib \
+ snmp_agent_test_get \
snmp_manager_user \
snmp_manager_user_old \
snmp_manager_user_test_lib \
snmp_test_global_sys_monitor \
snmp_test_sys_monitor \
- snmp_test_lib \
snmp_test_manager \
snmp_test_mgr \
snmp_test_mgr_misc \
@@ -52,10 +52,6 @@ TEST_UTIL_MODULES = \
test1 \
test2
-TEST_SERVER_MODULES = \
- snmp_test_server \
- snmp_test_suite
-
MODULES = \
$(TEST_UTIL_MODULES) \
$(SUITE_MODULES)
diff --git a/lib/snmp/test/snmp_agent_SUITE.erl b/lib/snmp/test/snmp_agent_SUITE.erl
index 6159aa9dda..2a6cfbedbe 100644
--- a/lib/snmp/test/snmp_agent_SUITE.erl
+++ b/lib/snmp/test/snmp_agent_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -481,22 +481,22 @@
-define(expect1(What),
- snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ ?ALIB:expect(?MODULE, ?LINE,
What)).
-define(expect2(What, ExpVBs),
- snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ ?ALIB:expect(?MODULE, ?LINE,
What, ExpVBs)).
-define(expect3(Err, Idx, ExpVBs),
- snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ ?ALIB:expect(?MODULE, ?LINE,
Err, Idx, ExpVBs)).
-define(expect4(Err, Idx, ExpVBs, To),
- snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ ?ALIB:expect(?MODULE, ?LINE,
Err, Idx, ExpVBs, To)).
-define(expect5(Type, Ent, Gen, Spec, ExpVBs),
- snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ ?ALIB:expect(?MODULE, ?LINE,
Type, Ent, Gen, Spec, ExpVBs)).
-define(expect6(Type, Ent, Gen, Spec, ExpVBs, To),
- snmp_agent_test_lib:expect(?MODULE, ?LINE,
+ ?ALIB:expect(?MODULE, ?LINE,
Type, Ent, Gen, Spec, ExpVBs, To)).
@@ -578,9 +578,9 @@ all_cases() ->
init_per_suite(Config0) when is_list(Config0) ->
- p("init_per_suite -> entry with"
- "~n Config: ~p"
- "~n Nodes: ~p", [Config0, erlang:nodes()]),
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config0, erlang:nodes()]),
case ?LIB:init_per_suite(Config0) of
{skip, _} = SKIP ->
@@ -601,33 +601,34 @@ init_per_suite(Config0) when is_list(Config0) ->
snmp_test_mgr_counter_server:start(),
- p("init_per_suite -> end when"
- "~n Config: ~p"
- "~n Nodes: ~p", [Config4, erlang:nodes()]),
+ ?IPRINT("init_per_suite -> end when"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config4, erlang:nodes()]),
Config4
end.
end_per_suite(Config0) when is_list(Config0) ->
- p("end_per_suite -> entry with"
- "~n Config0: ~p"
- "~n Nodes: ~p", [Config0, erlang:nodes()]),
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config0: ~p"
+ "~n Nodes: ~p", [Config0, erlang:nodes()]),
case snmp_test_mgr_counter_server:stop() of
{ok, Counters} ->
- p("end_per_suite -> sucessfully stopped counter server"
- "~n Counters: ~p", [Counters]);
+ ?IPRINT("end_per_suite -> sucessfully stopped counter server"
+ "~n Counters: ~p", [Counters]);
{error, Reason} ->
- p("end_per_suite -> failed stopping counter server"
- "~n Reason: ~p", [Reason])
+ ?IPRINT("end_per_suite -> failed stopping counter server"
+ "~n Reason: ~p", [Reason])
end,
snmp_test_sys_monitor:stop(),
Config1 = ?LIB:end_per_suite(Config0),
- p("end_per_suite -> end when"
- "~n Nodes: ~p", [erlang:nodes()]),
+ ?IPRINT("end_per_suite -> end when"
+ "~n Nodes: ~p", [erlang:nodes()]),
+
Config1.
@@ -739,7 +740,7 @@ init_per_group_ipv6(GroupName, Config, Init) ->
false ->
%% Even if this host supports IPv6 we don't use it unless its
%% one of the configured/supported IPv6 hosts...
- case (?HAS_SUPPORT_IPV6() andalso ?IS_IPV6_HOST()) of
+ case ?HAS_SUPPORT_IPV6() of
true ->
Init(
snmp_test_lib:init_group_top_dir(
@@ -813,18 +814,35 @@ end_per_group(_GroupName, Config) ->
%% ----- Init Per TestCase -----
%%
+%% T is in number of minutes
+wd_start(T, Config) ->
+ Factor = case ?config(snmp_factor, Config) of
+ F when (F > 0) ->
+ F-1;
+ _ ->
+ 0
+ end,
+ Dog = ?WD_START(?MINS(T + Factor)),
+ [{watchdog, Dog} | Config ].
+
+
+wd_stop(Config) ->
+ Dog = ?config(watchdog, Config),
+ ?WD_STOP(Dog),
+ lists:keydelete(Dog, 2, Config).
+
init_per_testcase(Case, Config) when is_list(Config) ->
- p("init_per_testcase -> entry with"
- "~n Config: ~p"
- "~n Nodes: ~p", [Config, erlang:nodes()]),
+ ?IPRINT("init_per_testcase -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config, erlang:nodes()]),
Result = init_per_testcase1(Case, Config),
snmp_test_global_sys_monitor:reset_events(),
- p("init_per_testcase -> done when"
- "~n Result: ~p"
- "~n Nodes: ~p", [Result, erlang:nodes()]),
+ ?IPRINT("init_per_testcase -> done when"
+ "~n Result: ~p"
+ "~n Nodes: ~p", [Result, erlang:nodes()]),
Result.
init_per_testcase1(otp8395 = Case, Config) when is_list(Config) ->
@@ -841,8 +859,7 @@ init_per_testcase1(otp_7157 = _Case, Config) when is_list(Config) ->
?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
- Dog = ?WD_START(?MINS(1)),
- [{watchdog, Dog} | Config ];
+ wd_start(1, Config);
init_per_testcase1(Case, Config)
when ((Case =:= otp_16092_simple_start_and_stop1) orelse
(Case =:= otp_16092_simple_start_and_stop2) orelse
@@ -852,30 +869,26 @@ init_per_testcase1(Case, Config)
?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
- Dog = ?WD_START(?MINS(1)),
- init_per_testcase2(Case, [{watchdog, Dog} | Config]);
+ init_per_testcase2(Case, wd_start(1, Config));
init_per_testcase1(v2_inform_i = _Case, Config) when is_list(Config) ->
?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
- Dog = ?WD_START(?MINS(10)),
- [{watchdog, Dog} | Config ];
+ wd_start(10, Config);
init_per_testcase1(v3_inform_i = _Case, Config) when is_list(Config) ->
?DBG("init_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
- Dog = ?WD_START(?MINS(10)),
- [{watchdog, Dog} | Config ];
+ wd_start(10, Config);
init_per_testcase1(_Case, Config) when is_list(Config) ->
?DBG("init_per_testcase -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
- Dog = ?WD_START(?MINS(6)),
- [{watchdog, Dog}| Config ].
+ wd_start(6, Config).
init_per_testcase2(Case, Config) ->
- ?DBG("end_per_testcase2 -> entry with"
+ ?DBG("init_per_testcase2 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [Case, Config]),
@@ -911,20 +924,48 @@ init_per_testcase2(Case, Config) ->
%% ---- End Per TestCase ----
end_per_testcase(Case, Config) when is_list(Config) ->
- p("end_per_testcase -> entry with"
- "~n Config: ~p"
- "~n Nodes: ~p", [Config, erlang:nodes()]),
- display_log(Config),
+ ?IPRINT("end_per_testcase -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p",
+ [Config, erlang:nodes()]),
+
+ ?IPRINT("system events during test: "
+ "~n ~p", [snmp_test_global_sys_monitor:events()]),
+
+ %% On some hosts, this operation can take a long time.
+ %% So long, that the timetrap expires and the test case
+ %% will be "failed".
+ %% So, wrap it in a process and for a successful test case,
+ %% give it 30 seconds, then kill it. If the test case has
+ %% already failed, we will want to get as much of the logs
+ %% as possible. So, set no timeout (infinity) and let the
+ %% test framework take care of things...
+ DisplayLogTimeout =
+ case ?config(tc_status, Config) of
+ ok ->
+ ?SECS(30);
+ _ ->
+ infinity
+ end,
+ Flag = process_flag(trap_exit, true),
+ Pid = spawn_link(fun() -> display_log(Config), exit(normal) end),
+ receive
+ {'EXIT', Pid, _} ->
+ process_flag(trap_exit, Flag),
+ ok
+ after DisplayLogTimeout ->
+ ?WPRINT("Display Log process fail to complete in time (~w msec): "
+ "kill it", [DisplayLogTimeout]),
+ process_flag(trap_exit, Flag),
+ exit(Pid, kill)
+ end,
- p("system events during test: "
- "~n ~p", [snmp_test_global_sys_monitor:events()]),
-
Result = end_per_testcase1(Case, Config),
- p("end_per_testcase -> done with"
- "~n Result: ~p"
- "~n Nodes: ~p", [Result, erlang:nodes()]),
+ ?IPRINT("end_per_testcase -> done with"
+ "~n Result: ~p"
+ "~n Nodes: ~p", [Result, erlang:nodes()]),
Result.
end_per_testcase1(otp8395, Config) when is_list(Config) ->
@@ -935,9 +976,7 @@ end_per_testcase1(_Case, Config) when is_list(Config) ->
?DBG("end_per_testcase1 -> entry with"
"~n Case: ~p"
"~n Config: ~p", [_Case, Config]),
- Dog = ?config(watchdog, Config),
- ?WD_STOP(Dog),
- Config.
+ wd_stop(Config).
@@ -975,37 +1014,37 @@ end_per_testcase1(_Case, Config) when is_list(Config) ->
init_all(Conf) ->
?DISPLAY_SUITE_INFO(),
- snmp_agent_test_lib:init_all(Conf).
+ ?ALIB:init_all(Conf).
finish_all(Conf) ->
- snmp_agent_test_lib:finish_all(Conf).
+ ?ALIB:finish_all(Conf).
start_v1_agent(Config) ->
- snmp_agent_test_lib:start_v1_agent(Config).
+ ?ALIB:start_v1_agent(Config).
start_v1_agent(Config, Opts) ->
- snmp_agent_test_lib:start_v1_agent(Config, Opts).
+ ?ALIB:start_v1_agent(Config, Opts).
start_v2_agent(Config) ->
- snmp_agent_test_lib:start_v2_agent(Config).
+ ?ALIB:start_v2_agent(Config).
start_v2_agent(Config, Opts) ->
- snmp_agent_test_lib:start_v2_agent(Config, Opts).
+ ?ALIB:start_v2_agent(Config, Opts).
%% start_v3_agent(Config) ->
-%% snmp_agent_test_lib:start_v3_agent(Config).
+%% ?ALIB:start_v3_agent(Config).
start_v3_agent(Config, Opts) ->
- snmp_agent_test_lib:start_v3_agent(Config, Opts).
+ ?ALIB:start_v3_agent(Config, Opts).
start_bilingual_agent(Config) ->
- snmp_agent_test_lib:start_bilingual_agent(Config).
+ ?ALIB:start_bilingual_agent(Config).
start_multi_threaded_agent(Config) when is_list(Config) ->
- snmp_agent_test_lib:start_mt_agent(Config).
+ ?ALIB:start_mt_agent(Config).
stop_agent(Config) ->
- snmp_agent_test_lib:stop_agent(Config).
+ ?ALIB:stop_agent(Config).
create_tables(SaNode) ->
@@ -1148,28 +1187,28 @@ varm_mib_storage_mnesia_cases() ->
[msm_varm_mib_start].
init_mib_storage_ets(Config) when is_list(Config) ->
- ?LOG("init_mib_storage_ets -> entry", []),
+ ?IPRINT("init_mib_storage_ets -> entry"),
MibStorage = {mib_storage, [{module, snmpa_mib_storage_ets}]},
init_ms(Config, [MibStorage]).
init_mib_storage_dets(Config) when is_list(Config) ->
- ?LOG("init_mib_storage_dets -> entry", []),
+ ?IPRINT("init_mib_storage_dets -> entry"),
?line AgentDbDir = ?GCONF(agent_db_dir, Config),
MibStorage = {mib_storage, [{module, snmpa_mib_storage_dets},
{options, [{dir, AgentDbDir}]}]},
init_ms(Config, [MibStorage]).
init_mib_storage_mnesia(Config) when is_list(Config) ->
- ?LOG("init_mib_storage_mnesia -> entry", []),
+ ?IPRINT("init_mib_storage_mnesia -> entry"),
?line AgentNode = ?GCONF(snmp_master, Config),
MibStorage = {mib_storage, [{module, snmpa_mib_storage_mnesia},
{options, [{nodes, [AgentNode]}]}]},
init_ms(Config, [MibStorage]).
init_ms(Config, Opts) when is_list(Config) ->
- ?LOG("init_ms -> entry with"
- "~n Config: ~p"
- "~n Opts: ~p", [Config, Opts]),
+ ?IPRINT("init_ms -> entry with"
+ "~n Config: ~p"
+ "~n Opts: ~p", [Config, Opts]),
?line SaNode = ?GCONF(snmp_sa, Config),
?line create_tables(SaNode),
?line AgentConfDir = ?GCONF(agent_conf_dir, Config),
@@ -1206,11 +1245,16 @@ init_size_check_ms(Config, Opts) when is_list(Config) ->
ok ->
case ?CRYPTO_SUPPORT() of
{no, Reason} ->
+ ?WPRINT("crypto support not sufficient:"
+ "~n ~p", [Reason]),
?SKIP({unsupported_encryption, Reason});
yes ->
+ ?IPRINT("crypto started"),
ok
end;
{error, Reason} ->
+ ?IPRINT("crypto not started:"
+ "~n ~p", [Reason]),
?SKIP({failed_starting_crypto, Reason})
end,
create_tables(SaNode),
@@ -1222,7 +1266,7 @@ init_size_check_ms(Config, Opts) when is_list(Config) ->
[{vsn, v3} | start_v3_agent(Config, Opts)].
init_varm_mib_storage_dets(Config) when is_list(Config) ->
- ?LOG("init_varm_mib_storage_dets -> entry", []),
+ ?IPRINT("init_varm_mib_storage_dets -> entry"),
?line SaNode = ?GCONF(snmp_sa, Config),
?line create_tables(SaNode),
?line AgentDbDir = ?GCONF(agent_db_dir, Config),
@@ -1243,7 +1287,7 @@ init_varm_mib_storage_dets(Config) when is_list(Config) ->
[{vsn, v1}, {agent_opts, Opts} | Config].
init_varm_mib_storage_mnesia(Config) when is_list(Config) ->
- ?LOG("init_varm_mib_storage_mnesia -> entry", []),
+ ?IPRINT("init_varm_mib_storage_mnesia -> entry"),
?line SaNode = ?GCONF(snmp_sa, Config),
?line create_tables(SaNode),
?line AgentConfDir = ?GCONF(agent_conf_dir, Config),
@@ -1264,7 +1308,7 @@ init_varm_mib_storage_mnesia(Config) when is_list(Config) ->
[{vsn, v1}, {agent_opts, Opts} | Config].
finish_mib_storage_ets(Config) when is_list(Config) ->
- ?LOG("finish_mib_storage_ets -> entry", []),
+ ?IPRINT("finish_mib_storage_ets -> entry"),
delete_tables(),
C1 = stop_agent(Config),
delete_files(C1),
@@ -1272,7 +1316,7 @@ finish_mib_storage_ets(Config) when is_list(Config) ->
lists:keydelete(agent_opts, 1, C2).
finish_mib_storage_dets(Config) when is_list(Config) ->
- ?LOG("finish_mib_storage_dets -> entry", []),
+ ?IPRINT("finish_mib_storage_dets -> entry"),
delete_tables(),
C1 = stop_agent(Config),
delete_files(C1),
@@ -1280,7 +1324,7 @@ finish_mib_storage_dets(Config) when is_list(Config) ->
lists:keydelete(agent_opts, 1, C2).
finish_mib_storage_mnesia(Config) when is_list(Config) ->
- ?LOG("finish_mib_storage_mnesia -> entry", []),
+ ?IPRINT("finish_mib_storage_mnesia -> entry"),
delete_tables(),
delete_mib_storage_mnesia_tables(),
C1 = stop_agent(Config),
@@ -1289,7 +1333,7 @@ finish_mib_storage_mnesia(Config) when is_list(Config) ->
lists:keydelete(agent_opts, 1, C2).
finish_varm_mib_storage_dets(Config) when is_list(Config) ->
- ?LOG("finish_varm_mib_storage_dets -> entry", []),
+ ?IPRINT("finish_varm_mib_storage_dets -> entry"),
delete_tables(),
%% C1 = stop_agent(Config), % In case something went wrong...
delete_files(Config),
@@ -1297,7 +1341,7 @@ finish_varm_mib_storage_dets(Config) when is_list(Config) ->
lists:keydelete(agent_opts, 1, C2).
finish_varm_mib_storage_mnesia(Config) when is_list(Config) ->
- ?LOG("finish_varm_mib_storage_mnesia -> entry", []),
+ ?IPRINT("finish_varm_mib_storage_mnesia -> entry"),
delete_tables(),
delete_mib_storage_mnesia_tables(),
%% C1 = stop_agent(Config), % In case something went wrong...
@@ -1408,7 +1452,7 @@ ms_size_check(suite) -> [];
ms_size_check(Config) when is_list(Config) ->
?P(ms_size_check),
init_case(Config),
- ?LOG("mib server size check...", []),
+ ?IPRINT("mib server size check..."),
?line load_master("Test2"),
?line load_master("TestTrap"),
@@ -1449,7 +1493,7 @@ ms_size_check(Config) when is_list(Config) ->
varm_mib_start(suite) -> [];
varm_mib_start(Config) when is_list(Config) ->
?P(varm_mib_start),
- ?LOG("varm_mib_start -> entry", []),
+ ?IPRINT("varm_mib_start -> entry"),
init_case(Config),
%% Start the agent
@@ -1694,24 +1738,64 @@ app_dir(App) ->
end.
create_local_db_dir(Config) when is_list(Config) ->
- ?P(create_local_db_dir),
- DataDir = snmp_test_lib:lookup(data_dir, Config),
- UName = erlang:unique_integer([positive]),
- T = {UName, UName, UName},
- [As,Bs,Cs] = [integer_to_list(I) || I <- tuple_to_list(T)],
- DbDir = filename:join([DataDir, As, Bs, Cs]),
- ok = del_dir(DbDir, 3),
- Name = list_to_atom(atom_to_list(create_local_db_dir)
- ++"-"++As++"-"++Bs++"-"++Cs),
- Pa = filename:dirname(code:which(?MODULE)),
- {ok,Node} = ?t:start_node(Name, slave, [{args, "-pa " ++ Pa}]),
+ Pre = fun() ->
+ DataDir = snmp_test_lib:lookup(data_dir, Config),
+ T = {erlang:unique_integer([positive]),
+ erlang:unique_integer([positive]),
+ erlang:unique_integer([positive])},
+ [As,Bs,Cs] = [integer_to_list(I) || I <- tuple_to_list(T)],
+ DbDir = filename:join([DataDir, As, Bs, Cs]),
+ Name = list_to_atom(atom_to_list(create_local_db_dir)
+ ++"_"++As++"_"++Bs++"_"++Cs),
+ ?IPRINT("try ensuring db-dir does not exist"),
+ try del_dir(DbDir, 3) of
+ ok ->
+ ok
+ catch
+ C:E:S ->
+ ?WPRINT("Failed pre db-dir delete: "
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [C, E, S]),
+ throw({skip, "Failed pre db-dir cleanup"})
+ end,
+ ?IPRINT("try start node ~p", [Name]),
+ case ?ALIB:start_node(Name) of
+ {ok, Node} ->
+ {DbDir, Node};
+ {error, Reason} ->
+ ?WPRINT("Failed starting node ~p:"
+ "~n ~p", [Reason]),
+ throw({skip, ?F("Failed starting node ~p", [Name])})
+ end
+ end,
+ Case = fun do_create_local_db_dir/1,
+ Post = fun({DbDir, Node}) ->
+ ?IPRINT("try stop node ~p", [Node]),
+ ?ALIB:stop_node(Node),
+ ?IPRINT("try delete db-dir"),
+ try del_dir(DbDir, 3)
+ catch
+ C:E:S ->
+ ?WPRINT("Failed post db-dir delete: "
+ "~n DbDir ~s"
+ "~n Class: ~p"
+ "~n Error: ~p"
+ "~n Stack: ~p", [DbDir, C, E, S]),
+ ok
+ end
+ end,
+ ?TC_TRY(create_local_db_dir, Pre, Case, Post).
+do_create_local_db_dir({DbDir, Node}) ->
+ ?P(create_local_db_dir),
%% first start with a nonexisting DbDir
Fun1 = fun() ->
false = filelib:is_dir(DbDir),
process_flag(trap_exit,true),
{error, {error, {failed_open_dets, {file_error, _, _}}}} =
- snmpa_local_db:start_link(normal, DbDir, [{verbosity,trace}]),
+ snmpa_local_db:start_link(normal, DbDir,
+ [{verbosity, trace}]),
false = filelib:is_dir(DbDir),
{ok, not_found}
end,
@@ -1729,21 +1813,21 @@ create_local_db_dir(Config) when is_list(Config) ->
{ok, found}
end,
{ok, found} = nodecall(Node, Fun2),
- %% cleanup
- ?t:stop_node(Node),
- ok = del_dir(DbDir, 3),
ok.
nodecall(Node, Fun) ->
Parent = self(),
- Ref = make_ref(),
- spawn_link(Node,
- fun() ->
- Res = Fun(),
- unlink(Parent),
- Parent ! {Ref, Res}
- end),
+ Ref = make_ref(),
+ Pid = spawn_link(Node,
+ fun() ->
+ Res = Fun(),
+ unlink(Parent),
+ Parent ! {Ref, Res}
+ end),
receive
+ %% Just so we are not left hanging
+ {'EXIT', Pid, Reason} ->
+ Reason;
{Ref, Res} ->
Res
end.
@@ -1992,11 +2076,16 @@ init_v3(Config) when is_list(Config) ->
ok ->
case ?CRYPTO_SUPPORT() of
{no, Reason} ->
+ ?WPRINT("crypto support not sufficient:"
+ "~n ~p", [Reason]),
?SKIP({unsupported_encryption, Reason});
yes ->
+ ?IPRINT("crypto started"),
ok
end;
{error, Reason} ->
+ ?IPRINT("crypto not started:"
+ "~n ~p", [Reason]),
?SKIP({failed_starting_crypto, Reason})
end,
SaNode = ?config(snmp_sa, Config),
@@ -2046,7 +2135,7 @@ finish_mt(Config) when is_list(Config) ->
%% This one *must* be run first in each case.
init_case(Config) ->
- snmp_agent_test_lib:init_case(Config).
+ ?ALIB:init_case(Config).
load_master(Mib) ->
@@ -2079,10 +2168,10 @@ unload_mibs(Mibs) ->
ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
start_subagent(SaNode, RegTree, Mib) ->
- snmp_agent_test_lib:start_subagent(SaNode, RegTree, Mib).
+ ?ALIB:start_subagent(SaNode, RegTree, Mib).
stop_subagent(SA) ->
- snmp_agent_test_lib:stop_subagent(SA).
+ ?ALIB:stop_subagent(SA).
%%-----------------------------------------------------------------
@@ -2116,7 +2205,7 @@ simple(Config) when is_list(Config) ->
try_test(simple_standard_test),
- p("done"),
+ ?IPRINT("done"),
ok.
simple_2(X) -> ?P(simple_2), simple(X).
@@ -2143,7 +2232,7 @@ big(Config) when is_list(Config) ->
{SaNode, _MgrNode, _MibDir} = init_case(Config),
- ?P1("Starting subagent..."),
+ ?NPRINT("Starting subagent..."),
?line pong = net_adm:ping(SaNode),
?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
@@ -2172,7 +2261,7 @@ big2(Config) when is_list(Config) ->
%% v2 equivalent of the mibs.
{SaNode, _MgrNode, _MibDir} = init_case(Config),
- ?P1("Starting subagent..."),
+ ?NPRINT("Starting subagent..."),
?line pong = net_adm:ping(SaNode),
?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"),
@@ -2278,7 +2367,7 @@ opaque_3(X) -> ?P(opaque_2), opaque(X).
change_target_addr_config(suite) -> [];
change_target_addr_config(Config) when is_list(Config) ->
?P(change_target_addr_config),
- ?LOG("change_target_addr_config -> entry",[]),
+ ?IPRINT("change_target_addr_config -> entry"),
init_case(Config),
put(sname,snmp_suite),
@@ -2286,43 +2375,43 @@ change_target_addr_config(Config) when is_list(Config) ->
MA = whereis(snmp_master_agent),
- ?LOG("change_target_addr_config -> load TestTrap",[]),
+ ?IPRINT("change_target_addr_config -> load TestTrap"),
?line load_master("TestTrap"),
- ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]),
+ ?IPRINT("change_target_addr_config -> set trace verbosity for local_db"),
?line snmpa:verbosity(local_db,trace),
%% First send some traps that will arive att the original manager
- ?LOG("change_target_addr_config -> send trap",[]),
+ ?IPRINT("change_target_addr_config -> send trap"),
try_test(ma_trap1, [MA]),
- ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]),
+ ?IPRINT("change_target_addr_config -> set silence verbosity for local_db"),
?line snmpa:verbosity(local_db, silence),
%% Start new dummy listener
- ?LOG("change_target_addr_config -> start dummy manager",[]),
+ ?IPRINT("change_target_addr_config -> start dummy manager"),
?line {ok,Pid,NewPort} = dummy_manager_start(MA),
%% Reconfigure
- ?LOG("change_target_addr_config -> reconfigure",[]),
+ ?IPRINT("change_target_addr_config -> reconfigure"),
AgentConfDir = ?config(agent_conf_dir, Config),
?line rewrite_target_addr_conf(AgentConfDir, NewPort),
?line snmp_target_mib:reconfigure(AgentConfDir),
%% Send the trap again
- ?LOG("change_target_addr_config -> send trap again",[]),
+ ?IPRINT("change_target_addr_config -> send trap again"),
catch dummy_manager_send_trap2(Pid),
- ?LOG("change_target_addr_config -> await trap ack",[]),
+ ?IPRINT("change_target_addr_config -> await trap ack"),
catch dummy_manager_await_trap2_ack(),
- ?LOG("change_target_addr_config -> stop dummy manager",[]),
+ ?IPRINT("change_target_addr_config -> stop dummy manager"),
?line ok = dummy_manager_stop(Pid),
- ?LOG("change_target_addr_config -> reset target address config",[]),
+ ?IPRINT("change_target_addr_config -> reset target address config"),
?line reset_target_addr_conf(AgentConfDir),
- ?LOG("change_target_addr_config -> unload TestTrap",[]),
+ ?IPRINT("change_target_addr_config -> unload TestTrap"),
?line unload_master("TestTrap").
@@ -2338,11 +2427,15 @@ await_dummy_manager_started(Pid) ->
?DBG("dummy_manager_start -> acknowledge received with"
"~n Port: ~p",[Port]),
{ok,Pid,Port};
+
{'EXIT', Pid, Reason} ->
+ ?EPRINT("dummy manager terminated: "
+ "~n ~p", [Reason]),
{error, Pid, Reason};
+
_O ->
- ?LOG("dummy_manager_start -> received unknown message:"
- "~n ~p",[_O]),
+ ?NPRINT("dummy_manager_start -> received unknown message:"
+ "~n ~p", [_O]),
await_dummy_manager_started(Pid)
end.
@@ -2354,7 +2447,7 @@ dummy_manager_stop(Pid) ->
?DBG("dummy_manager_stop -> acknowledge received",[]),
ok
after 10000 ->
- ?ERR("dummy_manager_stop -> timeout",[]),
+ ?EPRINT("dummy_manager_stop -> timeout"),
timeout
end.
@@ -2366,7 +2459,7 @@ dummy_manager_await_trap2_ack() ->
?DBG("dummy_manager_await_trap2 -> entry",[]),
receive
{received_trap, _Trap} ->
- ?LOG("dummy_manager_await_trap2 -> received trap: ~p", [_Trap]),
+ ?IPRINT("dummy_manager_await_trap2 -> received trap: ~p", [_Trap]),
%% Note:
%% Without this sleep the v2_inform_i testcase failes! There
%% is no relation between these two test cases as far as I
@@ -2374,10 +2467,10 @@ dummy_manager_await_trap2_ack() ->
?SLEEP(60000),
ok;
_O ->
- ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[_O]),
+ ?WPRINT("dummy_manager_await_trap2 -> unexpected message: ~p",[_O]),
ok
after 10000 ->
- ?ERR("dummy_manager_await_trap2 -> timeout",[]),
+ ?EPRINT("dummy_manager_await_trap2 -> timeout",[]),
timeout
end.
@@ -2393,18 +2486,18 @@ dummy_manager_init(Parent,MA) ->
dummy_manager_loop(Parent,S,MA).
dummy_manager_loop(P,S,MA) ->
- ?LOG("dummy_manager_loop -> ready for receive",[]),
+ ?IPRINT("dummy_manager_loop -> ready for receive"),
receive
{send_trap,Trap} ->
- ?LOG("dummy_manager_loop -> received trap send request"
- "~n Trap: ~p",[Trap]),
+ ?IPRINT("dummy_manager_loop -> received trap send request"
+ "~n Trap: ~p", [Trap]),
snmpa:send_trap(MA, Trap, "standard trap"),
dummy_manager_loop(P,S,MA);
{udp, _UdpId, _Ip, _UdpPort, Bytes} ->
- ?LOG("dummy_manager_loop -> received upd message"
- "~n from: ~p:~p"
- "~n size: ~p",
- [_Ip, _UdpPort, dummy_manager_message_sz(Bytes)]),
+ ?IPRINT("dummy_manager_loop -> received upd message"
+ "~n from: ~p:~p"
+ "~n size: ~p",
+ [_Ip, _UdpPort, dummy_manager_message_sz(Bytes)]),
R = dummy_manager_handle_message(Bytes),
?DBG("dummy_manager_loop -> R: ~p", [R]),
P ! R,
@@ -2415,30 +2508,31 @@ dummy_manager_loop(P,S,MA) ->
gen_udp:close(S),
exit(normal);
_O ->
- ?LOG("dummy_manager_loop -> received unknown message:"
- "~n ~p", [_O]),
+ ?WPRINT("dummy_manager_loop -> received unknown message:"
+ "~n ~p", [_O]),
dummy_manager_loop(P, S, MA)
end.
--ifdef(snmp_log).
+%% -ifdef(snmp_log).
dummy_manager_message_sz(B) when is_binary(B) ->
size(B);
dummy_manager_message_sz(L) when is_list(L) ->
length(L);
dummy_manager_message_sz(_) ->
undefined.
--endif.
+%% -endif.
dummy_manager_handle_message(Bytes) ->
case (catch snmp_pdus:dec_message(Bytes)) of
{'EXIT',Reason} ->
- ?ERR("dummy_manager_handle_message -> "
- "failed decoding message only:~n ~p",[Reason]),
- {error,Reason};
+ ?EPRINT("dummy_manager_handle_message -> "
+ "failed decoding message only:"
+ "~n ~p", [Reason]),
+ {error, Reason};
M ->
?DBG("dummy_manager_handle_message -> decoded message:"
- "~n ~p",[M]),
- {received_trap,M}
+ "~n ~p", [M]),
+ {received_trap, M}
end.
@@ -2465,19 +2559,20 @@ subagent(Config) when is_list(Config) ->
?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
try_test(load_test_sa),
- ?P1("Testing unregister subagent..."),
+ ?NPRINT("Testing unregister subagent..."),
MA = whereis(snmp_master_agent),
rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
try_test(unreg_test),
- ?P1("Loading previous subagent mib in master and testing..."),
+ ?NPRINT("Loading previous subagent mib in master and testing..."),
?line ok = snmpa:load_mib(MA, join(MibDir, "Klas1")),
try_test(load_test),
- ?P1("Unloading previous subagent mib in master and testing..."),
+ ?NPRINT("Unloading previous subagent mib in master and testing..."),
?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas1")),
try_test(unreg_test),
- ?P1("Testing register subagent..."),
+
+ ?NPRINT("Testing register subagent..."),
rpc:call(SaNode, snmp, register_subagent,
[MA, ?klas1, SA]),
try_test(load_test_sa),
@@ -2503,14 +2598,14 @@ mnesia(Config) when is_list(Config) ->
?P(mnesia),
{SaNode, _MgrNode, _MibDir} = init_case(Config),
- ?P1("Starting subagent with mnesia impl..."),
+ ?NPRINT("Starting subagent with mnesia impl..."),
{ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"),
?line load_master("OLD-SNMPEA-MIB"),
?line init_old(),
try_test(big_test_2),
- ?P1("Testing unregister subagent..."),
+ ?NPRINT("Testing unregister subagent..."),
MA = whereis(snmp_master_agent),
rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
try_test(unreg_test),
@@ -2577,7 +2672,7 @@ mul_get(Config) when is_list(Config) ->
?P(mul_get),
init_case(Config),
- ?P1("Testing multiple get..."),
+ ?NPRINT("Testing multiple get..."),
try_test(do_mul_get).
mul_get_2(X) -> ?P(mul_get_2), mul_get(X).
@@ -2590,7 +2685,7 @@ mul_get_err(Config) when is_list(Config) ->
?P(mul_get_err),
init_case(Config),
- ?P1("Testing multiple get with error..."),
+ ?NPRINT("Testing multiple get with error..."),
try_test(do_mul_get_err).
mul_get_err_2(X) -> ?P(mul_get_err_2), mul_get_err(X).
@@ -2603,7 +2698,7 @@ mul_next(Config) when is_list(Config) ->
?P(mul_next),
init_case(Config),
- ?P1("Testing multiple next..."),
+ ?NPRINT("Testing multiple next..."),
try_test(do_mul_next).
mul_next_2(X) -> ?P(mul_next_2), mul_next(X).
@@ -2616,7 +2711,7 @@ mul_next_err(Config) when is_list(Config) ->
?P(mul_next_err),
init_case(Config),
- ?P1("Testing multiple next..."),
+ ?NPRINT("Testing multiple next..."),
try_test(do_mul_next_err).
mul_next_err_2(X) -> ?P(mul_next_err_2), mul_next_err(X).
@@ -2629,7 +2724,7 @@ mul_set(Config) when is_list(Config) ->
?P(mul_set),
init_case(Config),
- ?P1("Testing multiple set..."),
+ ?NPRINT("Testing multiple set..."),
try_test(do_mul_set).
mul_set_2(X) -> ?P(mul_set_2), mul_set(X).
@@ -2642,7 +2737,7 @@ mul_set_err(Config) when is_list(Config) ->
?P(mul_set_err),
init_case(Config),
- ?P1("Testing multiple set with error..."),
+ ?NPRINT("Testing multiple set with error..."),
try_test(do_mul_set_err).
mul_set_err_2(X) -> ?P(mul_set_err_2), mul_set_err(X).
@@ -2656,30 +2751,30 @@ sa_register(Config) when is_list(Config) ->
{SaNode, _MgrNode, MibDir} = init_case(Config),
?DBG("sa_register -> start subagent", []),
- ?P1("start subagent..."),
+ ?NPRINT("start subagent..."),
?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
?DBG("sa_register -> unregister subagent", []),
- ?P1("Testing unregister subagent (2)..."),
+ ?NPRINT("Testing unregister subagent (2)..."),
MA = whereis(snmp_master_agent),
rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
try_test(unreg_test),
- ?P1("Unloading Klas1..."),
+ ?NPRINT("Unloading Klas1..."),
?DBG("sa_register -> unload mibs", []),
snmpa:unload_mib(SA, join(MibDir, "Klas1")),
- ?P1("Loading SA-MIB..."),
+ ?NPRINT("Loading SA-MIB..."),
?DBG("sa_register -> unload mibs", []),
snmpa:load_mib(SA, join(MibDir, "SA-MIB")),
- ?P1("register subagent..."),
+ ?NPRINT("register subagent..."),
?DBG("sa_register -> register subagent", []),
rpc:call(SaNode, snmp, register_subagent, [MA, ?sa, SA]),
try_test(sa_mib),
- ?P1("stop subagent..."),
+ ?NPRINT("stop subagent..."),
?DBG("sa_register -> stop subagent", []),
?line stop_subagent(SA).
@@ -2696,32 +2791,32 @@ v1_trap(Config) when is_list(Config) ->
trap1(Config) ->
{SaNode, _MgrNode, _MibDir} = init_case(Config),
- ?P1("start subagent..."),
+ ?NPRINT("start subagent..."),
?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
- ?P1("Testing trap sending from master agent..."),
+ ?NPRINT("Testing trap sending from master agent..."),
MA = whereis(snmp_master_agent),
- ?P1("load TestTrap & TestTrapv2..."),
+ ?NPRINT("load TestTrap & TestTrapv2..."),
?line load_master("TestTrap"),
?line load_master("TestTrapv2"),
- ?P1("Testing trap sending from master-agent..."),
+ ?NPRINT("Testing trap sending from master-agent..."),
try_test(ma_trap1, [MA]),
try_test(ma_trap2, [MA]),
try_test(ma_v2_2_v1_trap, [MA]),
try_test(ma_v2_2_v1_trap2, [MA]),
- ?P1("Testing trap sending from subagent..."),
+ ?NPRINT("Testing trap sending from subagent..."),
try_test(sa_trap1, [SA]),
try_test(sa_trap2, [SA]),
try_test(sa_trap3, [SA]),
- ?P1("unload TestTrap & TestTrapv2..."),
+ ?NPRINT("unload TestTrap & TestTrapv2..."),
?line unload_master("TestTrap"),
?line unload_master("TestTrapv2"),
- ?P1("stop subagent..."),
+ ?NPRINT("stop subagent..."),
?line stop_subagent(SA).
v2_trap(suite) -> [];
@@ -2732,17 +2827,17 @@ v2_trap(Config) when is_list(Config) ->
trap2(Config) ->
{SaNode, _MgrNode, _MibDir} = init_case(Config),
- ?P1("start subagent..."),
+ ?NPRINT("start subagent..."),
?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
- ?P1("Testing trap sending from master agent..."),
+ ?NPRINT("Testing trap sending from master agent..."),
MA = whereis(snmp_master_agent),
- ?P1("load TestTrap & TestTrapv2..."),
+ ?NPRINT("load TestTrap & TestTrapv2..."),
?line load_master("TestTrap"),
?line load_master("TestTrapv2"),
- ?P1("Testing trap sending from master-agent..."),
+ ?NPRINT("Testing trap sending from master-agent..."),
try_test(ma_v2_trap1, [MA]),
try_test(ma_v2_trap2, [MA]),
try_test(ma_v1_2_v2_trap, [MA]),
@@ -2750,16 +2845,16 @@ trap2(Config) ->
try_test(sa_mib),
- ?P1("Testing trap sending from subagent..."),
+ ?NPRINT("Testing trap sending from subagent..."),
try_test(sa_v1_2_v2_trap1, [SA]),
try_test(sa_v1_2_v2_trap2, [SA]),
try_test(sa_v1_2_v2_trap3, [SA]),
- ?P1("unload TestTrap & TestTrapv2..."),
+ ?NPRINT("unload TestTrap & TestTrapv2..."),
?line unload_master("TestTrap"),
?line unload_master("TestTrapv2"),
- ?P1("stop subagent..."),
+ ?NPRINT("stop subagent..."),
?line stop_subagent(SA).
v3_trap(suite) -> [];
@@ -2811,18 +2906,18 @@ inform_i(Config) ->
MA = whereis(snmp_master_agent),
- ?P1("load TestTrap & TestTrapv2..."),
+ ?NPRINT("load TestTrap & TestTrapv2..."),
?line load_master("TestTrap"),
?line load_master("TestTrapv2"),
- ?P1("Testing inform sending from master agent... "
+ ?NPRINT("Testing inform sending from master agent... "
"~nNOTE! This test takes a few minutes (10) to complete."),
try_test(ma_v2_inform1, [MA]),
try_test(ma_v2_inform2, [MA]),
try_test(ma_v2_inform3, [MA]),
- ?P1("unload TestTrap & TestTrapv2..."),
+ ?NPRINT("unload TestTrap & TestTrapv2..."),
?line unload_master("TestTrap"),
?line unload_master("TestTrapv2"),
ok.
@@ -2843,26 +2938,26 @@ sa_error(Config) when is_list(Config) ->
?P(sa_error),
{SaNode, _MgrNode, _MibDir} = init_case(Config),
- ?P1("load OLD-SNMPEA-MIB..."),
+ ?NPRINT("load OLD-SNMPEA-MIB..."),
?line load_master("OLD-SNMPEA-MIB"),
?line init_old(),
- ?P1("start subagent..."),
+ ?NPRINT("start subagent..."),
?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
- ?P1("Testing sa bad value (is_set_ok)..."),
+ ?NPRINT("Testing sa bad value (is_set_ok)..."),
try_test(sa_errs_bad_value),
- ?P1("Testing sa gen err (set)..."),
+ ?NPRINT("Testing sa gen err (set)..."),
try_test(sa_errs_gen_err),
- ?P1("Testing too big..."),
+ ?NPRINT("Testing too big..."),
try_test(sa_too_big),
- ?P1("unload OLD-SNMPEA-MIB..."),
+ ?NPRINT("unload OLD-SNMPEA-MIB..."),
?line unload_master("OLD-SNMPEA-MIB"),
- ?P1("stop subagent..."),
+ ?NPRINT("stop subagent..."),
stop_subagent(SA).
sa_error_2(X) ->
@@ -2886,35 +2981,35 @@ next_across_sa(Config) when is_list(Config) ->
{SaNode, _MgrNode, MibDir} = init_case(Config),
MA = whereis(snmp_master_agent),
- ?P1("start subagent (1)..."),
+ ?NPRINT("start subagent (1)..."),
?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
- ?P1("Loading another subagent mib (Klas1)..."),
+ ?NPRINT("Loading another subagent mib (Klas1)..."),
?line ok = snmpa:load_mib(SA, MibDir ++ "Klas1"),
- ?P1("register subagent..."),
+ ?NPRINT("register subagent..."),
rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]),
- ?P1("Load test subagent..."),
+ ?NPRINT("Load test subagent..."),
try_test(load_test_sa),
- ?P1("Testing next across subagent (endOfMibView from SA)..."),
+ ?NPRINT("Testing next across subagent (endOfMibView from SA)..."),
try_test(next_across_sa_test),
- ?P1("Unloading mib (Klas1)"),
+ ?NPRINT("Unloading mib (Klas1)"),
snmpa:unload_mib(SA, join(MibDir, "Klas1")),
rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
try_test(unreg_test),
- ?P1("Starting another subagent (2) "),
+ ?NPRINT("Starting another subagent (2) "),
?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
- ?P1("Testing next across subagent (wrong prefix from SA)..."),
+ ?NPRINT("Testing next across subagent (wrong prefix from SA)..."),
try_test(next_across_sa_test),
- ?P1("stop subagent (1)..."),
+ ?NPRINT("stop subagent (1)..."),
stop_subagent(SA),
- ?P1("stop subagent (2)..."),
+ ?NPRINT("stop subagent (2)..."),
stop_subagent(SA2).
next_across_sa_2(X) ->
@@ -2939,27 +3034,27 @@ undo(Config) when is_list(Config) ->
MA = whereis(snmp_master_agent),
- ?P1("start subagent (1)..."),
+ ?NPRINT("start subagent (1)..."),
?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
- ?P1("Load Klas3 & Klas4..."),
+ ?NPRINT("Load Klas3 & Klas4..."),
?line ok = snmpa:load_mib(MA, join(MibDir, "Klas3")),
?line ok = snmpa:load_mib(MA, join(MibDir, "Klas4")),
- ?P1("Testing undo phase at master agent..."),
+ ?NPRINT("Testing undo phase at master agent..."),
try_test(undo_test),
try_test(api_test2),
- ?P1("Unload Klas3..."),
+ ?NPRINT("Unload Klas3..."),
?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas3")),
- ?P1("Testing bad return values from instrum. funcs..."),
+ ?NPRINT("Testing bad return values from instrum. funcs..."),
try_test(bad_return),
- ?P1("Unload Klas4..."),
+ ?NPRINT("Unload Klas4..."),
?line ok = snmpa:unload_mib(MA, join(MibDir, "Klas4")),
- ?P1("Testing undo phase at subagent..."),
+ ?NPRINT("Testing undo phase at subagent..."),
?line ok = snmpa:load_mib(SA, join(MibDir, "Klas3")),
?line ok = snmpa:load_mib(SA, join(MibDir, "Klas4")),
?line ok = snmpa:register_subagent(MA, ?klas3, SA),
@@ -2967,11 +3062,11 @@ undo(Config) when is_list(Config) ->
try_test(undo_test),
try_test(api_test3),
- ?P1("Testing undo phase across master/subagents..."),
+ ?NPRINT("Testing undo phase across master/subagents..."),
try_test(undo_test),
try_test(api_test3),
- ?P1("stop subagent..."),
+ ?NPRINT("stop subagent..."),
stop_subagent(SA).
undo_2(X) ->
@@ -2995,12 +3090,12 @@ v1_processing(Config) when is_list(Config) ->
?DBG("v1_processing -> entry", []),
init_case(Config),
- ?P1("Load Test2..."),
+ ?NPRINT("Load Test2..."),
?line load_master("Test2"),
try_test(v1_proc),
- ?P1("Unload Test2..."),
+ ?NPRINT("Unload Test2..."),
?line unload_master("Test2").
%% Req. Test2
@@ -3009,12 +3104,12 @@ v2_processing(Config) when is_list(Config) ->
?P(v2_processing),
init_case(Config),
- ?P1("Load Test2..."),
+ ?NPRINT("Load Test2..."),
?line load_master("Test2"),
try_test(v2_proc),
- ?P1("Unload Test2..."),
+ ?NPRINT("Unload Test2..."),
?line unload_master("Test2").
%% Req. Test2
@@ -3023,12 +3118,12 @@ v3_processing(Config) when is_list(Config) ->
?P(v3_processing),
init_case(Config),
- ?P1("Load Test2..."),
+ ?NPRINT("Load Test2..."),
?line load_master("Test2"),
try_test(v2_proc), % same as v2!
- ?P1("Unload Test2..."),
+ ?NPRINT("Unload Test2..."),
?line unload_master("Test2").
@@ -3101,7 +3196,7 @@ v3_md5_auth(Config) when is_list(Config) ->
?P(v3_md5_auth),
init_case(Config),
- ?P1("Testing MD5 authentication...takes a few seconds..."),
+ ?NPRINT("Testing MD5 authentication...takes a few seconds..."),
AgentConfDir = ?config(agent_conf_dir, Config),
?line rewrite_target_params_conf(AgentConfDir, "authMD5", authNoPriv),
@@ -3128,7 +3223,7 @@ v3_sha_auth(Config) when is_list(Config) ->
?P(v3_sha_auth),
init_case(Config),
- ?P1("Testing SHA authentication...takes a few seconds..."),
+ ?NPRINT("Testing SHA authentication...takes a few seconds..."),
AgentConfDir = ?config(agent_conf_dir, Config),
?line rewrite_target_params_conf(AgentConfDir, "authSHA", authNoPriv),
@@ -3155,7 +3250,7 @@ v3_des_priv(Config) when is_list(Config) ->
?P(v3_des_priv),
init_case(Config),
- ?P1("Testing DES encryption...takes a few seconds..."),
+ ?NPRINT("Testing DES encryption...takes a few seconds..."),
AgentConfDir = ?config(agent_conf_dir, Config),
?line rewrite_target_params_conf(AgentConfDir, "privDES", authPriv),
@@ -3772,10 +3867,10 @@ big_test() ->
%% Req. system group, Klas2, OLD-SNMPEA-MIB
big_test_2() ->
- ?P1("Testing simple next/get/set @ master agent (2)..."),
+ ?NPRINT("Testing simple next/get/set @ master agent (2)..."),
simple_standard_test(),
- ?P1("Testing simple next/get/set @ subagent (2)..."),
+ ?NPRINT("Testing simple next/get/set @ subagent (2)..."),
gn([[klas2]]),
?line ?expect1([{[fname2,0], ""}]),
g([[fname2,0]]),
@@ -3787,7 +3882,7 @@ big_test_2() ->
otp_1298_test(),
- ?P1("Testing next from last object in master to subagent (2)..."),
+ ?NPRINT("Testing next from last object in master to subagent (2)..."),
gn([[?v1_2(sysServices, sysORLastChange),0]]),
?line ?expect1([{[fname2,0], "test set"}]),
gn([[1,1], [?v1_2(sysServices, sysORLastChange),0]]),
@@ -3796,7 +3891,7 @@ big_test_2() ->
table_test(),
- ?P1("Adding one row in subagent table (2)"),
+ ?NPRINT("Adding one row in subagent table (2)"),
_FTab = [friendsEntry2],
s([{[friendsEntry2, [2, 3]], s, "kompis3"},
{[friendsEntry2, [3, 3]], i, ?createAndGo}]),
@@ -3809,7 +3904,7 @@ big_test_2() ->
s([{[friendsEntry2, [3, 3]], i, ?destroy}]),
?line ?expect1([{[friendsEntry2, [3, 3]], ?destroy}]),
- ?P1("Adding two rows in subagent table with special INDEX (2)"),
+ ?NPRINT("Adding two rows in subagent table with special INDEX (2)"),
s([{[kompissEntry2, [1, 3]], s, "kompis3"},
{[kompissEntry2, [2, 3]], i, ?createAndGo}]),
?line ?expect1([{[kompissEntry2, [1, 3]], "kompis3"},
@@ -3838,7 +3933,7 @@ big_test_2() ->
%% Req. Test1
multi_threaded_test() ->
- ?P1("Testing multi threaded agent..."),
+ ?NPRINT("Testing multi threaded agent..."),
g([[multiStr,0]]),
Pid = get_multi_pid(),
g([[sysUpTime,0]]),
@@ -3865,7 +3960,7 @@ multi_threaded_test() ->
%% Req. Test1, TestTrapv2
mt_trap_test(MA) ->
- ?P1("Testing trap-sending with multi threaded agent..."),
+ ?NPRINT("Testing trap-sending with multi threaded agent..."),
?DBG("mt_trap_test(01) -> issue testTrapv22 (standard trap)", []),
snmpa:send_trap(MA, testTrapv22, "standard trap"),
?DBG("mt_trap_test(02) -> await v2trap", []),
@@ -3911,7 +4006,7 @@ get_multi_pid(N) ->
%% Req. Test1
types_v2_test() ->
- ?P1("Testing v2 types..."),
+ ?NPRINT("Testing v2 types..."),
s([{[bits1,0], 2#10}]),
?line ?expect1([{[bits1,0], ?str(2#10)}]),
@@ -3938,8 +4033,9 @@ types_v2_test() ->
%% Req. Test1
implied_test(MA) ->
- ?LOG("implied_test -> start",[]),
- ?P1("Testing IMPLIED..."),
+ ?IPRINT("implied_test -> start"),
+
+ ?NPRINT("Testing IMPLIED..."),
snmpa:verbosity(MA, trace),
@@ -3997,13 +4093,14 @@ implied_test(MA) ->
snmpa:verbosity(MA, log),
- ?LOG("implied_test -> done", []).
+ ?IPRINT("implied_test -> done", []),
+ ok.
%% Req. Test1
sparse_table_test() ->
- ?P1("Testing sparse table..."),
+ ?NPRINT("Testing sparse table..."),
%% Create two rows, check that they are get-nexted in correct order.
Idx1 = 1,
@@ -4033,11 +4130,12 @@ sparse_table_test() ->
%% Req. Test1
cnt_64_test(MA) ->
- ?LOG("start cnt64 test (~p)",[MA]),
+ ?IPRINT("start cnt64 test (~p)", [MA]),
snmpa:verbosity(MA, trace),
- ?LOG("start cnt64 test",[]),
- ?P1("Testing Counter64, and at the same time, "
- "RowStatus is not last column"),
+ ?IPRINT("start cnt64 test"),
+
+ ?NPRINT("Testing Counter64, and at the same time, "
+ "RowStatus is not last column"),
?DBG("get cnt64",[]),
g([[cnt64,0]]),
@@ -4096,7 +4194,7 @@ cnt_64_test(MA) ->
%% Req. Test1
opaque_test() ->
- ?P1("Testing Opaque datatype..."),
+ ?NPRINT("Testing Opaque datatype..."),
g([[opaqueObj,0]]),
?line ?expect1([{[opaqueObj,0], "opaque-data"}]).
@@ -4238,7 +4336,7 @@ do_mul_next_err() ->
%% Req. system group, Klas1, OLD-SNMPEA-MIB
do_mul_set() ->
- ?P1("Adding one row in subagent table, and one in master table"),
+ ?NPRINT("Adding one row in subagent table, and one in master table"),
NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
@@ -4272,7 +4370,7 @@ do_mul_set_err() ->
NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
- ?P1("Adding one row in subagent table, and one in master table"),
+ ?NPRINT("Adding one row in subagent table, and one in master table"),
s([{[friendsEntry, [2, 3]], s, "kompis3"},
{NewKeyc3, 2},
{[sysUpTime,0], 45}, % sysUpTime (readOnly)
@@ -4435,14 +4533,14 @@ ma_v2_inform1(MA) ->
"~n with receiver: ~p", [_Addr]),
ok;
{snmp_targets, T, Addrs} ->
- ?ERR("ma_v2_inform1 -> "
- "received unexpected snmp_targets"
- "~n with receivers: ~n ~p",[Addrs]),
+ ?EPRINT("ma_v2_inform1 -> "
+ "received unexpected snmp_targets"
+ "~n with receivers: ~n ~p",[Addrs]),
{error, {bad_addrs, Addrs}}
after
5000 ->
- ?ERR("ma_v2_inform1 -> "
- "timeout awaiting snmp_targets [~w]",[T]),
+ ?EPRINT("ma_v2_inform1 -> "
+ "timeout awaiting snmp_targets [~w]",[T]),
{error, snmp_targets_timeout}
end
end,
@@ -4456,16 +4554,16 @@ ma_v2_inform1(MA) ->
"[with manager response] from: ~n ~p", [_Addr]),
ok;
{snmp_notification, Tag03, {no_response, _Addr}} ->
- ?ERR("ma_v2_inform1 -> "
- "received unexpected snmp_notification "
- "[without manager response] from: ~n ~p",
- [_Addr]),
+ ?EPRINT("ma_v2_inform1 -> "
+ "received unexpected snmp_notification "
+ "[without manager response] from: ~n ~p",
+ [_Addr]),
{error, no_response}
after
20000 ->
- ?ERR("ma_v2_inform1 -> "
- "timeout awaiting snmp_notification [~p]",
- [Tag03]),
+ ?EPRINT("ma_v2_inform1 -> "
+ "timeout awaiting snmp_notification [~p]",
+ [Tag03]),
{error, snmp_notification_timeout}
end
end,
@@ -4490,9 +4588,9 @@ ma_v2_inform1(MA) ->
fun() ->
receive
{snmp_notification, Tag07, {got_response, _Addr}} ->
- ?ERR("ma_v2_inform1 -> "
- "received unexpected snmp_notification "
- "[with manager response] from: ~n ~p", [_Addr]),
+ ?EPRINT("ma_v2_inform1 -> "
+ "received unexpected snmp_notification "
+ "[with manager response] from: ~n ~p", [_Addr]),
{error, got_response};
{snmp_notification, Tag07, {no_response, _Addr}} ->
?DBG("ma_v2_inform1 -> "
@@ -4502,9 +4600,9 @@ ma_v2_inform1(MA) ->
ok
after
240000 ->
- ?ERR("ma_v2_inform1 -> "
- "timeout awaiting snmp_notification [~p]",
- [Tag07]),
+ ?EPRINT("ma_v2_inform1 -> "
+ "timeout awaiting snmp_notification [~p]",
+ [Tag07]),
{error, snmp_notification_timeout}
end
end,
@@ -4554,26 +4652,28 @@ ma_v2_inform2(MA) ->
%% Await callback(s)
CmdAwaitDeliveryCallback =
fun(Kind, Ref, Tag) ->
- io:format("CmdAwaitDeliveryCallback -> entry with"
- "~n Kind: ~p"
- "~n Ref: ~p"
- "~n Tag: ~p"
- "~n", [Kind, Ref, Tag]),
+ ?IPRINT("CmdAwaitDeliveryCallback -> entry with"
+ "~n Kind: ~p"
+ "~n Ref: ~p"
+ "~n Tag: ~p", [Kind, Ref, Tag]),
receive
{Kind, Ref, ok} ->
- io:format("CmdAwaitDeliveryCallback(~p,~p) -> received expected result: ok"
- "~n", [Tag, Ref]),
+ ?IPRINT("CmdAwaitDeliveryCallback(~p,~p) -> "
+ "received expected result: ok"
+ "~n", [Tag, Ref]),
ok;
{Kind, Ref, Error} ->
- io:format("CmdAwaitDeliveryCallback(~p,~p) -> received unexpected result: "
- "~n Error: ~p"
- "~n", [Tag, Ref, Error]),
+ ?IPRINT("CmdAwaitDeliveryCallback(~p,~p) -> "
+ "received unexpected result: "
+ "~n Error: ~p"
+ "~n", [Tag, Ref, Error]),
{error, {unexpected_response, Error}}
after
240000 ->
- ?ERR("ma_v2_inform2 -> "
- "timeout awaiting got_response for snmp_notification [~p]",
- [Tag]),
+ ?EPRINT("ma_v2_inform2 -> "
+ "timeout awaiting got_response for "
+ "snmp_notification [~p]",
+ [Tag]),
{error, snmp_notification_timeout}
end
end,
@@ -4645,25 +4745,27 @@ ma_v2_inform3(MA) ->
%% Await callback(s)
CmdAwaitDeliveryCallback =
fun(Kind, Ref, Tag) ->
- io:format("CmdAwaitDeliveryCallback -> entry with"
- "~n Kind: ~p"
- "~n Ref: ~p"
- "~n Tag: ~p"
- "~n", [Kind, Ref, Tag]),
+ ?IPRINT("CmdAwaitDeliveryCallback -> entry with"
+ "~n Kind: ~p"
+ "~n Ref: ~p"
+ "~n Tag: ~p", [Kind, Ref, Tag]),
receive
{Kind, Ref, ok} ->
- io:format("CmdAwaitDeliveryCallback(~p,~p) -> received expected result: ok"
- "~n", [Tag, Ref]),
+ ?IPRINT("CmdAwaitDeliveryCallback(~p,~p) -> "
+ "received expected result: ok"
+ "~n", [Tag, Ref]),
ok;
{Kind, Ref, Error} ->
- io:format("CmdAwaitDeliveryCallback(~p,~p) -> received unexpected result: "
- "~n Error: ~p"
- "~n", [Tag, Ref, Error]),
+ ?IPRINT("CmdAwaitDeliveryCallback(~p,~p) -> "
+ "received unexpected result: "
+ "~n Error: ~p"
+ "~n", [Tag, Ref, Error]),
{error, {unexpected_response, Error}}
after
240000 ->
- ?ERR("ma_v2_inform3 -> "
- "timeout awaiting got_response for snmp_notification [~p]",
+ ?EPRINT("ma_v2_inform3 -> "
+ "timeout awaiting got_response for "
+ "snmp_notification [~p]",
[Tag]),
{error, snmp_notification_timeout}
end
@@ -4746,16 +4848,16 @@ delivery_info(Tag, Address, DeliveryResult, Extra) ->
command_handler([]) ->
ok;
command_handler([{_No, _Desc, Cmd}|Rest]) ->
- ?LOG("command_handler -> command ~w: ~n ~s", [_No, _Desc]),
+ ?IPRINT("command_handler -> command ~w: ~n ~s", [_No, _Desc]),
case (catch Cmd()) of
ok ->
- ?LOG("command_handler -> ~w: ok", [_No]),
+ ?IPRINT("command_handler -> ~w: ok", [_No]),
command_handler(Rest);
{error, Reason} ->
- ?ERR("command_handler -> ~w error: ~n~p", [_No, Reason]),
+ ?EPRINT("command_handler -> ~w error: ~n~p", [_No, Reason]),
?line ?FAIL(Reason);
Error ->
- ?ERR("command_handler -> ~w unexpected: ~n~p", [_No, Error]),
+ ?EPRINT("command_handler -> ~w unexpected: ~n~p", [_No, Error]),
?line ?FAIL({unexpected_command_result, Error})
end.
@@ -5033,7 +5135,7 @@ standard_mibs2_cases() ->
snmpv2_mib_2(suite) -> [];
snmpv2_mib_2(Config) when is_list(Config) ->
?P(snmpv2_mib_2),
- ?LOG("snmpv2_mib_2 -> start",[]),
+ ?IPRINT("snmpv2_mib_2 -> start"),
init_case(Config),
?DBG("snmpv2_mib_2 -> standard mib init",[]),
@@ -5072,7 +5174,7 @@ snmpv2_mib_2(Config) when is_list(Config) ->
"then disable auth traps",[]),
try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]),
- ?LOG("snmpv2_mib_2 -> done", []),
+ ?IPRINT("snmpv2_mib_2 -> done"),
ok.
@@ -5190,7 +5292,7 @@ snmp_community_mib_2(X) -> ?P(snmp_community_mib_2), snmp_community_mib(X).
%% Req. SNMP-COMMUNITY-MIB
snmp_community_mib_test() ->
- ?INF("NOT YET IMPLEMENTED", []),
+ ?NPRINT("NOT YET IMPLEMENTED"),
nyi.
@@ -5215,41 +5317,69 @@ snmp_framework_mib_3(Config) when is_list(Config) ->
%% Req. SNMP-FRAMEWORK-MIB
+%% snmpEngineID in number of seconds.
+%% In theory, the Engine Time diff of the engine, should be exactly
+%% the same as the number of seconds we sleep (5 in this case).
+%% But because, on some (slow or/and high loaded) hosts, the actual
+%% time we sleep could be a lot larger (due to, for instance, scheduling).
+%% Therefor we must take that into account when we check if the
+%% Engine Time diff (between the two checks) is acceptably.
snmp_framework_mib_test() ->
+ Sleep = 5,
?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
T1 = snmp_misc:now(ms),
?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
T2 = snmp_misc:now(ms),
- ?SLEEP(5000),
+ ?SLEEP(?SECS(Sleep)),
T3 = snmp_misc:now(ms),
?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
T4 = snmp_misc:now(ms),
- ?PRINT2("snmp_framework_mib -> time(s): "
- "~n EngineTime 1: ~p"
- "~n Time to acquire: ~w ms"
- "~n EngineTime 2: ~p"
- "~n Time to acquire: ~w ms"
- "~n => (5 sec sleep between get(snmpEngineTime))"
- "~n Total time to acquire: ~w ms",
- [EngineTime, T2-T1, EngineTime2, T4-T3, T4-T1]),
- if
- (EngineTime+7) < EngineTime2 ->
- ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
- (EngineTime+4) > EngineTime2 ->
- ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
- true ->
- ok
+
+ %% Ok, we tried to sleep 5 seconds, but how long did we actually sleep
+ ASleep = ((T3-T2) + 500) div 1000,
+ EngineTimeDiff = EngineTime2 - EngineTime,
+ HighEngineTime = EngineTime + ASleep + 2,
+ LowEngineTime = EngineTime + ASleep - 1,
+
+ ?IPRINT("snmp_framework_mib -> time(s): "
+ "~n EngineTime 1: ~p"
+ "~n Time to acquire: ~w msec"
+ "~n EngineTime 2: ~p"
+ "~n Time to acquire: ~w msec"
+ "~n => Total time to acquire: ~w msec"
+ "~n Sleep between get(snmpEngineTime): ~w (~w) sec"
+ "~n Engine Time Diff: ~w sec"
+ "~n Success if:"
+ "~n ~w (low) =< Engine Time 2 =< ~w (high)",
+ [EngineTime, T2-T1,
+ EngineTime2, T4-T3,
+ T4-T1, ASleep, Sleep, EngineTimeDiff, LowEngineTime, HighEngineTime]),
+
+ if
+ (HighEngineTime < EngineTime2) ->
+ ?EPRINT("snmp_framework_mib -> (High) Engine Time diff (~w) too large: "
+ "~n ~w < ~w",
+ [EngineTimeDiff, HighEngineTime, EngineTime2]),
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ (LowEngineTime > EngineTime2) ->
+ ?EPRINT("snmp_framework_mib -> (Low) Engine Time diff (~w) too large: "
+ "~n ~w > ~w",
+ [EngineTimeDiff, LowEngineTime, EngineTime2]),
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ true ->
+ ok
end,
+
T5 = snmp_misc:now(ms),
?line case get_req(4, [[snmpEngineBoots,0]]) of
[Boots] when is_integer(Boots) ->
T6 = snmp_misc:now(ms),
- ?PRINT2("snmp_framework_mib -> "
+ ?IPRINT("snmp_framework_mib -> "
"~n boots: ~p"
"~n Time to acquire: ~w ms", [Boots, T6-T5]),
ok;
Else ->
- ?PRINT2("snmp_framework_mib -> failed get proper boots:"
+ ?EPRINT("snmp_framework_mib -> failed get proper boots:"
"~n ~p", [Else]),
?FAIL({invalid_boots, Else})
end,
@@ -5339,7 +5469,7 @@ snmp_target_mib_2(X) -> ?P(snmp_target_mib_2), snmp_target_mib(X).
snmp_target_mib_3(X) -> ?P(snmp_target_mib_3), snmp_target_mib(X).
snmp_target_mib_test() ->
- ?INF("NOT YET IMPLEMENTED", []),
+ ?NPRINT("NOT YET IMPLEMENTED"),
nyi.
snmp_notification_mib(suite) -> [];
@@ -5357,7 +5487,7 @@ snmp_notification_mib_3(X) -> ?P(snmp_notification_mib_3),
snmp_notification_mib(X).
snmp_notification_mib_test() ->
- ?INF("NOT YET IMPLEMENTED", []),
+ ?NPRINT("NOT YET IMPLEMENTED"),
nyi.
@@ -5393,7 +5523,7 @@ snmp_view_based_acm_mib_3(X) ->
snmp_view_based_acm_mib() ->
snmpa:verbosity(net_if,trace),
snmpa:verbosity(master_agent,trace),
- ?LOG("start snmp_view_based_acm_mib test",[]),
+ ?IPRINT("start snmp_view_based_acm_mib test"),
%% The user "no-rights" is present in USM, and is mapped to security
%% name 'no-rights", which is not present in VACM.
%% So, we'll add rights for it, try them and delete them.
@@ -5790,7 +5920,7 @@ usm_bad() ->
loop_mib_1(suite) -> [];
loop_mib_1(Config) when is_list(Config) ->
?P(loop_mib_1),
- ?LOG("loop_mib_1 -> initiate case",[]),
+ ?IPRINT("loop_mib_1 -> initiate case"),
{_SaNode, _MgrNode, _MibDir} = init_case(Config),
?DBG("loop_mib_1 -> ~n"
@@ -5827,14 +5957,14 @@ loop_mib_1(Config) when is_list(Config) ->
?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
%% snmpa:verbosity(master_agent,log),
%% snmpa:verbosity(mib_server,silence),
- ?LOG("loop_mib_1 -> done",[]),
+ ?IPRINT("loop_mib_1 -> done"),
ok.
loop_mib_2(suite) -> [];
loop_mib_2(Config) when is_list(Config) ->
?P(loop_mib_2),
- ?LOG("loop_mib_2 -> initiate case",[]),
+ ?IPRINT("loop_mib_2 -> initiate case"),
{_SaNode, _MgrNode, _MibDir} = init_case(Config),
?DBG("do_loop_mib_2 -> ~n"
"\tSaNode: ~p~n"
@@ -5857,14 +5987,14 @@ loop_mib_2(Config) when is_list(Config) ->
?line unload_master("SNMP-NOTIFICATION-MIB"),
?line unload_master("SNMP-FRAMEWORK-MIB"),
?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
- ?LOG("loop_mib_2 -> done",[]),
+ ?IPRINT("loop_mib_2 -> done"),
ok.
loop_mib_3(suite) -> [];
loop_mib_3(Config) when is_list(Config) ->
?P(loop_mib_3),
- ?LOG("loop_mib_3 -> initiate case",[]),
+ ?IPRINT("loop_mib_3 -> initiate case"),
{_SaNode, _MgrNode, _MibDir} = init_case(Config),
?DBG("loop_mib_3 -> ~n"
"\tSaNode: ~p~n"
@@ -5883,7 +6013,7 @@ loop_mib_3(Config) when is_list(Config) ->
?line unload_master("SNMP-NOTIFICATION-MIB"),
?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
?line unload_master("SNMP-USER-BASED-SM-MIB"),
- ?LOG("loop_mib_3 -> done",[]),
+ ?IPRINT("loop_mib_3 -> done"),
ok.
@@ -6378,7 +6508,7 @@ otp_1366_2(X) -> ?P(otp_1366_2), otp_1366(X).
otp_1366_3(X) -> ?P(otp_1366_3), otp_1366(X).
otp_1366_test() ->
- ?INF("NOT YET IMPLEMENTED", []),
+ ?NPRINT("NOT YET IMPLEMENTED"),
'NYI'.
@@ -6397,7 +6527,7 @@ otp_2776_2(X) -> ?P(otp_2776_2), otp_2776(X).
otp_2776_3(X) -> ?P(otp_2776_3), otp_2776(X).
otp_2776_test() ->
- io:format("Testing bug reported in ticket OTP-2776...~n"),
+ ?NPRINT("Testing bug reported in ticket OTP-2776..."),
Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00
@@ -6716,10 +6846,11 @@ otp_7157(Config) ->
%% ts:run(snmp, snmp_agent_test, [batch]).
otp_7157_test(MA) ->
- ?LOG("start otp_7157_test test (~p)",[MA]),
+ ?IPRINT("start otp_7157_test test (~p)", [MA]),
snmpa:verbosity(MA, trace),
- ?LOG("start otp_7157_test test",[]),
- ?P1("Testing that varbinds in traps/notifications are not reordered"),
+ ?IPRINT("start otp_7157_test test"),
+
+ ?NPRINT("Testing that varbinds in traps/notifications are not reordered"),
?DBG("send cntTrap",[]),
snmpa:send_trap(MA, cntTrap, "standard trap"),
@@ -6757,10 +6888,16 @@ otp_16092_simple_start_and_stop1(Config) ->
?P(otp_16092_simple_start_and_stop1),
?DBG("otp_16092_simple_start_and_stop1 -> entry", []),
- otp_16092_simple_start_and_stop(Config, default, success),
+ TC = fun() ->
+ otp_16092_simple_start_and_stop(Config, default, success)
+ end,
- ?DBG("otp_16092_simple_start_and_stop1 -> done", []),
- ok.
+ Result = otp_16092_try(TC),
+
+ ?DBG("otp_16092_simple_start_and_stop1 -> done: "
+ "~n ~p", [Result]),
+
+ Result.
otp_16092_simple_start_and_stop2(suite) -> [];
@@ -6768,10 +6905,16 @@ otp_16092_simple_start_and_stop2(Config) ->
?P(otp_16092_simple_start_and_stop2),
?DBG("otp_16092_simple_start_and_stop2 -> entry", []),
- otp_16092_simple_start_and_stop(Config, [], success),
+ TC = fun() ->
+ otp_16092_simple_start_and_stop(Config, [], success)
+ end,
- ?DBG("otp_16092_simple_start_and_stop2 -> done", []),
- ok.
+ Result = otp_16092_try(TC),
+
+ ?DBG("otp_16092_simple_start_and_stop2 -> done: "
+ "~n ~p", [Result]),
+
+ Result.
otp_16092_simple_start_and_stop3(suite) -> [];
@@ -6779,10 +6922,18 @@ otp_16092_simple_start_and_stop3(Config) ->
?P(otp_16092_simple_start_and_stop3),
?DBG("otp_16092_simple_start_and_stop3 -> entry", []),
- otp_16092_simple_start_and_stop(Config, 'this-should-be-ignored', success),
+ TC = fun() ->
+ otp_16092_simple_start_and_stop(Config,
+ 'this-should-be-ignored',
+ success)
+ end,
- ?DBG("otp_16092_simple_start_and_stop3 -> done", []),
- ok.
+ Result = otp_16092_try(TC),
+
+ ?DBG("otp_16092_simple_start_and_stop3 -> done: "
+ "~n ~p", [Result]),
+
+ Result.
otp_16092_simple_start_and_stop4(suite) -> [];
@@ -6790,29 +6941,35 @@ otp_16092_simple_start_and_stop4(Config) ->
?P(otp_16092_simple_start_and_stop4),
?DBG("otp_16092_simple_start_and_stop4 -> entry", []),
- otp_16092_simple_start_and_stop(Config, ['this-should-fail'], failure),
+ TC = fun() ->
+ otp_16092_simple_start_and_stop(Config,
+ ['this-should-fail'],
+ failure)
+ end,
+
+ Result = otp_16092_try(TC),
- ?DBG("otp_16092_simple_start_and_stop4 -> done", []),
- ok.
+ ?DBG("otp_16092_simple_start_and_stop4 -> done: "
+ "~n ", [Result]),
+
+ Result.
+otp_16092_try(TC) ->
+ try TC() of
+ Any ->
+ Any
+ catch
+ _:{skip, _} = SKIP ->
+ SKIP
+ end.
+
otp_16092_simple_start_and_stop(Config, ESO, Expected) ->
?line ConfDir = ?config(agent_conf_dir, Config),
?line DbDir = ?config(agent_db_dir, Config),
- p("try start agent node~n"),
- p(user, "try start agent node~n"),
- Node = case ?ALIB:start_node(agent_16092) of
- {ok, N} ->
- p("agent node ~p started~n", [N]),
- p(user, "agent node ~p started~n", [N]),
- N;
- {error, Reason} ->
- e("Failed starting agent node: "
- "~n ~p"
- "~n", [Reason]),
- ?SKIP({failed_starting_node, Reason})
- end,
+ ?NPRINT("try start agent node"),
+ {ok, Node} = ?ALIB:start_node(agent_16092),
Vsns = [v1],
IP = tuple_to_list(?config(ip, Config)),
@@ -6841,30 +6998,29 @@ otp_16092_simple_start_and_stop(Config, ESO, Expected) ->
{config, ConfOpts},
{net_if, NiOpts}],
-
otp16092_try_start_and_stop_agent(Node, Opts, Expected),
- p("try stop agent node ~p~n", [Node]),
- p(user, "try stop agent node ~p~n", [Node]),
+ ?NPRINT("try stop agent node ~p", [Node]),
?ALIB:stop_node(Node),
?SLEEP(1000),
- p("done~n"),
- p(user, "done~n"),
+ ?NPRINT("done"),
ok.
-
+
otp16092_try_start_and_stop_agent(Node, Opts, Expected) ->
- i("try start snmp (agent) supervisor (on ~p) - expect ~p~n", [Node, Expected]),
+ ?IPRINT("try start snmp (agent) supervisor (on ~p) - expect ~p",
+ [Node, Expected]),
case start_standalone_agent(Node, Opts) of
Pid when is_pid(Pid) andalso (Expected =:= success) ->
- i("Expected success starting snmp (agent) supervisor~n"),
+ ?IPRINT("Expected success starting snmp (agent) supervisor"),
?SLEEP(1000),
stop_standalone_agent(Pid),
ok;
Pid when is_pid(Pid) andalso (Expected =:= failure) ->
- e("Unexpected success starting snmp (agent) supervisor: (~p)~n", [Pid]),
+ ?EPRINT("Unexpected success starting snmp (agent) supervisor: (~p)",
+ [Pid]),
?SLEEP(1000),
stop_standalone_agent(Pid),
?FAIL('unexpected-start-success');
@@ -6875,18 +7031,18 @@ otp16092_try_start_and_stop_agent(Node, Opts, Expected) ->
{shutdown,
{failed_to_start_child, snmpa_agent,
{net_if_error, Reason}}}}} when (Expected =:= failure) ->
- p("Expected (shutdown, net-if) error starting "
- "snmp (agent) supervisor (on ~p):"
- "~n ~p", [Node, Reason]),
+ ?IPRINT("Expected (shutdown, net-if) error starting "
+ "snmp (agent) supervisor (on ~p):"
+ "~n ~p", [Node, Reason]),
ok;
{error, {shutdown, Reason}} when (Expected =:= failure) ->
- p("Expected (shutdown) error starting "
- "snmp (agent) supervisor (on ~p):"
- "~n ~p", [Node, Reason]),
+ ?IPRINT("Expected (shutdown) error starting "
+ "snmp (agent) supervisor (on ~p):"
+ "~n ~p", [Node, Reason]),
ok;
{error, Reason} when (Expected =:= failure) ->
- p("Expected error starting snmp (agent) supervisor (on ~p):"
- "~n ~p", [Node, Reason]),
+ ?IPRINT("Expected error starting snmp (agent) supervisor (on ~p):"
+ "~n ~p", [Node, Reason]),
ok;
{badrpc,
@@ -6896,23 +7052,24 @@ otp16092_try_start_and_stop_agent(Node, Opts, Expected) ->
{shutdown,
{failed_to_start_child, snmpa_agent,
{net_if_error, Reason}}}}}}} when (Expected =:= failure) ->
- p("Expected (badrpc, shutdown, net-if) error starting "
- "snmp (agent) supervisor (on ~p):"
- "~n ~p", [Node, Reason]),
+ ?IPRINT("Expected (badrpc, shutdown, net-if) error starting "
+ "snmp (agent) supervisor (on ~p):"
+ "~n ~p", [Node, Reason]),
ok;
{badrpc, {'EXIT', {shutdown, Reason}}} when (Expected =:= failure) ->
- p("Expected (badrpc, shutdown) error starting "
- "snmp (agent) supervisor (on ~p):"
- "~n ~p", [Node, Reason]),
+ ?IPRINT("Expected (badrpc, shutdown) error starting "
+ "snmp (agent) supervisor (on ~p):"
+ "~n ~p", [Node, Reason]),
ok;
{badrpc, {'EXIT', Reason}} when (Expected =:= failure) ->
- p("Expected (badrpc) error starting snmp (agent) supervisor (on ~p):"
- "~n ~p", [Node, Reason]),
+ ?IPRINT("Expected (badrpc) error starting snmp (agent) supervisor "
+ "(on ~p):"
+ "~n ~p", [Node, Reason]),
ok;
{badrpc, Reason} = BADRPC ->
- e("Bad RPC to node ~p failed:"
- "~n ~p", [Node, Reason]),
+ ?WPRINT("Bad RPC to node ~p failed:"
+ "~n ~p", [Node, Reason]),
?SKIP({BADRPC, Node})
end,
@@ -7006,9 +7163,7 @@ otp8395({init, Config}) when is_list(Config) ->
%% Create watchdog
%%
- Dog = ?WD_START(?MINS(1)),
-
- [{watchdog, Dog} | Config2];
+ wd_start(1, Config2);
otp8395({fin, Config}) when is_list(Config) ->
?DBG("otp8395(fin) -> entry with"
@@ -7047,9 +7202,7 @@ otp8395({fin, Config}) when is_list(Config) ->
?DBG("otp8395(fin) -> stop manager node", []),
stop_node(ManagerNode),
- Dog = ?config(watchdog, Config),
- ?WD_STOP(Dog),
- lists:keydelete(watchdog, 1, Config);
+ wd_stop(Config);
otp8395(doc) ->
"OTP-8395 - ATL with sequence numbering. ";
@@ -7102,7 +7255,7 @@ otp9884({fin, Config}) when is_list(Config) ->
fin_v1_agent(Config);
otp9884(doc) ->
- "OTP-9884 - Simlutaneous backup call should not work. ";
+ "OTP-9884 - Simultaneous backup(s) call should not work. ";
otp9884(Config) when is_list(Config) ->
?DBG("otp9884 -> entry with"
@@ -7111,10 +7264,15 @@ otp9884(Config) when is_list(Config) ->
AgentNode = ?config(agent_node, Config),
[AgentBkpDir1, AgentBkpDir2] = ?config(agent_backup_dirs, Config),
Self = self(),
- timer:apply_after(1000,
- ?MODULE, otp9884_backup, [AgentNode, Self, first, AgentBkpDir1]),
- timer:apply_after(1000,
- ?MODULE, otp9884_backup, [AgentNode, Self, second, AgentBkpDir2]),
+ timer:apply_after(1000,
+ ?MODULE,
+ otp9884_backup,
+ [AgentNode, Self, first, AgentBkpDir1]),
+ timer:apply_after(1000,
+ ?MODULE,
+ otp9884_backup,
+ [AgentNode, Self, second, AgentBkpDir2]),
+ otp9884_await_backup_started(),
otp9884_await_backup_completion(undefined, undefined),
?DBG("otp9884 -> done", []),
@@ -7122,20 +7280,47 @@ otp9884(Config) when is_list(Config) ->
otp9884_backup(Node, Pid, Tag, Dir) ->
- io:format("[~w] call backup function~n", [Tag]),
+ ?IPRINT("[~w] backup - await continue", [Tag]),
+ Pid ! {otp9884_backup_started, Tag, self()},
+ receive
+ {otp9884_backup_continue, Tag, Pid} ->
+ ok
+ end,
+ ?IPRINT("[~w] backup start", [Tag]),
Res = rpc:call(Node, snmpa, backup, [Dir]),
- io:format("[~w] backup result: ~p~n", [Tag, Res]),
+ ?IPRINT("[~w] backup result: ~p", [Tag, Res]),
Pid ! {otp9884_backup_complete, Tag, Res}.
+
+otp9884_await_backup_started() ->
+ otp9884_await_backup_started(undefined, undefined).
+
+otp9884_await_backup_started(First, Second)
+ when is_pid(First) andalso is_pid(Second) ->
+ ?IPRINT("otp9884_await_backup_started -> order first continue"),
+ First ! {otp9884_backup_continue, first, self()},
+ ?IPRINT("otp9884_await_backup_started -> order second continue"),
+ Second ! {otp9884_backup_continue, second, self()},
+ ok;
+otp9884_await_backup_started(First, Second) ->
+ receive
+ {otp9884_backup_started, first, Pid} when (First =:= undefined) ->
+ ?IPRINT("otp9884_await_backup_started -> received started from first"),
+ otp9884_await_backup_started(Pid, Second);
+ {otp9884_backup_started, second, Pid} when (Second =:= undefined) ->
+ ?IPRINT("otp9884_await_backup_started -> received started from second"),
+ otp9884_await_backup_started(First, Pid)
+ end.
+
otp9884_await_backup_completion(ok, Second)
when ((Second =/= ok) andalso (Second =/= undefined)) ->
- io:format("otp9884_await_backup_completion -> "
- "first backup succeed and second failed (~p)~n", [Second]),
+ ?IPRINT("otp9884_await_backup_completion -> "
+ "first backup succeed and second failed (~p)", [Second]),
ok;
otp9884_await_backup_completion(First, ok)
when ((First =/= ok) andalso (First =/= undefined)) ->
- io:format("otp9884_await_backup_completion -> "
- "second backup succeed and first failed (~p)~n", [First]),
+ ?IPRINT("otp9884_await_backup_completion -> "
+ "second backup succeed and first failed (~p)", [First]),
ok;
otp9884_await_backup_completion(First, Second)
when (((First =:= undefined) andalso (Second =:= undefined))
@@ -7143,22 +7328,28 @@ otp9884_await_backup_completion(First, Second)
((First =:= undefined) andalso (Second =/= undefined))
orelse
((First =/= undefined) andalso (Second =:= undefined))) ->
- io:format("otp9884_await_backup_completion -> await complete messages~n", []),
+ ?IPRINT("otp9884_await_backup_completion -> await complete messages"),
receive
{otp9884_backup_complete, first, Res} ->
- io:format("otp9884_await_backup_completion -> "
- "received complete message for first: ~p~n", [Res]),
+ ?IPRINT("otp9884_await_backup_completion -> "
+ "received complete message for first: ~p", [Res]),
otp9884_await_backup_completion(Res, Second);
{otp9884_backup_complete, second, Res} ->
- io:format("otp9884_await_backup_completion -> "
- "received complete message for second: ~p~n", [Res]),
+ ?IPRINT("otp9884_await_backup_completion -> "
+ "received complete message for second: ~p", [Res]),
otp9884_await_backup_completion(First, Res)
after 10000 ->
%% we have waited long enough
+ ?EPRINT("otp9884_await_backup_completion -> timeout"),
throw({error, {timeout, First, Second}})
end;
otp9884_await_backup_completion(First, Second) ->
+ ?EPRINT("Bad Completion: "
+ "~n First: ~p"
+ "~n Second: ~p", [First, Second]),
throw({error, {bad_completion, First, Second}}).
+
+
%%-----------------------------------------------------------------
agent_log_validation(Node) ->
@@ -7382,16 +7573,16 @@ verify_subinfo(Info0, [Key|Keys]) ->
is(S) -> [length(S) | S].
try_test(Func) ->
- ?P2("try test ~w...", [Func]),
- snmp_agent_test_lib:try_test(?MODULE, Func).
+ ?NPRINT("try test ~w...", [Func]),
+ ?ALIB:try_test(?MODULE, Func).
try_test(Func, A) ->
- ?P2("try test ~w...", [Func]),
- snmp_agent_test_lib:try_test(?MODULE, Func, A).
+ ?NPRINT("try test ~w...", [Func]),
+ ?ALIB:try_test(?MODULE, Func, A).
try_test(Func, A, Opts) ->
- ?P2("try test ~w...", [Func]),
- snmp_agent_test_lib:try_test(?MODULE, Func, A, Opts).
+ ?NPRINT("try test ~w...", [Func]),
+ ?ALIB:try_test(?MODULE, Func, A, Opts).
%% Test manager wrapperfunctions:
@@ -7402,77 +7593,80 @@ gb(NR, MR, Oids) -> snmp_test_mgr:gb(NR, MR, Oids).
s(VAV) -> snmp_test_mgr:s(VAV).
get_req(Id, Vars) ->
- snmp_agent_test_lib:get_req(Id, Vars).
+ ?ALIB:get_req(Id, Vars).
get_next_req(Vars) ->
- snmp_agent_test_lib:get_next_req(Vars).
+ ?ALIB:get_next_req(Vars).
start_node(Name) ->
- snmp_agent_test_lib:start_node(Name).
+ ?ALIB:start_node(Name).
+stop_node(undefined) ->
+ ok;
stop_node(Node) ->
- snmp_agent_test_lib:stop_node(Node).
+ ?ALIB:stop_node(Node).
%%%-----------------------------------------------------------------
%%% Configuration
%%%-----------------------------------------------------------------
delete_files(Config) ->
- snmp_agent_test_lib:delete_files(Config).
+ ?ALIB:delete_files(Config).
config(Vsns, MgrDir, AgentDir, MIp, AIp) ->
- snmp_agent_test_lib:config(Vsns, MgrDir, AgentDir, MIp, AIp).
+ ?ALIB:config(Vsns, MgrDir, AgentDir, MIp, AIp).
config(Vsns, MgrDir, AgentDir, MIp, AIp, IpFamily) ->
- snmp_agent_test_lib:config(Vsns, MgrDir, AgentDir, MIp, AIp, IpFamily).
+ ?ALIB:config(Vsns, MgrDir, AgentDir, MIp, AIp, IpFamily).
update_usm(Vsns, Dir) ->
- snmp_agent_test_lib:update_usm(Vsns, Dir).
+ ?ALIB:update_usm(Vsns, Dir).
update_usm_mgr(Vsns, Dir) ->
- snmp_agent_test_lib:update_usm_mgr(Vsns, Dir).
+ ?ALIB:update_usm_mgr(Vsns, Dir).
rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
- snmp_agent_test_lib:rewrite_usm_mgr(Dir, ShaKey, DesKey).
+ ?ALIB:rewrite_usm_mgr(Dir, ShaKey, DesKey).
reset_usm_mgr(Dir) ->
- snmp_agent_test_lib:reset_usm_mgr(Dir).
+ ?ALIB:reset_usm_mgr(Dir).
update_vacm(Vsn, Dir) ->
- snmp_agent_test_lib:update_vacm(Vsn, Dir).
+ ?ALIB:update_vacm(Vsn, Dir).
write_community_conf(Dir, Conf) ->
- snmp_agent_test_lib:write_community_conf(Dir, Conf).
+ ?ALIB:write_community_conf(Dir, Conf).
write_target_addr_conf(Dir, Conf) ->
- snmp_agent_test_lib:write_target_addr_conf(Dir, Conf).
+ ?ALIB:write_target_addr_conf(Dir, Conf).
rewrite_target_addr_conf(Dir, NewPort) ->
- snmp_agent_test_lib:rewrite_target_addr_conf(Dir, NewPort).
+ ?ALIB:rewrite_target_addr_conf(Dir, NewPort).
reset_target_addr_conf(Dir) ->
- snmp_agent_test_lib:reset_target_addr_conf(Dir).
+ ?ALIB:reset_target_addr_conf(Dir).
write_target_params_conf(Dir, Vsns) ->
- snmp_agent_test_lib:write_target_params_conf(Dir, Vsns).
+ ?ALIB:write_target_params_conf(Dir, Vsns).
rewrite_target_params_conf(Dir, SecName, SecLevel) ->
- snmp_agent_test_lib:rewrite_target_params_conf(Dir, SecName, SecLevel).
+ ?ALIB:rewrite_target_params_conf(Dir, SecName, SecLevel).
reset_target_params_conf(Dir) ->
- snmp_agent_test_lib:reset_target_params_conf(Dir).
+ ?ALIB:reset_target_params_conf(Dir).
write_notify_conf(Dir) ->
- snmp_agent_test_lib:write_notify_conf(Dir).
+ ?ALIB:write_notify_conf(Dir).
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
copy_file(From, To) ->
- snmp_agent_test_lib:copy_file(From, To).
+ ?ALIB:copy_file(From, To).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -7485,25 +7679,25 @@ display_log(Config) ->
LogDir = Dir,
Mibs = [],
OutFile = join(LogDir, "snmpa_log.txt"),
- p("~n"
- "========================="
- " < Audit Trail Log > "
- "========================="
- "~n"),
+ ?IPRINT("~n"
+ "========================="
+ " < Audit Trail Log > "
+ "========================="
+ "~n"),
rcall(Node, snmpa, log_to_txt, [LogDir, Mibs, OutFile]),
rcall(Node, snmpa, log_to_io, [LogDir, Mibs]),
- p("~n"
- "========================="
- " < / Audit Trail Log > "
- "========================="
- "~n", []);
+ ?IPRINT("~n"
+ "========================="
+ " < / Audit Trail Log > "
+ "========================="
+ "~n");
false ->
- p("display_log -> no agent node found"),
+ ?IPRINT("display_log -> no agent node found"),
ok
end;
false ->
- p("display_log -> no agent log dir found: "
- "~n ~p", [Config]),
+ ?IPRINT("display_log -> no agent log dir found: "
+ "~n ~p", [Config]),
ok
end.
@@ -7518,8 +7712,7 @@ display_memory_usage() ->
SSMU = display_symbolic_store_memory_usage(Info),
LDBMU = display_local_db_memory_usage(Info),
MSMU = display_mib_server_memory_usage(Info),
- ?INF("Memory usage: ~n" ++
- AMU ++ NIMU ++ NSMU ++ SSMU ++ LDBMU ++ MSMU, []),
+ ?NPRINT("Memory usage: ~n" ++ AMU ++ NIMU ++ NSMU ++ SSMU ++ LDBMU ++ MSMU),
ok.
display_agent_memory_usage(Info) ->
@@ -7536,62 +7729,57 @@ display_agent_memory_usage(Info) ->
lists_key1search([db_memory,community_cache], AgentInfo),
VacmSize =
lists_key1search([db_memory,vacm], AgentInfo),
- lists:flatten(
- io_lib:format(" Agent memory usage: "
- "~n Master process memory size: ~p"
- "~n Worker process memory size: ~p"
- "~n Set-worker process memory size: ~p"
- "~n Agent tab size: ~p"
- "~n Community cache size: ~p"
- "~n Vacm tab size: ~p"
- "~n",
- [ProcMem, WProcMem, SWProcMem,
- TabSize, CCSize, VacmSize])).
+ ?F(" Agent memory usage: "
+ "~n Master process memory size: ~p"
+ "~n Worker process memory size: ~p"
+ "~n Set-worker process memory size: ~p"
+ "~n Agent tab size: ~p"
+ "~n Community cache size: ~p"
+ "~n Vacm tab size: ~p"
+ "~n",
+ [ProcMem, WProcMem, SWProcMem,
+ TabSize, CCSize, VacmSize]).
display_net_if_memory_usage(Info) ->
NiInfo = lists_key1search(net_if, Info),
ProcMem = lists_key1search(process_memory, NiInfo),
- lists:flatten(
- io_lib:format(" Net if memory usage: "
- "~n Process memory size: ~p"
- "~n",[ProcMem])).
+ ?F(" Net if memory usage: "
+ "~n Process memory size: ~p"
+ "~n", [ProcMem]).
display_note_store_memory_usage(Info) ->
NsInfo = lists_key1search(note_store, Info),
ProcMem = lists_key1search([process_memory,notes], NsInfo),
ProcTmrMem = lists_key1search([process_memory,timer], NsInfo),
TabSize = lists_key1search([db_memory,notes], NsInfo),
- lists:flatten(
- io_lib:format(" Note store memory usage: "
- "~n Notes process memory size: ~p"
- "~n Timer process memory size: ~p"
- "~n Notes tab size: ~p"
- "~n",
- [ProcMem, ProcTmrMem, TabSize])).
+ ?F(" Note store memory usage: "
+ "~n Notes process memory size: ~p"
+ "~n Timer process memory size: ~p"
+ "~n Notes tab size: ~p"
+ "~n",
+ [ProcMem, ProcTmrMem, TabSize]).
display_symbolic_store_memory_usage(Info) ->
SsInfo = lists_key1search(symbolic_store, Info),
ProcMem = lists_key1search(process_memory, SsInfo),
DbMem = lists_key1search(db_memory, SsInfo),
- lists:flatten(
- io_lib:format(" Symbolic store memory usage: "
- "~n Process memory size: ~p"
- "~n DB size: ~p"
- "~n",
- [ProcMem, DbMem])).
+ ?F(" Symbolic store memory usage: "
+ "~n Process memory size: ~p"
+ "~n DB size: ~p"
+ "~n",
+ [ProcMem, DbMem]).
display_local_db_memory_usage(Info) ->
LdInfo = lists_key1search(local_db, Info),
ProcMem = lists_key1search(process_memory, LdInfo),
EtsSize = lists_key1search([db_memory,ets], LdInfo),
DetsSize = lists_key1search([db_memory,dets], LdInfo),
- lists:flatten(
- io_lib:format(" Local DB memory usage: "
- "~n Process memory size: ~p"
- "~n DB [ets] size: ~p"
- "~n DB [dets] size: ~p"
- "~n",
- [ProcMem, EtsSize, DetsSize])).
+ ?F(" Local DB memory usage: "
+ "~n Process memory size: ~p"
+ "~n DB [ets] size: ~p"
+ "~n DB [dets] size: ~p"
+ "~n",
+ [ProcMem, EtsSize, DetsSize]).
display_mib_server_memory_usage(Info) ->
MibInfo = lists_key1search(mib_server, Info),
@@ -7600,15 +7788,14 @@ display_mib_server_memory_usage(Info) ->
MibDbSize = lists_key1search([db_memory,mib], MibInfo),
NodeDbSize = lists_key1search([db_memory,node], MibInfo),
TreeDbSize = lists_key1search([db_memory,tree], MibInfo),
- lists:flatten(
- io_lib:format(" MIB server memory usage: "
- "~n Process memory size: ~p"
- "~n Tree size: ~p"
- "~n Mib db size: ~p"
- "~n Node db size: ~p"
- "~n Tree db size: ~p"
- "~n",
- [ProcMem, TreeSize, MibDbSize, NodeDbSize, TreeDbSize])).
+ ?F(" MIB server memory usage: "
+ "~n Process memory size: ~p"
+ "~n Tree size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p"
+ "~n",
+ [ProcMem, TreeSize, MibDbSize, NodeDbSize, TreeDbSize]).
lists_key1search([], Res) ->
Res;
@@ -7630,56 +7817,6 @@ lists_key1search(Key, List) when is_atom(Key) ->
%% ------
-join(Parts) ->
- filename:join(Parts).
-
-join(Dir, File) ->
- filename:join(Dir, File).
-
-
-%% ------
-
-rcall(Node, Mod, Func, Args) ->
- case rpc:call(Node, Mod, Func, Args) of
- {badrpc, nodedown} ->
- ?FAIL({rpc_failure, Node});
- Else ->
- Else
- end.
-
-
-%% ------
-
-%% e(F) ->
-%% e(F, []).
-
-e(F, A) ->
- p(user, "<ERROR> " ++ F, A),
- p(standard_io, "<ERROR> " ++ F, A).
-
-i(F) ->
- i(F, []).
-i(F, A) ->
- p(user, F, A),
- p(standard_io, F, A).
-
-p(F) ->
- p(F, []).
-
-p(Dev, F) when is_atom(Dev) ->
- p(Dev, F, []);
-p(F, A) ->
- p(standard_io, F, A).
-
-p(Dev, F, A) ->
- io:format(Dev,
- "*** [~s] ***"
- "~n" ++ F ++ "~n", [formated_timestamp()|A]).
-
-formated_timestamp() ->
- snmp_test_lib:formated_timestamp().
-
-
init_v1_agent(Config) ->
%% --
%% Start nodes
@@ -7750,9 +7887,7 @@ init_v1_agent(Config) ->
%% Create watchdog
%%
- Dog = ?WD_START(?MINS(1)),
-
- [{watchdog, Dog} | Config2].
+ wd_start(1, Config2).
fin_v1_agent(Config) ->
AgentNode = ?config(agent_node, Config),
@@ -7787,10 +7922,7 @@ fin_v1_agent(Config) ->
%%
stop_node(ManagerNode),
- Dog = ?config(watchdog, Config),
- ?WD_STOP(Dog),
- lists:keydelete(watchdog, 1, Config).
-
+ wd_stop(Config).
config_ipfamily(Config) ->
@@ -7800,3 +7932,25 @@ config_ipfamily(Config) ->
Value ->
Value
end.
+
+
+%% ------
+
+join(Parts) ->
+ filename:join(Parts).
+
+join(Dir, File) ->
+ filename:join(Dir, File).
+
+
+%% ------
+
+rcall(Node, Mod, Func, Args) ->
+ case rpc:call(Node, Mod, Func, Args) of
+ {badrpc, nodedown} ->
+ ?FAIL({rpc_failure, Node});
+ Else ->
+ Else
+ end.
+
+
diff --git a/lib/snmp/test/snmp_agent_conf_SUITE.erl b/lib/snmp/test/snmp_agent_conf_SUITE.erl
index 889af630a4..1f0ad3708b 100644
--- a/lib/snmp/test/snmp_agent_conf_SUITE.erl
+++ b/lib/snmp/test/snmp_agent_conf_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -101,7 +101,7 @@ init_per_testcase(_Case, Config) when is_list(Config) ->
Config.
end_per_testcase(_Case, Config) when is_list(Config) ->
- ?PRINT2("system events during test: "
+ ?IPRINT("system events during test: "
"~n ~p", [snmp_test_global_sys_monitor:events()]),
Config.
diff --git a/lib/snmp/test/snmp_agent_mibs_SUITE.erl b/lib/snmp/test/snmp_agent_mibs_SUITE.erl
index 9545dfdcc9..150e015554 100644
--- a/lib/snmp/test/snmp_agent_mibs_SUITE.erl
+++ b/lib/snmp/test/snmp_agent_mibs_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,6 +67,9 @@
]).
+-define(ALIB, snmp_agent_test_lib).
+
+
%%======================================================================
%% Common Test interface functions
%%======================================================================
@@ -166,27 +169,18 @@ init_per_testcase(Case, Config0) when is_list(Config0) ->
init_per_testcase2(size_check_ets2_bad_file1, Config) when is_list(Config) ->
DbDir = ?config(db_dir, Config),
- %% Create a ad file
+ %% Create a bad file
ok = file:write_file(join(DbDir, "snmpa_symbolic_store.db"),
"calvin and hoppes play chess"),
Config;
init_per_testcase2(size_check_ets3_bad_file1, Config) when is_list(Config) ->
DbDir = ?config(db_dir, Config),
- %% Create a ad file
+ %% Create a bad file
ok = file:write_file(join(DbDir, "snmpa_symbolic_store.db"),
"calvin and hoppes play chess"),
Config;
init_per_testcase2(size_check_mnesia, Config) when is_list(Config) ->
- DbDir = ?config(db_dir, Config),
- try
- begin
- mnesia_start([{dir, DbDir}]),
- Config
- end
- catch
- throw:{skip, _} = SKIP ->
- SKIP
- end;
+ Config;
init_per_testcase2(cache_test, Config) when is_list(Config) ->
Min = timer:minutes(5),
Timeout =
@@ -205,7 +199,7 @@ init_per_testcase2(_Case, Config) when is_list(Config) ->
end_per_testcase(Case, Config) when is_list(Config) ->
- ?PRINT2("system events during test: "
+ ?IPRINT("system events during test: "
"~n ~p", [snmp_test_global_sys_monitor:events()]),
end_per_testcase1(Case, Config).
@@ -301,7 +295,8 @@ size_check_ets1(suite) ->
[];
size_check_ets1(Config) when is_list(Config) ->
MibStorage = [{module, snmpa_mib_storage_ets}],
- do_size_check([{mib_storage, MibStorage}|Config]).
+ do_size_check(size_check_ets1,
+ [{mib_storage, MibStorage}|Config]).
size_check_ets2(suite) ->
[];
@@ -309,7 +304,8 @@ size_check_ets2(Config) when is_list(Config) ->
Dir = ?config(db_dir, Config),
MibStorage = [{module, snmpa_mib_storage_ets},
{options, [{dir, Dir}]}],
- do_size_check([{mib_storage, MibStorage}|Config]).
+ do_size_check(size_check_ets2,
+ [{mib_storage, MibStorage}|Config]).
size_check_ets2_bad_file1(suite) ->
[];
@@ -319,7 +315,8 @@ size_check_ets2_bad_file1(Config) when is_list(Config) ->
MibStorage = [{module, snmpa_mib_storage_ets},
{options, [{dir, Dir},
{action, clear}]}],
- do_size_check([{mib_storage, MibStorage}|Config]).
+ do_size_check(size_check_ets2_bad_file1,
+ [{mib_storage, MibStorage}|Config]).
size_check_ets3(suite) ->
[];
@@ -328,7 +325,8 @@ size_check_ets3(Config) when is_list(Config) ->
MibStorage = [{module, snmpa_mib_storage_ets},
{options, [{dir, Dir},
{checksum, true}]}],
- do_size_check([{mib_storage, MibStorage}|Config]).
+ do_size_check(size_check_ets3,
+ [{mib_storage, MibStorage}|Config]).
size_check_ets3_bad_file1(suite) ->
[];
@@ -339,7 +337,8 @@ size_check_ets3_bad_file1(Config) when is_list(Config) ->
{options, [{dir, Dir},
{action, clear},
{checksum, true}]}],
- do_size_check([{mib_storage, MibStorage}|Config]).
+ do_size_check(size_check_ets3_bad_file1,
+ [{mib_storage, MibStorage}|Config]).
size_check_dets(suite) ->
[];
@@ -347,18 +346,72 @@ size_check_dets(Config) when is_list(Config) ->
Dir = ?config(db_dir, Config),
MibStorage = [{module, snmpa_mib_storage_dets},
{options, [{dir, Dir}]}],
- do_size_check([{mib_storage, MibStorage}|Config]).
+ do_size_check(size_check_dets,
+ [{mib_storage, MibStorage}|Config]).
size_check_mnesia(suite) ->
[];
size_check_mnesia(Config) when is_list(Config) ->
MibStorage = [{module, snmpa_mib_storage_mnesia},
- {options, [{nodes, [node()]}]}],
- do_size_check([{mib_storage, MibStorage}|Config]).
+ {options, [{nodes, []}]}],
+ DbDir = ?config(db_dir, Config),
+ Init = fun() -> mnesia_start([{dir, DbDir}]), ok end,
+ do_size_check(size_check_mnesia,
+ Init,
+ [{mib_storage, MibStorage}|Config]).
+
+do_size_check(Name, Config) ->
+ Init = fun() -> ok end,
+ do_size_check(Name, Init, Config).
+
+do_size_check(Name, Init, Config) ->
+ Pre = fun() ->
+ {ok, Node} = ?ALIB:start_node(unique(Name)),
+ ok = run_on(Node, Init),
+ Node
+ end,
+ Case = fun(Node) ->
+ monitor_node(Node, true),
+ Pid = spawn_link(Node, fun() -> do_size_check(Config) end),
+ receive
+ {nodedown, Node} = N ->
+ exit(N);
+ {'EXIT', Pid, normal} ->
+ monitor_node(Node, false),
+ ok;
+ {'EXIT', Pid, ok} ->
+ monitor_node(Node, false),
+ ok;
+ {'EXIT', Pid, Reason} ->
+ monitor_node(Node, false),
+ exit(Reason)
+ end
+ end,
+ Post = fun({Node, _}) ->
+ ?STOP_NODE(Node)
+ end,
+ ?TC_TRY(Name, Pre, Case, Post).
+
+run_on(Node, F) when is_atom(Node) andalso is_function(F, 0) ->
+ monitor_node(Node, true),
+ Pid = spawn_link(Node, F),
+ receive
+ {nodedown, Node} = N ->
+ exit(N);
+ {'EXIT', Pid, normal} ->
+ monitor_node(Node, false),
+ ok;
+ {'EXIT', Pid, Reason} ->
+ monitor_node(Node, false),
+ Reason
+ end.
+
+unique(PreName) ->
+ list_to_atom(?F("~w_~w", [PreName, erlang:system_time(millisecond)])).
do_size_check(Config) ->
- ?DBG("do_size_check -> start with"
- "~n Config: ~p", [Config]),
+ ?IPRINT("do_size_check -> start with"
+ "~n Config: ~p", [Config]),
Prio = normal,
Verbosity = trace,
@@ -404,7 +457,7 @@ do_size_check(Config) ->
?DBG("do_size_check -> stop symbolic store", []),
?line sym_stop(),
- ?DBG("do_size_check -> done", []),
+ ?IPRINT("do_size_check -> done", []),
ok.
@@ -635,7 +688,7 @@ mnesia_start(Opts, Nodes) ->
%% We can accept mnesia beeing loaded but *not* started.
%% If its started it *may* contain data that will invalidate
%% this test case.
- ?PRINT2("mnesia_start -> try load mnesia when:"
+ ?IPRINT("mnesia_start -> try load mnesia when:"
"~n Loaded: ~p"
"~n Running: ~p", [apps_loaded(), apps_running()]),
?line ok = case application:load(mnesia) of
@@ -647,12 +700,12 @@ mnesia_start(Opts, Nodes) ->
ERROR
end,
F = fun({Key, Val}) ->
- ?PRINT2("mnesia_start -> try set mnesia env: "
+ ?IPRINT("mnesia_start -> try set mnesia env: "
"~n ~p -> ~p", [Key, Val]),
?line application_controller:set_env(mnesia, Key, Val)
end,
lists:foreach(F, Opts),
- ?PRINT2("mnesia_start -> create mnesia schema on ~p", [Nodes]),
+ ?IPRINT("mnesia_start -> create mnesia schema on ~p", [Nodes]),
?line case mnesia:create_schema(Nodes) of
ok ->
ok;
@@ -662,7 +715,7 @@ mnesia_start(Opts, Nodes) ->
throw({skip,
?F("Failed create mnesia schema: ~p", [SchemaReason])})
end,
- ?PRINT2("mnesia_start -> start mnesia", []),
+ ?IPRINT("mnesia_start -> start mnesia", []),
?line case application:start(mnesia) of
ok ->
ok;
@@ -672,19 +725,19 @@ mnesia_start(Opts, Nodes) ->
throw({skip,
?F("Failed starting mnesia: ~p", [StartReason])})
end,
- ?PRINT2("mnesia_start -> mnesia started", []),
+ ?IPRINT("mnesia_start -> mnesia started", []),
ok.
mnesia_stop() ->
- ?PRINT2("mnesia_stop -> try stop mnesia when:"
+ ?IPRINT("mnesia_stop -> try stop mnesia when:"
"~n Loaded: ~p"
"~n Running: ~p", [apps_loaded(), apps_running()]),
application:stop(mnesia),
- ?PRINT2("mnesia_stop -> try unload mnesia when"
+ ?IPRINT("mnesia_stop -> try unload mnesia when"
"~n Loaded: ~p"
"~n Running: ~p", [apps_loaded(), apps_running()]),
application:unload(mnesia),
- ?PRINT2("mnesia_stop -> done when:"
+ ?IPRINT("mnesia_stop -> done when:"
"~n Loaded: ~p"
"~n Running: ~p", [apps_loaded(), apps_running()]),
ok.
@@ -856,19 +909,19 @@ display_memory_usage(MibsPid) ->
MibDbSize = key1search([db_memory,mib], MibsInfo),
NodeDbSize = key1search([db_memory,node], MibsInfo),
TreeDbSize = key1search([db_memory,tree], MibsInfo),
- ?INF("Symbolic store memory usage: "
- "~n Process memory size: ~p"
- "~n Db size: ~p"
- "~n"
- "~nMib server memory usage: "
- "~n Tree size: ~p"
- "~n Process memory size: ~p"
- "~n Mib db size: ~p"
- "~n Node db size: ~p"
- "~n Tree db size: ~p"
- "~n",
- [SymProcSize, DbSize,
- TreeSize, MibsProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
+ ?IPRINT("Symbolic store memory usage: "
+ "~n Process memory size: ~p"
+ "~n Db size: ~p"
+ "~n"
+ "~nMib server memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p"
+ "~n",
+ [SymProcSize, DbSize,
+ TreeSize, MibsProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
key1search([], Res) ->
Res;
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
index c0da47dc4c..6a4c582f36 100644
--- a/lib/snmp/test/snmp_agent_test_lib.erl
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -122,8 +122,8 @@
init_all(Config) when is_list(Config) ->
- ?LOG("init_all -> entry with"
- "~n Config: ~p",[Config]),
+ ?IPRINT("init_all -> entry with"
+ "~n Config: ~p",[Config]),
%% --
%% Start nodes
@@ -300,7 +300,7 @@ try_test(TcRunMod, TcRunFunc, TcRunArgs, TcRunOpts) ->
%% process as well.
tc_try(N, M, F, A) ->
- ?PRINT2("tc_try -> entry with"
+ ?IPRINT("tc_try -> entry with"
"~n N: ~p"
"~n M: ~p"
"~n F: ~p"
@@ -312,32 +312,32 @@ tc_try(N, M, F, A) ->
get()]),
case net_adm:ping(N) of
pong ->
- ?PRINT2("tc_try -> ~p still running - start runner~n", [N]),
+ ?IPRINT("tc_try -> ~p still running - start runner~n", [N]),
OldFlag = trap_exit(true), % Make sure we catch it
Runner = spawn_link(N, ?MODULE, tc_wait, [self(), get(), M, F, A]),
await_tc_runner_started(Runner, OldFlag),
await_tc_runner_done(Runner, OldFlag);
pang ->
- ?EPRINT2("tc_try -> ~p *not* running~n", [N]),
+ ?WPRINT("tc_try -> ~p *not* running~n", [N]),
skip({node_not_running, N})
end.
await_tc_runner_started(Runner, OldFlag) ->
- ?PRINT2("await tc-runner (~p) start ack~n", [Runner]),
+ ?IPRINT("await tc-runner (~p) start ack~n", [Runner]),
receive
{'EXIT', Runner, Reason} ->
- ?EPRINT2("TC runner start failed: "
- "~n ~p~n", [Reason]),
+ ?EPRINT("TC runner start failed: "
+ "~n ~p~n", [Reason]),
exit({tx_runner_start_failed, Reason});
{tc_runner_started, Runner} ->
- ?PRINT2("TC runner start acknowledged~n"),
+ ?IPRINT("TC runner start acknowledged~n"),
ok
after 10000 -> %% We should *really* not have to wait this long, but...
trap_exit(OldFlag),
unlink_and_flush_exit(Runner),
- RunnerInfo = process_info(Runner),
- ?EPRINT2("TC runner start timeout: "
- "~n ~p", [RunnerInfo]),
+ RunnerInfo = ?PINFO(Runner),
+ ?EPRINT("TC runner start timeout: "
+ "~n ~p", [RunnerInfo]),
%% If we don't get a start ack within 10 seconds, we are f*ed
exit(Runner, kill),
exit({tc_runner_start, timeout, RunnerInfo})
@@ -352,18 +352,18 @@ await_tc_runner_done(Runner, OldFlag) ->
SysEvs = snmp_test_global_sys_monitor:events(),
if
(SysEvs =:= []) ->
- ?EPRINT2("TC runner failed: "
- "~n ~p~n", [Reason]),
+ ?EPRINT("TC runner failed: "
+ "~n ~p~n", [Reason]),
exit({tx_runner_failed, Reason});
true ->
- ?EPRINT2("TC runner failed when we got system events: "
- "~n Reason: ~p"
- "~n Sys Events: ~p"
- "~n", [Reason, SysEvs]),
+ ?WPRINT("TC runner failed when we got system events: "
+ "~n Reason: ~p"
+ "~n Sys Events: ~p"
+ "~n", [Reason, SysEvs]),
skip([{reason, Reason}, {system_events, SysEvs}])
end;
{tc_runner_done, Runner, {'EXIT', {skip, Reason}}, Loc} ->
- ?PRINT2("call -> done with skip: "
+ ?WPRINT("call -> done with skip: "
"~n Reason: ~p"
"~n Loc: ~p"
"~n", [Reason, Loc]),
@@ -372,7 +372,7 @@ await_tc_runner_done(Runner, OldFlag) ->
put(test_server_loc, Loc),
skip(Reason);
{tc_runner_done, Runner, {'EXIT', Rn}, Loc} ->
- ?PRINT2("call -> done with exit: "
+ ?EPRINT("call -> done with exit: "
"~n Rn: ~p"
"~n Loc: ~p"
"~n", [Rn, Loc]),
@@ -409,7 +409,7 @@ unlink_and_flush_exit(Pid) ->
end.
tc_wait(From, Env, M, F, A) ->
- ?PRINT2("tc_wait -> entry with"
+ ?IPRINT("tc_wait -> entry with"
"~n From: ~p"
"~n Env: ~p"
"~n M: ~p"
@@ -417,9 +417,9 @@ tc_wait(From, Env, M, F, A) ->
"~n A: ~p", [From, Env, M, F, A]),
From ! {tc_runner_started, self()},
lists:foreach(fun({K,V}) -> put(K,V) end, Env),
- ?PRINT2("tc_wait -> env set - now run tc~n"),
+ ?IPRINT("tc_wait -> env set - now run tc~n"),
Res = (catch apply(M, F, A)),
- ?PRINT2("tc_wait -> tc run done: "
+ ?IPRINT("tc_wait -> tc run done: "
"~n ~p"
"~n", [Res]),
From ! {tc_runner_done, self(), Res, get(test_server_loc)},
@@ -437,7 +437,7 @@ tc_wait(From, Env, M, F, A) ->
end.
tc_run(Mod, Func, Args, Opts) ->
- ?PRINT2("tc_run -> entry with"
+ ?IPRINT("tc_run -> entry with"
"~n Mod: ~p"
"~n Func: ~p"
"~n Args: ~p"
@@ -456,7 +456,7 @@ tc_run(Mod, Func, Args, Opts) ->
?DBG("tc_run -> Crypto: ~p", [_CryptoRes]),
StdM = join(code:priv_dir(snmp), "mibs") ++ "/",
Vsn = get(vsn),
- ?PRINT2("tc_run -> config:"
+ ?IPRINT("tc_run -> config:"
"~n M: ~p"
"~n Vsn: ~p"
"~n Dir: ~p"
@@ -469,7 +469,7 @@ tc_run(Mod, Func, Args, Opts) ->
"~n", [M,Vsn,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
{packet_server_debug, true},
- {debug, true},
+ {debug, false},
{agent, get(master_host)},
{ipfamily, get(ipfamily)},
{agent_udp, 4000},
@@ -487,7 +487,7 @@ tc_run(Mod, Func, Args, Opts) ->
{ok, _Pid} ->
case (catch apply(Mod, Func, Args)) of
{'EXIT', {skip, Reason}} ->
- ?EPRINT2("apply skip detected: "
+ ?WPRINT("apply skip detected: "
"~n ~p", [Reason]),
(catch snmp_test_mgr:stop()),
?SKIP(Reason);
@@ -500,11 +500,11 @@ tc_run(Mod, Func, Args, Opts) ->
(catch snmp_test_mgr:stop()),
if
(SysEvs =:= []) ->
- ?EPRINT2("TC runner failed: "
- "~n ~p~n", [Reason]),
+ ?EPRINT("TC runner failed: "
+ "~n ~p~n", [Reason]),
?FAIL({apply_failed, {Mod, Func, Args}, Reason});
true ->
- ?EPRINT2("apply exit catched when we got system events: "
+ ?WPRINT("apply exit catched when we got system events: "
"~n Reason: ~p"
"~n Sys Events: ~p"
"~n", [Reason, SysEvs]),
@@ -516,14 +516,14 @@ tc_run(Mod, Func, Args, Opts) ->
end;
{error, Reason} ->
- ?EPRINT2("Failed starting (test) manager: "
- "~n ~p", [Reason]),
+ ?EPRINT("Failed starting (test) manager: "
+ "~n ~p", [Reason]),
(catch snmp_test_mgr:stop()),
?line ?FAIL({mgr_start_error, Reason});
Err ->
- ?EPRINT2("Failed starting (test) manager: "
- "~n ~p", [Err]),
+ ?EPRINT("Failed starting (test) manager: "
+ "~n ~p", [Err]),
(catch snmp_test_mgr:stop()),
?line ?FAIL({mgr_start_failure, Err})
end.
@@ -570,10 +570,10 @@ start_agent(Config, Vsns) ->
start_agent(Config, Vsns, []).
start_agent(Config, Vsns, Opts) ->
- ?LOG("start_agent -> entry (~p) with"
- "~n Config: ~p"
- "~n Vsns: ~p"
- "~n Opts: ~p", [node(), Config, Vsns, Opts]),
+ ?IPRINT("start_agent -> entry (~p) with"
+ "~n Config: ~p"
+ "~n Vsns: ~p"
+ "~n Opts: ~p", [node(), Config, Vsns, Opts]),
?line AgentLogDir = ?config(agent_log_dir, Config),
?line AgentConfDir = ?config(agent_conf_dir, Config),
@@ -603,17 +603,17 @@ start_agent(Config, Vsns, Opts) ->
process_flag(trap_exit,true),
- ?PRINT2("start_agent -> try start snmp app supervisor", []),
+ ?IPRINT("start_agent -> try start snmp app supervisor", []),
{ok, AppSup} = snmp_app_sup:start_link(),
unlink(AppSup),
?DBG("start_agent -> snmp app supervisor: ~p", [AppSup]),
- ?PRINT2("start_agent -> try start master agent",[]),
+ ?IPRINT("start_agent -> try start master agent",[]),
?line Sup = start_sup(Env),
?line unlink(Sup),
?DBG("start_agent -> snmp supervisor: ~p", [Sup]),
- ?PRINT2("start_agent -> try (rpc) start sub agent on ~p", [SaNode]),
+ ?IPRINT("start_agent -> try (rpc) start sub agent on ~p", [SaNode]),
?line SaDir = ?config(sa_dir, Config),
?line {ok, Sub} = start_sub_sup(SaNode, SaDir),
?DBG("start_agent -> done", []),
@@ -813,36 +813,33 @@ merge_agent_options([{Key, _Value} = Opt|Opts], Options) ->
stop_agent(Config) when is_list(Config) ->
- ?PRINT2("stop_agent -> entry with"
+ ?IPRINT("stop_agent -> entry with"
"~n Config: ~p",[Config]),
%% Stop the sub-agent (the agent supervisor)
{SubSup, SubPar} = ?config(snmp_sub, Config),
- ?PRINT2("stop_agent -> attempt to stop sub agent (~p)"
+ ?IPRINT("stop_agent -> attempt to stop sub agent (~p)"
"~n Sub Sup info: "
"~n ~p"
"~n Sub Par info: "
"~n ~p",
- [SubSup,
- (catch process_info(SubSup)),
- (catch process_info(SubPar))]),
+ [SubSup, ?PINFO(SubSup), ?PINFO(SubPar)]),
stop_sup(SubSup, SubPar),
Config2 = lists:keydelete(snmp_sub, 1, Config),
%% Stop the master-agent (the top agent supervisor)
{MasterSup, MasterPar} = ?config(snmp_sup, Config),
- ?PRINT2("stop_agent -> attempt to stop master agent (~p)"
+ ?IPRINT("stop_agent -> attempt to stop master agent (~p)"
"~n Master Sup: "
"~n ~p"
"~n Master Par: "
"~n ~p"
"~n Agent Info: "
"~n ~p",
- [MasterSup,
- (catch process_info(MasterSup)),
- (catch process_info(MasterPar)),
+ [MasterSup,
+ ?PINFO(MasterSup), ?PINFO(MasterPar),
agent_info(MasterSup)]),
stop_sup(MasterSup, MasterPar),
Config3 = lists:keydelete(snmp_sup, 1, Config2),
@@ -850,25 +847,24 @@ stop_agent(Config) when is_list(Config) ->
%% Stop the top supervisor (of the snmp app)
AppSup = ?config(snmp_app_sup, Config),
- ?PRINT2("stop_agent -> attempt to app sup ~p"
+ ?IPRINT("stop_agent -> attempt to app sup ~p"
"~n App Sup: ~p",
- [AppSup,
- (catch process_info(AppSup))]),
+ [AppSup, ?PINFO(AppSup)]),
Config4 = lists:keydelete(snmp_app_sup, 1, Config3),
- ?PRINT2("stop_agent -> done", []),
+ ?IPRINT("stop_agent -> done", []),
Config4.
start_sup(Env) ->
case (catch snmp_app_sup:start_agent(normal, Env)) of
{ok, S} ->
- ?DBG("start_agent -> started, Sup: ~p",[S]),
+ ?DBG("start_agent -> started, Sup: ~p", [S]),
S;
Else ->
- ?DBG("start_agent -> unknown result: ~n~p",[Else]),
+ ?EPRINT("start_agent -> unknown result: ~n~p", [Else]),
%% Get info about the apps we depend on
?FAIL({start_failed, Else, ?IS_MNESIA_RUNNING()})
end.
@@ -876,18 +872,18 @@ start_sup(Env) ->
stop_sup(Pid, _) when (node(Pid) =:= node()) ->
case (catch process_info(Pid)) of
PI when is_list(PI) ->
- ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ ?IPRINT("stop_sup -> attempt to stop ~p", [Pid]),
Ref = erlang:monitor(process, Pid),
exit(Pid, kill),
await_stopped(Pid, Ref);
{'EXIT', _Reason} ->
- ?LOG("stop_sup -> ~p not running", [Pid]),
+ ?IPRINT("stop_sup -> ~p not running", [Pid]),
ok
end;
stop_sup(Pid, _) ->
- ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ ?IPRINT("stop_sup -> attempt to stop ~p", [Pid]),
Ref = erlang:monitor(process, Pid),
- ?LOG("stop_sup -> Ref: ~p", [Ref]),
+ ?IPRINT("stop_sup -> Ref: ~p", [Ref]),
exit(Pid, kill),
await_stopped(Pid, Ref).
@@ -897,7 +893,7 @@ await_stopped(Pid, Ref) ->
?DBG("received down message for ~p", [Pid]),
ok
after 10000 ->
- ?INF("await_stopped -> timeout for ~p",[Pid]),
+ ?EPRINT("await_stopped -> timeout for ~p",[Pid]),
erlang:demonitor(Ref),
?FAIL({failed_stop,Pid})
end.
@@ -1076,7 +1072,7 @@ io_format_expect(F) ->
io_format_expect(F, []).
io_format_expect(F, A) ->
- ?PRINT2("EXPECT " ++ F, A).
+ ?IPRINT("EXPECT " ++ F, A).
do_expect(Expect) when is_atom(Expect) ->
@@ -1518,7 +1514,7 @@ get_req(Id, Vars) ->
get_next_req(Vars) ->
?DBG("get_next_req -> entry with"
- "~n Vars: ~p",[Vars]),
+ "~n Vars: ~p", [Vars]),
snmp_test_mgr:gn(Vars),
?DBG("get_next_req -> await response",[]),
Response = snmp_test_mgr:receive_response(),
@@ -1529,42 +1525,37 @@ get_next_req(Vars) ->
%% --- start and stop nodes ---
start_node(Name) ->
- ?LOG("start_node -> entry with"
- "~n Name: ~p"
- "~n when"
- "~n hostname of this node: ~p",
- [Name, list_to_atom(?HOSTNAME(node()))]),
+ ?IPRINT("start_node -> entry with"
+ "~n Name: ~p"
+ "~n when"
+ "~n hostname of this node: ~p",
+ [Name, list_to_atom(?HOSTNAME(node()))]),
+
Pa = filename:dirname(code:which(?MODULE)),
- ?DBG("start_node -> Pa: ~p",[Pa]),
-
- Args = case init:get_argument('CC_TEST') of
- {ok, [[]]} ->
- " -pa /clearcase/otp/libraries/snmp/ebin ";
- {ok, [[Path]]} ->
- " -pa " ++ Path;
- error ->
- ""
- end,
- %% Do not use start_link!!! (the proc that calls this one is tmp)
- ?DBG("start_node -> Args: ~p~n", [Args]),
- A = Args ++ " -pa " ++ Pa ++
+ ?DBG("start_node -> Pa: ~p", [Pa]),
+
+ A = " -pa " ++ Pa ++
" -s " ++ atom_to_list(snmp_test_sys_monitor) ++ " start" ++
" -s global sync",
- case (catch ?START_NODE(Name, A)) of
+ case ?START_NODE(Name, A) of
{ok, Node} ->
- %% Tell the test_server to not clean up things it never started.
- ?DBG("start_node -> Node: ~p",[Node]),
+ ?DBG("start_node -> Node: ~p", [Node]),
global:sync(),
{ok, Node};
+ {error, Reason} ->
+ ?WPRINT("start_node -> failed starting node ~p:"
+ "~n Reason: ~p", [Name, Reason]),
+ ?line ?SKIP({failed_start_node, Reason});
Else ->
- ?ERR("start_node -> failed with(other): Else: ~p",[Else]),
+ ?EPRINT("start_node -> failed starting node ~p:"
+ "~n ~p", [Name, Else]),
?line ?FAIL(Else)
end.
stop_node(Node) ->
- ?LOG("stop_node -> Node: ~p",[Node]),
- rpc:cast(Node, erlang, halt, []).
+ ?IPRINT("stop_node -> Node: ~p", [Node]),
+ ?STOP_NODE(Node).
%%%-----------------------------------------------------------------
@@ -1575,14 +1566,14 @@ config(Vsns, MgrDir, AgentConfDir, MIp, AIp) ->
config(Vsns, MgrDir, AgentConfDir, MIp, AIp, inet).
config(Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily) ->
- ?LOG("config -> entry with"
- "~n Vsns: ~p"
- "~n MgrDir: ~p"
- "~n AgentConfDir: ~p"
- "~n MIp: ~p"
- "~n AIp: ~p"
- "~n IpFamily: ~p",
- [Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily]),
+ ?IPRINT("config -> entry with"
+ "~n Vsns: ~p"
+ "~n MgrDir: ~p"
+ "~n AgentConfDir: ~p"
+ "~n MIp: ~p"
+ "~n AIp: ~p"
+ "~n IpFamily: ~p",
+ [Vsns, MgrDir, AgentConfDir, MIp, AIp, IpFamily]),
?line {Domain, ManagerAddr} =
case IpFamily of
inet6 ->
@@ -1753,8 +1744,8 @@ rewrite_target_addr_conf(Dir, NewPort) ->
{ok, _} ->
ok;
{error, _R} ->
- ?ERR("failure reading file info of "
- "target address config file: ~p", [_R]),
+ ?WPRINT("failure reading file info of "
+ "target address config file: ~p", [_R]),
ok
end,
@@ -1778,10 +1769,10 @@ rewrite_target_addr_conf_check(O) ->
rewrite_target_addr_conf2(NewPort,
{Name, Ip, _Port, Timeout, Retry,
"std_trap", EngineId}) ->
- ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]),
+ ?IPRINT("rewrite_target_addr_conf2 -> entry with std_trap",[]),
{Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId};
rewrite_target_addr_conf2(_NewPort,O) ->
- ?LOG("rewrite_target_addr_conf2 -> entry with "
+ ?IPRINT("rewrite_target_addr_conf2 -> entry with "
"~n O: ~p",[O]),
O.
@@ -1835,12 +1826,12 @@ display_memory_usage() ->
MibDbSize = key1search([db_memory,mib], Info),
NodeDbSize = key1search([db_memory,node], Info),
TreeDbSize = key1search([db_memory,tree], Info),
- ?INF("Memory usage: "
- "~n Tree size: ~p"
- "~n Process memory size: ~p"
- "~n Mib db size: ~p"
- "~n Node db size: ~p"
- "~n Tree db size: ~p",
+ ?IPRINT("Memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p",
[TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
key1search([], Res) ->
@@ -1876,51 +1867,3 @@ join(Dir, File) ->
skip(R) ->
exit({skip, R}).
-%% await_pdu(To) ->
-%% await_response(To, pdu).
-%%
-%% await_trap(To) ->
-%% await_response(To, trap).
-%%
-%% await_any(To) ->
-%% await_response(To, any).
-%%
-%%
-%% await_response(To, What) ->
-%% await_response(To, What, []).
-%%
-%% await_response(To, What, Stuff) when is_integer(To) andalso (To >= 0) ->
-%% T = t(),
-%% receive
-%% {snmp_pdu, PDU} when is_record(Trap, pdu) andalso (What =:= pdu) ->
-%% {ok, PDU};
-%% {snmp_pdu, Trap} is_when record(Trap, trappdu) andalso (What =:= trap) ->
-%% {ok, Trap};
-%% Any when What =:= any ->
-%% {ok, Any};
-%% Any ->
-%% %% Recalc time
-%% NewTo = To - (t() - T)
-%% await_reponse(NewTo, What, [{NewTo, Any}|Stuff])
-%% after To ->
-%% {error, {timeout, Stuff}}
-%% end;
-%% await_response(_, Stuff) ->
-%% {error, {timeout, Stuff}}.
-%%
-%%
-%% t() ->
-%% {A,B,C} = os:timestamp(),
-%% A*1000000000+B*1000+(C div 1000).
-%%
-%%
-%% timeout() ->
-%% timeout(os:type()).
-%%
-%% timeout(_) -> 3500.
-
-
-%% Time in milli seconds
-%% t() ->
-%% {A,B,C} = os:timestamp(),
-%% A*1000000000+B*1000+(C div 1000).
diff --git a/lib/snmp/test/snmp_compiler_SUITE.erl b/lib/snmp/test/snmp_compiler_SUITE.erl
index aeb055742e..f4ba914919 100644
--- a/lib/snmp/test/snmp_compiler_SUITE.erl
+++ b/lib/snmp/test/snmp_compiler_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -106,26 +106,48 @@ tickets_cases() ->
init_per_suite(Config0) when is_list(Config0) ->
- ?DBG("init_per_suite -> entry with"
- "~n Config0: ~p", [Config0]),
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config0, erlang:nodes()]),
- Config1 = snmp_test_lib:init_suite_top_dir(?MODULE, Config0),
- Config2 = snmp_test_lib:fix_data_dir(Config1),
+ case ?LIB:init_per_suite(Config0) of
+ {skip, _} = SKIP ->
+ SKIP;
- %% Mib-dirs
- %% data_dir is trashed by the test-server / common-test
- %% so there is no point in fixing it...
- MibDir = snmp_test_lib:lookup(data_dir, Config2),
- StdMibDir = filename:join([code:priv_dir(snmp), "mibs"]),
+ Config1 when is_list(Config1) ->
+ Config2 = snmp_test_lib:init_suite_top_dir(?MODULE, Config1),
+ Config3 = snmp_test_lib:fix_data_dir(Config2),
- [{mib_dir, MibDir}, {std_mib_dir, StdMibDir} | Config2].
+ %% Mib-dirs
+ %% data_dir is trashed by the test-server / common-test
+ %% so there is no point in fixing it...
+ MibDir = snmp_test_lib:lookup(data_dir, Config3),
+ StdMibDir = filename:join([code:priv_dir(snmp), "mibs"]),
-end_per_suite(Config) when is_list(Config) ->
+ Config4 = [{mib_dir, MibDir}, {std_mib_dir, StdMibDir} | Config3],
+
+ %% We need a monitor on this node also
+ snmp_test_sys_monitor:start(),
- ?DBG("end_per_suite -> entry with"
- "~n Config: ~p", [Config]),
+ snmp_test_mgr_counter_server:start(),
- Config.
+ ?IPRINT("init_per_suite -> end when"
+ "~n Config: ~p", [Config4]),
+
+ Config4
+ end.
+
+
+end_per_suite(Config0) when is_list(Config0) ->
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
+
+ snmp_test_sys_monitor:stop(),
+ Config1 = ?LIB:end_per_suite(Config0),
+
+ ?IPRINT("end_per_suite -> end"),
+
+ Config1.
%%
@@ -165,7 +187,8 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
description(suite) -> [];
description(Config) when is_list(Config) ->
put(tname,desc),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
Filename = join(Dir,"test"),
@@ -179,14 +202,14 @@ description(Config) when is_list(Config) ->
{warnings, false},
{description, false}]),
MIB1 = read_mib(MibBinName),
- %% io:format("description -> MIB1: ~n~p~n", [MIB1]),
+ %% ?IPRINT("description -> MIB1: ~n~p~n", [MIB1]),
check_mib(MIB1#mib.mes, Oid, undefined),
?line {ok,_} = snmpc:compile(MibSrcName, [{outdir, Dir},
{group_check, false},
{warnings, false},
{description, true}]),
MIB2 = read_mib(MibBinName),
- %% io:format("description -> MIB2: ~n~p~n", [MIB2]),
+ %% ?IPRINT("description -> MIB2: ~n~p~n", [MIB2]),
check_mib(MIB2#mib.mes, Oid, Desctext),
%% Cleanup
@@ -200,7 +223,8 @@ description(Config) when is_list(Config) ->
oid_conflicts(suite) -> [];
oid_conflicts(Config) when is_list(Config) ->
put(tname,oid_conflicts),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
Mib = join(Dir,"TESTv2.mib"),
@@ -232,7 +256,8 @@ agent_capabilities(suite) ->
[];
agent_capabilities(Config) when is_list(Config) ->
put(tname,agent_capabilities),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
SnmpPrivDir = which_priv_dir(snmp),
SnmpMibsDir = join(SnmpPrivDir, "mibs"),
@@ -253,11 +278,10 @@ agent_capabilities(Config) when is_list(Config) ->
?line {ok, Mib2} = snmp_misc:read_mib(MibFile2),
MEDiff = Mib2#mib.mes -- Mib1#mib.mes,
%% This is a rather pathetic test, but it is somthing...
- io:format("agent_capabilities -> "
- "~n MEDiff: ~p"
- "~n Mib1: ~p"
- "~n Mib2: ~p"
- "~n", [MEDiff, Mib1, Mib2]),
+ ?IPRINT("agent_capabilities -> "
+ "~n MEDiff: ~p"
+ "~n Mib1: ~p"
+ "~n Mib2: ~p", [MEDiff, Mib1, Mib2]),
case length(MEDiff) of
2 ->
ok;
@@ -272,8 +296,9 @@ agent_capabilities(Config) when is_list(Config) ->
module_compliance(suite) ->
[];
module_compliance(Config) when is_list(Config) ->
- put(tname,module_compliance),
- p("starting with Config: ~p~n", [Config]),
+ put(tname, module_compliance),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
SnmpPrivDir = which_priv_dir(snmp),
SnmpMibsDir = join(SnmpPrivDir, "mibs"),
@@ -294,11 +319,10 @@ module_compliance(Config) when is_list(Config) ->
?line {ok, Mib2} = snmp_misc:read_mib(MibFile2),
MEDiff = Mib2#mib.mes -- Mib1#mib.mes,
%% This is a rather pathetic test, but it is somthing...
- io:format("module_compliance -> "
- "~n MEDiff: ~p"
- "~n Mib1: ~p"
- "~n Mib2: ~p"
- "~n", [MEDiff, Mib1, Mib2]),
+ ?IPRINT("module_compliance -> "
+ "~n MEDiff: ~p"
+ "~n Mib1: ~p"
+ "~n Mib2: ~p", [MEDiff, Mib1, Mib2]),
case length(MEDiff) of
1 ->
ok;
@@ -314,7 +338,8 @@ warnings_as_errors(suite) ->
["OTP-9437"];
warnings_as_errors(Config) when is_list(Config) ->
put(tname,warnings_as_errors),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
MibFile = join(MibDir, "OTP8574-MIB.mib"),
@@ -338,14 +363,16 @@ otp_6150(suite) ->
[];
otp_6150(Config) when is_list(Config) ->
put(tname, otp6150),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
MibFile = join(MibDir, "ERICSSON-TOP-MIB.mib"),
?line {ok, Mib} =
snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]),
- io:format("otp_6150 -> Mib: ~n~p~n", [Mib]),
+ ?IPRINT("otp_6150 -> Mib: "
+ "~n ~p", [Mib]),
ok.
@@ -355,29 +382,30 @@ otp_8574(suite) ->
[];
otp_8574(Config) when is_list(Config) ->
put(tname, otp8574),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
MibFile = join(MibDir, "OTP8574-MIB.mib"),
- p("ensure compile fail without relaxed assign check"),
+ ?IPRINT("ensure compile fail without relaxed assign check"),
case snmpc:compile(MibFile, [{group_check, false}, {outdir, Dir}]) of
{error, compilation_failed} ->
- p("with relaxed assign check MIB compiles with warning"),
+ ?IPRINT("with relaxed assign check MIB compiles with warning"),
case snmpc:compile(MibFile, [{group_check, false},
{outdir, Dir},
relaxed_row_name_assign_check]) of
{ok, _Mib} ->
ok;
{error, Reason} ->
- p("unexpected compile failure: "
- "~n Reason: ~p", [Reason]),
+ ?EPRINT("unexpected compile failure: "
+ "~n Reason: ~p", [Reason]),
exit({unexpected_compile_failure, Reason})
end;
{ok, _} ->
- p("unexpected compile success"),
+ ?EPRINT("unexpected compile success"),
exit(unexpected_compile_success)
end.
@@ -388,7 +416,8 @@ otp_8595(suite) ->
[];
otp_8595(Config) when is_list(Config) ->
put(tname, otp8595),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
@@ -397,7 +426,7 @@ otp_8595(Config) when is_list(Config) ->
snmpc:compile(MibFile, [{outdir, Dir},
{verbosity, trace},
{group_check, false}]),
- p("Mib: ~n~p~n", [Mib]),
+ ?IPRINT("Mib: ~n~p~n", [Mib]),
ok.
@@ -407,14 +436,16 @@ otp_10799(suite) ->
[];
otp_10799(Config) when is_list(Config) ->
put(tname, otp10799),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
MibFile = join(MibDir, "OTP10799-MIB.mib"),
?line {ok, Mib} =
snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]),
- p("Mib: ~n~p~n", [Mib]),
+ ?IPRINT("Mib: "
+ "~n ~p", [Mib]),
ok.
@@ -424,7 +455,8 @@ otp_10808(suite) ->
[];
otp_10808(Config) when is_list(Config) ->
put(tname, otp10808),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
@@ -433,7 +465,8 @@ otp_10808(Config) when is_list(Config) ->
snmpc:compile(MibFile, [{outdir, Dir},
{verbosity, trace},
{group_check, false}]),
- p("Mib: ~n~p~n", [Mib]),
+ ?IPRINT("Mib: "
+ "~n ~p", [Mib]),
ok.
@@ -443,7 +476,8 @@ otp_14145(suite) ->
[];
otp_14145(Config) when is_list(Config) ->
put(tname, otp14145),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
@@ -454,7 +488,8 @@ otp_14145(Config) when is_list(Config) ->
{verbosity, trace},
{group_check, false},
module_compliance]),
- p("Mib: ~n~p~n", [MibBin]),
+ ?IPRINT("Mib: "
+ "~n ~p", [MibBin]),
MIB = read_mib(MibBin),
Oid = [1,3,6,1,2,1,67,4],
check_mib(MIB#mib.mes, Oid, undefined),
@@ -467,7 +502,8 @@ otp_13014(suite) ->
[];
otp_13014(Config) when is_list(Config) ->
put(tname, otp13014),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
@@ -478,7 +514,8 @@ otp_13014(Config) when is_list(Config) ->
{verbosity, log},
{group_check, false},
module_compliance]),
- p("Mib: ~n~p~n", [MibBin]),
+ ?IPRINT("Mib: "
+ "~n ~p", [MibBin]),
#mib{mes = MEs} = read_mib(MibBin),
Oid = [1,0,8802,1,1,2,1,1,7],
#me{
@@ -494,20 +531,23 @@ otp_13014(Config) when is_list(Config) ->
TableInfo,
ok.
+
%%======================================================================
otp_14196(suite) ->
[];
otp_14196(Config) when is_list(Config) ->
put(tname, otp14196),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
MibFile = join(MibDir, "OTP14196-MIB.mib"),
?line {ok, Mib} =
snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]),
- p("Mib: ~n~p~n", [Mib]),
+ ?IPRINT("Mib: "
+ "~n ~p", [Mib]),
ok.
@@ -517,7 +557,8 @@ augments_extra_info(suite) ->
[];
augments_extra_info(Config) when is_list(Config) ->
put(tname, augments_extra_info),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Dir = ?config(case_top_dir, Config),
MibDir = ?config(mib_dir, Config),
@@ -527,28 +568,30 @@ augments_extra_info(Config) when is_list(Config) ->
snmpc:compile(Test2File, [{outdir, Dir},
{verbosity, silence},
{group_check, false}]),
- io:format("Test2BinFile: ~n~p~n", [Test2BinFile]),
+ ?IPRINT("Test2BinFile: "
+ "~n ~p", [Test2BinFile]),
?line {ok, Test3BinFile} =
snmpc:compile(Test3File, [{i, [MibDir]},
{outdir, Dir},
{verbosity, silence},
{group_check, true}]),
- io:format("Test3BinFile: ~n~p~n", [Test3BinFile]),
+ ?IPRINT("Test3BinFile: "
+ "~n ~p", [Test3BinFile]),
{ok, Test3Mib} = snmp_misc:read_mib(Test3BinFile),
- io:format("Test3Mib: ~n~p~n", [Test3Mib]),
+ ?IPRINT("Test3Mib: "
+ "~n ~p", [Test3Mib]),
%% There is only one table in this mib
#mib{table_infos = [{TableName, TI}]} = Test3Mib,
- io:format("TableName: ~p"
- "~n Table Info: ~p"
- "~n", [TableName, TI]),
+ ?IPRINT("TableName: ~p"
+ "~n Table Info: ~p", [TableName, TI]),
#table_info{nbr_of_cols = 4,
defvals = DefVals,
not_accessible = [2,4],
index_types = {augments, {tEntry, undefined}},
first_accessible = 1} = TI,
- io:format("Table info: ~p"
- "~n DefVals: ~p"
- "~n", [TableName, DefVals]),
+ ?IPRINT("Table info: ~p"
+ "~n DefVals: ~p"
+ "~n", [TableName, DefVals]),
ok.
@@ -750,21 +793,3 @@ which_priv_dir(App) ->
join(A,B) ->
filename:join(A,B).
-
-%% ------
-
-%% p(F) ->
-%% p(F, []).
-
-p(F) ->
- p(F, []).
-
-p(F, A) ->
- p(get(tname), F, A).
-
-p(TName, F, A) ->
- io:format("*** [~w][~s] ***"
- "~n" ++ F ++ "~n", [TName, formated_timestamp()|A]).
-
-formated_timestamp() ->
- snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_conf_SUITE.erl b/lib/snmp/test/snmp_conf_SUITE.erl
index bd8375b400..7d60485060 100644
--- a/lib/snmp/test/snmp_conf_SUITE.erl
+++ b/lib/snmp/test/snmp_conf_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -97,11 +97,34 @@ groups() ->
%% -----
%%
-init_per_suite(Config) when is_list(Config) ->
- Config.
+init_per_suite(Config0) when is_list(Config0) ->
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
-end_per_suite(Config) when is_list(Config) ->
- Config.
+ case ?LIB:init_per_suite(Config0) of
+ {skip, _} = SKIP ->
+ SKIP;
+
+ Config1 when is_list(Config1) ->
+ %% We need a monitor on this node also
+ snmp_test_sys_monitor:start(),
+
+ ?IPRINT("init_per_suite -> end when"
+ "~n Config: ~p", [Config1]),
+
+ Config1
+ end.
+
+end_per_suite(Config0) when is_list(Config0) ->
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
+
+ snmp_test_sys_monitor:stop(),
+ Config1 = ?LIB:end_per_suite(Config0),
+
+ ?IPRINT("end_per_suite -> end"),
+
+ Config1.
@@ -136,7 +159,7 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
check_mandatory(suite) -> [];
check_mandatory(Config) when is_list(Config) ->
?P(check_mandatory),
- %% d("check_mandatory -> entry"),
+ %% ?IPRINT("check_mandatory -> entry"),
A1 = [{a, hej}, {b, hopp}, {c, 10}, {d, 10101}, {f, 10.88}],
B1 = [{a, {value, hejsan}},
{b, mandatory},
@@ -696,8 +719,3 @@ read_files(Config) when is_list(Config) ->
%% Internal functions
%%======================================================================
-% d(F) ->
-% d(F, []).
-
-% d(F, A) ->
-% io:format("~w:" ++ F ++ "~n", [?MODULE|A]).
diff --git a/lib/snmp/test/snmp_log_SUITE.erl b/lib/snmp/test/snmp_log_SUITE.erl
index 6f9e7f5e49..b63c9e3b34 100644
--- a/lib/snmp/test/snmp_log_SUITE.erl
+++ b/lib/snmp/test/snmp_log_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -67,7 +67,7 @@
%% Internal exports
%%----------------------------------------------------------------------
-export([
- log_writer_main/5,
+ log_writer_main/6,
log_reader_main/1,
next_seqno/2
]).
@@ -175,7 +175,7 @@ init_per_testcase(Case, Config) when is_list(Config) ->
end_per_testcase(_Case, Config) when is_list(Config) ->
- ?PRINT2("system events during test: "
+ ?IPRINT("system events during test: "
"~n ~p", [snmp_test_global_sys_monitor:events()]),
%% Leave the dirs created above (enable debugging of the test case(s))
@@ -191,7 +191,7 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
open_and_close(suite) -> [];
open_and_close(Config) when is_list(Config) ->
- p(open_and_close),
+ ?P(open_and_close),
put(sname,open_and_close),
put(verbosity,trace),
Dir = ?config(log_dir, Config),
@@ -213,7 +213,7 @@ open_write_and_close1(suite) ->
open_write_and_close1(doc) ->
"Open a plain (no sequence-numbering) log file";
open_write_and_close1(Config) when is_list(Config) ->
- p(open_write_and_close1),
+ ?P(open_write_and_close1),
put(sname,open_write_and_close1),
put(verbosity,trace),
?DBG("open_write_and_close1 -> start", []),
@@ -232,7 +232,7 @@ open_write_and_close2(suite) ->
open_write_and_close2(doc) ->
"Open a log file with sequence-numbering explicitly disabled";
open_write_and_close2(Config) when is_list(Config) ->
- p(open_write_and_close2),
+ ?P(open_write_and_close2),
put(sname,open_write_and_close2),
put(verbosity,trace),
?DBG("open_write_and_close2 -> start", []),
@@ -251,7 +251,7 @@ open_write_and_close3(suite) ->
open_write_and_close3(doc) ->
"Open a log file with sequence-numbering using MFA";
open_write_and_close3(Config) when is_list(Config) ->
- p(open_write_and_close3),
+ ?P(open_write_and_close3),
put(sname,open_write_and_close3),
put(verbosity,trace),
?DBG("open_write_and_close2 -> start", []),
@@ -272,7 +272,7 @@ open_write_and_close4(suite) ->
open_write_and_close4(doc) ->
"Open a log file with sequence-numbering using fun";
open_write_and_close4(Config) when is_list(Config) ->
- p(open_write_and_close4),
+ ?P(open_write_and_close4),
put(sname,open_write_and_close4),
put(verbosity,trace),
?DBG("open_write_and_close2 -> start", []),
@@ -371,7 +371,7 @@ log_to_io1(suite) -> [];
log_to_io1(doc) -> "Log to io from the same process that opened "
"and wrote the log";
log_to_io1(Config) when is_list(Config) ->
- p(log_to_io1),
+ ?P(log_to_io1),
put(sname,l2i1),
put(verbosity,debug),
?DBG("log_to_io1 -> start", []),
@@ -426,18 +426,20 @@ log_to_io2(doc) -> "Log to io from a different process than which "
"opened and wrote the log";
log_to_io2(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- p(log_to_io2),
+ ?P(log_to_io2),
put(sname, l2i2),
put(verbosity,debug),
?DBG("log_to_io2 -> start", []),
Dir = ?config(log_dir, Config),
+ Factor = ?config(snmp_factor, Config),
Name = "snmp_test_l2i2",
File = join(Dir, "snmp_test_l2i2.log"),
Size = {1024, 10},
Repair = true,
?DBG("log_to_io2 -> create log writer process", []),
- ?line {ok, Log, Logger} = log_writer_start(Name, File, Size, Repair),
+ ?line {ok, Log, Logger} =
+ log_writer_start(Name, File, Size, Repair, Factor),
?DBG("log_to_io2 -> create log reader process", []),
?line {ok, Reader} = log_reader_start(),
@@ -485,7 +487,7 @@ log_to_io2(Config) when is_list(Config) ->
log_to_txt1(suite) -> [];
log_to_txt1(Config) when is_list(Config) ->
- p(log_to_txt1),
+ ?P(log_to_txt1),
put(sname,l2t1),
put(verbosity,debug),
?DBG("log_to_txt1 -> start", []),
@@ -503,7 +505,7 @@ log_to_txt1(Config) when is_list(Config) ->
log_to_txt2(suite) -> [];
log_to_txt2(Config) when is_list(Config) ->
- p(log_to_txt2),
+ ?P(log_to_txt2),
put(sname,l2t2),
put(verbosity,debug),
?DBG("log_to_txt2 -> start", []),
@@ -640,11 +642,12 @@ log_to_txt3(doc) ->
"opened and wrote the log";
log_to_txt3(Config) when is_list(Config) ->
process_flag(trap_exit, true),
- p(log_to_txt3),
+ ?P(log_to_txt3),
put(sname,l2t3),
put(verbosity,debug),
?DBG("log_to_txt3 -> start", []),
Dir = ?config(log_dir, Config),
+ Factor = ?config(snmp_factor, Config),
Name = "snmp_test_l2t3",
LogFile = join(Dir, "snmp_test_l2t3.log"),
TxtFile = join(Dir, "snmp_test_l2t3.txt"),
@@ -656,7 +659,8 @@ log_to_txt3(Config) when is_list(Config) ->
Mibs = [join(StdMibDir, "SNMPv2-MIB")],
?DBG("log_to_txt3 -> create log writer process", []),
- ?line {ok, Log, Logger} = log_writer_start(Name, LogFile, Size, Repair),
+ ?line {ok, Log, Logger} =
+ log_writer_start(Name, LogFile, Size, Repair, Factor),
?DBG("log_to_txt3 -> create log reader process", []),
?line {ok, Reader} = log_reader_start(),
@@ -679,9 +683,7 @@ log_to_txt3(Config) when is_list(Config) ->
R = snmp_log:log_to_txt(Log, LogFile, Dir,
Mibs, TxtFile),
T2 = snmp_misc:now(ms),
- io:format(user,
- "Time converting file: ~w ms~n",
- [T2 - T1]),
+ ?IPRINT("Time converting file: ~w ms", [T2 - T1]),
{R, I}
end),
@@ -693,9 +695,9 @@ log_to_txt3(Config) when is_list(Config) ->
?DBG("log_to_txt3 -> text file size: ~p", [FileSize]),
validate_size(FileSize);
{Error, Info} ->
- ?DBG("log_to_txt3 -> log to txt failed: "
- "~n Error: ~p"
- "~n Info: ~p", [Error, Info]),
+ ?EPRINT("log to txt failed: "
+ "~n Error: ~p"
+ "~n Info: ~p", [Error, Info]),
?line ?FAIL({log_lo_txt_failed, Error, Info})
end,
@@ -705,7 +707,7 @@ log_to_txt3(Config) when is_list(Config) ->
?DBG("log_to_txt3 -> instruct the log reader to stop", []),
?line log_reader_stop(Reader),
- ?DBG("log_to_txt3 -> done", []),
+ ?IPRINT("log_to_txt3 -> done", []),
ok.
@@ -730,9 +732,9 @@ validate_size(A, B) ->
%% Internal functions
%%======================================================================
-log_writer_start(Name, File, Size, Repair) ->
+log_writer_start(Name, File, Size, Repair, Factor) ->
Pid = spawn_link(?MODULE, log_writer_main,
- [Name, File, Size, Repair, self()]),
+ [Name, File, Size, Repair, self(), Factor]),
receive
{log, Log, Pid} ->
{ok, Log, Pid};
@@ -750,7 +752,7 @@ log_writer_stop(Pid) ->
receive
{'EXIT', Pid, normal} ->
_T2 = snmp_misc:now(ms),
- ?DBG("it took ~w ms to stop the writer", [_T2 - _T1]),
+ ?IPRINT("it took ~w ms to stop the writer", [_T2 - _T1]),
ok
after 60000 ->
Msg = receive Any -> Any after 0 -> nothing end,
@@ -767,7 +769,7 @@ log_writer_sleep(Pid, Time) ->
receive
{sleeping, Pid} ->
_T2 = snmp_misc:now(ms),
- ?DBG("it took ~w ms to put the writer to sleep", [_T2 - _T1]),
+ ?IPRINT("it took ~w ms to put the writer to sleep", [_T2 - _T1]),
ok;
{'EXIT', Pid, Reason} ->
{error, Reason}
@@ -777,13 +779,16 @@ log_writer_sleep(Pid, Time) ->
exit({failed_put_writer_to_sleep, timeout, Msg, Info})
end.
-log_writer_main(Name, File, Size, Repair, P) ->
+log_writer_main(Name, File, Size, Repair, P, Factor) ->
process_flag(trap_exit, true),
- %% put(sname,log_writer),
- %% put(verbosity,trace),
+ put(tname, "LOG-WRITER"),
{ok, Log} = snmp_log:create(Name, File, Size, Repair),
P ! {log, Log, self()},
- Msgs = lists:flatten(lists:duplicate(10, messages())),
+ Msgs = lists:flatten(lists:duplicate(if
+ (Factor > 10) -> 1;
+ true -> 10 div Factor
+ end,
+ messages())),
Addr = ?LOCALHOST(),
Port = 162,
Logger = fun(Packet) ->
@@ -797,39 +802,34 @@ log_writer_main(Name, File, Size, Repair, P) ->
log_writer(Log, BatchLogger, P).
log_writer(Log, Fun, P) ->
- lp("entry"),
+ ?IPRINT("entry"),
receive
{stop, P} ->
- lp("received stop request"),
+ ?IPRINT("received stop request"),
ok = snmp_log:close(Log),
exit(normal);
{info, P} ->
- lp("received info request"),
+ ?IPRINT("received info request"),
{ok, Info} = snmp_log:info(Log),
display_info(Info),
log_writer(Log, Fun, P);
{sleep, Time, P} ->
- lp("received sleep (~w) request", [Time]),
+ ?IPRINT("received sleep (~w) request", [Time]),
P ! {sleeping, self()},
?SLEEP(Time),
- lp("done sleeping"),
+ ?IPRINT("done sleeping"),
log_writer(Log, Fun, P);
ELSE ->
- io:format("ERROR:logger - received unknown message: "
- "~n ~p~n", [ELSE]),
+ ?EPRINT("Received unknown message: "
+ "~n ~p", [ELSE]),
log_writer(Log, Fun, P)
after 1000 ->
- lp("log some messages"),
+ ?IPRINT("log some messages"),
To = lists:duplicate(100, 100),
lists:foreach(Fun, To),
log_writer(Log, Fun, P)
end.
-lp(F) ->
- lp(F, []).
-
-lp(F, A) ->
- io:format(user,"writer [~w] " ++ F ++ "~n", [self()|A]).
%% --
@@ -839,7 +839,7 @@ log_reader_start() ->
receive
{started, Pid} ->
_T2 = snmp_misc:now(ms),
- ?DBG("it took ~w ms to start the reader", [_T2 - _T1]),
+ ?IPRINT("it took ~w ms to start the reader", [_T2 - _T1]),
{ok, Pid};
{'EXIT', Pid, Reason} ->
{error, Reason}
@@ -853,7 +853,7 @@ log_reader_stop(Pid) ->
receive
{'EXIT', Pid, normal} ->
_T2 = snmp_misc:now(ms),
- ?DBG("it took ~w ms to put the reader to eleep", [_T2 - _T1]),
+ ?IPRINT("it took ~w ms to stop the reader", [_T2 - _T1]),
ok
after 1000 ->
Msg = receive Any -> Any after 0 -> nothing end,
@@ -868,35 +868,28 @@ log_reader_log_to(Pid, LogToFun) when is_function(LogToFun) ->
end.
log_reader_main(P) ->
- put(sname,log_reader),
- put(verbosity,trace),
+ put(tname, "LOG-READER"),
P ! {started, self()},
log_reader(P).
log_reader(P) ->
- rp("entry"),
+ ?IPRINT("entry"),
receive
{stop, P} ->
- rp("received stop request"),
+ ?IPRINT("received stop request"),
exit(normal);
{log_to, F, P} ->
- rp("received log_to request"),
+ ?IPRINT("received log_to request"),
Res = F(),
- rp("done with log_to - sending reply"),
+ ?IPRINT("done with log_to - sending reply"),
P ! {log_to_reply, Res, self()},
log_reader(P);
ELSE ->
- io:format("ERROR:reader - received unknown message: "
- "~n ~p~n", [ELSE]),
+ ?EPRINT("Received unknown message: "
+ "~n ~p", [ELSE]),
log_reader(P)
end.
-rp(F) ->
- rp(F, []).
-
-rp(F, A) ->
- io:format(user, "reader [~w] " ++ F ++ "~n", [self()|A]).
-
%%======================================================================
@@ -1115,23 +1108,6 @@ varbinds([{Oid, Type, Value, Idx}|T], Acc) ->
org_index = Idx},
varbinds(T, [Varbind|Acc]).
-% enc_message('version-3' = Vsn, Community, Pdu) ->
-% ScopedPDU = #scopedPdu{contextEngineID = ContextEngineID,
-% contextName = ContextName,
-% data = Pdu},
-% NUsmSecParams =
-% UsmSecParams#usmSecurityParameters{msgAuthenticationParameters =
-% AuthParams},
-% SecBytes = snmp_pdus:enc_usm_security_parameters(NUsmSecParams),
-% V3Hdr = #v3_hdr{msgID = MsgID,
-% msgMaxSize = AgentMS,
-% msgFlags = snmp_misc:mk_msg_flags(Type, SecLevel),
-% msgSecurityParameters = SecBytes
-% msgSecurityModel = MsgSecurityModel},
-% Msg = #message{version = Vsn, vsn_hdr = V3Hdr,
-% data = ScopedPDUBytes},
-% snmp_pdus:enc_message_only(Message2);
-
enc_message(Vsn, Community, Pdu) ->
PduBytes = snmp_pdus:enc_pdu(Pdu),
Msg = #message{version = Vsn,
@@ -1144,14 +1120,13 @@ display_info(Info) ->
CurrentFile = get_info(current_file, Info, -1),
NoItems = get_info(no_current_items, Info, -1),
NoBytes = get_info(no_current_bytes, Info, -1),
- io:format(user, "Disk log info: "
- "~n Number of filled since opened: ~p"
- "~n Number of filled since last info: ~p"
- "~n Current file: ~p"
- "~n Number of items in file: ~p"
- "~n Number of bytes in file: ~p"
- "~n",
- [SinceOpened, SinceLastInfo, CurrentFile, NoItems, NoBytes]).
+ ?NPRINT("Disk log info: "
+ "~n Number of filled since opened: ~p"
+ "~n Number of filled since last info: ~p"
+ "~n Current file: ~p"
+ "~n Number of items in file: ~p"
+ "~n Number of bytes in file: ~p",
+ [SinceOpened, SinceLastInfo, CurrentFile, NoItems, NoBytes]).
get_info(Key, Info, Def) ->
case lists:keysearch(Key, 1, Info) of
@@ -1164,5 +1139,3 @@ get_info(Key, Info, Def) ->
join(D, F) ->
filename:join(D, F).
-p(Case) ->
- io:format(user, "test case: ~w~n", [Case]).
diff --git a/lib/snmp/test/snmp_manager_SUITE.erl b/lib/snmp/test/snmp_manager_SUITE.erl
index 98aa8336fb..9d8e2efacf 100644
--- a/lib/snmp/test/snmp_manager_SUITE.erl
+++ b/lib/snmp/test/snmp_manager_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -337,31 +337,34 @@ ipv6_tests() ->
init_per_suite(Config0) when is_list(Config0) ->
- ?DBG("init_per_suite -> entry with"
- "~n Config0: ~p", [Config0]),
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
- case snmp_test_lib:init_per_suite(Config0) of
+ case ?LIB:init_per_suite(Config0) of
{skip, _} = SKIP ->
SKIP;
Config1 ->
+ ?IPRINT("init_per_suite -> common init done"
+ "~n Config1: ~p", [Config1]),
+
%% Preferably this test SUITE should be divided into groups
%% so that if crypto does not work only v3 tests that
%% need crypto will be skipped, but as this is only a
%% problem with one legacy test machine, we will procrastinate
%% until we have a more important reason to fix this.
- case snmp_test_lib:crypto_start() of
+ case ?LIB:crypto_start() of
ok ->
%% We need one on this node also
snmp_test_sys_monitor:start(),
- Config2 = snmp_test_lib:init_suite_top_dir(?MODULE, Config1),
- Config3 = snmp_test_lib:fix_data_dir(Config2),
+ Config2 = ?LIB:init_suite_top_dir(?MODULE, Config1),
+ Config3 = ?LIB:fix_data_dir(Config2),
%% Mib-dirs
%% data_dir is trashed by the test-server / common-test
%% so there is no point in fixing it...
- MibDir = snmp_test_lib:lookup(data_dir, Config3),
+ MibDir = ?LIB:lookup(data_dir, Config3),
StdMibDir = filename:join([code:priv_dir(snmp), "mibs"]),
[{mib_dir, MibDir}, {std_mib_dir, StdMibDir} | Config3];
@@ -372,15 +375,15 @@ init_per_suite(Config0) when is_list(Config0) ->
end_per_suite(Config0) when is_list(Config0) ->
- p("end_per_suite -> entry with"
- "~n Config0: ~p"
- "~n Nodes: ~p", [Config0, erlang:nodes()]),
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config0: ~p"
+ "~n Nodes: ~p", [Config0, erlang:nodes()]),
snmp_test_sys_monitor:stop(),
- Config1 = snmp_test_lib:end_per_suite(Config0),
+ Config1 = ?LIB:end_per_suite(Config0),
- p("end_per_suite -> end when"
- "~n Nodes: ~p", [erlang:nodes()]),
+ ?IPRINT("end_per_suite -> end when"
+ "~n Nodes: ~p", [erlang:nodes()]),
Config1.
@@ -389,11 +392,11 @@ end_per_suite(Config0) when is_list(Config0) ->
%%
init_per_group(request_tests_mt = GroupName, Config) ->
- snmp_test_lib:init_group_top_dir(
+ ?LIB:init_group_top_dir(
GroupName,
[{manager_net_if_module, snmpm_net_if_mt} | Config]);
init_per_group(event_tests_mt = GroupName, Config) ->
- snmp_test_lib:init_group_top_dir(
+ ?LIB:init_group_top_dir(
GroupName,
[{manager_net_if_module, snmpm_net_if_mt} | Config]);
init_per_group(ipv6_mt = GroupName, Config) ->
@@ -402,7 +405,7 @@ init_per_group(ipv6_mt = GroupName, Config) ->
init_per_group(ipv6 = GroupName, Config) ->
init_per_group_ipv6(GroupName, Config);
init_per_group(GroupName, Config) ->
- snmp_test_lib:init_group_top_dir(GroupName, Config).
+ ?LIB:init_group_top_dir(GroupName, Config).
init_per_group_ipv6(GroupName, Config) ->
@@ -429,9 +432,9 @@ init_per_group_ipv6(GroupName, Config) ->
false ->
%% Even if this host supports IPv6 we don't use it unless its
%% one of the configures/supported IPv6 hosts...
- case (?HAS_SUPPORT_IPV6() andalso ?IS_IPV6_HOST()) of
+ case ?HAS_SUPPORT_IPV6() of
true ->
- ipv6_init(snmp_test_lib:init_group_top_dir(GroupName, Config));
+ ipv6_init(?LIB:init_group_top_dir(GroupName, Config));
false ->
{skip, "Host does not support IPv6"}
end
@@ -450,8 +453,10 @@ end_per_group(_GroupName, Config) ->
%%
init_per_testcase(Case, Config) when is_list(Config) ->
- p(Case, "init_per_testcase begin when"
- "~n Nodes: ~p~n~n", [erlang:nodes()]),
+
+ ?IPRINT("init_per_testcase -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p", [Config, erlang:nodes()]),
snmp_test_global_sys_monitor:reset_events(),
@@ -469,15 +474,19 @@ init_per_testcase(Case, Config) when is_list(Config) ->
C:{skip, _} = E:_ when ((C =:= throw) orelse
(C =:= exit)) ->
E;
+ exit:{suite_failed, {{Reason, _CS},_MFA}, Mod, Line}:_ ->
+ {skip, {Reason, Mod, Line}};
+ exit:{suite_failed, Reason, Mod, Line}:_ ->
+ {skip, {Reason, Mod, Line}};
C:E:_ when ((C =:= throw) orelse
(C =:= exit)) ->
{skip, {catched, C, E}}
end
end,
- p(Case, "init_per_testcase end when"
- "~n Nodes: ~p"
- "~n Result: ~p"
- "~n~n", [Result, erlang:nodes()]),
+ ?IPRINT("init_per_testcase end when"
+ "~n Nodes: ~p"
+ "~n Result: ~p"
+ "~n~n", [erlang:nodes(), Result]),
Result.
init_per_testcase2(Case, Config) ->
@@ -524,10 +533,14 @@ init_per_testcase2(Case, Config) ->
InformSwarm when (InformSwarm =:= inform_swarm_cbp_def) orelse
(InformSwarm =:= inform_swarm_cbp_temp) orelse
(InformSwarm =:= inform_swarm_cbp_perm) ->
- ?MINS(60);
+ case ?config(snmp_factor, Config) of
+ N when is_integer(N) -> ?MINS(2*N);
+ _ -> ?MINS(2)
+ end;
_ ->
?MINS(1)
end,
+ ?IPRINT("Set test case timetrap: ~p", [TO]),
ct:timetrap(TO),
Conf = [{ipfamily, Family},
@@ -606,12 +619,12 @@ init_per_testcase3(Case, Config) ->
(Case =:= inform_swarm_cbp_temp) orelse
(Case =:= inform_swarm_cbp_perm) ->
Verb = [{manager_config_verbosity, silence},
- {manager_note_store_verbosity, silence},
- {manager_server_verbosity, info},
- {manager_net_if_verbosity, info},
- {agent_verbosity, info},
- {agent_net_if_verbosity, info}],
- Verb ++ Config;
+ {manager_note_store_verbosity, silence},
+ {manager_server_verbosity, info},
+ {manager_net_if_verbosity, info},
+ {agent_verbosity, info},
+ {agent_net_if_verbosity, info}],
+ Verb ++ Config;
Case =:= otp8395_1 ->
[{manager_atl_seqno, true} | Config];
true ->
@@ -667,20 +680,21 @@ init_per_testcase_fail_agent_cleanup(Conf) ->
(catch fin_agent(Conf)).
end_per_testcase(Case, Config) when is_list(Config) ->
- p(Case, "end_per_testcase begin when"
- "~n Nodes: ~p~n~n", [erlang:nodes()]),
+ ?IPRINT("end_per_testcase -> entry with"
+ "~n Config: ~p"
+ "~n Nodes: ~p",
+ [Config, erlang:nodes()]),
- ?PRINT2("system events during test: "
+ ?IPRINT("system events during test: "
"~n ~p", [snmp_test_global_sys_monitor:events()]),
- %% Dog = ?config(watchdog, Config),
- %% ?WD_STOP(Dog),
- %% Conf1 = lists:keydelete(watchdog, 1, Config),
Conf1 = Config,
Conf2 = end_per_testcase2(Case, Conf1),
- p(Case, "end_per_testcase end when"
- "~n Nodes: ~p~n~n", [erlang:nodes()]),
+ ?IPRINT("end_per_testcase -> done with"
+ "~n Condif: ~p"
+ "~n Nodes: ~p", [Conf2, erlang:nodes()]),
+
Conf2.
end_per_testcase2(Case, Config) ->
@@ -760,7 +774,8 @@ simple_start_and_stop1(Config) when is_list(Config) ->
fun() -> do_simple_start_and_stop1(Config) end).
do_simple_start_and_stop1(Config) ->
- p("starting with Config: ~n~p", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -771,12 +786,12 @@ do_simple_start_and_stop1(Config) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start_link(Opts),
?SLEEP(1000),
- p("manager started, now try to stop"),
+ ?IPRINT("manager started, now try to stop"),
ok = snmpm:stop(),
?SLEEP(1000),
@@ -788,13 +803,18 @@ do_simple_start_and_stop1(Config) ->
simple_start_and_stop2(suite) -> [];
simple_start_and_stop2(Config) when is_list(Config) ->
- ?TC_TRY(simple_start_and_stop2,
- fun() -> do_simple_start_and_stop2(Config) end).
-
-do_simple_start_and_stop2(Config) ->
- p("starting with Config: ~p~n", [Config]),
-
- ManagerNode = start_manager_node(),
+ Pre = fun() ->
+ ManagerNode = start_manager_node(),
+ [ManagerNode]
+ end,
+ Case = fun(State) -> do_simple_start_and_stop2(State, Config) end,
+ Post = fun([ManagerNode]) -> stop_node(ManagerNode) end,
+ ?TC_TRY(simple_start_and_stop2, Pre, Case, Post).
+
+do_simple_start_and_stop2([ManagerNode], Config) ->
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -807,27 +827,24 @@ do_simple_start_and_stop2(Config) ->
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try load snmp application"),
+ ?IPRINT("try load snmp application"),
?line ok = load_snmp(ManagerNode),
- p("try set manager env for the snmp application"),
+ ?IPRINT("try set manager env for the snmp application"),
?line ok = set_mgr_env(ManagerNode, Opts),
- p("try starting snmp application (with only manager)"),
+ ?IPRINT("try starting snmp application (with only manager)"),
?line ok = start_snmp(ManagerNode),
- p("started"),
+ ?IPRINT("started"),
?SLEEP(1000),
- p("try stopping snmp application (with only manager)"),
+ ?IPRINT("try stopping snmp application (with only manager)"),
?line ok = stop_snmp(ManagerNode),
?SLEEP(1000),
-
- stop_node(ManagerNode),
-
- ?SLEEP(1000),
+ ?IPRINT("end"),
ok.
@@ -840,7 +857,9 @@ simple_start_and_stop3(Config) when is_list(Config) ->
fun() -> do_simple_start_and_stop3(Config) end).
do_simple_start_and_stop3(Config) ->
- p("starting with Config: ~n~p", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
+
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -851,17 +870,19 @@ do_simple_start_and_stop3(Config) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
try snmpm:start_link(Opts) of
ok ->
+ (catch snmpm:stop()),
?FAIL('unexpected-success')
catch
_:_:_ ->
- p("expected start failure"),
+ ?IPRINT("expected start failure"),
ok
end,
?SLEEP(1000),
+ ?IPRINT("end"),
ok.
@@ -874,7 +895,8 @@ simple_start_and_monitor_crash1(Config) when is_list(Config) ->
fun() -> do_simple_start_and_monitor_crash1(Config) end).
do_simple_start_and_monitor_crash1(Config) ->
- p("starting with Config: ~n~p", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -886,15 +908,15 @@ do_simple_start_and_monitor_crash1(Config) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start(Opts),
?SLEEP(1000),
- p("create the monitor"),
+ ?IPRINT("create the monitor"),
Ref = snmpm:monitor(),
- p("make sure it has not already crashed..."),
+ ?IPRINT("make sure it has not already crashed..."),
receive
{'DOWN', Ref, process, Obj1, Reason1} ->
?FAIL({unexpected_down, Obj1, Reason1})
@@ -902,20 +924,28 @@ do_simple_start_and_monitor_crash1(Config) ->
ok
end,
- p("stop the manager"),
+ ?IPRINT("stop the manager"),
ok = snmpm:stop(),
- p("await the down-message"),
+ ?IPRINT("await the down-message"),
receive
{'DOWN', Ref, process, Obj2, Reason2} ->
- p("received expected down-message: "
- "~n Obj2: ~p"
- "~n Reason2: ~p",
- [Obj2, Reason2]),
+ ?IPRINT("received expected down-message: "
+ "~n Obj2: ~p"
+ "~n Reason2: ~p",
+ [Obj2, Reason2]),
ok
after 1000 ->
+ %% The manager is an entire process tree and we can't
+ %% wait for all of them. Instead, we assume that if
+ %% we deal with the top supervisor, all the other procs
+ %% will also follow...
+ ?ENSURE_NOT_RUNNING(snmpm_supervisor,
+ fun() -> snmpm:stop() end,
+ 1000),
?FAIL(timeout)
end,
+ ?IPRINT("end"),
ok.
@@ -924,11 +954,22 @@ do_simple_start_and_monitor_crash1(Config) ->
simple_start_and_monitor_crash2(suite) -> [];
simple_start_and_monitor_crash2(Config) when is_list(Config) ->
+ Cond = fun() -> case os:type() of
+ {unix, netbsd} ->
+ {skip, "Unstable on NetBSD"};
+ _ ->
+ ok
+ end
+ end,
+ Pre = fun() -> undefined end,
+ Case = fun(_) -> do_simple_start_and_monitor_crash2(Config) end,
+ Post = fun(_) -> ok end,
?TC_TRY(simple_start_and_monitor_crash2,
- fun() -> do_simple_start_and_monitor_crash2(Config) end).
+ Cond, Pre, Case, Post).
do_simple_start_and_monitor_crash2(Config) ->
- p("starting with Config: ~n~p", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -941,15 +982,15 @@ do_simple_start_and_monitor_crash2(Config) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start(Opts),
?SLEEP(1000),
- p("create the monitor"),
+ ?IPRINT("create the monitor"),
Ref = snmpm:monitor(),
- p("make sure it has not already crashed..."),
+ ?IPRINT("make sure it has not already crashed..."),
receive
{'DOWN', Ref, process, Obj1, Reason1} ->
?FAIL({unexpected_down, Obj1, Reason1})
@@ -957,16 +998,16 @@ do_simple_start_and_monitor_crash2(Config) ->
ok
end,
- p("crash the manager"),
+ ?IPRINT("crash the manager"),
simulate_crash(),
- p("await the down-message"),
+ ?IPRINT("await the down-message"),
receive
{'DOWN', Ref, process, Obj2, Reason2} ->
- p("received expected down-message: "
- "~n Obj2: ~p"
- "~n Reason2: ~p",
- [Obj2, Reason2]),
+ ?IPRINT("received expected down-message: "
+ "~n Obj2: ~p"
+ "~n Reason2: ~p",
+ [Obj2, Reason2]),
ok
after 1000 ->
?FAIL(timeout)
@@ -993,16 +1034,17 @@ simulate_crash(?MAX_KILLS, _) ->
ok
end;
simulate_crash(NumKills, Pid) when (NumKills < ?MAX_KILLS) and is_pid(Pid) ->
- p("similate_crash -> ~w, ~p", [NumKills, Pid]),
+ ?IPRINT("similate_crash -> ~w, ~p", [NumKills, Pid]),
Ref = erlang:monitor(process, Pid),
exit(Pid, kill),
receive
{'DOWN', Ref, process, _Object, _Info} ->
- p("received expected 'DOWN' message"),
+ ?IPRINT("received expected 'DOWN' message"),
simulate_crash(NumKills + 1, server_pid())
after 1000 ->
case server_pid() of
P when is_pid(P) ->
+ ?EPRINT("received expected 'DOWN' message"),
exit({error, {no_down_from_server, P}});
_ ->
ok
@@ -1021,7 +1063,8 @@ notify_started01(Config) when is_list(Config) ->
fun() -> do_notify_started01(Config) end).
do_notify_started01(Config) ->
- p("starting with Config: ~n~p", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -1033,11 +1076,11 @@ do_notify_started01(Config) ->
{note_store, [{verbosity, silence}]},
{config, [{verbosity, log}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("request start notification (1)"),
+ ?IPRINT("request start notification (1)"),
Pid1 = snmpm:notify_started(10000),
receive
{snmpm_start_timeout, Pid1} ->
- p("received expected start timeout"),
+ ?IPRINT("received expected start timeout"),
ok;
Any1 ->
?FAIL({unexpected_message, Any1})
@@ -1045,17 +1088,17 @@ do_notify_started01(Config) ->
?FAIL({unexpected_timeout, Pid1})
end,
- p("request start notification (2)"),
+ ?IPRINT("request start notification (2)"),
Pid2 = snmpm:notify_started(10000),
- p("start the snmpm starter"),
+ ?IPRINT("start the snmpm starter"),
Pid = snmpm_starter(Opts, 5000),
- p("await the start notification"),
+ ?IPRINT("await the start notification"),
Ref =
receive
{snmpm_started, Pid2} ->
- p("received started message -> create the monitor"),
+ ?IPRINT("received started message -> create the monitor"),
snmpm:monitor();
Any2 ->
?FAIL({unexpected_message, Any2})
@@ -1063,7 +1106,7 @@ do_notify_started01(Config) ->
?FAIL({unexpected_timeout, Pid2})
end,
- p("[~p] make sure it has not already crashed...", [Ref]),
+ ?IPRINT("[~p] make sure it has not already crashed...", [Ref]),
receive
{'DOWN', Ref, process, Obj1, Reason1} ->
?FAIL({unexpected_down, Obj1, Reason1})
@@ -1071,22 +1114,22 @@ do_notify_started01(Config) ->
ok
end,
- p("stop the manager"),
+ ?IPRINT("stop the manager"),
Pid ! {stop, self()}, %ok = snmpm:stop(),
- p("await the down-message"),
+ ?IPRINT("await the down-message"),
receive
{'DOWN', Ref, process, Obj2, Reason2} ->
- p("received expected down-message: "
- "~n Obj2: ~p"
- "~n Reason2: ~p",
- [Obj2, Reason2]),
+ ?IPRINT("received expected down-message: "
+ "~n Obj2: ~p"
+ "~n Reason2: ~p",
+ [Obj2, Reason2]),
ok
after 5000 ->
?FAIL(down_timeout)
end,
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -1135,7 +1178,8 @@ notify_started02_cond(Config) ->
?NON_PC_TC_MAYBE_SKIP(Config, Condition).
do_notify_started02(Config) ->
- p("starting with Config: ~n~p", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -1147,11 +1191,11 @@ do_notify_started02(Config) ->
{note_store, [{verbosity, silence}]},
{config, [{verbosity, debug}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("start snmpm client process"),
+ ?IPRINT("start snmpm client process"),
NumIterations = 5,
Pid1 = ns02_client_start(NumIterations),
- p("start snmpm ctrl (starter) process"),
+ ?IPRINT("start snmpm ctrl (starter) process"),
Pid2 = ns02_ctrl_start(Opts, NumIterations),
%% On a reasonably fast machine, one iteration takes approx 4 seconds.
@@ -1173,7 +1217,8 @@ do_notify_started02(Config) ->
?SKIP(Reason)
end,
- p("await snmpm client process exit (max ~p+10000 msec)", [ApproxStartTime]),
+ ?IPRINT("await snmpm client process exit (max ~p+10000 msec)",
+ [ApproxStartTime]),
receive
%% We take this opportunity to check if we got a skip from
%% the ctrl process.
@@ -1191,7 +1236,7 @@ do_notify_started02(Config) ->
?FAIL(timeout)
end,
- p("await snmpm starter process exit"),
+ ?IPRINT("await snmpm starter process exit"),
receive
{'EXIT', Pid2, normal} ->
ok;
@@ -1205,7 +1250,7 @@ do_notify_started02(Config) ->
?FAIL(timeout)
end,
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -1218,8 +1263,8 @@ ns02_client_await_approx_runtime(Pid) ->
{?MODULE, client_time, Time} ->
{ok, Time};
{'EXIT', Pid, Reason} ->
- p("client (~p) failed: "
- "~n ~p", [Pid, Reason]),
+ ?EPRINT("client (~p) failed: "
+ "~n ~p", [Pid, Reason]),
{error, Reason}
after 30000 ->
@@ -1231,48 +1276,48 @@ ns02_client_await_approx_runtime(Pid) ->
ns02_client(Parent, N) when is_pid(Parent) ->
put(tname, ns02_client),
- p("starting"),
+ ?IPRINT("starting"),
ns02_client_loop(Parent,
dummy, snmpm:notify_started(?NS_TIMEOUT),
snmp_misc:now(ms), undefined,
N).
ns02_client_loop(_Parent, _Ref, _Pid, _Begin, _End, 0) ->
- %% p("loop -> done"),
+ %% ?IPRINT("loop -> done"),
exit(normal);
ns02_client_loop(Parent, Ref, Pid, Begin, End, N)
when is_pid(Parent) andalso is_integer(Begin) andalso is_integer(End) ->
- %% p("loop -> [~w] inform parent: ~w, ~w => ~w", [N, Begin, End, End-Begin]),
+ %% ?IPRINT("loop -> [~w] inform parent: ~w, ~w => ~w", [N, Begin, End, End-Begin]),
Parent ! {?MODULE, client_time, N*(End-Begin)},
ns02_client_loop(undefined, Ref, Pid, snmp_misc:now(ms), undefined, N);
ns02_client_loop(Parent, Ref, Pid, Begin, End, N)
when is_integer(Begin) andalso is_integer(End) ->
- %% p("loop -> [~w] entry when"
+ %% ?IPRINT("loop -> [~w] entry when"
%% "~n Ref: ~p"
%% "~n Pid: ~p"
%% "~n Begin: ~p"
%% "~n End: ~p", [N, Ref, Pid, Begin, End]),
ns02_client_loop(Parent, Ref, Pid, snmp_misc:now(ms), undefined, N);
ns02_client_loop(Parent, Ref, Pid, Begin, End, N) ->
- %% p("loop(await message) -> [~w] entry when"
+ %% ?IPRINT("loop(await message) -> [~w] entry when"
%% "~n Ref: ~p"
%% "~n Pid: ~p"
%% "~n Begin: ~p"
%% "~n End: ~p", [N, Ref, Pid, Begin, End]),
receive
{snmpm_started, Pid} ->
- p("received expected started message (~w)", [N]),
+ ?IPRINT("received expected started message (~w)", [N]),
ns02_client_loop(Parent,
snmpm:monitor(), dummy,
Begin, End,
N);
{snmpm_start_timeout, Pid} ->
- p("unexpected timout"),
+ ?EPRINT("unexpected timeout"),
?FAIL({unexpected_start_timeout, Pid});
{'DOWN', Ref, process, Obj, Reason} ->
- p("received expected DOWN message (~w) with"
- "~n Obj: ~p"
- "~n Reason: ~p", [N, Obj, Reason]),
+ ?IPRINT("received expected DOWN message (~w) with"
+ "~n Obj: ~p"
+ "~n Reason: ~p", [N, Obj, Reason]),
ns02_client_loop(Parent,
dummy, snmpm:notify_started(?NS_TIMEOUT),
Begin, snmp_misc:now(ms),
@@ -1284,7 +1329,7 @@ ns02_ctrl_start(Opts, N) ->
ns02_ctrl(Opts, N) ->
put(tname, ns02_ctrl),
- p("starting"),
+ ?IPRINT("starting"),
ns02_ctrl_loop(Opts, N).
@@ -1294,36 +1339,36 @@ ns02_ctrl(Opts, N) ->
%% So, we try to monitor each start attempt. We allow 5 sec (just
%% to give slow boxes a chance).
ns02_ctrl_loop(_Opts, 0) ->
- p("done"),
+ ?IPRINT("done"),
exit(normal);
ns02_ctrl_loop(Opts, N) ->
- p("entry when N: ~p", [N]),
+ ?IPRINT("entry when N: ~p", [N]),
?SLEEP(2000),
- p("start manager"),
+ ?IPRINT("start manager"),
TS1 = erlang:system_time(millisecond),
{StarterPid, StarterMRef} =
erlang:spawn_monitor(fun() -> exit(snmpm:start(Opts)) end),
receive
{'DOWN', StarterMRef, process, StarterPid, ok} ->
TS2 = erlang:system_time(millisecond),
- p("manager started: ~w ms", [TS2-TS1]),
+ ?IPRINT("manager started: ~w ms", [TS2-TS1]),
ok
after 5000 ->
- p("manager (~p) start timeout - kill", [StarterPid]),
+ ?EPRINT("manager (~p) start timeout - kill", [StarterPid]),
exit(StarterPid, kill),
exit({skip, start_timeout})
end,
?SLEEP(2000),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?SLEEP(100), % Give the verbosity to take effect...
TS3 = erlang:system_time(millisecond),
case snmpm:stop(5000) of
ok ->
TS4 = erlang:system_time(millisecond),
- p("manager stopped: ~p ms", [TS4-TS3]),
+ ?IPRINT("manager stopped: ~p ms", [TS4-TS3]),
ok;
{error, timeout} ->
- p("manager stop timeout - kill (cleanup) and skip"),
+ ?EPRINT("manager stop timeout - kill (cleanup) and skip"),
exit(whereis(snmpm_supervisor), kill),
exit({skip, stop_timeout})
end,
@@ -1335,37 +1380,44 @@ ns02_ctrl_loop(Opts, N) ->
info(suite) -> [];
info(Config) when is_list(Config) ->
- ?TC_TRY(info,
- fun() -> do_info(Config) end).
-
-do_info(Config) ->
- p("starting with Config: ~n~p", [Config]),
-
- ConfDir = ?config(manager_conf_dir, Config),
- DbDir = ?config(manager_db_dir, Config),
+ Pre = fun() ->
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace},
+ {dir, ConfDir},
+ {db_dir, DbDir}]}],
+ ?IPRINT("try starting manager"),
+ ok = snmpm:start(Opts),
+ ?SLEEP(1000),
+ ok
+ end,
+ Case = fun(_) -> do_info(Config) end,
+ Post = fun(_) ->
+ ?IPRINT("info verified, now try to stop"),
+ snmpm:stop(),
+ ?SLEEP(1000),
+ ok
+ end,
+ ?TC_TRY(info, Pre, Case, Post).
- write_manager_conf(ConfDir),
-
- Opts = [{server, [{verbosity, trace}]},
- {net_if, [{verbosity, trace}]},
- {note_store, [{verbosity, trace}]},
- {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
-
- p("try starting manager"),
- ok = snmpm:start(Opts),
- ?SLEEP(1000),
+do_info(Config) ->
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
- p("manager started, now get info"),
+ ?IPRINT("get info"),
Info = snmpm:info(),
- p("got info, now verify: ~n~p", [Info]),
+ ?IPRINT("got info, now verify: "
+ "~n ~p", [Info]),
ok = verify_info( Info ),
- p("info verified, now try to stop"),
- ok = snmpm:stop(),
-
- ?SLEEP(1000),
-
+ ?IPRINT("end"),
ok.
verify_info(Info) when is_list(Info) ->
@@ -1405,13 +1457,18 @@ verify_info([{Key, SubKeys}|Keys], Info) ->
register_user1(suite) -> [];
register_user1(Config) when is_list(Config) ->
- ?TC_TRY(register_user1,
- fun() -> do_register_user1(Config) end).
-
-do_register_user1(Config) ->
- p("starting with Config: ~p~n", [Config]),
-
- ManagerNode = start_manager_node(),
+ Pre = fun() ->
+ ManagerNode = start_manager_node(),
+ [ManagerNode]
+ end,
+ Case = fun(State) -> do_register_user1(State, Config) end,
+ Post = fun([ManagerNode]) -> stop_node(ManagerNode) end,
+ ?TC_TRY(register_user1, Pre, Case, Post).
+
+do_register_user1([ManagerNode], Config) ->
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -1424,64 +1481,60 @@ do_register_user1(Config) ->
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("load snmp application"),
+ ?IPRINT("load snmp application"),
?line ok = load_snmp(ManagerNode),
- p("set manager env for the snmp application"),
+ ?IPRINT("set manager env for the snmp application"),
?line ok = set_mgr_env(ManagerNode, Opts),
- p("starting snmp application (with only manager)"),
+ ?IPRINT("starting snmp application (with only manager)"),
?line ok = start_snmp(ManagerNode),
- p("started"),
+ ?IPRINT("started"),
?SLEEP(1000),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("try register user(s)"),
+ ?IPRINT("try register user(s)"),
?line ok = mgr_register_user(ManagerNode, calvin, snmpm_user_default,
[self(), "various misc info"]),
Users1 = mgr_which_users(ManagerNode),
- p("users: ~p~n", [Users1]),
+ ?IPRINT("users: ~p~n", [Users1]),
?line ok = verify_users(Users1, [calvin]),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
?line ok = mgr_register_user(ManagerNode, hobbe, snmpm_user_default,
{"misc info", self()}),
Users2 = mgr_which_users(ManagerNode),
- p("users: ~p~n", [Users2]),
+ ?IPRINT("users: ~p~n", [Users2]),
?line ok = verify_users(Users2, [calvin, hobbe]),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("try unregister user(s)"),
+ ?IPRINT("try unregister user(s)"),
?line ok = mgr_unregister_user(ManagerNode, calvin),
Users3 = mgr_which_users(ManagerNode),
- p("users: ~p~n", [Users3]),
+ ?IPRINT("users: ~p~n", [Users3]),
?line ok = verify_users(Users3, [hobbe]),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
?line ok = mgr_unregister_user(ManagerNode, hobbe),
Users4 = mgr_which_users(ManagerNode),
- p("users: ~p~n", [Users4]),
+ ?IPRINT("users: ~p~n", [Users4]),
?line ok = verify_users(Users4, []),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
?SLEEP(1000),
- p("stop snmp application (with only manager)"),
+ ?IPRINT("stop snmp application (with only manager)"),
?line ok = stop_snmp(ManagerNode),
?SLEEP(1000),
- stop_node(ManagerNode),
-
- ?SLEEP(1000),
-
ok.
verify_users([], []) ->
@@ -1504,13 +1557,18 @@ register_agent_old(doc) ->
register_agent_old(suite) ->
[];
register_agent_old(Config) when is_list(Config) ->
- ?TC_TRY(register_agent_old,
- fun() -> do_register_agent_old(Config) end).
-
-do_register_agent_old(Config) ->
- p("starting with Config: ~p~n", [Config]),
-
- ManagerNode = start_manager_node(),
+ Pre = fun() ->
+ ManagerNode = start_manager_node(),
+ [ManagerNode]
+ end,
+ Case = fun(State) -> do_register_agent_old(State, Config) end,
+ Post = fun([ManagerNode]) -> stop_node(ManagerNode) end,
+ ?TC_TRY(register_agent_old, Pre, Case, Post).
+
+do_register_agent_old([ManagerNode], Config) ->
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
@@ -1523,104 +1581,105 @@ do_register_agent_old(Config) ->
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("load snmp application"),
+ ?IPRINT("load snmp application"),
?line ok = load_snmp(ManagerNode),
- p("set manager env for the snmp application"),
+ ?IPRINT("set manager env for the snmp application"),
?line ok = set_mgr_env(ManagerNode, Opts),
- p("starting snmp application (with only manager)"),
+ ?IPRINT("starting snmp application (with only manager)"),
?line ok = start_snmp(ManagerNode),
- p("started"),
+ ?IPRINT("started"),
?SLEEP(1000),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("register user(s) user_alfa & user_beta"),
+ ?IPRINT("register user(s) user_alfa & user_beta"),
?line ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []),
?line ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("register agent(s)"),
+ ?IPRINT("register agent(s)"),
?line ok = mgr_register_agent(ManagerNode, user_alfa, 5000, []),
?line ok = mgr_register_agent(ManagerNode, user_alfa, 5001, []),
?line ok = mgr_register_agent(ManagerNode, user_beta, 5002, []),
?line ok = mgr_register_agent(ManagerNode, user_beta, 5003, []),
- p("verify all agent(s): expect 4"),
+ ?IPRINT("verify all agent(s): expect 4"),
case mgr_which_agents(ManagerNode) of
Agents1 when length(Agents1) =:= 4 ->
- p("all agents: ~p~n", [Agents1]),
+ ?IPRINT("all agents: ~p~n", [Agents1]),
ok;
Agents1 ->
?FAIL({agent_registration_failure, Agents1})
end,
- p("verify user_alfa agent(s)"),
+ ?IPRINT("verify user_alfa agent(s)"),
case mgr_which_agents(ManagerNode, user_alfa) of
Agents2 when length(Agents2) =:= 2 ->
- p("calvin agents: ~p~n", [Agents2]),
+ ?IPRINT("calvin agents: ~p", [Agents2]),
ok;
Agents2 ->
?FAIL({agent_registration_failure, Agents2})
end,
- p("verify user_beta agent(s)"),
+ ?IPRINT("verify user_beta agent(s)"),
case mgr_which_agents(ManagerNode, user_beta) of
Agents3 when length(Agents3) =:= 2 ->
- p("hobbe agents: ~p~n", [Agents3]),
+ ?IPRINT("hobbe agents: ~p", [Agents3]),
ok;
Agents3 ->
?FAIL({agent_registration_failure, Agents3})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(ManagerNode)]),
- p("unregister user user_alfa"),
+ ?IPRINT("unregister user user_alfa"),
?line ok = mgr_unregister_user(ManagerNode, user_alfa),
- p("verify all agent(s): expect 2"),
+ ?IPRINT("verify all agent(s): expect 2"),
case mgr_which_agents(ManagerNode) of
Agents4 when length(Agents4) =:= 2 ->
- p("all agents: ~p~n", [Agents4]),
+ ?IPRINT("all agents: ~p", [Agents4]),
ok;
Agents4 ->
?FAIL({agent_unregistration_failure, Agents4})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p~n", [mgr_info(ManagerNode)]),
- p("unregister user_beta agents"),
+ ?IPRINT("unregister user_beta agents"),
?line ok = mgr_unregister_agent(ManagerNode, user_beta, 5002),
?line ok = mgr_unregister_agent(ManagerNode, user_beta, 5003),
- p("verify all agent(s): expect 0"),
+ ?IPRINT("verify all agent(s): expect 0"),
case mgr_which_agents(ManagerNode) of
[] ->
ok;
Agents5 ->
- p("all agents: ~p~n", [Agents5]),
+ ?IPRINT("all agents: ~p~n", [Agents5]),
?FAIL({agent_unregistration_failure, Agents5})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(ManagerNode)]),
- p("unregister user hobbe"),
+ ?IPRINT("unregister user hobbe"),
?line ok = mgr_unregister_user(ManagerNode, user_beta),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(ManagerNode)]),
?SLEEP(1000),
- p("stop snmp application (with only manager)"),
+ ?IPRINT("stop snmp application (with only manager)"),
?line ok = stop_snmp(ManagerNode),
?SLEEP(1000),
-
- stop_node(ManagerNode),
-
- ?SLEEP(1000),
+ ?IPRINT("end"),
ok.
@@ -1632,19 +1691,22 @@ register_agent2(doc) ->
register_agent2(suite) ->
[];
register_agent2(Config) when is_list(Config) ->
- ?TC_TRY(register_agent2,
- fun() -> do_register_agent2(Config) end).
-
-do_register_agent2(Config) ->
- p("starting with Config: ~p~n", [Config]),
-
- ManagerNode = start_manager_node(),
-
- ConfDir = ?config(manager_conf_dir, Config),
- DbDir = ?config(manager_db_dir, Config),
+ Pre = fun() ->
+ ManagerNode = start_manager_node(),
+ [ManagerNode]
+ end,
+ Case = fun(State) -> do_register_agent2(State, Config) end,
+ Post = fun([ManagerNode]) -> stop_node(ManagerNode) end,
+ ?TC_TRY(register_agent2, Pre, Case, Post).
+
+do_register_agent2([ManagerNode], Config) ->
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
LocalHost = snmp_test_lib:localhost(),
-
write_manager_conf(ConfDir),
Opts = [{server, [{verbosity, trace}]},
@@ -1652,28 +1714,27 @@ do_register_agent2(Config) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
-
- p("load snmp application"),
+ ?IPRINT("load snmp application"),
?line ok = load_snmp(ManagerNode),
- p("set manager env for the snmp application"),
+ ?IPRINT("set manager env for the snmp application"),
?line ok = set_mgr_env(ManagerNode, Opts),
- p("starting snmp application (with only manager)"),
+ ?IPRINT("starting snmp application (with only manager)"),
?line ok = start_snmp(ManagerNode),
- p("started"),
+ ?IPRINT("started"),
?SLEEP(1000),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("register user(s) user_alfa & user_beta"),
+ ?IPRINT("register user(s) user_alfa & user_beta"),
?line ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []),
?line ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("register agent(s)"),
+ ?IPRINT("register agent(s)"),
TargetName1 = "agent1",
?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName1,
[{address, LocalHost},
@@ -1695,79 +1756,75 @@ do_register_agent2(Config) ->
{port, 5004},
{engine_id, "agentEngineId-4"}]),
- p("verify all agent(s): expect 4"),
+ ?IPRINT("verify all agent(s): expect 4"),
case mgr_which_agents(ManagerNode) of
Agents1 when length(Agents1) =:= 4 ->
- p("all agents: ~p~n", [Agents1]),
+ ?IPRINT("all agents: ~p~n", [Agents1]),
ok;
Agents1 ->
?FAIL({agent_registration_failure, Agents1})
end,
- p("verify user_alfa agent(s)"),
+ ?IPRINT("verify user_alfa agent(s)"),
case mgr_which_agents(ManagerNode, user_alfa) of
Agents2 when length(Agents2) =:= 2 ->
- p("calvin agents: ~p~n", [Agents2]),
+ ?IPRINT("calvin agents: ~p~n", [Agents2]),
ok;
Agents2 ->
?FAIL({agent_registration_failure, Agents2})
end,
- p("verify user_beta agent(s)"),
+ ?IPRINT("verify user_beta agent(s)"),
case mgr_which_agents(ManagerNode, user_beta) of
Agents3 when length(Agents3) =:= 2 ->
- p("hobbe agents: ~p~n", [Agents3]),
+ ?IPRINT("hobbe agents: ~p~n", [Agents3]),
ok;
Agents3 ->
?FAIL({agent_registration_failure, Agents3})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("unregister user user_alfa"),
+ ?IPRINT("unregister user user_alfa"),
?line ok = mgr_unregister_user(ManagerNode, user_alfa),
- p("verify all agent(s): expect 2"),
+ ?IPRINT("verify all agent(s): expect 2"),
case mgr_which_agents(ManagerNode) of
Agents4 when length(Agents4) =:= 2 ->
- p("all agents: ~p~n", [Agents4]),
+ ?IPRINT("all agents: ~p~n", [Agents4]),
ok;
Agents4 ->
?FAIL({agent_unregistration_failure, Agents4})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("unregister user_beta agents"),
+ ?IPRINT("unregister user_beta agents"),
?line ok = mgr_unregister_agent(ManagerNode, user_beta, TargetName3),
?line ok = mgr_unregister_agent(ManagerNode, user_beta, TargetName4),
- p("verify all agent(s): expect 0"),
+ ?IPRINT("verify all agent(s): expect 0"),
case mgr_which_agents(ManagerNode) of
[] ->
ok;
Agents5 ->
- p("all agents: ~p~n", [Agents5]),
+ ?IPRINT("all agents: ~p~n", [Agents5]),
?FAIL({agent_unregistration_failure, Agents5})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("unregister user user_beta"),
+ ?IPRINT("unregister user user_beta"),
?line ok = mgr_unregister_user(ManagerNode, user_beta),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
?SLEEP(1000),
- p("stop snmp application (with only manager)"),
+ ?IPRINT("stop snmp application (with only manager)"),
?line ok = stop_snmp(ManagerNode),
?SLEEP(1000),
- stop_node(ManagerNode),
-
- ?SLEEP(1000),
-
ok.
@@ -1779,16 +1836,20 @@ register_agent3(doc) ->
register_agent3(suite) ->
[];
register_agent3(Config) when is_list(Config) ->
- ?TC_TRY(register_agent3,
- fun() -> do_register_agent3(Config) end).
-
-do_register_agent3(Config) ->
- p("starting with Config: ~p~n", [Config]),
-
- ManagerNode = start_manager_node(),
-
- ConfDir = ?config(manager_conf_dir, Config),
- DbDir = ?config(manager_db_dir, Config),
+ Pre = fun() ->
+ ManagerNode = start_manager_node(),
+ [ManagerNode]
+ end,
+ Case = fun(State) -> do_register_agent3(State, Config) end,
+ Post = fun([ManagerNode]) -> stop_node(ManagerNode) end,
+ ?TC_TRY(register_agent3, Pre, Case, Post).
+
+do_register_agent3([ManagerNode], Config) ->
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
LocalHost = snmp_test_lib:localhost(),
@@ -1800,27 +1861,27 @@ do_register_agent3(Config) ->
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("load snmp application"),
+ ?IPRINT("load snmp application"),
?line ok = load_snmp(ManagerNode),
- p("set manager env for the snmp application"),
+ ?IPRINT("set manager env for the snmp application"),
?line ok = set_mgr_env(ManagerNode, Opts),
- p("starting snmp application (with only manager)"),
+ ?IPRINT("starting snmp application (with only manager)"),
?line ok = start_snmp(ManagerNode),
- p("started"),
+ ?IPRINT("started"),
?SLEEP(1000),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("register user(s) user_alfa & user_beta"),
+ ?IPRINT("register user(s) user_alfa & user_beta"),
?line ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []),
?line ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("register agent(s)"),
+ ?IPRINT("register agent(s)"),
TargetName1 = "agent2",
?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName1,
[{tdomain, transportDomainUdpIpv4},
@@ -1840,7 +1901,7 @@ do_register_agent3(Config) ->
{address, LocalHost},
{port, 5003},
{engine_id, "agentEngineId-3"}]),
- p("Expected registration failure: ~p", [Reason4]),
+ ?IPRINT("Expected registration failure: ~p", [Reason4]),
TargetName4 = "agent5",
?line {error, {unknown_domain, _} = Reason5} =
mgr_register_agent(ManagerNode, user_beta, TargetName4,
@@ -1848,77 +1909,73 @@ do_register_agent3(Config) ->
{address, LocalHost},
{port, 5004},
{engine_id, "agentEngineId-4"}]),
- p("Expected registration failure: ~p", [Reason5]),
+ ?IPRINT("Expected registration failure: ~p", [Reason5]),
- p("verify all agent(s): expect 2"),
+ ?IPRINT("verify all agent(s): expect 2"),
case mgr_which_agents(ManagerNode) of
Agents1 when length(Agents1) =:= 2 ->
- p("all agents: ~p~n", [Agents1]),
+ ?IPRINT("all agents: ~p~n", [Agents1]),
ok;
Agents1 ->
?FAIL({agent_registration_failure, Agents1})
end,
- p("verify user_alfa agent(s)"),
+ ?IPRINT("verify user_alfa agent(s)"),
case mgr_which_agents(ManagerNode, user_alfa) of
Agents2 when length(Agents2) =:= 2 ->
- p("calvin agents: ~p~n", [Agents2]),
+ ?IPRINT("calvin agents: ~p~n", [Agents2]),
ok;
Agents2 ->
?FAIL({agent_registration_failure, Agents2})
end,
- p("verify user_beta agent(s)"),
+ ?IPRINT("verify user_beta agent(s)"),
case mgr_which_agents(ManagerNode, user_beta) of
Agents3 when length(Agents3) =:= 0 ->
- p("hobbe agents: ~p~n", [Agents3]),
+ ?IPRINT("hobbe agents: ~p~n", [Agents3]),
ok;
Agents3 ->
?FAIL({agent_registration_failure, Agents3})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("unregister user user_alfa"),
+ ?IPRINT("unregister user user_alfa"),
?line ok = mgr_unregister_user(ManagerNode, user_alfa),
- p("verify all agent(s): expect 0"),
+ ?IPRINT("verify all agent(s): expect 0"),
case mgr_which_agents(ManagerNode) of
Agents4 when length(Agents4) =:= 0 ->
- p("all agents: ~p~n", [Agents4]),
+ ?IPRINT("all agents: ~p~n", [Agents4]),
ok;
Agents4 ->
?FAIL({agent_unregistration_failure, Agents4})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("verify all agent(s): expect 0"),
+ ?IPRINT("verify all agent(s): expect 0"),
case mgr_which_agents(ManagerNode) of
[] ->
ok;
Agents5 ->
- p("all agents: ~p~n", [Agents5]),
+ ?EPRINT("all agents: ~p~n", [Agents5]),
?FAIL({agent_unregistration_failure, Agents5})
end,
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
- p("unregister user user_beta"),
+ ?IPRINT("unregister user user_beta"),
?line ok = mgr_unregister_user(ManagerNode, user_beta),
- p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+ ?IPRINT("manager info: ~p~n", [mgr_info(ManagerNode)]),
?SLEEP(1000),
- p("stop snmp application (with only manager)"),
+ ?IPRINT("stop snmp application (with only manager)"),
?line ok = stop_snmp(ManagerNode),
?SLEEP(1000),
- stop_node(ManagerNode),
-
- ?SLEEP(1000),
-
ok.
@@ -1932,26 +1989,28 @@ simple_sync_get2(Config) when is_list(Config) ->
fun() -> do_simple_sync_get2(Config) end).
do_simple_sync_get2(Config) ->
- p("starting with Config: ~n~p", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Get = fun(Node, TargetName, Oids) ->
mgr_user_sync_get(Node, TargetName, Oids)
end,
PostVerify = fun() -> ok end,
- do_simple_sync_get2(Config, Get, PostVerify),
+ Res = do_simple_sync_get2(Config, Get, PostVerify),
display_log(Config),
- ok.
+ Res.
do_simple_sync_get2(Config, Get, PostVerify) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Node = ?config(manager_node, Config),
TargetName = ?config(manager_agent_target_name, Config),
- p("issue get-request without loading the mib"),
+ ?IPRINT("issue get-request without loading the mib"),
Oids1 = [?sysObjectID_instance, ?sysDescr_instance, ?sysUpTime_instance],
?line ok = do_simple_sync_get2(Node, TargetName, Oids1, Get, PostVerify),
- p("issue get-request after first loading the mibs"),
+ ?IPRINT("issue get-request after first loading the mibs"),
?line ok = mgr_user_load_mib(Node, std_mib()),
Oids2 = [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]],
?line ok = do_simple_sync_get2(Node, TargetName, Oids2, Get, PostVerify),
@@ -1973,17 +2032,19 @@ do_simple_sync_get2(Node, TargetName, Oids, Get, PostVerify)
value = SysDescr},
#varbind{oid = ?sysUpTime_instance,
value = SysUpTime}]} ->
- p("expected result from get: "
- "~n SysObjectID: ~p"
- "~n SysDescr: ~s"
- "~n SysUpTime: ~w",
- [SysObjectID, SysDescr, SysUpTime]),
+ ?IPRINT("expected result from get: "
+ "~n SysObjectID: ~p"
+ "~n SysDescr: ~s"
+ "~n SysUpTime: ~w",
+ [SysObjectID, SysDescr, SysUpTime]),
PostVerify();
{noError, 0, Vbs} ->
- p("unexpected varbinds: ~n~p", [Vbs]),
+ ?EPRINT("unexpected varbinds: "
+ "~n ~p", [Vbs]),
{error, {unexpected_vbs, Vbs}};
Else ->
- p("unexpected reply: ~n~p", [Else]),
+ ?EPRINT("unexpected reply: "
+ "~n ~p", [Else]),
{error, {unexpected_response, Else}}
end,
ok.
@@ -1999,7 +2060,8 @@ simple_sync_get3(Config) when is_list(Config) ->
fun() -> do_simple_sync_get3(Config) end).
do_simple_sync_get3(Config) ->
- p("starting with Config: ~n~p", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Self = self(),
Msg = simple_sync_get3,
Fun = fun() -> Self ! Msg end,
@@ -2018,9 +2080,9 @@ do_simple_sync_get3(Config) ->
ok
end
end,
- do_simple_sync_get2(Config, Get, PostVerify),
+ Res = do_simple_sync_get2(Config, Get, PostVerify),
display_log(Config),
- ok.
+ Res.
@@ -2028,7 +2090,7 @@ do_simple_sync_get3(Config) ->
%%======================================================================
sag_verify({noError, 0, _Vbs}, any) ->
- p("verified [any]"),
+ ?IPRINT("verified [any]"),
ok;
sag_verify({noError, 0, Vbs}, Exp) ->
?DBG("verified first stage ok: "
@@ -2046,13 +2108,13 @@ sag_verify_vbs(Vbs, []) ->
sag_verify_vbs([], Exp) ->
{error, {expected_vbs, Exp}};
sag_verify_vbs([#varbind{oid = Oid}|Vbs], [any|Exp]) ->
- p("verified [any] oid ~w", [Oid]),
+ ?IPRINT("verified [any] oid ~w", [Oid]),
sag_verify_vbs(Vbs, Exp);
sag_verify_vbs([#varbind{oid = Oid, value = Value}|Vbs], [Oid|Exp]) ->
- p("verified oid ~w [~p]", [Oid, Value]),
+ ?IPRINT("verified oid ~w [~p]", [Oid, Value]),
sag_verify_vbs(Vbs, Exp);
sag_verify_vbs([#varbind{oid = Oid, value = Value}|Vbs], [{Oid,Value}|Exp]) ->
- p("verified oid ~w and ~p", [Oid, Value]),
+ ?IPRINT("verified oid ~w and ~p", [Oid, Value]),
sag_verify_vbs(Vbs, Exp);
sag_verify_vbs([Vb|_], [E|_]) ->
{error, {unexpected_vb, Vb, E}}.
@@ -2068,7 +2130,8 @@ simple_async_get2(Config) when is_list(Config) ->
fun() -> do_simple_async_get2(Config) end).
do_simple_async_get2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
TargetName = ?config(manager_agent_target_name, Config),
@@ -2127,13 +2190,17 @@ do_simple_async_sync_get2(MgrInfo, AgentInfo, Get, PostVerify)
end}
],
- p("manager info when starting test: ~n~p", [MgrInfo()]),
- p("agent info when starting test: ~n~p", [AgentInfo()]),
+ ?IPRINT("manager info when starting test: "
+ "~n ~p", [MgrInfo()]),
+ ?IPRINT("agent info when starting test: "
+ "~n ~p", [AgentInfo()]),
?line ok = async_exec(Requests, []),
- p("manager info when ending test: ~n~p", [MgrInfo()]),
- p("agent info when ending test: ~n~p", [AgentInfo()]),
+ ?IPRINT("manager info when ending test: "
+ "~n ~p", [MgrInfo()]),
+ ?IPRINT("agent info when ending test: "
+ "~n ~p", [AgentInfo()]),
ok.
@@ -2151,7 +2218,8 @@ simple_async_get3(Config) when is_list(Config) ->
fun() -> do_simple_async_get3(Config) end).
do_simple_async_get3(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
TargetName = ?config(manager_agent_target_name, Config),
@@ -2167,9 +2235,9 @@ do_simple_async_get3(Config) ->
PostVerify = fun(ok) -> receive Msg -> ok end;
(Error) -> Error
end,
- do_simple_async_sync_get2(Config, MgrNode, AgentNode, Get, PostVerify),
+ Res = do_simple_async_sync_get2(Config, MgrNode, AgentNode, Get, PostVerify),
display_log(Config),
- ok.
+ Res.
async_g_exec3(Node, TargetName, Oids, SendOpts) ->
mgr_user_async_get2(Node, TargetName, Oids, SendOpts).
@@ -2219,15 +2287,16 @@ simple_sync_get_next2(Config) when is_list(Config) ->
fun() -> do_simple_sync_get_next2(Config) end).
do_simple_sync_get_next2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
GetNext = fun(Node, TargetName, Oids) ->
mgr_user_sync_get_next(Node, TargetName, Oids)
end,
PostVerify = fun(Res) -> Res end,
- do_simple_sync_get_next2(Config, GetNext, PostVerify),
+ Res = do_simple_sync_get_next2(Config, GetNext, PostVerify),
display_log(Config),
- ok.
+ Res.
do_simple_sync_get_next2(Config, GetNext, PostVerify)
@@ -2322,7 +2391,7 @@ do_simple_sync_get_next2(Config, GetNext, PostVerify)
do_simple_get_next(N, Node, TargetName, Oids, Verify, GetNext, PostVerify) ->
- p("issue get-next command ~w", [N]),
+ ?IPRINT("issue get-next command ~w", [N]),
case GetNext(Node, TargetName, Oids) of
{ok, Reply, _Rem} ->
?DBG("get-next ok:"
@@ -2344,7 +2413,8 @@ simple_sync_get_next3(suite) -> [];
simple_sync_get_next3(Config) when is_list(Config) ->
process_flag(trap_exit, true),
put(tname, ssgn3),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Self = self(),
Msg = simple_sync_get_next3,
Fun = fun() -> Self ! Msg end,
@@ -2374,7 +2444,8 @@ simple_async_get_next2(Config) when is_list(Config) ->
fun() -> do_simple_async_get_next2(Config) end).
do_simple_async_get_next2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -2388,9 +2459,9 @@ do_simple_async_get_next2(Config) ->
async_gn_exec2(MgrNode, TargetName, Oids)
end,
PostVerify = fun(Res) -> Res end,
- do_simple_async_get_next2(MgrNode, AgentNode, GetNext, PostVerify),
+ Res = do_simple_async_get_next2(MgrNode, AgentNode, GetNext, PostVerify),
display_log(Config),
- ok.
+ Res.
do_simple_async_get_next2(MgrNode, AgentNode, GetNext, PostVerify)
when is_function(GetNext, 1) andalso is_function(PostVerify, 1) ->
@@ -2461,13 +2532,17 @@ do_simple_async_get_next2(MgrNode, AgentNode, GetNext, PostVerify)
end}
],
- p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
- p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info when starting test: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info when starting test: "
+ "~n ~p", [agent_info(AgentNode)]),
?line ok = async_exec(Requests, []),
- p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
- p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info when ending test: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info when ending test: "
+ "~n ~p", [agent_info(AgentNode)]),
ok.
@@ -2505,7 +2580,8 @@ simple_async_get_next3(Case, Config) when is_list(Config) ->
do_simple_async_get_next3(Config) ->
%% process_flag(trap_exit, true),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -2532,9 +2608,9 @@ do_simple_async_get_next3(Config) ->
(Error) -> Error
end,
- do_simple_async_get_next2(MgrNode, AgentNode, GetNext, PostVerify),
+ Res = do_simple_async_get_next2(MgrNode, AgentNode, GetNext, PostVerify),
display_log(Config),
- ok.
+ Res.
async_gn_exec3(Node, TargetName, Oids, SendOpts) ->
mgr_user_async_get_next2(Node, TargetName, Oids, SendOpts).
@@ -2563,16 +2639,17 @@ simple_sync_set2(Config) when is_list(Config) ->
fun() -> do_simple_sync_set2(Config) end).
do_simple_sync_set2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Set = fun(Node, TargetName, VAVs) ->
mgr_user_sync_set(Node, TargetName, VAVs)
end,
PostVerify = fun() -> ok end,
- do_simple_sync_set2(Config, Set, PostVerify),
+ Res = do_simple_sync_set2(Config, Set, PostVerify),
display_log(Config),
- ok.
+ Res.
do_simple_sync_set2(Config, Set, PostVerify)
when is_function(Set, 3) andalso is_function(PostVerify, 0) ->
@@ -2580,7 +2657,7 @@ do_simple_sync_set2(Config, Set, PostVerify)
Node = ?config(manager_node, Config),
TargetName = ?config(manager_agent_target_name, Config),
- p("issue set-request without loading the mib"),
+ ?IPRINT("issue set-request without loading the mib"),
Val11 = "Arne Anka",
Val12 = "Stockholm",
VAVs1 = [
@@ -2589,7 +2666,7 @@ do_simple_sync_set2(Config, Set, PostVerify)
],
?line ok = do_simple_set2(Node, TargetName, VAVs1, Set, PostVerify),
- p("issue set-request after first loading the mibs"),
+ ?IPRINT("issue set-request after first loading the mibs"),
?line ok = mgr_user_load_mib(Node, std_mib()),
Val21 = "Sune Anka",
Val22 = "Gothenburg",
@@ -2619,7 +2696,8 @@ do_simple_set2(Node, TargetName, VAVs, Set, PostVerify) ->
{noError, 0, Vbs} ->
{error, {unexpected_vbs, Vbs}};
Else ->
- p("unexpected reply: ~n~p", [Else]),
+ ?EPRINT("unexpected reply: "
+ "~n ~p", [Else]),
{error, {unexpected_response, Else}}
end,
ok.
@@ -2635,7 +2713,8 @@ simple_sync_set3(Config) when is_list(Config) ->
fun() -> do_simple_sync_set3(Config) end).
do_simple_sync_set3(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p", [Config]),
Self = self(),
Msg = simple_sync_set3,
@@ -2651,15 +2730,15 @@ do_simple_sync_set3(Config) ->
end,
PostVerify = fun() -> receive Msg -> ok end end,
- do_simple_sync_set2(Config, Set, PostVerify),
+ Res = do_simple_sync_set2(Config, Set, PostVerify),
display_log(Config),
- ok.
+ Res.
%%======================================================================
sas_verify({noError, 0, _Vbs}, any) ->
- p("verified [any]"),
+ ?IPRINT("verified [any]"),
ok;
sas_verify({noError, 0, Vbs}, Expected) ->
?DBG("verified stage 1: "
@@ -2676,13 +2755,13 @@ sas_verify_vbs(Vbs, []) ->
sas_verify_vbs([], Exp) ->
{error, {expected_vbs, Exp}};
sas_verify_vbs([#varbind{oid = Oid}|Vbs], [any|Exp]) ->
- p("verified [any] oid ~w", [Oid]),
+ ?IPRINT("verified [any] oid ~w", [Oid]),
sas_verify_vbs(Vbs, Exp);
sas_verify_vbs([#varbind{oid = Oid, value = Value}|Vbs], [Oid|Exp]) ->
- p("verified oid ~w [~p]", [Oid, Value]),
+ ?IPRINT("verified oid ~w [~p]", [Oid, Value]),
sas_verify_vbs(Vbs, Exp);
sas_verify_vbs([#varbind{oid = Oid, value = Value}|Vbs], [{Oid,Value}|Exp]) ->
- p("verified oid ~w and ~p", [Oid, Value]),
+ ?IPRINT("verified oid ~w and ~p", [Oid, Value]),
sas_verify_vbs(Vbs, Exp);
sas_verify_vbs([Vb|_], [E|_]) ->
{error, {unexpected_vb, Vb, E}}.
@@ -2698,7 +2777,9 @@ simple_async_set2(Config) when is_list(Config) ->
fun() -> do_simple_async_set2(Config) end).
do_simple_async_set2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -2715,9 +2796,9 @@ do_simple_async_set2(Config) ->
end,
PostVerify = fun(Res) -> Res end,
- do_simple_async_set2(MgrNode, AgentNode, Set, PostVerify),
+ Res = do_simple_async_set2(MgrNode, AgentNode, Set, PostVerify),
display_log(Config),
- ok.
+ Res.
do_simple_async_set2(MgrNode, AgentNode, Set, PostVerify) ->
Requests =
@@ -2748,13 +2829,17 @@ do_simple_async_set2(MgrNode, AgentNode, Set, PostVerify) ->
end}
],
- p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
- p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info when starting test: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info when starting test: "
+ "~n ~p", [agent_info(AgentNode)]),
?line ok = async_exec(Requests, []),
- p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
- p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info when ending test: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info when ending test: "
+ "~n ~p", [agent_info(AgentNode)]),
ok.
@@ -2788,7 +2873,8 @@ simple_async_set3(Case, Config) ->
fun() -> do_simple_async_set3(Config) end).
do_simple_async_set3(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -2816,9 +2902,9 @@ do_simple_async_set3(Config) ->
(Res) -> Res
end,
- do_simple_async_set2(MgrNode, AgentNode, Set, PostVerify),
+ Res = do_simple_async_set2(MgrNode, AgentNode, Set, PostVerify),
display_log(Config),
- ok.
+ Res.
async_s_exec3(Node, TargetName, VAVs, SendOpts) ->
mgr_user_async_set2(Node, TargetName, VAVs, SendOpts).
@@ -2871,7 +2957,8 @@ simple_sync_get_bulk2(Config) when is_list(Config) ->
fun() -> do_simple_sync_get_bulk2(Config) end).
do_simple_sync_get_bulk2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -2884,9 +2971,9 @@ do_simple_sync_get_bulk2(Config) ->
end,
PostVerify = fun(Res) -> Res end,
- do_simple_sync_get_bulk2(Config, MgrNode, AgentNode, GetBulk, PostVerify),
+ Res = do_simple_sync_get_bulk2(Config, MgrNode, AgentNode, GetBulk, PostVerify),
display_log(Config),
- ok.
+ Res.
do_simple_sync_get_bulk2(Config, MgrNode, AgentNode, GetBulk, PostVerify) ->
%% -- 1 --
@@ -2986,7 +3073,7 @@ do_simple_sync_get_bulk2(Config, MgrNode, AgentNode, GetBulk, PostVerify) ->
%% -- 11 --
?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
- p("TCnt2: ~p", [TCnt2]),
+ ?IPRINT("TCnt2: ~p", [TCnt2]),
VF11 = fun(X) ->
verify_ssgb_reply2(X,
[{fl([TCnt2,2]), 100},
@@ -3005,7 +3092,7 @@ do_simple_get_bulk2(N,
when is_function(Verify, 1) andalso
is_function(GetBulk, 3) andalso
is_function(PostVerify) ->
- p("issue get-bulk command ~w", [N]),
+ ?IPRINT("issue get-bulk command ~w", [N]),
case GetBulk(NonRep, MaxRep, Oids) of
{ok, Reply, _Rem} ->
?DBG("get-bulk ok:"
@@ -3029,7 +3116,8 @@ simple_sync_get_bulk3(Config) when is_list(Config) ->
fun() -> do_simple_sync_get_bulk3(Config) end).
do_simple_sync_get_bulk3(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -3053,9 +3141,9 @@ do_simple_sync_get_bulk3(Config) ->
(Res) -> Res
end,
- do_simple_sync_get_bulk2(Config, MgrNode, AgentNode, GetBulk, PostVerify),
+ Res = do_simple_sync_get_bulk2(Config, MgrNode, AgentNode, GetBulk, PostVerify),
display_log(Config),
- ok.
+ Res.
%%======================================================================
@@ -3068,7 +3156,8 @@ simple_async_get_bulk2(Config) when is_list(Config) ->
fun() -> do_simple_async_get_bulk2(Config) end).
do_simple_async_get_bulk2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~p ~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -3085,9 +3174,9 @@ do_simple_async_get_bulk2(Config) ->
end,
PostVerify = fun(Res) -> Res end,
- do_simple_async_get_bulk2(MgrNode, AgentNode, GetBulk, PostVerify),
+ Res = do_simple_async_get_bulk2(MgrNode, AgentNode, GetBulk, PostVerify),
display_log(Config),
- ok.
+ Res.
do_simple_async_get_bulk2(MgrNode, AgentNode, GetBulk, PostVerify) ->
%% We re-use the verification functions from the ssgb test-case
@@ -3200,13 +3289,17 @@ do_simple_async_get_bulk2(MgrNode, AgentNode, GetBulk, PostVerify) ->
VF10}
],
- p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
- p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info when starting test: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info when starting test: "
+ "~n ~p", [agent_info(AgentNode)]),
?line ok = async_exec(Requests, []),
- p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
- p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info when ending test: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info when ending test: "
+ "~n ~p", [agent_info(AgentNode)]),
ok.
@@ -3230,7 +3323,8 @@ simple_async_get_bulk3(Case, Config) ->
do_simple_async_get_bulk3(Config) ->
process_flag(trap_exit, true),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -3258,9 +3352,9 @@ do_simple_async_get_bulk3(Config) ->
(Res) -> Res
end,
- do_simple_async_get_bulk2(MgrNode, AgentNode, GetBulk, PostVerify),
+ Res = do_simple_async_get_bulk2(MgrNode, AgentNode, GetBulk, PostVerify),
display_log(Config),
- ok.
+ Res.
async_gb_exec3(Node, TargetName, {NR, MR, Oids}, SendOpts) ->
mgr_user_async_get_bulk2(Node, TargetName, NR, MR, Oids, SendOpts).
@@ -3296,7 +3390,9 @@ misc_async2(Config) when is_list(Config) ->
fun() -> do_misc_async2(Config) end).
do_misc_async2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -3465,13 +3561,17 @@ do_misc_async2(Config) ->
end}
],
- p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
- p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info when starting test: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info when starting test: "
+ "~n ~p", [agent_info(AgentNode)]),
?line ok = async_exec(Requests, []),
- p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
- p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info when ending test: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info when ending test: "
+ "~n ~p", [agent_info(AgentNode)]),
display_log(Config),
ok.
@@ -3497,45 +3597,47 @@ collect_traps(0, TrapInfo) ->
collect_traps(N, Acc) ->
receive
{async_event, _From, {trap, TrapInfo}} ->
- p("collect_traps -> received trap: ~n ~p", [TrapInfo]),
+ ?IPRINT("collect_traps -> received trap: "
+ "~n ~p", [TrapInfo]),
collect_traps(N-1, [TrapInfo|Acc])
after 10000 ->
- p("collect_traps -> still awaiting ~w trap(s) - giving up", [N]),
+ ?WPRINT("collect_traps -> still awaiting ~w trap(s) - giving up", [N]),
Acc
end.
verify_traps([], []) ->
- p("verify_traps -> done"),
+ ?IPRINT("verify_traps -> done"),
ok;
verify_traps([], Verifiers) ->
- p("verify_traps -> done when ~w verifiers remain", [length(Verifiers)]),
+ ?IPRINT("verify_traps -> done when ~w verifiers remain", [length(Verifiers)]),
{error, {failed_verify, [Id || {Id, _} <- Verifiers]}};
verify_traps([Trap|Traps], Verifiers0) ->
- p("verify_traps -> entry"),
+ ?IPRINT("verify_traps -> entry"),
case verify_trap(Trap, Verifiers0) of
{ok, Id} ->
- p("verify_traps -> trap verified: ~p", [Id]),
+ ?IPRINT("verify_traps -> trap verified: ~p", [Id]),
Verifiers = lists:keydelete(Id, 1, Verifiers0),
verify_traps(Traps, Verifiers);
error ->
- p("verify_traps -> failed verifying trap: ~n ~p", [Trap]),
+ ?EPRINT("verify_traps -> failed verifying trap: "
+ "~n ~p", [Trap]),
{error, {failed_verifying_trap, Trap}}
end.
verify_trap(Trap, []) ->
- p("verify_trap -> could not verify trap:"
- "~n Trap: ~p", [Trap]),
+ ?EPRINT("verify_trap -> could not verify trap:"
+ "~n Trap: ~p", [Trap]),
error;
verify_trap(Trap, [{Id, Verifier}|Verifiers]) ->
- p("verify_trap -> entry with"
- "~n Id: ~p"
- "~n Trap: ~p", [Id, Trap]),
+ ?IPRINT("verify_trap -> entry with"
+ "~n Id: ~p"
+ "~n Trap: ~p", [Id, Trap]),
case Verifier(Trap) of
ok ->
- p("verify_trap -> verified"),
+ ?IPRINT("verify_trap -> verified"),
{ok, Id};
{error, _} ->
- p("verify_trap -> not verified"),
+ ?NPRINT("verify_trap -> not verified"),
verify_trap(Trap, Verifiers)
end.
@@ -3548,7 +3650,9 @@ trap1(Config) when is_list(Config) ->
fun() -> do_trap1(Config) end).
do_trap1(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -3569,32 +3673,33 @@ do_trap1(Config) ->
fun(Ent, Gen, Spec, ExpVBs, Trap) ->
case Trap of
{Ent, Gen, Spec, _Timestamp, VBs} ->
- p("trap info as expected"),
+ ?IPRINT("trap info as expected"),
case (catch validate_vbs(MgrNode,
ExpVBs, VBs)) of
ok ->
- p("valid trap"),
+ ?IPRINT("valid trap"),
ok;
Error ->
- p("invalid trap: ~n Error: ~p", [Error]),
+ ?EPRINT("invalid trap: "
+ "~n ~p", [Error]),
Error
end;
{Enteprise, Generic, Spec, Timestamp, VBs} ->
- p("unepxected v1 trap info:"
- "~n Enteprise: ~p"
- "~n Generic: ~p"
- "~n Spec: ~p"
- "~n Timestamp: ~p"
- "~n VBs: ~p",
- [Enteprise, Generic, Spec, Timestamp, VBs]),
+ ?EPRINT("unepxected v1 trap info:"
+ "~n Enteprise: ~p"
+ "~n Generic: ~p"
+ "~n Spec: ~p"
+ "~n Timestamp: ~p"
+ "~n VBs: ~p",
+ [Enteprise, Generic, Spec, Timestamp, VBs]),
ExpTrap = {Ent, Gen, Spec, ignore, ExpVBs},
Reason = {unexpected_trap, {ExpTrap, Trap}},
{error, Reason};
{Err, Idx, VBs} ->
- p("unexpected trap info: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected trap info: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -3605,24 +3710,25 @@ do_trap1(Config) ->
fun(ExpVBs, Trap) ->
case Trap of
{noError, 0, VBs0} ->
- p("trap info as expected: ~n~p", [VBs0]),
+ ?IPRINT("trap info as expected: "
+ "~n ~p", [VBs0]),
%% The first two are a timestamp and oid
[_,_|VBs] = VBs0,
case (catch validate_vbs(MgrNode,
ExpVBs, VBs)) of
ok ->
- p("valid trap"),
+ ?IPRINT("valid trap"),
ok;
Error ->
- p("invalid trap: ~n Error: ~p",
- [Error]),
+ ?EPRINT("invalid trap: "
+ "~n ~p", [Error]),
Error
end;
{Err, Idx, VBs} ->
- p("unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -3633,8 +3739,10 @@ do_trap1(Config) ->
%% Collect various info about the manager and the agent
Cmd1 =
fun() ->
- p("manager info: ~n~p", [mgr_info(MgrNode)]),
- p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info: "
+ "~n ~p", [agent_info(AgentNode)]),
ok
end,
@@ -3690,9 +3798,9 @@ do_trap1(Config) ->
{5, "Manager and agent info after test completion", Cmd1}
],
- command_handler(Commands),
+ Res = command_handler(Commands),
display_log(Config),
- ok.
+ Res.
%%======================================================================
@@ -3703,7 +3811,9 @@ trap2(Config) when is_list(Config) ->
fun() -> do_trap2(Config) end).
do_trap2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -3724,32 +3834,32 @@ do_trap2(Config) ->
fun(Ent, Gen, Spec, ExpVBs, Trap) ->
case Trap of
{Ent, Gen, Spec, _Timestamp, VBs} ->
- p("trap info as expected"),
+ ?IPRINT("trap info as expected"),
case (catch validate_vbs(MgrNode,
ExpVBs, VBs)) of
ok ->
- p("valid trap"),
+ ?IPRINT("valid trap"),
ok;
Error ->
- p("invalid trap: ~n Error: ~p", [Error]),
+ ?EPRINT("invalid trap: ~n Error: ~p", [Error]),
Error
end;
{Enteprise, Generic, Spec, Timestamp, VBs} ->
- p("unepxected v1 trap info:"
- "~n Enteprise: ~p"
- "~n Generic: ~p"
- "~n Spec: ~p"
- "~n Timestamp: ~p"
- "~n VBs: ~p",
- [Enteprise, Generic, Spec, Timestamp, VBs]),
+ ?EPRINT("unepxected v1 trap info:"
+ "~n Enteprise: ~p"
+ "~n Generic: ~p"
+ "~n Spec: ~p"
+ "~n Timestamp: ~p"
+ "~n VBs: ~p",
+ [Enteprise, Generic, Spec, Timestamp, VBs]),
ExpTrap = {Ent, Gen, Spec, ignore, ExpVBs},
Reason = {unexpected_trap, {ExpTrap, Trap}},
{error, Reason};
{Err, Idx, VBs} ->
- p("unexpected trap info: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected trap info: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -3760,24 +3870,24 @@ do_trap2(Config) ->
fun(ExpVBs, Trap) ->
case Trap of
{noError, 0, VBs0} ->
- p("trap info as expected: ~n~p", [VBs0]),
+ ?IPRINT("trap info as expected: ~n~p", [VBs0]),
%% The first two are a timestamp and oid
[_,_|VBs] = VBs0,
case (catch validate_vbs(MgrNode,
ExpVBs, VBs)) of
ok ->
- p("valid trap"),
+ ?IPRINT("valid trap"),
ok;
Error ->
- p("invalid trap: ~n Error: ~p",
- [Error]),
+ ?EPRINT("invalid trap: "
+ "~n ~p", [Error]),
Error
end;
{Err, Idx, VBs} ->
- p("unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -3787,8 +3897,10 @@ do_trap2(Config) ->
%% Collect various info about the manager and the agent
Cmd1 =
fun() ->
- p("manager info: ~n~p", [mgr_info(MgrNode)]),
- p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info: "
+ "~n ~p", [agent_info(AgentNode)]),
ok
end,
@@ -3885,9 +3997,9 @@ do_trap2(Config) ->
{7, "Manager and agent info after test completion", Cmd1}
],
- command_handler(Commands),
+ Res = command_handler(Commands),
display_log(Config),
- ok.
+ Res.
%%======================================================================
@@ -3898,7 +4010,9 @@ inform1(Config) when is_list(Config) ->
fun() -> do_inform1(Config) end).
do_inform1(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -3917,9 +4031,12 @@ do_inform1(Config) ->
Cmd1 =
fun() ->
- p("manager info: ~n~p", [mgr_info(MgrNode)]),
- p("manager system info: ~n~p", [mgr_sys_info(MgrNode)]),
- p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("manager system info: "
+ "~n ~p", [mgr_sys_info(MgrNode)]),
+ ?IPRINT("agent info: "
+ "~n ~p", [agent_info(AgentNode)]),
ok
end,
@@ -3933,26 +4050,26 @@ do_inform1(Config) ->
fun() ->
receive
{async_event, From, {inform, Pid, Inform}} ->
- p("received inform"),
+ ?IPRINT("received inform"),
case Inform of
{noError, 0, VBs} when is_list(VBs) ->
case (catch validate_testTrapv22_vbs(MgrNode,
VBs)) of
ok ->
- p("valid inform"),
+ ?IPRINT("valid inform"),
Pid ! {handle_inform_no_response,
From},
ok;
Error ->
- p("invalid inform: ~n Error: ~p",
- [Error]),
+ ?EPRINT("invalid inform: "
+ "~n ~p", [Error]),
Error
end;
{Err, Idx, VBs} ->
- p("unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -3970,25 +4087,25 @@ do_inform1(Config) ->
fun() ->
receive
{async_event, From, {inform, Pid, Inform}} ->
- p("received inform"),
+ ?IPRINT("received inform"),
case Inform of
{noError, 0, VBs} when is_list(VBs) ->
case (catch validate_testTrapv22_vbs(MgrNode,
VBs)) of
ok ->
- p("valid inform"),
+ ?IPRINT("valid inform"),
Pid ! {handle_inform_response, From},
ok;
Error ->
- p("invalid inform: ~n Error: ~p",
- [Error]),
+ ?EPRINT("invalid inform: "
+ "~n ~p", [Error]),
Error
end;
{Err, Idx, VBs} ->
- p("unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -4014,9 +4131,9 @@ do_inform1(Config) ->
{6, "Manager and agent info after test completion", Cmd1}
],
- command_handler(Commands),
+ Res = command_handler(Commands),
display_log(Config),
- ok.
+ Res.
%%======================================================================
@@ -4027,7 +4144,9 @@ inform2(Config) when is_list(Config) ->
fun() -> do_inform2(Config) end).
do_inform2(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -4047,8 +4166,10 @@ do_inform2(Config) ->
Cmd1 =
fun() ->
- p("manager info: ~n~p", [mgr_info(MgrNode)]),
- p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info: "
+ "~n ~p", [agent_info(AgentNode)]),
ok
end,
@@ -4066,7 +4187,7 @@ do_inform2(Config) ->
fun() ->
receive
{snmp_targets, inform2_tag1, Addrs} ->
- p("sent inform to ~p", [Addrs]),
+ ?IPRINT("sent inform to ~p", [Addrs]),
ok
after 10000 ->
receive
@@ -4082,26 +4203,26 @@ do_inform2(Config) ->
fun() ->
receive
{async_event, From, {inform, Pid, Inform}} ->
- p("received inform"),
+ ?IPRINT("received inform"),
case Inform of
{noError, 0, VBs} when is_list(VBs) ->
case (catch validate_testTrapv22_vbs(MgrNode,
VBs)) of
ok ->
- p("valid inform"),
+ ?IPRINT("valid inform"),
Pid ! {handle_inform_no_response,
From},
ok;
Error ->
- p("invalid inform: ~n Error: ~p",
- [Error]),
+ ?IPRINT("invalid inform: "
+ "~n ~p", [Error]),
Error
end;
{Err, Idx, VBs} ->
- p("unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -4119,25 +4240,25 @@ do_inform2(Config) ->
fun() ->
receive
{async_event, From, {inform, Pid, Inform}} ->
- p("received inform"),
+ ?IPRINT("received inform"),
case Inform of
{noError, 0, VBs} when is_list(VBs) ->
case (catch validate_testTrapv22_vbs(MgrNode,
VBs)) of
ok ->
- p("valid inform"),
+ ?IPRINT("valid inform"),
Pid ! {handle_inform_response, From},
ok;
Error ->
- p("invalid inform: ~n Error: ~p",
- [Error]),
+ ?EPRINT("invalid inform: "
+ "~n ~p", [Error]),
Error
end;
{Err, Idx, VBs} ->
- p("unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -4155,14 +4276,14 @@ do_inform2(Config) ->
fun() ->
receive
{snmp_notification, inform2_tag1, {got_response, Addr}} ->
- p("received expected \"got response\" notification "
- "from: "
- "~n ~p", [Addr]),
+ ?IPRINT("received expected \"got response\" notification "
+ "from: "
+ "~n ~p", [Addr]),
ok;
{snmp_notification, inform2_tag1, {no_response, Addr}} ->
- e("Received unexpected \"no response\" "
- "notification from: "
- "~n ~p", [Addr]),
+ ?EPRINT("Received unexpected \"no response\" "
+ "notification from: "
+ "~n ~p", [Addr]),
{error, no_response}
after 10000 ->
receive
@@ -4188,9 +4309,9 @@ do_inform2(Config) ->
{8, "Manager and agent info after test completion", Cmd1}
],
- command_handler(Commands),
+ Res = command_handler(Commands),
display_log(Config),
- ok.
+ Res.
%%======================================================================
@@ -4201,7 +4322,8 @@ inform3(Config) when is_list(Config) ->
fun() -> do_inform3(Config) end).
do_inform3(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -4219,8 +4341,10 @@ do_inform3(Config) ->
Cmd1 =
fun() ->
- p("manager info: ~n~p", [mgr_info(MgrNode)]),
- p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info: "
+ "~n ~p", [agent_info(AgentNode)]),
ok
end,
@@ -4238,7 +4362,7 @@ do_inform3(Config) ->
fun() ->
receive
{snmp_targets, inform3_tag1, [_Addr]} ->
- p("received inform-sent acknowledgement", []),
+ ?IPRINT("received inform-sent ack"),
ok
after 10000 ->
receive
@@ -4254,26 +4378,25 @@ do_inform3(Config) ->
fun() ->
receive
{async_event, From, {inform, Pid, Inform}} ->
- p("received inform"),
+ ?IPRINT("received inform"),
case Inform of
{noError, 0, VBs} when is_list(VBs) ->
case (catch validate_testTrapv22_vbs(MgrNode,
VBs)) of
ok ->
- p("valid inform"),
- Pid ! {handle_inform_no_response,
- From},
+ ?IPRINT("valid inform"),
+ Pid ! {handle_inform_no_response, From},
ok;
Error ->
- p("invalid inform: ~n Error: ~p",
- [Error]),
+ ?EPRINT("invalid inform: "
+ "~n ~p", [Error]),
Error
end;
{Err, Idx, VBs} ->
- p("unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -4291,15 +4414,15 @@ do_inform3(Config) ->
fun() ->
receive
{snmp_notification, inform3_tag1, {no_response, Addr}} ->
- p("received expected \"no response\" notification "
- "from: "
- "~n ~p", [Addr]),
+ ?IPRINT("received expected \"no response\" notification "
+ "from: "
+ "~n ~p", [Addr]),
ok;
{snmp_notification, inform3_tag1, {got_response, Addr}} ->
- e("Received unexpected \"got response\" "
- "notification from: "
- "~n ~p",
- [Addr]),
+ ?EPRINT("Received unexpected \"got response\" "
+ "notification from: "
+ "~n ~p",
+ [Addr]),
{error, {got_response, Addr}}
after 120000 ->
receive
@@ -4326,9 +4449,9 @@ do_inform3(Config) ->
{9, "Manager and agent info after test completion", Cmd1}
],
- command_handler(Commands),
+ Res = command_handler(Commands),
display_log(Config),
- ok.
+ Res.
%%======================================================================
@@ -4339,7 +4462,8 @@ inform4(Config) when is_list(Config) ->
fun() -> do_inform4(Config) end).
do_inform4(Config) ->
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~n ~p~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -4357,8 +4481,10 @@ do_inform4(Config) ->
Cmd1 =
fun() ->
- p("manager info: ~n~p", [mgr_info(MgrNode)]),
- p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info: "
+ "~n ~p", [agent_info(AgentNode)]),
ok
end,
@@ -4372,13 +4498,13 @@ do_inform4(Config) ->
fun() ->
receive
{async_event, From, {inform, Pid, Inform}} ->
- p("received inform"),
+ ?IPRINT("received inform"),
case Inform of
{noError, 0, VBs} when is_list(VBs) ->
case (catch validate_testTrapv22_vbs(MgrNode,
VBs)) of
ok ->
- p("valid inform"),
+ ?IPRINT("valid inform"),
%% Actually, as we have
%% configured the manager in
%% this test case (irb = auto)
@@ -4386,15 +4512,15 @@ do_inform4(Config) ->
Pid ! {handle_inform_response, From},
ok;
Error ->
- p("invalid inform: ~n Error: ~p",
- [Error]),
+ ?EPRINT("invalid inform: "
+ "~n ~p", [Error]),
Error
end;
{Err, Idx, VBs} ->
- p("unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end
@@ -4413,11 +4539,11 @@ do_inform4(Config) ->
%% fun() ->
%% receive
%% {async_event, _ReqId, {error, Reason}} ->
-%% p("received error"),
+%% ?IPRINT("received error"),
%% case Reason of
%% {failed_processing_message,
%% {securityError, usmStatsUnknownEngineIDs}} ->
-%% p("expected error"),
+%% ?IPRINT("expected error"),
%% ok;
%% _ ->
%% p("unexpected error: "
@@ -4446,9 +4572,9 @@ do_inform4(Config) ->
{6, "Manager and agent info after test completion", Cmd1}
],
- command_handler(Commands),
+ Res = command_handler(Commands),
display_log(Config),
- ok.
+ Res.
%%======================================================================
@@ -4473,7 +4599,8 @@ inform_swarm(Case, Config) ->
do_inform_swarm(Config) ->
%% process_flag(trap_exit, true),
- p("starting with Config: ~p~n", [Config]),
+ ?IPRINT("starting with Config: "
+ "~p ~n", [Config]),
MgrNode = ?config(manager_node, Config),
AgentNode = ?config(agent_node, Config),
@@ -4502,7 +4629,7 @@ do_inform_swarm(Config) ->
Seqs = lists:seq(1, NumInforms),
lists:foreach(
fun(N) ->
- p("send notification ~w", [N]),
+ ?IPRINT("send notification ~w", [N]),
agent_send_notif(AgentNode,
testTrapv22,
{{inform2_tag1, N}, Collector},
@@ -4513,11 +4640,11 @@ do_inform_swarm(Config) ->
if
N rem 100 == 0 ->
Sleep = 1000,
- p("sleep ~w [~w]", [Sleep, N]),
+ ?IPRINT("sleep ~w [~w]", [Sleep, N]),
?SLEEP(Sleep);
N rem 10 == 0 ->
Sleep = 100,
- p("sleep ~w [~w]", [Sleep, N]),
+ ?IPRINT("sleep ~w [~w]", [Sleep, N]),
?SLEEP(Sleep);
true ->
ok
@@ -4529,8 +4656,10 @@ do_inform_swarm(Config) ->
Cmd1 =
fun() ->
- p("manager info: ~n~p", [mgr_info(MgrNode)]),
- p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ?IPRINT("manager info: "
+ "~n ~p", [mgr_info(MgrNode)]),
+ ?IPRINT("agent info: "
+ "~n ~p", [agent_info(AgentNode)]),
ok
end,
@@ -4553,13 +4682,13 @@ do_inform_swarm(Config) ->
{5, "Manager and agent info after test completion", Cmd1}
],
- command_handler(Commands),
+ Res = command_handler(Commands),
display_log(Config),
- ok.
+ Res.
inform_swarm_collector(N) ->
- inform_swarm_collector(N, 0, 0, 0, 10000).
+ inform_swarm_collector(N, 0, 0, 0, ?SECS(60)).
%% Note that we need to deal with re-transmissions!
%% That is, the agent did not receive the ack in time,
@@ -4575,60 +4704,65 @@ inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, _)
when ((N == SentAckCnt) and
(N == RespCnt) and
(N =< RecvCnt)) ->
- p("inform_swarm_collector -> done when"
- "~n N: ~w"
- "~n SentAckCnt: ~w"
- "~n RecvCnt: ~w"
- "~n RespCnt: ~w", [N, SentAckCnt, RecvCnt, RespCnt]),
+ ?IPRINT("inform_swarm_collector -> done when"
+ "~n N: ~w"
+ "~n SentAckCnt: ~w"
+ "~n RecvCnt: ~w"
+ "~n RespCnt: ~w", [N, SentAckCnt, RecvCnt, RespCnt]),
ok;
inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, Timeout) ->
- p("inform_swarm_collector -> entry with"
- "~n N: ~w"
- "~n SentAckCnt: ~w"
- "~n RecvCnt: ~w"
- "~n RespCnt: ~w", [N, SentAckCnt, RecvCnt, RespCnt]),
+ %% ?IPRINT("inform_swarm_collector -> entry with"
+ %% "~n N: ~w"
+ %% "~n SentAckCnt: ~w"
+ %% "~n RecvCnt: ~w"
+ %% "~n RespCnt: ~w", [N, SentAckCnt, RecvCnt, RespCnt]),
receive
{snmp_targets, {inform2_tag1, Id}, [_Addr]} ->
- p("received inform-sent acknowledgement for ~w", [Id]),
+ ?IPRINT("received inform-sent acknowledgement for ~w", [Id]),
inform_swarm_collector(N, SentAckCnt+1, RecvCnt, RespCnt,
Timeout);
%% The manager has received the actual inform
{async_event, From, {inform, Pid, Inform}} ->
- p("received inform"),
+ ?IPRINT("received inform"),
case Inform of
{noError, 0, VBs} when is_list(VBs) ->
Pid ! {handle_inform_response, From},
inform_swarm_collector(N, SentAckCnt, RecvCnt+1, RespCnt,
Timeout);
{Err, Idx, VBs} ->
- e("Unexpected error status: "
- "~n Err: ~p"
- "~n Idx: ~p"
- "~n VBs: ~p", [Err, Idx, VBs]),
+ ?EPRINT("Unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
Reason = {unexpected_status, {Err, Idx, VBs}},
{error, Reason}
end;
%% The agent has received ack from the manager
{snmp_notification, {inform2_tag1, Id}, {got_response, Addr}} ->
- p("received expected \"got response\" for ~w "
- "notification from: "
- "~n ~p",
- [Id, Addr]),
+ ?IPRINT("received expected \"got response\" for ~w "
+ "notification from: "
+ "~n ~p", [Id, Addr]),
inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt+1,
Timeout);
%% The agent did not received ack from the manager in time
{snmp_notification, inform2_tag1, {no_response, Addr}} ->
- e("Received expected \"no response\" notification "
- "from: "
- "~n ~p", [Addr]),
+ ?EPRINT("Received expected \"no response\" notification "
+ "from: "
+ "~n ~p", [Addr]),
Reason = {no_response, Addr, {N, SentAckCnt, RecvCnt, RespCnt}},
{error, Reason}
after Timeout ->
%% Give up when we have been dead in the water for Timeout ms
+ ?EPRINT("timeout when"
+ "~n N: ~p"
+ "~n SentAckCnt: ~p"
+ "~n RecvCnt: ~p"
+ "~n RespCnt: ~p",
+ [N, SentAckCnt, RecvCnt, RespCnt]),
{error, {timeout, N, SentAckCnt, RecvCnt, RespCnt}}
end.
@@ -4646,48 +4780,54 @@ report(Config) when is_list(Config) ->
otp8015_1(doc) -> ["OTP-8015:1 - testing the new api-function."];
otp8015_1(suite) -> [];
otp8015_1(Config) when is_list(Config) ->
- ?TC_TRY(otp8015_1,
- fun() -> do_otp8015_1(Config) end).
+ Pre = fun() ->
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace},
+ {dir, ConfDir},
+ {db_dir, DbDir}]}],
+
+ ?IPRINT("starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+ ok
+ end,
+ Case = fun(_) -> do_otp8015_1(Config) end,
+ Post = fun(_) ->
+ ?IPRINT("stop manager"),
+ ok = snmpm:stop(),
+ ?SLEEP(1000),
+ ok
+ end,
+ ?TC_TRY(otp8015_1, Pre, Case, Post).
do_otp8015_1(Config) ->
- p("starting with Config: ~p~n", [Config]),
-
- ConfDir = ?config(manager_conf_dir, Config),
- DbDir = ?config(manager_db_dir, Config),
-
- write_manager_conf(ConfDir),
-
- Opts = [{server, [{verbosity, trace}]},
- {net_if, [{verbosity, trace}]},
- {note_store, [{verbosity, trace}]},
- {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
-
- p("starting manager"),
- ok = snmpm:start_link(Opts),
-
- ?SLEEP(1000),
+ ?IPRINT("starting with Config: "
+ "~n ~p"
+ "~n", [Config]),
snmpm:load_mib(std_mib()),
snmpm:load_mib(test_trap_mib(Config)),
- p("manager started, now sleep some"),
+ ?IPRINT("manager started, now sleep some"),
?SLEEP(1000),
- p("loaded mibs: ~p", [snmpm:which_mibs()]),
+ ?IPRINT("loaded mibs: ~p", [snmpm:which_mibs()]),
- p("get some type(s) from the mibs"),
+ ?IPRINT("get some type(s) from the mibs"),
{ok, 'Counter32'} = snmpm:oid_to_type(?snmpOutTraps),
- {ok, [IfIndex]} = snmpm:name_to_oid(ifIndex),
- {ok, 'INTEGER'} = snmpm:oid_to_type(IfIndex),
+ {ok, [IfIndex]} = snmpm:name_to_oid(ifIndex),
+ {ok, 'INTEGER'} = snmpm:oid_to_type(IfIndex),
-
- p("stop manager"),
- ok = snmpm:stop(),
-
- ?SLEEP(1000),
-
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -4708,27 +4848,30 @@ do_otp8395_1(Config) ->
%%======================================================================
async_exec([], Acc) ->
- p("all async request's sent => now await reponses"),
+ ?IPRINT("all async request's sent => now await responses"),
async_verify(async_collector(Acc, []));
async_exec([{Id, Data, Exec, Ver}|Reqs], Acc) ->
- p("issue async request ~w", [Id]),
+ ?IPRINT("issue async request ~w", [Id]),
?line {ok, ReqId} = Exec(Data),
async_exec(Reqs, [{ReqId, Id, Ver}|Acc]).
async_collector([], Acc) ->
- p("received replies for all requests - now sort"),
+ ?IPRINT("received replies for all requests - now sort"),
lists:keysort(1, Acc);
async_collector(Expected, Acc) ->
receive
{async_event, ReqId, Reply} ->
- p("received async event with request-id ~w", [ReqId]),
+ ?IPRINT("received async event with request-id ~w", [ReqId]),
case lists:keysearch(ReqId, 1, Expected) of
{value, {_, Id, Ver}} ->
- p("event was for request ~w", [Id]),
+ ?IPRINT("event was for request ~w", [Id]),
Expected2 = lists:keydelete(ReqId, 1, Expected),
async_collector(Expected2, [{Id, Ver, Reply}|Acc]);
false ->
% Duplicate reply?
+ ?EPRINT("unexpected async event: "
+ "~n ReqId: ~p"
+ "~n Reply: ~p", [ReqId, Reply]),
?FAIL({unexpected_async_event, ReqId, Reply})
end
after 10000 ->
@@ -4738,7 +4881,7 @@ async_collector(Expected, Acc) ->
async_verify([]) ->
ok;
async_verify([{Id, Verify, Reply}|Replies]) ->
- p("verify reply ~w", [Id]),
+ ?IPRINT("verify reply ~w", [Id]),
Verify(Reply),
async_verify(Replies).
@@ -4795,17 +4938,19 @@ purify_oid(Node, Oid) ->
command_handler([]) ->
ok;
command_handler([{No, Desc, Cmd}|Cmds]) ->
- p("command_handler -> command ~w: "
- "~n ~s", [No, Desc]),
+ ?IPRINT("command_handler -> command ~w: "
+ "~n ~s", [No, Desc]),
case (catch Cmd()) of
ok ->
- p("command_handler -> ~w: ok",[No]),
+ ?IPRINT("command_handler -> ~w: ok", [No]),
command_handler(Cmds);
{error, Reason} ->
- e("Command_handler -> ~w error: ~n~p",[No, Reason]),
+ ?EPRINT("Command_handler -> ~w error: "
+ "~n ~p", [No, Reason]),
?line ?FAIL({command_failed, No, Reason});
Error ->
- e("Command_handler -> ~w unexpected: ~n~p",[No, Error]),
+ ?EPRINT("Command_handler -> ~w unexpected: "
+ "~n ~p", [No, Error]),
?line ?FAIL({unexpected_command_result, No, Error})
end.
@@ -4814,9 +4959,9 @@ command_handler([{No, Desc, Cmd}|Cmds]) ->
init_manager(AutoInform, Config) ->
- ?LOG("init_manager -> entry with"
- "~n AutoInform: ~p"
- "~n Config: ~p", [AutoInform, Config]),
+ ?IPRINT("init_manager -> entry with"
+ "~n AutoInform: ~p"
+ "~n Config: ~p", [AutoInform, Config]),
%% --
%% Start node
@@ -4856,11 +5001,18 @@ init_manager(AutoInform, Config) ->
start_manager(Node, Vsns, Conf)
end
catch
+ C:{suite_failed, Reason, _M, _L} = E:S when (C =:= exit) ->
+ ?EPRINT("Failure during manager start (suite-failed):"
+ "~n Reason: ~p"
+ "~n StackTrace: ~p", [Reason, S]),
+ %% And now, *try* to cleanup
+ (catch stop_node(Node)),
+ erlang:raise(C, E, S);
C:E:S ->
- p("Failure during manager start: "
- "~n Error Class: ~p"
- "~n Error: ~p"
- "~n StackTrace: ~p", [C, E, S]),
+ ?EPRINT("Failure during manager start: "
+ "~n Error Class: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [C, E, S]),
%% And now, *try* to cleanup
(catch stop_node(Node)),
?FAIL({failed_starting_manager, C, E, S})
@@ -4871,19 +5023,19 @@ fin_manager(Config) ->
StopMgrRes = stop_manager(Node),
StopCryptoRes = fin_crypto(Node),
StopNode = stop_node(Node),
- p("fin_manager -> stop apps and (mgr node ~p) node results: "
- "~n SNMP Mgr: ~p"
- "~n Crypto: ~p"
- "~n Node: ~p",
- [Node, StopMgrRes, StopCryptoRes, StopNode]),
+ ?IPRINT("fin_manager -> stop apps and (mgr node ~p) node results: "
+ "~n SNMP Mgr: ~p"
+ "~n Crypto: ~p"
+ "~n Node: ~p",
+ [Node, StopMgrRes, StopCryptoRes, StopNode]),
Config.
%% -- Misc agent functions --
init_agent(Config) ->
- ?LOG("init_agent -> entry with"
- "~n Config: ~p", [Config]),
+ ?IPRINT("init_agent -> entry with"
+ "~n Config: ~p", [Config]),
%% --
%% Retrieve some dir's
@@ -4937,11 +5089,18 @@ init_agent(Config) ->
start_agent(Node, Vsns, Conf)
end
catch
+ C:{suite_failed, Reason, _M, _L} = E:S when (C =:= exit) ->
+ ?EPRINT("Failure during agent start (suite-failed):"
+ "~n Reason: ~p"
+ "~n StackTrace: ~p", [Reason, S]),
+ %% And now, *try* to cleanup
+ (catch stop_node(Node)),
+ erlang:raise(C, E, S);
C:E:S ->
- p("Failure during agent start: "
- "~n Error Class: ~p"
- "~n Error: ~p"
- "~n StackTrace: ~p", [C, E, S]),
+ ?EPRINT("Failure during agent start: "
+ "~n Error Class: ~p"
+ "~n Error: ~p"
+ "~n StackTrace: ~p", [C, E, S]),
%% And now, *try* to cleanup
(catch stop_node(Node)),
?FAIL({failed_starting_agent, C, E, S})
@@ -4949,17 +5108,17 @@ init_agent(Config) ->
fin_agent(Config) ->
- Node = ?config(agent_node, Config),
+ Node = ?config(agent_node, Config),
StopAgentRes = stop_agent(Node),
StopCryptoRes = fin_crypto(Node),
StopMnesiaRes = fin_mnesia(Node),
StopNode = stop_node(Node),
- p("fin_agent -> stop apps and (agent node ~p) node results: "
- "~n SNMP Agent: ~p"
- "~n Crypto: ~p"
- "~n Mnesia: ~p"
- "~n Node: ~p",
- [Node, StopAgentRes, StopCryptoRes, StopMnesiaRes, StopNode]),
+ ?IPRINT("fin_agent -> stop apps and (agent node ~p) node results: "
+ "~n SNMP Agent: ~p"
+ "~n Crypto: ~p"
+ "~n Mnesia: ~p"
+ "~n Node: ~p",
+ [Node, StopAgentRes, StopCryptoRes, StopMnesiaRes, StopNode]),
Config.
init_mnesia(Node, Dir, MnesiaDebug)
@@ -5025,8 +5184,8 @@ load_app(Node, App) ->
({error, {already_loaded, LoadedApp}}) when (LoadedApp =:= App) ->
ok;
({error, Reason}) ->
- p("failed loading app ~w on ~p: "
- "~n ~p", [App, Node, Reason]),
+ ?EPRINT("failed loading app ~w on ~p: "
+ "~n ~p", [App, Node, Reason]),
?FAIL({failed_load, Node, App, Reason})
end,
do_load_app(Node, App, VerifySuccess).
@@ -5046,8 +5205,8 @@ start_app(Node, App) ->
({error, {already_started, LoadedApp}}) when (LoadedApp =:= App) ->
ok;
({error, Reason}) ->
- p("failed starting app ~w on ~p: "
- "~n ~p", [App, Node, Reason]),
+ ?EPRINT("failed starting app ~w on ~p: "
+ "~n Reason: ~p", [App, Node, Reason]),
?FAIL({failed_start, Node, App, Reason})
end,
start_app(Node, App, VerifySuccess).
@@ -5065,8 +5224,8 @@ stop_app(Node, App) ->
({error, {not_started, LoadedApp}}) when (LoadedApp =:= App) ->
ok;
({error, Reason}) ->
- p("failed stopping app ~w on ~p: "
- "~n ~p", [App, Node, Reason]),
+ ?EPRINT("failed stopping app ~w on ~p: "
+ "~n ~p", [App, Node, Reason]),
?FAIL({failed_stop, Node, App, Reason})
end,
stop_app(Node, App, VerifySuccess).
@@ -5082,11 +5241,11 @@ set_app_env(Node, App, Key, Val) ->
VerifySuccess = fun(ok) ->
ok;
({error, Reason}) ->
- p("failed setting app ~w env on ~p"
- "~n Key: ~p"
- "~n Val: ~p"
- "~n Reason: ~p"
- "~n ~p", [App, Node, Key, Val, Reason]),
+ ?EPRINT("failed setting app ~w env on ~p"
+ "~n Key: ~p"
+ "~n Val: ~p"
+ "~n Reason: ~p",
+ [App, Node, Key, Val, Reason]),
?FAIL({failed_set_app_env,
Node, App, Key, Val, Reason})
end,
@@ -5488,12 +5647,13 @@ start_manager(Node, Vsns, Conf0, _Opts) ->
ConfigVerbosity = get_opt(manager_config_verbosity, Conf0, trace),
NoteStoreVerbosity = get_opt(manager_note_store_verbosity, Conf0, log),
- ServerVerbosity = get_opt(manager_server_verbosity, Conf0, trace),
NetIfVerbosity = get_opt(manager_net_if_verbosity, Conf0, trace),
AtlSeqNo = get_opt(manager_atl_seqno, Conf0, false),
+ ServerVerbosity = get_opt(manager_server_verbosity, Conf0, trace),
CBP = get_opt(manager_server_cbproxy, Conf0, temporary),
+ NIS = get_opt(manager_server_nis, Conf0, none),
NetIfConf =
case get_opt(manager_net_if_module, Conf0, no_module) of
@@ -5516,12 +5676,22 @@ start_manager(Node, Vsns, Conf0, _Opts) ->
{verbosity, ConfigVerbosity}]},
{note_store, [{verbosity, NoteStoreVerbosity}]},
{server, [{verbosity, ServerVerbosity},
- {cbproxy, CBP}]},
+ {cbproxy, CBP},
+ {netif_sup, NIS}]},
{net_if, NetIfConf}],
?line ok = set_mgr_env(Node, Env),
- ?line ok = start_snmp(Node),
-
+ ?line ok = try start_snmp(Node) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?FAIL({failed_start_manager, Reason})
+ catch
+ exit:{suite_failed, {failed_start, _, _, Reason}, _M, _L}:_ ->
+ ?FAIL({failed_start_manager, Reason});
+ C:E:S ->
+ erlang:raise(C, E, S)
+ end,
Conf0.
stop_manager(Node) ->
@@ -5577,7 +5747,17 @@ start_agent(Node, Vsns, Conf0, _Opts) ->
{multi_threaded, true}],
?line ok = set_agent_env(Node, Env),
- ?line ok = start_snmp(Node),
+ ?line try start_snmp(Node) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?FAIL({failed_start_agent, Reason})
+ catch
+ exit:{suite_failed, {failed_start, _, _, Reason}, _M, _L}:_ ->
+ ?FAIL({failed_start_agent, Reason});
+ C:E:S ->
+ erlang:raise(C, E, S)
+ end,
Conf0.
stop_agent(Node) ->
@@ -5641,7 +5821,7 @@ start_node(Name, Retry) ->
global:sync(),
Node;
{error, timeout} ->
- e("Failed starting node ~p: timeout", [Name]),
+ ?EPRINT("Failed starting node ~p: timeout", [Name]),
?line ?FAIL({error_starting_node, Name, timeout});
{error, {already_running, Node}} when (Retry =:= true) ->
%% Ouch
@@ -5650,24 +5830,24 @@ start_node(Name, Retry) ->
%% timeout) but actually succeeded. Regardless, we don't know
%% the state of this node, so (try) stop it and then (re-) try
%% start again.
- e("Failed starting node ~p: Already Running - try stop", [Node]),
+ ?WPRINT("Failed starting node ~p: Already Running - try stop", [Node]),
case ?STOP_NODE(Node) of
true ->
- p("Successfully stopped old node ~p", [Node]),
+ ?IPRINT("Successfully stopped old node ~p", [Node]),
start_node(Name, false);
false ->
- e("Failed stop old node ~p", [Node]),
+ ?EPRINT("Failed stop old node ~p", [Node]),
?line ?FAIL({error_starting_node, Node, Retry, already_running})
end;
{error, {already_running, Node}} ->
- e("Failed starting node ~p: Already Running", [Node]),
+ ?EPRINT("Failed starting node ~p: Already Running", [Node]),
?line ?FAIL({error_starting_node, Node, Retry, already_running});
{error, Reason} ->
- e("Failed starting node ~p: ~p", [Name, Reason]),
+ ?EPRINT("Failed starting node ~p: ~p", [Name, Reason]),
?line ?FAIL({error_starting_node, Name, Reason})
catch
exit:{suite_failed, Reason} ->
- e("(suite) Failed starting node ~p: ~p", [Name, Reason]),
+ ?EPRINT("(suite) Failed starting node ~p: ~p", [Name, Reason]),
?line ?FAIL({failed_starting_node, Name, Reason})
end.
@@ -5846,24 +6026,24 @@ display_log(Config) ->
LogDir = Dir,
Mibs = [],
OutFile = j(LogDir, "snmpm_log.txt"),
- p("~n"
- "========================="
- " < Audit Trail Log > "
- "========================="
- "~n"),
+ ?IPRINT("~n"
+ "========================="
+ " < Audit Trail Log > "
+ "========================="
+ "~n"),
rcall(Node, snmpm, log_to_txt, [LogDir, Mibs, OutFile]),
rcall(Node, snmpm, log_to_io, [LogDir, Mibs]),
- p("~n"
- "========================="
- " < / Audit Trail Log > "
- "========================="
- "~n");
+ ?IPRINT("~n"
+ "========================="
+ " < / Audit Trail Log > "
+ "========================="
+ "~n");
false ->
- p("display_log -> no manager node found"),
+ ?IPRINT("display_log -> no manager node found"),
ok
end;
false ->
- p("display_log -> no manager log dir found"),
+ ?IPRINT("display_log -> no manager log dir found"),
ok
end.
@@ -5914,32 +6094,5 @@ rcall(Node, Mod, Func, Args) ->
%% ------
-%% Time in milli sec
-%% t() ->
-%% {A,B,C} = os:timestamp(),
-%% A*1000000000+B*1000+(C div 1000).
-
-
-%% ------
-
-e(F, A) ->
- p("<ERROR> " ++ F, A).
-
-p(F) ->
- p(F, []).
-
-p(F, A) ->
- p(get(tname), F, A).
-
-p(TName, F, A) ->
- io:format("*** [~w][~s] ***"
- "~n " ++ F ++ "~n", [TName, formated_timestamp()|A]).
-
-formated_timestamp() ->
- snmp_test_lib:formated_timestamp().
-
-%% p(TName, F, A) ->
-%% io:format("~w -> " ++ F ++ "~n", [TName|A]).
-
ipv6_init(Config) when is_list(Config) ->
[{ipfamily, inet6} | Config].
diff --git a/lib/snmp/test/snmp_manager_config_SUITE.erl b/lib/snmp/test/snmp_manager_config_SUITE.erl
index b5c1894294..9a7b485a60 100644
--- a/lib/snmp/test/snmp_manager_config_SUITE.erl
+++ b/lib/snmp/test/snmp_manager_config_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -29,6 +29,7 @@
%%----------------------------------------------------------------------
-module(snmp_manager_config_SUITE).
+
%%----------------------------------------------------------------------
%% Include files
%%----------------------------------------------------------------------
@@ -97,6 +98,7 @@
]).
+
%%----------------------------------------------------------------------
%% Internal exports
%%----------------------------------------------------------------------
@@ -219,24 +221,40 @@ otp_8395_cases() ->
otp_8395_4
].
+
init_per_suite(Config0) when is_list(Config0) ->
- ?DBG("init_per_suite -> entry with"
- "~n Config0: ~p", [Config0]),
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
- Config1 = snmp_test_lib:init_suite_top_dir(?MODULE, Config0),
+ case ?LIB:init_per_suite(Config0) of
+ {skip, _} = SKIP ->
+ SKIP;
- ?DBG("init_per_suite -> done when"
- "~n Config1: ~p", [Config1]),
+ Config1 ->
- Config1.
+ Config2 = snmp_test_lib:init_suite_top_dir(?MODULE, Config1),
-end_per_suite(Config) when is_list(Config) ->
+ %% We need one on this node also
+ snmp_test_sys_monitor:start(),
- ?DBG("end_per_suite -> entry with"
- "~n Config: ~p", [Config]),
+ ?IPRINT("init_per_suite -> end when"
+ "~n Config: ~p", [Config2]),
- Config.
+ Config2
+ end.
+
+end_per_suite(Config0) when is_list(Config0) ->
+
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
+
+ snmp_test_sys_monitor:stop(),
+ Config1 = ?LIB:end_per_suite(Config0),
+
+ ?IPRINT("end_per_suite -> end"),
+
+ Config1.
init_per_group(_GroupName, Config) ->
@@ -247,11 +265,16 @@ end_per_group(_GroupName, Config) ->
init_per_testcase(Case, Config) when is_list(Config) ->
- p("init_per_testcase -> Case: ~p", [Case]),
+ ?IPRINT("init_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
+
+ snmp_test_global_sys_monitor:reset_events(),
+
SuiteTopDir = ?config(snmp_suite_top_dir, Config),
CaseTopDir = filename:join(SuiteTopDir, atom_to_list(Case)),
?line ok = file:make_dir(CaseTopDir),
- p("init_per_testcase -> CaseTopDir: ~p", [CaseTopDir]),
+
+ ?IPRINT("init_per_testcase -> CaseTopDir: ~p", [CaseTopDir]),
MgrTopDir = filename:join(CaseTopDir, "manager/"),
?line ok = file:make_dir(MgrTopDir),
MgrConfDir = filename:join(MgrTopDir, "conf/"),
@@ -265,15 +288,26 @@ init_per_testcase(Case, Config) when is_list(Config) ->
end,
MgrLogDir = filename:join(MgrTopDir, "log/"),
?line ok = file:make_dir(MgrLogDir),
- [{case_top_dir, CaseTopDir},
- {manager_dir, MgrTopDir},
- {manager_conf_dir, MgrConfDir},
- {manager_db_dir, MgrDbDir},
- {manager_log_dir, MgrLogDir} | Config].
+ Config1 = [{case_top_dir, CaseTopDir},
+ {manager_dir, MgrTopDir},
+ {manager_conf_dir, MgrConfDir},
+ {manager_db_dir, MgrDbDir},
+ {manager_log_dir, MgrLogDir} | Config],
+
+ ?IPRINT("init_per_testcase -> done when"
+ "~n Config1: ~p", [Config1]),
+ Config1.
+
+
+end_per_testcase(_Case, Config) when is_list(Config) ->
+
+ ?IPRINT("end_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
+
+ ?IPRINT("system events during test: "
+ "~n ~p", [snmp_test_global_sys_monitor:events()]),
-end_per_testcase(Case, Config) when is_list(Config) ->
- p("end_per_testcase -> Case: ~p", [Case]),
%% The cleanup is removed due to some really discusting NFS behaviour...
%% Also, it can always be useful to retain "all the stuff" after
%% the test case in case of debugging...
@@ -293,8 +327,8 @@ simple_start_and_stop(doc) ->
"Start the snmp manager config process with the \n"
"minimum setof options (config dir).";
simple_start_and_stop(Conf) when is_list(Conf) ->
- put(tname,ssas),
- p("start"),
+ put(tname, "SIME-START_AND_STOP"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -319,9 +353,9 @@ start_without_mandatory_opts1(doc) ->
"Start the snmp manager config process with some of the \n"
"mandatory options missing.";
start_without_mandatory_opts1(Conf) when is_list(Conf) ->
- put(tname,swomo1),
- put(verbosity,trace),
- p("start"),
+ put(tname, "START-WO-MAND-OPTS-1"),
+ put(verbosity, trace),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -330,12 +364,12 @@ start_without_mandatory_opts1(Conf) when is_list(Conf) ->
%% config, but no dir:
- p("config option, but no dir"),
+ ?IPRINT("config option, but no dir"),
Opts = [{priority, normal},
{config, [{verbosity, trace}, {db_dir, DbDir}]}, {mibs, []}],
?line {error, {missing_mandatory,dir}} = config_start(Opts),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -348,9 +382,9 @@ start_without_mandatory_opts2(doc) ->
"Start the snmp manager config process with some of the \n"
"mandatory options missing.";
start_without_mandatory_opts2(Conf) when is_list(Conf) ->
- put(tname,swomo2),
+ put(tname, "START-WO-MAND-OPTS-2"),
put(verbosity,trace),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -358,13 +392,13 @@ start_without_mandatory_opts2(Conf) when is_list(Conf) ->
%% Second set of options (no config):
- p("no config option"),
+ ?IPRINT("no config option"),
Opts = [{priority, normal},
{mibs, []}],
?line {error, {missing_mandatory,config,[dir, db_dir]}} =
config_start(Opts),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -377,8 +411,9 @@ start_with_all_valid_opts(doc) ->
"Start the snmp manager config process with the \n"
"complete set of all the valid options.";
start_with_all_valid_opts(Conf) when is_list(Conf) ->
+ put(tname, "START-W-ALL-VALID-OPTS"),
put(tname,swavo),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -389,16 +424,22 @@ start_with_all_valid_opts(Conf) when is_list(Conf) ->
%% Third set of options (no versions):
- p("all options"),
+ ?IPRINT("all options"),
NetIfOpts = [{module, snmpm_net_if},
{verbosity, trace},
{options, [{recbuf, 30000},
{bind_to, false},
{no_reuse, false}]}],
- ServerOpts = [{timeout, 10000}, {verbosity, trace}],
- NoteStoreOpts = [{timeout, 20000}, {verbosity, trace}],
- ConfigOpts = [{dir, ConfDir}, {verbosity, trace},
- {db_dir, DbDir}, {db_init_error, create}],
+ ServerOpts = [{timeout, ?SECS(10)},
+ {verbosity, trace},
+ {cbproxy, permanent},
+ {netif_sup, {?SECS(60), ?SECS(5)}}],
+ NoteStoreOpts = [{timeout, ?SECS(20)},
+ {verbosity, trace}],
+ ConfigOpts = [{dir, ConfDir},
+ {verbosity, trace},
+ {db_dir, DbDir},
+ {db_init_error, create}],
Mibs = [join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
join(StdMibDir, "SNMP-USER-BASED-SM-MIB")],
Prio = normal,
@@ -418,7 +459,7 @@ start_with_all_valid_opts(Conf) when is_list(Conf) ->
?line {ok, _Pid} = config_start(Opts),
?line ok = config_stop(),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -431,8 +472,8 @@ start_with_unknown_opts(doc) ->
"Start the snmp manager config process when some of\n"
"the options are unknown.";
start_with_unknown_opts(Conf) when is_list(Conf) ->
- put(tname,swuo),
- p("start"),
+ put(tname, "START-W-UNKNOWN-OPTS"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -443,7 +484,7 @@ start_with_unknown_opts(Conf) when is_list(Conf) ->
%% Third set of options (no versions):
- p("all options"),
+ ?IPRINT("all options"),
NetIfOpts = [{module, snmpm_net_if},
{verbosity, trace},
{options, [{recbuf, 30000},
@@ -471,7 +512,10 @@ start_with_unknown_opts(Conf) when is_list(Conf) ->
{versions, Vsns}],
?line {ok, _Pid} = config_start(Opts),
- p("done"),
+ ?IPRINT("(config) started - now stop"),
+ ?line ok = config_stop(),
+
+ ?IPRINT("done"),
ok.
@@ -484,8 +528,8 @@ start_with_incorrect_opts(doc) ->
"Start the snmp manager config process when some of\n"
"the options has incorrect values.";
start_with_incorrect_opts(Conf) when is_list(Conf) ->
- put(tname,swio),
- p("start"),
+ put(tname, "START-W-INCORRECT-OPTS"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -496,135 +540,135 @@ start_with_incorrect_opts(Conf) when is_list(Conf) ->
ConfigOpts = [{verbosity,trace}, {dir, ConfDir}, {db_dir, DbDir}],
- p("net-if - incorrect module"),
+ ?IPRINT("net-if - incorrect module"),
NetIfOpts1 = [{module, snmpm_user}], %% Behaviour check will fail
Opts01 = [{config, ConfigOpts}, {versions, [v1]},
{net_if, NetIfOpts1}],
?line {error, Reason01} = config_start(Opts01),
- p("net-if (module) res: ~p", [Reason01]),
+ ?IPRINT("net-if (module) res: ~p", [Reason01]),
- p("net-if - incorrect verbosity"),
+ ?IPRINT("net-if - incorrect verbosity"),
NetIfOpts2 = [{verbosity, invalid_verbosity}],
Opts02 = [{config, ConfigOpts}, {versions, [v1]},
{net_if, NetIfOpts2}],
?line {error, Reason02} = config_start(Opts02),
- p("net-if (verbosity) res: ~p", [Reason02]),
+ ?IPRINT("net-if (verbosity) res: ~p", [Reason02]),
- p("net-if - incorrect options"),
+ ?IPRINT("net-if - incorrect options"),
NetIfOpts3 = [{options, invalid_options}],
Opts03 = [{config, ConfigOpts}, {versions, [v1]},
{net_if, NetIfOpts3}],
?line {error, Reason03} = config_start(Opts03),
- p("net-if (options) res: ~p", [Reason03]),
+ ?IPRINT("net-if (options) res: ~p", [Reason03]),
- p("server - incorrect timeout (1)"),
+ ?IPRINT("server - incorrect timeout (1)"),
ServerOpts1 = [{timeout, invalid_timeout}],
Opts08 = [{config, ConfigOpts}, {versions, [v1]},
{server, ServerOpts1}],
?line {error, Reason08} = config_start(Opts08),
- p("server (timeout) res: ~p", [Reason08]),
+ ?IPRINT("server (timeout) res: ~p", [Reason08]),
- p("server - incorrect timeout (2)"),
+ ?IPRINT("server - incorrect timeout (2)"),
ServerOpts2 = [{timeout, 0}],
Opts09 = [{config, ConfigOpts}, {versions, [v1]},
{server, ServerOpts2}],
?line {error, Reason09} = config_start(Opts09),
- p("server (timeout) res: ~p", [Reason09]),
+ ?IPRINT("server (timeout) res: ~p", [Reason09]),
- p("server - incorrect timeout (3)"),
+ ?IPRINT("server - incorrect timeout (3)"),
ServerOpts3 = [{timeout, -1000}],
Opts10 = [{config, ConfigOpts},
{versions, [v1]},
{server, ServerOpts3}],
?line {error, Reason10} = config_start(Opts10),
- p("server (timeout) res: ~p", [Reason10]),
+ ?IPRINT("server (timeout) res: ~p", [Reason10]),
- p("server - incorrect verbosity"),
+ ?IPRINT("server - incorrect verbosity"),
ServerOpts4 = [{verbosity, invalid_verbosity}],
Opts11 = [{config, ConfigOpts},
{versions, [v1]},
{server, ServerOpts4}],
?line {error, Reason11} = config_start(Opts11),
- p("server (verbosity) res: ~p", [Reason11]),
+ ?IPRINT("server (verbosity) res: ~p", [Reason11]),
- p("note-store - incorrect timeout (1)"),
+ ?IPRINT("note-store - incorrect timeout (1)"),
NoteStoreOpts1 = [{timeout, invalid_timeout}],
Opts12 = [{config, ConfigOpts},
{versions, [v1]},
{note_store, NoteStoreOpts1}],
?line {error, Reason12} = config_start(Opts12),
- p("note-store (timeout) res: ~p", [Reason12]),
+ ?IPRINT("note-store (timeout) res: ~p", [Reason12]),
- p("note-store - incorrect timeout (2)"),
+ ?IPRINT("note-store - incorrect timeout (2)"),
NoteStoreOpts2 = [{timeout, 0}],
Opts13 = [{config, ConfigOpts},
{versions, [v1]},
{note_store, NoteStoreOpts2}],
?line {error, Reason13} = config_start(Opts13),
- p("note-store (timeout) res: ~p", [Reason13]),
+ ?IPRINT("note-store (timeout) res: ~p", [Reason13]),
- p("note-store - incorrect timeout (3)"),
+ ?IPRINT("note-store - incorrect timeout (3)"),
NoteStoreOpts3 = [{timeout, -2000}],
Opts14 = [{config, ConfigOpts},
{versions, [v1]},
{note_store, NoteStoreOpts3}],
?line {error, Reason14} = config_start(Opts14),
- p("note-store (timeout) res: ~p", [Reason14]),
+ ?IPRINT("note-store (timeout) res: ~p", [Reason14]),
- p("note-store - incorrect verbosity"),
+ ?IPRINT("note-store - incorrect verbosity"),
NoteStoreOpts4 = [{timeout, 20000}, {verbosity, invalid_verbosity}],
Opts15 = [{config, ConfigOpts},
{versions, [v1]},
{note_store, NoteStoreOpts4}],
?line {error, Reason15} = config_start(Opts15),
- p("note-store (verbosity) res: ~p", [Reason15]),
+ ?IPRINT("note-store (verbosity) res: ~p", [Reason15]),
- p("config - incorrect dir (1)"),
+ ?IPRINT("config - incorrect dir (1)"),
ConfigOpts1 = [{dir, invalid_dir}],
Opts16 = [{config, ConfigOpts1},
{versions, [v1]}],
?line {error, Reason16} = config_start(Opts16),
- p("config (dir) res: ~p", [Reason16]),
+ ?IPRINT("config (dir) res: ~p", [Reason16]),
- p("config - incorrect dir (2)"),
+ ?IPRINT("config - incorrect dir (2)"),
ConfigOpts2 = [{dir, "/invalid/dir"}],
Opts17 = [{config, ConfigOpts2},
{versions, [v1]}],
?line {error, Reason17} = config_start(Opts17),
- p("config (dir) res: ~p", [Reason17]),
+ ?IPRINT("config (dir) res: ~p", [Reason17]),
- p("config - incorrect verbosity"),
+ ?IPRINT("config - incorrect verbosity"),
ConfigOpts3 = [{dir, ConfDir}, {verbosity, invalid_verbosity}],
Opts18 = [{config, ConfigOpts3},
{versions, [v1]}],
?line {error, Reason18} = config_start(Opts18),
- p("config (verbosity) res: ~p", [Reason18]),
+ ?IPRINT("config (verbosity) res: ~p", [Reason18]),
- p("mibs - incorrect mibs (1)"),
+ ?IPRINT("mibs - incorrect mibs (1)"),
Mibs1 = invalid_mibs,
Opts19 = [{config, ConfigOpts},
{versions, [v1]},
{mibs, Mibs1}],
?line {error, Reason19} = config_start(Opts19),
- p("mibs (mibs) res: ~p", [Reason19]),
+ ?IPRINT("mibs (mibs) res: ~p", [Reason19]),
- p("mibs - incorrect mibs (2)"),
+ ?IPRINT("mibs - incorrect mibs (2)"),
Mibs2 = [join(StdMibDir, "INVALID-MIB")],
Opts20 = [{config, ConfigOpts},
{versions, [v1]},
{mibs, Mibs2}],
?line {error, Reason20} = config_start(Opts20),
- p("mibs (mibs) res: ~p", [Reason20]),
+ ?IPRINT("mibs (mibs) res: ~p", [Reason20]),
- p("prio - incorrect prio"),
+ ?IPRINT("prio - incorrect prio"),
Prio1 = invalid_prio,
Opts21 = [{config, ConfigOpts},
{versions, [v1]},
{priority, Prio1}],
?line {error, Reason21} = config_start(Opts21),
- p("prio (prio) res: ~p", [Reason21]),
+ ?IPRINT("prio (prio) res: ~p", [Reason21]),
- p("atl - incorrect type"),
+ ?IPRINT("atl - incorrect type"),
ATL1 = [{type, invalid_type},
{dir, LogDir},
{size, {10,10240}},
@@ -633,9 +677,9 @@ start_with_incorrect_opts(Conf) when is_list(Conf) ->
{versions, [v1]},
{audit_trail_log, ATL1}],
?line {error, Reason22} = config_start(Opts22),
- p("atl (type) res: ~p", [Reason22]),
+ ?IPRINT("atl (type) res: ~p", [Reason22]),
- p("atl - incorrect dir (1)"),
+ ?IPRINT("atl - incorrect dir (1)"),
ATL2 = [{type, read_write},
{dir, invalid_dir},
{size, {10,10240}},
@@ -644,9 +688,9 @@ start_with_incorrect_opts(Conf) when is_list(Conf) ->
{versions, [v1]},
{audit_trail_log, ATL2}],
?line {error, Reason23} = config_start(Opts23),
- p("atl (dir) res: ~p", [Reason23]),
+ ?IPRINT("atl (dir) res: ~p", [Reason23]),
- p("atl - incorrect dir (2)"),
+ ?IPRINT("atl - incorrect dir (2)"),
ATL3 = [{type, read_write},
{dir, "/invalid/dir"},
{size, {10,10240}},
@@ -655,9 +699,9 @@ start_with_incorrect_opts(Conf) when is_list(Conf) ->
{versions, [v1]},
{audit_trail_log, ATL3}],
?line {error, Reason24} = config_start(Opts24),
- p("atl (dir) res: ~p", [Reason24]),
+ ?IPRINT("atl (dir) res: ~p", [Reason24]),
- p("atl - incorrect size (1)"),
+ ?IPRINT("atl - incorrect size (1)"),
ATL4 = [{type, read_write},
{dir, LogDir},
{size, invalid_size},
@@ -666,9 +710,9 @@ start_with_incorrect_opts(Conf) when is_list(Conf) ->
{versions, [v1]},
{audit_trail_log, ATL4}],
?line {error, Reason25} = config_start(Opts25),
- p("atl (size) res: ~p", [Reason25]),
+ ?IPRINT("atl (size) res: ~p", [Reason25]),
- p("atl - incorrect size (2)"),
+ ?IPRINT("atl - incorrect size (2)"),
ATL5 = [{type, read_write},
{dir, LogDir},
{size, {10,invalid_file_size}},
@@ -677,9 +721,9 @@ start_with_incorrect_opts(Conf) when is_list(Conf) ->
{versions, [v1]},
{audit_trail_log, ATL5}],
?line {error, Reason26} = config_start(Opts26),
- p("atl (size) res: ~p", [Reason26]),
+ ?IPRINT("atl (size) res: ~p", [Reason26]),
- p("atl - incorrect size (3)"),
+ ?IPRINT("atl - incorrect size (3)"),
ATL6 = [{type, read_write},
{dir, LogDir},
{size, {invalid_file_num,10240}},
@@ -688,9 +732,9 @@ start_with_incorrect_opts(Conf) when is_list(Conf) ->
{versions, [v1]},
{audit_trail_log, ATL6}],
?line {error, Reason27} = config_start(Opts27),
- p("atl (size) res: ~p", [Reason27]),
+ ?IPRINT("atl (size) res: ~p", [Reason27]),
- p("atl - incorrect repair"),
+ ?IPRINT("atl - incorrect repair"),
ATL7 = [{type, read_write},
{dir, LogDir},
{size, {10,10240}},
@@ -699,23 +743,23 @@ start_with_incorrect_opts(Conf) when is_list(Conf) ->
{versions, [v1]},
{audit_trail_log, ATL7}],
?line {error, Reason28} = config_start(Opts28),
- p("atl (repair) res: ~p", [Reason28]),
+ ?IPRINT("atl (repair) res: ~p", [Reason28]),
- p("version - incorrect versions (1)"),
+ ?IPRINT("version - incorrect versions (1)"),
Vsns1 = invalid_vsns,
Opts29 = [{config, ConfigOpts},
{versions, Vsns1}],
?line {error, Reason29} = config_start(Opts29),
- p("versions (versions) res: ~p", [Reason29]),
+ ?IPRINT("versions (versions) res: ~p", [Reason29]),
- p("version - incorrect versions (2)"),
+ ?IPRINT("version - incorrect versions (2)"),
Vsns2 = [v1,v2,v3,v9],
Opts30 = [{config, ConfigOpts},
{versions, Vsns2}],
?line {error, Reason30} = config_start(Opts30),
- p("versions (versions) res: ~p", [Reason30]),
+ ?IPRINT("versions (versions) res: ~p", [Reason30]),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -727,8 +771,8 @@ start_with_invalid_manager_conf_file1(suite) -> [];
start_with_invalid_manager_conf_file1(doc) ->
"Start with invalid manager config file (1).";
start_with_invalid_manager_conf_file1(Conf) when is_list(Conf) ->
- put(tname,swimcf),
- p("start"),
+ put(tname, "START-W-INV-MGR-CONF-FILE-1"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -737,142 +781,142 @@ start_with_invalid_manager_conf_file1(Conf) when is_list(Conf) ->
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
%% --
- p("write manager config file with invalid IP address (1)"),
+ ?IPRINT("write manager config file with invalid IP address (1)"),
write_manager_conf(ConfDir,
"arne-anka", "4001", "500", "\"bmkEngine\""),
?line {error, Reason11} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason11]),
+ ?IPRINT("start failed (as expected): ~p", [Reason11]),
?line {failed_reading, _, _, 1, {parse_error, _}} = Reason11,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid IP address (2)"),
+ ?IPRINT("write manager config file with invalid IP address (2)"),
write_manager_conf(ConfDir,
"arne_anka", "4001", "500", "\"bmkEngine\""),
?line {error, Reason12} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason12]),
+ ?IPRINT("start failed (as expected): ~p", [Reason12]),
?line {failed_check, _, _, 2, {bad_address, _}} = Reason12,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid IP address (3)"),
+ ?IPRINT("write manager config file with invalid IP address (3)"),
write_manager_conf(ConfDir,
"9999", "4001", "500", "\"bmkEngine\""),
?line {error, Reason13} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason13]),
+ ?IPRINT("start failed (as expected): ~p", [Reason13]),
?line {failed_check, _, _, 2, {bad_address, _}} = Reason13,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid port (2)"),
+ ?IPRINT("write manager config file with invalid port (2)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "kalle-anka", "500", "\"bmkEngine\""),
?line {error, Reason21} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason21]),
+ ?IPRINT("start failed (as expected): ~p", [Reason21]),
?line {failed_reading, _, _, 2, {parse_error, _}} = Reason21,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid port (1)"),
+ ?IPRINT("write manager config file with invalid port (1)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "-1", "500", "\"bmkEngine\""),
?line {error, Reason22} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason22]),
+ ?IPRINT("start failed (as expected): ~p", [Reason22]),
io:format("Reason22: ~p~n", [Reason22]),
?line {failed_check, _, _, 3, {bad_port, _}} = Reason22,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid port (3)"),
+ ?IPRINT("write manager config file with invalid port (3)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "\"kalle-anka\"", "500", "\"bmkEngine\""),
?line {error, Reason23} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason23]),
+ ?IPRINT("start failed (as expected): ~p", [Reason23]),
?line {failed_check, _, _, 3, {bad_port, _}} = Reason23,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid EngineID (1)"),
+ ?IPRINT("write manager config file with invalid EngineID (1)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "4001", "500", "bmkEngine"),
?line {error, Reason31} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason31]),
+ ?IPRINT("start failed (as expected): ~p", [Reason31]),
?line {failed_check, _, _, 5, {invalid_string, _}} = Reason31,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid EngineID (2)"),
+ ?IPRINT("write manager config file with invalid EngineID (2)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "4001", "500", "{1,2,3}"),
?line {error, Reason32} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason32]),
+ ?IPRINT("start failed (as expected): ~p", [Reason32]),
?line {failed_check, _, _, 5, {invalid_string, _}} = Reason32,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid EngineID (3)"),
+ ?IPRINT("write manager config file with invalid EngineID (3)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "4001", "500", "10101"),
?line {error, Reason33} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason33]),
+ ?IPRINT("start failed (as expected): ~p", [Reason33]),
?line {failed_check, _, _, 5, {invalid_string, _}} = Reason33,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid MMS (1)"),
+ ?IPRINT("write manager config file with invalid MMS (1)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "4001", "483", "\"bmkEngine\""),
?line {error, Reason41} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason41]),
+ ?IPRINT("start failed (as expected): ~p", [Reason41]),
?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason41,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid MMS (2)"),
+ ?IPRINT("write manager config file with invalid MMS (2)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "4001", "-1", "\"bmkEngine\""),
?line {error, Reason42} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason42]),
+ ?IPRINT("start failed (as expected): ~p", [Reason42]),
?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason42,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid MMS (3)"),
+ ?IPRINT("write manager config file with invalid MMS (3)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "4001", "\"kalle-anka\"", "\"bmkEngine\""),
?line {error, Reason43} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason43]),
+ ?IPRINT("start failed (as expected): ~p", [Reason43]),
?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason43,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with invalid MMS (4)"),
+ ?IPRINT("write manager config file with invalid MMS (4)"),
write_manager_conf(ConfDir,
"[134,138,177,189]", "4001", "kalle_anka", "\"bmkEngine\""),
?line {error, Reason44} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason44]),
+ ?IPRINT("start failed (as expected): ~p", [Reason44]),
?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason44,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with unknown option"),
+ ?IPRINT("write manager config file with unknown option"),
write_manager_conf(ConfDir,
"{kalle, anka}."),
?line {error, Reason51} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason51]),
+ ?IPRINT("start failed (as expected): ~p", [Reason51]),
?line {failed_check, _, _, 1, {unknown_config, _}} = Reason51,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write manager config file with unknown option"),
+ ?IPRINT("write manager config file with unknown option"),
write_manager_conf(ConfDir,
"kalle_anka."),
?line {error, Reason52} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason52]),
+ ?IPRINT("start failed (as expected): ~p", [Reason52]),
?line {failed_check, _, _, 1, {unknown_config, _}} = Reason52,
- await_config_not_running(),
+ config_ensure_not_running(),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -884,8 +928,8 @@ start_with_invalid_users_conf_file1(suite) -> [];
start_with_invalid_users_conf_file1(doc) ->
"Start with invalid users config file.";
start_with_invalid_users_conf_file1(Conf) when is_list(Conf) ->
- put(tname,swiucf),
- p("start"),
+ put(tname, "START-W-INV-USER-CONF-FILE-1"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -899,74 +943,74 @@ start_with_invalid_users_conf_file1(Conf) when is_list(Conf) ->
write_manager_conf(ConfDir),
%% --
- p("write users config file with invalid module (1)"),
+ ?IPRINT("write users config file with invalid module (1)"),
write_users_conf(ConfDir, [{"kalle", "kalle", "dummy"}]),
?line {error, Reason11} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason11]),
+ ?IPRINT("start failed (as expected): ~p", [Reason11]),
?line {failed_check, _, _, _, {bad_module, kalle}} = Reason11,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write users config file with invalid module (1)"),
+ ?IPRINT("write users config file with invalid module (1)"),
write_users_conf(ConfDir, [{"kalle", "snmpm", "dummy"}]),
?line {error, Reason12} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason12]),
+ ?IPRINT("start failed (as expected): ~p", [Reason12]),
?line {failed_check, _, _, _, {bad_module, _}} = Reason12,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write users config file with invalid module (2)"),
+ ?IPRINT("write users config file with invalid module (2)"),
write_users_conf(ConfDir, [{"kalle1", "10101", "dummy"}]),
?line {error, Reason13} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason13]),
+ ?IPRINT("start failed (as expected): ~p", [Reason13]),
?line {failed_check, _, _, _, {bad_module, _}} = Reason13,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write users config file with invalid user tuple (1)"),
+ ?IPRINT("write users config file with invalid user tuple (1)"),
write_users_conf2(ConfDir, "{kalle, snmpm_user_default}."),
?line {error, Reason21} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason21]),
+ ?IPRINT("start failed (as expected): ~p", [Reason21]),
?line {failed_check, _, _, _, {bad_user_config, _}} = Reason21,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write users config file with invalid user tuple (2)"),
+ ?IPRINT("write users config file with invalid user tuple (2)"),
write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, [], olle}."),
?line {error, Reason22} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason22]),
+ ?IPRINT("start failed (as expected): ~p", [Reason22]),
?line {failed_check, _, _, _, {bad_user_config, _}} = Reason22,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write users config file with invalid user tuple (3)"),
+ ?IPRINT("write users config file with invalid user tuple (3)"),
write_users_conf2(ConfDir, "snmpm_user_default."),
?line {error, Reason23} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason23]),
+ ?IPRINT("start failed (as expected): ~p", [Reason23]),
?line {failed_check, _, _, _, {bad_user_config, _}} = Reason23,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write users config file with invalid user tuple (4)"),
+ ?IPRINT("write users config file with invalid user tuple (4)"),
write_users_conf2(ConfDir, "[kalle, snmpm_user_default, kalle]."),
?line {error, Reason24} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason24]),
+ ?IPRINT("start failed (as expected): ~p", [Reason24]),
?line {failed_check, _, _, _, {bad_user_config, _}} = Reason24,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write users config file with invalid user agent default config (1)"),
+ ?IPRINT("write users config file with invalid user agent default config (1)"),
write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, olle}."),
?line {error, Reason31} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason31]),
+ ?IPRINT("start failed (as expected): ~p", [Reason31]),
?line {failed_check, _, _, _, {bad_default_agent_config, _}} = Reason31,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("write users config file with invalid user agent default config (2)"),
+ ?IPRINT("write users config file with invalid user agent default config (2)"),
write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, [olle]}."),
?line {error, Reason32} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason32]),
+ ?IPRINT("start failed (as expected): ~p", [Reason32]),
%% ?line {failed_check, _, _, _, {bad_default_agent_config, _}} = Reason32,
case Reason32 of
{failed_check, _, _, _, {bad_default_agent_config, _}} ->
@@ -974,9 +1018,9 @@ start_with_invalid_users_conf_file1(Conf) when is_list(Conf) ->
{A, B, C, D} ->
exit({bad_error, A, B, C, D})
end,
- await_config_not_running(),
+ config_ensure_not_running(),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -988,8 +1032,8 @@ start_with_invalid_agents_conf_file1(suite) -> [];
start_with_invalid_agents_conf_file1(doc) ->
"Start with invalid agents config file.";
start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) ->
- put(tname, swiacf),
- p("start"),
+ put(tname, "START-W-INV-AGS-CONF-FILE-1"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -1009,375 +1053,391 @@ start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) ->
"any", "\"initial\"", "noAuthNoPriv"},
%% --
- p("[test 11] write agents config file with invalid user (1)"),
+ ?IPRINT("[test 11] write agents config file with invalid user (1)"),
Agent11 = setelement(1, Agent0, "kalle-anka"),
write_agents_conf(ConfDir, [Agent11]),
case config_start(Opts) of
{error, Reason11} ->
- p("start failed (as expected): ~p", [Reason11]),
+ ?IPRINT("start failed (as expected): ~p", [Reason11]),
?line {failed_reading, _, _, _, {parse_error, _}} = Reason11,
- await_config_not_running();
+ config_ensure_not_running();
OK_11 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "11", OK_11}})
end,
%% --
- p("[test 21] write agents config file with invalid target name (1)"),
+ ?IPRINT("[test 21] write agents config file with invalid target name (1)"),
Agent21 = setelement(2, Agent0, "targ-hobbes"),
write_agents_conf(ConfDir, [Agent21]),
case config_start(Opts) of
{error, Reason21} ->
- p("start failed (as expected): ~p", [Reason21]),
+ ?IPRINT("start failed (as expected): ~p", [Reason21]),
?line {failed_reading, _, _, _, {parse_error, _}} = Reason21,
- await_config_not_running();
+ config_ensure_not_running();
OK_21 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "21", OK_21}})
end,
%% --
- p("[test 22] write agents config file with invalid target name (2)"),
+ ?IPRINT("[test 22] write agents config file with invalid target name (2)"),
Agent22 = setelement(2, Agent0, "targ_hobbes"),
write_agents_conf(ConfDir, [Agent22]),
case config_start(Opts) of
{error, Reason22} ->
- p("start failed (as expected): ~p", [Reason22]),
+ ?IPRINT("start failed (as expected): ~p", [Reason22]),
?line {failed_check, _, _, _, {invalid_string, _}} = Reason22,
- await_config_not_running();
+ config_ensure_not_running();
OK_22 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "22", OK_22}})
end,
%% --
- p("[test 23] write agents config file with invalid target name (3)"),
+ ?IPRINT("[test 23] write agents config file with invalid target name (3)"),
Agent23 = setelement(2, Agent0, "10101"),
write_agents_conf(ConfDir, [Agent23]),
case config_start(Opts) of
{error, Reason23} ->
- p("start failed (as expected): ~p", [Reason23]),
+ ?IPRINT("start failed (as expected): ~p", [Reason23]),
?line {failed_check, _, _, _, {invalid_string, _}} = Reason23,
- await_config_not_running();
+ config_ensure_not_running();
OK_23 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "23", OK_23}})
end,
%% --
- p("[test 31] write agents config file with invalid community (1)"),
+ ?IPRINT("[test 31] write agents config file with invalid community (1)"),
Agent31 = setelement(3, Agent0, "targ-hobbes"),
write_agents_conf(ConfDir, [Agent31]),
case config_start(Opts) of
{error, Reason31} ->
- p("start failed (as expected): ~p", [Reason31]),
+ ?IPRINT("start failed (as expected): ~p", [Reason31]),
?line {failed_reading, _, _, _, {parse_error, _}} = Reason31,
- await_config_not_running();
+ config_ensure_not_running();
OK_31 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "31", OK_31}})
end,
%% --
- p("[test 32] write agents config file with invalid community (2)"),
+ ?IPRINT("[test 32] write agents config file with invalid community (2)"),
Agent32 = setelement(3, Agent0, "targ_hobbes"),
write_agents_conf(ConfDir, [Agent32]),
case config_start(Opts) of
{error, Reason32} ->
- p("start failed (as expected): ~p", [Reason32]),
+ ?IPRINT("start failed (as expected): ~p", [Reason32]),
?line {failed_check, _, _, _, {invalid_string, _}} = Reason32,
- await_config_not_running();
+ config_ensure_not_running();
OK_32 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "32", OK_32}})
end,
%% --
- p("[test 33] write agents config file with invalid community (3)"),
+ ?IPRINT("[test 33] write agents config file with invalid community (3)"),
Agent33 = setelement(3, Agent0, "10101"),
write_agents_conf(ConfDir, [Agent33]),
case config_start(Opts) of
{error, Reason33} ->
- p("start failed (as expected): ~p", [Reason33]),
+ ?IPRINT("start failed (as expected): ~p", [Reason33]),
?line {failed_check, _, _, _, {invalid_string, _}} = Reason33,
- await_config_not_running();
+ config_ensure_not_running();
OK_33 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "33", OK_33}})
end,
%% --
- p("[test 51] write agents config file with invalid ip (1)"),
+ ?IPRINT("[test 51] write agents config file with invalid ip (1)"),
Agent51 = setelement(4, Agent0, "kalle_anka"),
write_agents_conf(ConfDir, [Agent51]),
case config_start(Opts) of
{error, Reason51} ->
- p("start failed (as expected): ~p", [Reason51]),
+ ?IPRINT("start failed (as expected): ~p", [Reason51]),
?line {failed_check, _, _, _, {bad_domain, _}} = Reason51,
- await_config_not_running();
+ config_ensure_not_running();
OK_51 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "51", OK_51}})
end,
%% --
- p("[test 52] write agents config file with invalid ip (2)"),
+ ?IPRINT("[test 52] write agents config file with invalid ip (2)"),
Agent52 = setelement(4, Agent0, "10101"),
write_agents_conf(ConfDir, [Agent52]),
case config_start(Opts) of
{error, Reason52} ->
- p("start failed (as expected): ~p", [Reason52]),
+ ?IPRINT("start failed (as expected): ~p", [Reason52]),
?line {failed_check, _, _, _, {bad_address, _}} = Reason52,
- await_config_not_running();
+ config_ensure_not_running();
OK_52 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "52", OK_52}})
end,
%% --
- p("[test 53] write agents config file with invalid ip (3)"),
+ ?IPRINT("[test 53] write agents config file with invalid ip (3)"),
Agent53 = setelement(4, Agent0, "[192,168,0]"),
write_agents_conf(ConfDir, [Agent53]),
case config_start(Opts) of
{error, Reason53} ->
- p("start failed (as expected): ~p", [Reason53]),
+ ?IPRINT("start failed (as expected): ~p", [Reason53]),
?line {failed_check, _, _, _, {bad_address, _}} = Reason53,
- await_config_not_running();
+ config_ensure_not_running();
OK_53 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "53", OK_53}})
end,
%% --
- p("[test 54] write agents config file with invalid ip (4)"),
+ ?IPRINT("[test 54] write agents config file with invalid ip (4)"),
Agent54 = setelement(4, Agent0, "[192,168,0,100,99]"),
write_agents_conf(ConfDir, [Agent54]),
case config_start(Opts) of
{error, Reason54} ->
- p("start failed (as expected): ~p", [Reason54]),
+ ?IPRINT("start failed (as expected): ~p", [Reason54]),
?line {failed_check, _, _, _, {bad_address, _}} = Reason54,
- await_config_not_running();
+ config_ensure_not_running();
OK_54 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "54", OK_54}})
end,
%% --
- p("[test 55] write agents config file with invalid ip (5)"),
+ ?IPRINT("[test 55] write agents config file with invalid ip (5)"),
Agent55 = setelement(4, Agent0, "[192,168,0,arne]"),
write_agents_conf(ConfDir, [Agent55]),
?line {error, Reason55} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason55]),
+ ?IPRINT("start failed (as expected): ~p", [Reason55]),
?line {failed_check, _, _, _, {bad_address, _}} = Reason55,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 61] write agents config file with invalid port (1)"),
+ ?IPRINT("[test 61] write agents config file with invalid port (1)"),
Agent61 = setelement(5, Agent0, "kalle_anka"),
write_agents_conf(ConfDir, [Agent61]),
?line {error, Reason61} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason61]),
+ ?IPRINT("start failed (as expected): ~p", [Reason61]),
?line {failed_check, _, _, _, {bad_address, _}} = Reason61,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 62] write agents config file with invalid port (2)"),
+ ?IPRINT("[test 62] write agents config file with invalid port (2)"),
Agent62 = setelement(5, Agent0, "-1"),
write_agents_conf(ConfDir, [Agent62]),
?line {error, Reason62} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason62]),
+ ?IPRINT("start failed (as expected): ~p", [Reason62]),
?line {failed_check, _, _, _, {bad_address, _}} = Reason62,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 63] write agents config file with invalid port (3)"),
+ ?IPRINT("[test 63] write agents config file with invalid port (3)"),
Agent63 = setelement(5, Agent0, "\"100\""),
write_agents_conf(ConfDir, [Agent63]),
?line {error, Reason63} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason63]),
+ ?IPRINT("start failed (as expected): ~p", [Reason63]),
?line {failed_check, _, _, _, {bad_address, _}} = Reason63,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 71] write agents config file with invalid engine-id (1)"),
+ ?IPRINT("[test 71] write agents config file with invalid engine-id (1)"),
Agent71 = setelement(6, Agent0, "kalle_anka"),
write_agents_conf(ConfDir, [Agent71]),
?line {error, Reason71} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason71]),
+ ?IPRINT("start failed (as expected): ~p", [Reason71]),
?line {failed_check, _, _, _, {invalid_string, _}} = Reason71,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 72] write agents config file with invalid engine-id (2)"),
+ ?IPRINT("[test 72] write agents config file with invalid engine-id (2)"),
Agent72 = setelement(6, Agent0, "10101"),
write_agents_conf(ConfDir, [Agent72]),
?line {error, Reason72} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason72]),
+ ?IPRINT("start failed (as expected): ~p", [Reason72]),
?line {failed_check, _, _, _, {invalid_string, _}} = Reason72,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 81] write agents config file with invalid timeout (1)"),
+ ?IPRINT("[test 81] write agents config file with invalid timeout (1)"),
Agent81 = setelement(7, Agent0, "kalle_anka"),
write_agents_conf(ConfDir, [Agent81]),
?line {error, Reason81} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason81]),
+ ?IPRINT("start failed (as expected): ~p", [Reason81]),
?line {failed_check, _, _, _, {invalid_timer, _}} = Reason81,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 82] write agents config file with invalid timeout (2)"),
+ ?IPRINT("[test 82] write agents config file with invalid timeout (2)"),
Agent82 = setelement(7, Agent0, "-1"),
write_agents_conf(ConfDir, [Agent82]),
?line {error, Reason82} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason82]),
+ ?IPRINT("start failed (as expected): ~p", [Reason82]),
?line {failed_check, _, _, _, {invalid_timer, _}} = Reason82,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 83] write agents config file with invalid timeout (3)"),
+ ?IPRINT("[test 83] write agents config file with invalid timeout (3)"),
Agent83 = setelement(7, Agent0, "{1000, 1, 10, kalle}"),
write_agents_conf(ConfDir, [Agent83]),
?line {error, Reason83} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason83]),
+ ?IPRINT("start failed (as expected): ~p", [Reason83]),
?line {failed_check, _, _, _, {invalid_timer, _}} = Reason83,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 84] write agents config file with invalid timeout (4)"),
+ ?IPRINT("[test 84] write agents config file with invalid timeout (4)"),
Agent84 = setelement(7, Agent0, "{1000, -1, 10, 10}"),
write_agents_conf(ConfDir, [Agent84]),
?line {error, Reason84} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason84]),
+ ?IPRINT("start failed (as expected): ~p", [Reason84]),
?line {failed_check, _, _, _, {invalid_timer, _}} = Reason84,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 85] write agents config file with invalid timeout (5)"),
+ ?IPRINT("[test 85] write agents config file with invalid timeout (5)"),
Agent85 = setelement(7, Agent0, "{1000, 1, -100, 10}"),
write_agents_conf(ConfDir, [Agent85]),
?line {error, Reason85} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason85]),
+ ?IPRINT("start failed (as expected): ~p", [Reason85]),
?line {failed_check, _, _, _, {invalid_timer, _}} = Reason85,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 86] write agents config file with invalid timeout (6)"),
+ ?IPRINT("[test 86] write agents config file with invalid timeout (6)"),
Agent86 = setelement(7, Agent0, "{1000, 1, 100, -1}"),
write_agents_conf(ConfDir, [Agent86]),
?line {error, Reason86} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason86]),
+ ?IPRINT("start failed (as expected): ~p", [Reason86]),
?line {failed_check, _, _, _, {invalid_timer, _}} = Reason86,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 91] write agents config file with invalid max-message-size (1)"),
+ ?IPRINT("[test 91] write agents config file with invalid max-message-size (1)"),
Agent91 = setelement(8, Agent0, "483"),
write_agents_conf(ConfDir, [Agent91]),
?line {error, Reason91} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason91]),
+ ?IPRINT("start failed (as expected): ~p", [Reason91]),
?line {failed_check, _, _, _, {invalid_packet_size, _}} = Reason91,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 92] write agents config file with invalid max-message-size (2)"),
+ ?IPRINT("[test 92] write agents config file with invalid max-message-size (2)"),
Agent92 = setelement(8, Agent0, "kalle_anka"),
write_agents_conf(ConfDir, [Agent92]),
?line {error, Reason92} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason92]),
+ ?IPRINT("start failed (as expected): ~p", [Reason92]),
?line {failed_check, _, _, _, {invalid_packet_size, _}} = Reason92,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test A1] write agents config file with invalid version (1)"),
+ ?IPRINT("[test A1] write agents config file with invalid version (1)"),
AgentA1 = setelement(9, Agent0, "1"),
write_agents_conf(ConfDir, [AgentA1]),
?line {error, ReasonA1} = config_start(Opts),
- p("start failed (as expected): ~p", [ReasonA1]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonA1]),
?line {failed_check, _, _, _, {bad_version, _}} = ReasonA1,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test A2] write agents config file with invalid version (2)"),
+ ?IPRINT("[test A2] write agents config file with invalid version (2)"),
AgentA2 = setelement(9, Agent0, "v30"),
write_agents_conf(ConfDir, [AgentA2]),
?line {error, ReasonA2} = config_start(Opts),
- p("start failed (as expected): ~p", [ReasonA2]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonA2]),
?line {failed_check, _, _, _, {bad_version, _}} = ReasonA2,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test B1] write agents config file with invalid sec-model (1)"),
+ ?IPRINT("[test B1] write agents config file with invalid sec-model (1)"),
AgentB1 = setelement(10, Agent0, "\"any\""),
write_agents_conf(ConfDir, [AgentB1]),
?line {error, ReasonB1} = config_start(Opts),
- p("start failed (as expected): ~p", [ReasonB1]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonB1]),
?line {failed_check, _, _, _, {invalid_sec_model, _}} = ReasonB1,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test B2] write agents config file with invalid sec-model (2)"),
+ ?IPRINT("[test B2] write agents config file with invalid sec-model (2)"),
AgentB2 = setelement(10, Agent0, "v3"),
write_agents_conf(ConfDir, [AgentB2]),
?line {error, ReasonB2} = config_start(Opts),
- p("start failed (as expected): ~p", [ReasonB2]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonB2]),
?line {failed_check, _, _, _, {invalid_sec_model, _}} = ReasonB2,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test C1] write agents config file with invalid sec-name (1)"),
+ ?IPRINT("[test C1] write agents config file with invalid sec-name (1)"),
AgentC1 = setelement(11, Agent0, "initial"),
write_agents_conf(ConfDir, [AgentC1]),
case config_start(Opts) of
{error, ReasonC1} ->
- p("start failed (as expected): ~p", [ReasonC1]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonC1]),
?line {failed_check, _, _, _, {bad_sec_name, _}} = ReasonC1,
- await_config_not_running();
+ config_ensure_not_running();
OK_C1 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "C1", OK_C1}})
end,
%% --
- p("[test C2] write agents config file with invalid sec-name (2)"),
+ ?IPRINT("[test C2] write agents config file with invalid sec-name (2)"),
AgentC2 = setelement(11, Agent0, "10101"),
write_agents_conf(ConfDir, [AgentC2]),
case config_start(Opts) of
{error, ReasonC2} ->
- p("start failed (as expected): ~p", [ReasonC2]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonC2]),
?line {failed_check, _, _, _, {bad_sec_name, _}} = ReasonC2,
- await_config_not_running();
+ config_ensure_not_running();
OK_C2 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "C2", OK_C2}})
end,
%% --
- p("[test D1] write agents config file with invalid sec-level (1)"),
+ ?IPRINT("[test D1] write agents config file with invalid sec-level (1)"),
AgentD1 = setelement(12, Agent0, "\"noAuthNoPriv\""),
write_agents_conf(ConfDir, [AgentD1]),
case config_start(Opts) of
{error, ReasonD1} ->
- p("start failed (as expected): ~p", [ReasonD1]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonD1]),
?line {failed_check, _, _, _, {invalid_sec_level, _}} = ReasonD1,
- await_config_not_running();
+ config_ensure_not_running();
OK_D1 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "D1", OK_D1}})
end,
%% --
- p("[test D2] write agents config file with invalid sec-level (2)"),
+ ?IPRINT("[test D2] write agents config file with invalid sec-level (2)"),
AgentD2 = setelement(12, Agent0, "99"),
write_agents_conf(ConfDir, [AgentD2]),
case config_start(Opts) of
{error, ReasonD2} ->
- p("start failed (as expected): ~p", [ReasonD2]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonD2]),
?line {failed_check, _, _, _, {invalid_sec_level, _}} = ReasonD2,
- await_config_not_running();
+ config_ensure_not_running();
OK_D2 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "D2", OK_D2}})
end,
%% --
- p("[test E1] write agents config file with invalid agent (1)"),
+ ?IPRINT("[test E1] write agents config file with invalid agent (1)"),
write_agents_conf2(ConfDir, "{swiacf, \"targ-hobbes\"}."),
case config_start(Opts) of
{error, ReasonE1} ->
- p("start failed (as expected): ~p", [ReasonE1]),
+ ?IPRINT("start failed (as expected): ~p", [ReasonE1]),
?line {failed_check, _, _, _, {bad_agent_config, _}} = ReasonE1,
- await_config_not_running();
+ config_ensure_not_running();
OK_E1 ->
+ config_ensure_not_running(),
exit({error, {unexpected_success, "E1", OK_E1}})
end,
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -1389,8 +1449,8 @@ start_with_invalid_usm_conf_file1(suite) -> [];
start_with_invalid_usm_conf_file1(doc) ->
"Start with invalid usm config file.";
start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) ->
- put(tname,swiusmcf),
- p("start"),
+ put(tname, "START-W-INV-USM-CONF-FILE-1"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
case ?CRYPTO_START() of
@@ -1424,179 +1484,179 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) ->
"usmNoPrivProtocol", "[]"},
%% --
- p("[test 11] write usm config file with invalid engine-id (1)"),
+ ?IPRINT("[test 11] write usm config file with invalid engine-id (1)"),
Usm11 = setelement(1, Usm0, "kalle-anka"),
write_usm_conf(ConfDir, [Usm11]),
?line {error, Reason11} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason11]),
+ ?IPRINT("start failed (as expected): ~p", [Reason11]),
?line {failed_reading, _, _, _, {parse_error, _}} = Reason11,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 12] write usm config file with invalid engine-id (2)"),
+ ?IPRINT("[test 12] write usm config file with invalid engine-id (2)"),
Usm12 = setelement(1, Usm0, "kalle_anka"),
write_usm_conf(ConfDir, [Usm12]),
?line {error, Reason12} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason12]),
+ ?IPRINT("start failed (as expected): ~p", [Reason12]),
?line {failed_check, _, _, _, {bad_usm_engine_id, _}} = Reason12,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 13] write usm config file with invalid engine-id (3)"),
+ ?IPRINT("[test 13] write usm config file with invalid engine-id (3)"),
Usm13 = setelement(1, Usm1, "10101"),
write_usm_conf(ConfDir, [Usm13]),
?line {error, Reason13} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason13]),
+ ?IPRINT("start failed (as expected): ~p", [Reason13]),
?line {failed_check, _, _, _, {bad_usm_engine_id, _}} = Reason13,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 21] write usm config file with invalid user-name (1)"),
+ ?IPRINT("[test 21] write usm config file with invalid user-name (1)"),
Usm21 = setelement(2, Usm0, "kalle_anka"),
write_usm_conf(ConfDir, [Usm21]),
?line {error, Reason21} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason21]),
+ ?IPRINT("start failed (as expected): ~p", [Reason21]),
?line {failed_check, _, _, _, {bad_usm_user_name, _}} = Reason21,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 22] write usm config file with invalid user-name (1)"),
+ ?IPRINT("[test 22] write usm config file with invalid user-name (1)"),
Usm22 = setelement(2, Usm1, "10101"),
write_usm_conf(ConfDir, [Usm22]),
?line {error, Reason22} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason22]),
+ ?IPRINT("start failed (as expected): ~p", [Reason22]),
?line {failed_check, _, _, _, {bad_usm_user_name, _}} = Reason22,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 31] write usm config file with invalid sec-name (1)"),
+ ?IPRINT("[test 31] write usm config file with invalid sec-name (1)"),
Usm31 = setelement(3, Usm1, "kalle_anka"),
write_usm_conf(ConfDir, [Usm31]),
?line {error, Reason31} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason31]),
+ ?IPRINT("start failed (as expected): ~p", [Reason31]),
?line {failed_check, _, _, _, {bad_usm_sec_name, _}} = Reason31,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 32] write usm config file with invalid sec-name (2)"),
+ ?IPRINT("[test 32] write usm config file with invalid sec-name (2)"),
Usm32 = setelement(3, Usm1, "10101"),
write_usm_conf(ConfDir, [Usm32]),
?line {error, Reason32} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason32]),
+ ?IPRINT("start failed (as expected): ~p", [Reason32]),
?line {failed_check, _, _, _, {bad_usm_sec_name, _}} = Reason32,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 41] write usm config file with invalid auth-protocol (1)"),
+ ?IPRINT("[test 41] write usm config file with invalid auth-protocol (1)"),
Usm41 = setelement(3, Usm0, "\"usmNoAuthProtocol\""),
write_usm_conf(ConfDir, [Usm41]),
?line {error, Reason41} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason41]),
+ ?IPRINT("start failed (as expected): ~p", [Reason41]),
?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason41,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 42] write usm config file with invalid auth-protocol (2)"),
+ ?IPRINT("[test 42] write usm config file with invalid auth-protocol (2)"),
Usm42 = setelement(3, Usm0, "kalle"),
write_usm_conf(ConfDir, [Usm42]),
?line {error, Reason42} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason42]),
+ ?IPRINT("start failed (as expected): ~p", [Reason42]),
?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason42,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 43] write usm config file with invalid auth-protocol (3)"),
+ ?IPRINT("[test 43] write usm config file with invalid auth-protocol (3)"),
Usm43 = setelement(3, Usm0, "10101"),
write_usm_conf(ConfDir, [Usm43]),
?line {error, Reason43} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason43]),
+ ?IPRINT("start failed (as expected): ~p", [Reason43]),
?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason43,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 51] write usm config file with invalid auth-key (1)"),
+ ?IPRINT("[test 51] write usm config file with invalid auth-key (1)"),
Usm51 = setelement(3, Usm0, "usmHMACMD5AuthProtocol"),
write_usm_conf(ConfDir, [Usm51]),
?line {error, Reason51} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason51]),
+ ?IPRINT("start failed (as expected): ~p", [Reason51]),
?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason51,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 52] write usm config file with invalid auth-key (2)"),
+ ?IPRINT("[test 52] write usm config file with invalid auth-key (2)"),
Usm52 = setelement(4, Usm51, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]"),
write_usm_conf(ConfDir, [Usm52]),
?line {error, Reason52} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason52]),
+ ?IPRINT("start failed (as expected): ~p", [Reason52]),
?line {failed_check, _, _, _, {invalid_auth_key, _, 15}} = Reason52,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 53] write usm config file with invalid auth-key (3)"),
+ ?IPRINT("[test 53] write usm config file with invalid auth-key (3)"),
Usm53 = setelement(4, Usm51, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7]"),
write_usm_conf(ConfDir, [Usm53]),
?line {error, Reason53} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason53]),
+ ?IPRINT("start failed (as expected): ~p", [Reason53]),
?line {failed_check, _, _, _, {invalid_auth_key, _, 17}} = Reason53,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 54] write usm config file with invalid auth-key (4)"),
+ ?IPRINT("[test 54] write usm config file with invalid auth-key (4)"),
Usm54 = setelement(4, Usm51, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,kalle]"),
write_usm_conf(ConfDir, [Usm54]),
?line maybe_start_crypto(), %% Make sure it's started...
?line {error, Reason54} = config_start(Opts),
?line ok = maybe_stop_crypto(),
- p("start failed (as expected): ~p", [Reason54]),
+ ?IPRINT("start failed (as expected): ~p", [Reason54]),
?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason54,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 55] write usm config file with invalid auth-key (5)"),
+ ?IPRINT("[test 55] write usm config file with invalid auth-key (5)"),
Usm55 = setelement(4, Usm51, "arne_anka"),
write_usm_conf(ConfDir, [Usm55]),
?line {error, Reason55} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason55]),
+ ?IPRINT("start failed (as expected): ~p", [Reason55]),
?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason55,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 56] write usm config file with invalid auth-key (6)"),
+ ?IPRINT("[test 56] write usm config file with invalid auth-key (6)"),
Usm56 = setelement(4, Usm51, "10101"),
write_usm_conf(ConfDir, [Usm56]),
?line {error, Reason56} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason56]),
+ ?IPRINT("start failed (as expected): ~p", [Reason56]),
?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason56,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 57] write usm config file with invalid auth-key (7)"),
+ ?IPRINT("[test 57] write usm config file with invalid auth-key (7)"),
Usm57 = setelement(3, Usm0, "usmHMACSHAAuthProtocol"),
write_usm_conf(ConfDir, [Usm57]),
?line {error, Reason57} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason57]),
+ ?IPRINT("start failed (as expected): ~p", [Reason57]),
?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason57,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 58] write usm config file with invalid auth-key (8)"),
+ ?IPRINT("[test 58] write usm config file with invalid auth-key (8)"),
Usm58 = setelement(4, Usm57, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]"),
write_usm_conf(ConfDir, [Usm58]),
?line {error, Reason58} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason58]),
+ ?IPRINT("start failed (as expected): ~p", [Reason58]),
?line {failed_check, _, _, _, {invalid_auth_key, _, 16}} = Reason58,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 59] write usm config file with invalid auth-key (9)"),
+ ?IPRINT("[test 59] write usm config file with invalid auth-key (9)"),
Usm59 = setelement(4, Usm57, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,ka]"),
write_usm_conf(ConfDir, [Usm59]),
?line ok = maybe_start_crypto(),
?line {error, Reason59} = config_start(Opts),
?line ok = maybe_stop_crypto(),
- p("start failed (as expected): ~p", [Reason59]),
+ ?IPRINT("start failed (as expected): ~p", [Reason59]),
?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason59,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
%% <CRYPTO-MODIFICATIONS>
@@ -1604,16 +1664,16 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) ->
%% explicitly (all of it is as of R14 implemented with NIFs).
case (catch crypto:version()) of
{'EXIT', {undef, _}} ->
- p("[test 5A] write usm config file with valid auth-key "
+ ?IPRINT("[test 5A] write usm config file with valid auth-key "
"when crypto not started (10)"),
Usm5A = setelement(4,
Usm57,
"[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]"),
write_usm_conf(ConfDir, [Usm5A]),
?line {error, Reason5A} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason5A]),
+ ?IPRINT("start failed (as expected): ~p", [Reason5A]),
?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason5A,
- await_config_not_running();
+ config_ensure_not_running();
_ ->
%% This function is only present in version 2.0 or greater.
%% The crypto app no longer needs to be explicitly started
@@ -1622,87 +1682,87 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) ->
%% </CRYPTO-MODIFICATIONS>
%% --
- p("[test 61] write usm config file with invalid priv-protocol (1)"),
+ ?IPRINT("[test 61] write usm config file with invalid priv-protocol (1)"),
Usm61 = setelement(5, Usm0, "\"usmNoPrivProtocol\""),
write_usm_conf(ConfDir, [Usm61]),
?line {error, Reason61} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason61]),
+ ?IPRINT("start failed (as expected): ~p", [Reason61]),
?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason61,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 62] write usm config file with invalid priv-protocol (2)"),
+ ?IPRINT("[test 62] write usm config file with invalid priv-protocol (2)"),
Usm62 = setelement(5, Usm0, "kalle"),
write_usm_conf(ConfDir, [Usm62]),
?line {error, Reason62} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason62]),
+ ?IPRINT("start failed (as expected): ~p", [Reason62]),
?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason62,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 63] write usm config file with invalid priv-protocol (3)"),
+ ?IPRINT("[test 63] write usm config file with invalid priv-protocol (3)"),
Usm63 = setelement(5, Usm0, "10101"),
write_usm_conf(ConfDir, [Usm63]),
?line {error, Reason63} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason63]),
+ ?IPRINT("start failed (as expected): ~p", [Reason63]),
?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason63,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 71] write usm config file with invalid priv-key (1)"),
+ ?IPRINT("[test 71] write usm config file with invalid priv-key (1)"),
Usm71 = setelement(5, Usm0, "usmDESPrivProtocol"),
write_usm_conf(ConfDir, [Usm71]),
?line {error, Reason71} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason71]),
+ ?IPRINT("start failed (as expected): ~p", [Reason71]),
?line {failed_check, _, _, _, {invalid_priv_key, _, _}} = Reason71,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 72] write usm config file with invalid priv-key (2)"),
+ ?IPRINT("[test 72] write usm config file with invalid priv-key (2)"),
Usm72 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]"),
write_usm_conf(ConfDir, [Usm72]),
?line {error, Reason72} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason72]),
+ ?IPRINT("start failed (as expected): ~p", [Reason72]),
?line {failed_check, _, _, _, {invalid_priv_key, _, 15}} = Reason72,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 73] write usm config file with invalid priv-key (3)"),
+ ?IPRINT("[test 73] write usm config file with invalid priv-key (3)"),
Usm73 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7]"),
write_usm_conf(ConfDir, [Usm73]),
?line {error, Reason73} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason73]),
+ ?IPRINT("start failed (as expected): ~p", [Reason73]),
?line {failed_check, _, _, _, {invalid_priv_key, _, 17}} = Reason73,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 74] write usm config file with invalid priv-key (4)"),
+ ?IPRINT("[test 74] write usm config file with invalid priv-key (4)"),
Usm74 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,kalle]"),
write_usm_conf(ConfDir, [Usm74]),
?line ok = maybe_start_crypto(),
?line {error, Reason74} = config_start(Opts),
?line ok = maybe_stop_crypto(),
- p("start failed (as expected): ~p", [Reason74]),
+ ?IPRINT("start failed (as expected): ~p", [Reason74]),
?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason74,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 75] write usm config file with invalid priv-key (5)"),
+ ?IPRINT("[test 75] write usm config file with invalid priv-key (5)"),
Usm75 = setelement(6, Usm71, "arne_anka"),
write_usm_conf(ConfDir, [Usm75]),
?line {error, Reason75} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason75]),
+ ?IPRINT("start failed (as expected): ~p", [Reason75]),
?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason75,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("[test 76] write usm config file with invalid priv-key (6)"),
+ ?IPRINT("[test 76] write usm config file with invalid priv-key (6)"),
Usm76 = setelement(6, Usm71, "10101"),
write_usm_conf(ConfDir, [Usm76]),
?line {error, Reason76} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason76]),
+ ?IPRINT("start failed (as expected): ~p", [Reason76]),
?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason76,
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
%% <CRYPTO-MODIFICATIONS>
@@ -1710,14 +1770,14 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) ->
%% explicitly (all of it is as of R14 implemented with NIFs).
case (catch crypto:version()) of
{'EXIT', {undef, _}} ->
- p("[test 77] write usm config file with valid priv-key "
+ ?IPRINT("[test 77] write usm config file with valid priv-key "
"when crypto not started (7)"),
Usm77 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]"),
write_usm_conf(ConfDir, [Usm77]),
?line {error, Reason77} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason77]),
+ ?IPRINT("start failed (as expected): ~p", [Reason77]),
?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason77,
- await_config_not_running();
+ config_ensure_not_running();
_ ->
%% This function is only present in version 2.0 or greater.
%% The crypto app no longer needs to be explicitly started
@@ -1726,14 +1786,14 @@ start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) ->
%% </CRYPTO-MODIFICATIONS>
%% --
- p("[test 78] write usm config file with invalid usm (1)"),
+ ?IPRINT("[test 78] write usm config file with invalid usm (1)"),
write_usm_conf2(ConfDir, "{\"bmkEngine\", \"swiusmcf\"}."),
?line {error, Reason81} = config_start(Opts),
- p("start failed (as expected): ~p", [Reason81]),
+ ?IPRINT("start failed (as expected): ~p", [Reason81]),
?line {failed_check, _, _, _, {bad_usm_config, _}} = Reason81,
- await_config_not_running(),
+ config_ensure_not_running(),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -1746,28 +1806,28 @@ start_with_create_db_and_dir_opt(doc) ->
"Start the snmp manager config process with the\n"
"create_db_and_dir option.";
start_with_create_db_and_dir_opt(Conf) when is_list(Conf) ->
- put(tname, swcdado),
- p("start"),
+ put(tname, "START-W-CRE-DB-AND-DIR-OPT"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
true = not filelib:is_dir(DbDir) and not filelib:is_file(DbDir),
write_manager_conf(ConfDir),
- p("verify nonexistent db_dir"),
+ ?IPRINT("verify nonexistent db_dir"),
ConfigOpts01 = [{verbosity,trace}, {dir, ConfDir}, {db_dir, DbDir}],
{error, Reason01} = config_start([{config, ConfigOpts01}]),
- p("nonexistent db_dir res: ~p", [Reason01]),
+ ?IPRINT("nonexistent db_dir res: ~p", [Reason01]),
{invalid_conf_db_dir, _, not_found} = Reason01,
- p("verify nonexistent db_dir gets created"),
+ ?IPRINT("verify nonexistent db_dir gets created"),
ConfigOpts02 = [{db_init_error, create_db_and_dir} | ConfigOpts01],
{ok, _Pid} = config_start([{config, ConfigOpts02}]),
true = filelib:is_dir(DbDir),
- p("verified: nonexistent db_dir was correctly created"),
+ ?IPRINT("verified: nonexistent db_dir was correctly created"),
ok = config_stop(),
- p("done"),
+ ?IPRINT("done"),
ok.
%%
@@ -1780,8 +1840,8 @@ simple_system_op(doc) ->
"Access some of the known system info and some \n"
"system info that does not exist.";
simple_system_op(Conf) when is_list(Conf) ->
- put(tname,sso),
- p("start"),
+ put(tname, "SIMPLE-SYS-OP"),
+ ?IPRINT("start"),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -1790,21 +1850,21 @@ simple_system_op(Conf) when is_list(Conf) ->
Opts = [{versions, [v1]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("start config"),
+ ?IPRINT("start config"),
?line {ok, _Pid} = config_start(Opts),
- p("retreive various configs"),
+ ?IPRINT("retreive various configs"),
?line {ok, _Time} = snmpm_config:system_start_time(),
?line {ok, _EngineId} = snmpm_config:get_engine_id(),
?line {ok, _MMS} = snmpm_config:get_engine_max_message_size(),
- p("attempt to retreive nonexisting"),
+ ?IPRINT("attempt to retreive nonexisting"),
?line {error, not_found} = snmpm_config:system_info(kalle),
?line ok = config_stop(),
- await_config_not_running(),
+ config_ensure_not_running(),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -1822,8 +1882,8 @@ register_user_using_file(suite) -> [];
register_user_using_file(doc) ->
"Register user using the 'users.conf' file.";
register_user_using_file(Conf) when is_list(Conf) ->
- put(tname,ruufi),
- p("start"),
+ put(tname, "REG-USER-USING-FILE"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
_ConfDir = ?config(manager_conf_dir, Conf),
_DbDir = ?config(manager_db_dir, Conf),
@@ -1838,8 +1898,8 @@ register_user_using_function(suite) -> [];
register_user_using_function(doc) ->
"Register user using the API (function).";
register_user_using_function(Conf) when is_list(Conf) ->
- put(tname,ruufu),
- p("start"),
+ put(tname, "REG-USER-USING-FUNC"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
_ConfDir = ?config(manager_conf_dir, Conf),
_DbDir = ?config(manager_db_dir, Conf),
@@ -1854,8 +1914,8 @@ register_user_failed_using_function1(suite) -> [];
register_user_failed_using_function1(doc) ->
"Register user failed using incorrect arguments to API (function).";
register_user_failed_using_function1(Conf) when is_list(Conf) ->
- put(tname,rufufu1),
- p("start"),
+ put(tname, "REG-USER-FAIL-USING-FUNC-1"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
_ConfDir = ?config(manager_conf_dir, Conf),
_DbDir = ?config(manager_db_dir, Conf),
@@ -1872,13 +1932,29 @@ register_user_failed_using_function1(Conf) when is_list(Conf) ->
%% ---
%%
+%% This test case tests that we can "register" agents using a config file.
+%% So, starting the config process is part of the actual test, but even
+%% if the test fails, we want to make sure the config process is actually
+%% stop'ed. So, we put config stop in the post.
+
register_agent_using_file(suite) -> [];
register_agent_using_file(doc) ->
"Register agents using the 'agents'conf' file.";
register_agent_using_file(Conf) when is_list(Conf) ->
- put(tname,raufi),
- p("start"),
+ put(tname, "REG-AG-USING-FILE"),
process_flag(trap_exit, true),
+ Pre = fun() -> ok end,
+ Case = fun(_) -> do_register_agent_using_file(Conf) end,
+ Post = fun(_) ->
+ ?IPRINT("stop config process"),
+ ?line ok = snmpm_config:stop(),
+ config_ensure_not_running(),
+ ok
+ end,
+ ?TC_TRY(register_agent_using_file, Pre, Case, Post).
+
+do_register_agent_using_file(Conf) ->
+ ?IPRINT("start"),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -1887,11 +1963,11 @@ register_agent_using_file(Conf) when is_list(Conf) ->
%% --
- p("write manager config file"),
+ ?IPRINT("write manager config file"),
write_manager_conf(ConfDir),
%% --
- p("write users config file"),
+ ?IPRINT("write users config file"),
UserId1 = raufi1,
UserId1Str = str(UserId1),
UserId2 = raufi2,
@@ -1901,7 +1977,7 @@ register_agent_using_file(Conf) when is_list(Conf) ->
write_users_conf(ConfDir, [User1, User2]),
%% --
- p("write agents config file"),
+ ?IPRINT("write agents config file"),
AgentAddr1 = [192,168,0,101],
AgentAddr1Str = str(AgentAddr1),
AgentPort1 = 162,
@@ -1929,38 +2005,38 @@ register_agent_using_file(Conf) when is_list(Conf) ->
write_agents_conf(ConfDir, [Agent1Str, Agent2Str]),
%% --
- p("start the config process"),
+ ?IPRINT("start the config process"),
?line {ok, _Pid} = config_start(Opts),
%% --
- p("which agents"),
+ ?IPRINT("which agents"),
?line [_, _] = All = snmpm_config:which_agents(),
- p("all agents: ~n ~p", [All]),
+ ?IPRINT("all agents: ~n ~p", [All]),
?line [A1] = snmpm_config:which_agents(UserId1),
- p("agents belonging to ~w: ~n ~p", [UserId1, A1]),
+ ?IPRINT("agents belonging to ~w: ~n ~p", [UserId1, A1]),
?line [A2] = snmpm_config:which_agents(UserId2),
- p("agents belonging to ~w: ~n ~p", [UserId2, A2]),
+ ?IPRINT("agents belonging to ~w: ~n ~p", [UserId2, A2]),
%% --
- p("All info for agent <~w,~w>", [AgentAddr1, AgentPort1]),
+ ?IPRINT("All info for agent <~w,~w>", [AgentAddr1, AgentPort1]),
?line {ok, AllInfo1} =
snmpm_config:agent_info(AgentAddr1, AgentPort1, all),
- p("all agent info for agent: ~n ~p", [AllInfo1]),
+ ?IPRINT("all agent info for agent: ~n ~p", [AllInfo1]),
%% --
- p("EngineID (~p) for agent <~w,~w>", [EngineID1, AgentAddr1, AgentPort1]),
+ ?IPRINT("EngineID (~p) for agent <~w,~w>", [EngineID1, AgentAddr1, AgentPort1]),
?line {ok, EngineID1} =
snmpm_config:agent_info(AgentAddr1, AgentPort1, engine_id),
%% --
- p("All info for agent <~w,~w>", [AgentAddr2, AgentPort2]),
+ ?IPRINT("All info for agent <~w,~w>", [AgentAddr2, AgentPort2]),
?line {ok, AllInfo2} =
snmpm_config:agent_info(AgentAddr2, AgentPort2, all),
- p("all agent info for agent: ~n ~p", [AllInfo2]),
+ ?IPRINT("all agent info for agent: ~n ~p", [AllInfo2]),
%% --
- p("EngineID (~p) for agent <~w,~w>", [EngineID2, AgentAddr2, AgentPort2]),
+ ?IPRINT("EngineID (~p) for agent <~w,~w>", [EngineID2, AgentAddr2, AgentPort2]),
?line {ok, EngineID2} =
snmpm_config:agent_info(AgentAddr2, AgentPort2, engine_id),
@@ -1968,7 +2044,7 @@ register_agent_using_file(Conf) when is_list(Conf) ->
?line {ok, MMS2} =
snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size),
NewMMS21 = 2048,
- p("try update agent info max-message-size to ~w for agent <~w,~w>",
+ ?IPRINT("try update agent info max-message-size to ~w for agent <~w,~w>",
[NewMMS21, AgentAddr2, AgentPort2]),
?line ok = snmpm_config:update_agent_info(UserId2, AgentAddr2, AgentPort2,
max_message_size, NewMMS21),
@@ -1976,34 +2052,29 @@ register_agent_using_file(Conf) when is_list(Conf) ->
snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size),
%% --
- p("try (and fail) to update agent info max-message-size to ~w "
+ ?IPRINT("try (and fail) to update agent info max-message-size to ~w "
"for agent <~w,~w> "
"with user ~w (not owner)",
[NewMMS21, AgentAddr2, AgentPort2, UserId1]),
?line {error, Reason01} =
snmpm_config:update_agent_info(UserId1, AgentAddr2, AgentPort2,
max_message_size, NewMMS21),
- p("expected failure. Reason01: ~p", [Reason01]),
+ ?IPRINT("expected failure. Reason01: ~p", [Reason01]),
?line {ok, NewMMS21} =
snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size),
%% --
NewMMS22 = 400,
- p("try (and fail) to update agent info max-message-size to ~w "
+ ?IPRINT("try (and fail) to update agent info max-message-size to ~w "
"for agent <~w,~w>",
[NewMMS22, AgentAddr2, AgentPort2]),
?line {error, Reason02} =
snmpm_config:update_agent_info(UserId1, AgentAddr2, AgentPort2,
max_message_size, NewMMS22),
- p("expected failure. Reason02: ~p", [Reason02]),
+ ?IPRINT("expected failure. Reason02: ~p", [Reason02]),
%% --
- p("stop config process"),
- ?line ok = snmpm_config:stop(),
- await_config_not_running(),
-
- %% --
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -2015,8 +2086,8 @@ register_agent_using_function(suite) -> [];
register_agent_using_function(doc) ->
"Register agents using the API (function).";
register_agent_using_function(Conf) when is_list(Conf) ->
- put(tname,raufu),
- p("start"),
+ put(tname, "REG-AG-USING-FUNC"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
_ConfDir = ?config(manager_conf_dir, Conf),
_DbDir = ?config(manager_db_dir, Conf),
@@ -2032,8 +2103,8 @@ register_agent_failed_using_function1(doc) ->
"Register agents failng using the API (function) with incorrect "
"config (1).";
register_agent_failed_using_function1(Conf) when is_list(Conf) ->
- put(tname,rafuf1),
- p("start"),
+ put(tname, "REG-AG-FAIL-USING-FUNC-1"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
_ConfDir = ?config(manager_conf_dir, Conf),
_DbDir = ?config(manager_db_dir, Conf),
@@ -2054,8 +2125,8 @@ register_usm_user_using_file(suite) -> [];
register_usm_user_using_file(doc) ->
"Register usm user using the 'usm.conf' file.";
register_usm_user_using_file(Conf) when is_list(Conf) ->
- put(tname,ruuufi),
- p("start"),
+ put(tname, "REG-USM-USER-USING-FILE"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
case ?CRYPTO_START() of
@@ -2077,11 +2148,11 @@ register_usm_user_using_file(Conf) when is_list(Conf) ->
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
%% --
- p("write manager config file"),
+ ?IPRINT("write manager config file"),
write_manager_conf(ConfDir),
%% --
- p("write usm user config file"),
+ ?IPRINT("write usm user config file"),
SecEngineID = "loctzp's engine",
SecName1 = "samu_auth1",
UserName1 = SecName1,
@@ -2101,31 +2172,31 @@ register_usm_user_using_file(Conf) when is_list(Conf) ->
write_usm_conf(ConfDir, [UsmUser1, UsmUser2]),
%% --
- p("start the config process"),
+ ?IPRINT("start the config process"),
?line {ok, _Pid} = config_start(Opts),
%% --
- p("lookup 1 (ok)"),
+ ?IPRINT("lookup 1 (ok)"),
?line {ok, #usm_user{name = UserName1} = User1} =
snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName1),
- p("User: ~p", [User1]),
+ ?IPRINT("User: ~p", [User1]),
- p("lookup 2 (ok)"),
+ ?IPRINT("lookup 2 (ok)"),
?line {ok, #usm_user{name = UserName2} = User2} =
snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName2),
- p("User: ~p", [User2]),
+ ?IPRINT("User: ~p", [User2]),
- p("lookup 3 (error)"),
+ ?IPRINT("lookup 3 (error)"),
?line {error, not_found} =
snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName2 ++ "_1"),
%% --
- p("stop config process"),
+ ?IPRINT("stop config process"),
?line ok = snmpm_config:stop(),
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -2137,8 +2208,8 @@ register_usm_user_using_function(suite) -> [];
register_usm_user_using_function(doc) ->
"Register usm user using the API (function).";
register_usm_user_using_function(Conf) when is_list(Conf) ->
- put(tname,ruuufu),
- p("start"),
+ put(tname, "REG-USM-USER-USING-FUNC"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
case ?CRYPTO_START() of
@@ -2160,18 +2231,18 @@ register_usm_user_using_function(Conf) when is_list(Conf) ->
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
%% --
- p("write manager config file"),
+ ?IPRINT("write manager config file"),
write_manager_conf(ConfDir),
%% --
- p("start the config process"),
+ ?IPRINT("start the config process"),
?line {ok, _Pid} = config_start(Opts),
%% --
- p("register usm user's"),
+ ?IPRINT("register usm user's"),
EngineID = "loctzp's engine",
- p("register user 1 (ok)"),
+ ?IPRINT("register user 1 (ok)"),
UserName1 = "samu_auth1",
SecName1 = UserName1,
UsmConfig1 = [{sec_name, SecName1},
@@ -2179,11 +2250,11 @@ register_usm_user_using_function(Conf) when is_list(Conf) ->
{auth_key, [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]},
{priv, usmNoPrivProtocol}],
?line ok = snmpm_config:register_usm_user(EngineID, UserName1, UsmConfig1),
- p("try register user 1 again (error)"),
+ ?IPRINT("try register user 1 again (error)"),
?line {error, {already_registered, EngineID, UserName1}} =
snmpm_config:register_usm_user(EngineID, UserName1, UsmConfig1),
- p("register user 2 (ok)"),
+ ?IPRINT("register user 2 (ok)"),
UserName2 = "samu_auth2",
SecName2 = UserName2,
UsmConfig2 = [{auth, usmHMACMD5AuthProtocol},
@@ -2191,7 +2262,7 @@ register_usm_user_using_function(Conf) when is_list(Conf) ->
{priv, usmNoPrivProtocol}],
?line ok = snmpm_config:register_usm_user(EngineID, UserName2, UsmConfig2),
- p("register user 3 (ok)"),
+ ?IPRINT("register user 3 (ok)"),
UserName3 = "samu3",
SecName3 = "samu_auth3",
UsmConfig3 = [{sec_name, SecName3},
@@ -2200,32 +2271,32 @@ register_usm_user_using_function(Conf) when is_list(Conf) ->
{priv, usmNoPrivProtocol}],
?line ok = snmpm_config:register_usm_user(EngineID, UserName3, UsmConfig3),
- p("lookup 1 (ok)"),
+ ?IPRINT("lookup 1 (ok)"),
?line {ok, #usm_user{name = UserName1} = User1} =
snmpm_config:get_usm_user_from_sec_name(EngineID, SecName1),
- p("User: ~p", [User1]),
+ ?IPRINT("User: ~p", [User1]),
- p("lookup 2 (ok)"),
+ ?IPRINT("lookup 2 (ok)"),
?line {ok, #usm_user{name = UserName2} = User2} =
snmpm_config:get_usm_user_from_sec_name(EngineID, SecName2),
- p("User: ~p", [User2]),
+ ?IPRINT("User: ~p", [User2]),
- p("lookup 3 (ok)"),
+ ?IPRINT("lookup 3 (ok)"),
?line {ok, #usm_user{name = UserName3} = User3} =
snmpm_config:get_usm_user_from_sec_name(EngineID, SecName3),
- p("User: ~p", [User3]),
+ ?IPRINT("User: ~p", [User3]),
- p("lookup 4 (error)"),
+ ?IPRINT("lookup 4 (error)"),
?line {error, not_found} =
snmpm_config:get_usm_user_from_sec_name(EngineID, SecName3 ++ "_1"),
%% --
- p("stop config process"),
+ ?IPRINT("stop config process"),
?line ok = snmpm_config:stop(),
- await_config_not_running(),
+ config_ensure_not_running(),
%% --
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -2237,8 +2308,8 @@ register_usm_user_failed_using_function1(suite) -> [];
register_usm_user_failed_using_function1(doc) ->
"Register usm user failed using incorrect arguments to API (function).";
register_usm_user_failed_using_function1(Conf) when is_list(Conf) ->
- put(tname,ruufufu1),
- p("start"),
+ put(tname, "REG-USM-USER-FAIL-USING-FUNC"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
case ?CRYPTO_START() of
@@ -2266,8 +2337,8 @@ update_usm_user_info(suite) -> [];
update_usm_user_info(doc) ->
"Update usm user info.";
update_usm_user_info(Conf) when is_list(Conf) ->
- put(tname,ruufufu1),
- p("start"),
+ put(tname, "UPD-USM-USER-INFO"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
case ?CRYPTO_START() of
@@ -2301,8 +2372,8 @@ create_and_increment(suite) -> [];
create_and_increment(doc) ->
"Craete and increment counters.";
create_and_increment(Conf) when is_list(Conf) ->
- put(tname,cai),
- p("start"),
+ put(tname, "CRE-AND-INC"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -2317,10 +2388,6 @@ create_and_increment(Conf) when is_list(Conf) ->
%% Random init
?SNMP_RAND_SEED(),
- %% rand:seed(exrop,
- %% {erlang:phash2([node()]),
- %% erlang:monotonic_time(),
- %% erlang:unique_integer()}),
StartVal = rand:uniform(2147483647),
IncVal = 42,
@@ -2330,7 +2397,7 @@ create_and_increment(Conf) when is_list(Conf) ->
?line EndVal = snmpm_config:incr_counter(test_id, IncVal),
?line ok = snmpm_config:stop(),
- await_config_not_running(),
+ config_ensure_not_running(),
ok.
@@ -2348,8 +2415,8 @@ stats_create_and_increment(suite) -> [];
stats_create_and_increment(doc) ->
"Create and increment statistics counters.";
stats_create_and_increment(Conf) when is_list(Conf) ->
- put(tname,scai),
- p("start"),
+ put(tname, "STATS-CRE-AND-INC"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -2362,26 +2429,26 @@ stats_create_and_increment(Conf) when is_list(Conf) ->
?line {ok, _Pid} = snmpm_config:start_link(Opts),
- p("stats table (1): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?IPRINT("stats table (1): ~p", [ets:tab2list(snmpm_stats_table)]),
?line 0 = snmpm_config:maybe_cre_stats_counter(stats1, 0),
- p("stats table (2): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?IPRINT("stats table (2): ~p", [ets:tab2list(snmpm_stats_table)]),
?line ok = snmpm_config:maybe_cre_stats_counter(stats1, 0),
- p("stats table (3): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?IPRINT("stats table (3): ~p", [ets:tab2list(snmpm_stats_table)]),
?line 1 = snmpm_config:maybe_cre_stats_counter(stats2, 1),
- p("stats table (4): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?IPRINT("stats table (4): ~p", [ets:tab2list(snmpm_stats_table)]),
?line 10 = snmpm_config:cre_stats_counter(stats3, 10),
- p("stats table (5): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?IPRINT("stats table (5): ~p", [ets:tab2list(snmpm_stats_table)]),
Stats1Inc = fun() -> snmpm_config:incr_stats_counter(stats1, 1) end,
?line 10 = loop(10, -1, Stats1Inc),
- p("stats table (6): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?IPRINT("stats table (6): ~p", [ets:tab2list(snmpm_stats_table)]),
?line ok = snmpm_config:reset_stats_counter(stats1),
?line 10 = loop(10, -1, Stats1Inc),
?line ok = snmpm_config:stop(),
- await_config_not_running(),
+ config_ensure_not_running(),
ok.
@@ -2403,46 +2470,46 @@ otp_7219(suite) ->
otp_7219(doc) ->
"Test-case for ticket OTP-7219";
otp_7219(Config) when is_list(Config) ->
- put(tname, otp7219),
- p("start"),
+ put(tname, "OTP-7219"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Config),
DbDir = ?config(manager_db_dir, Config),
- p("write manager configuration"),
+ ?IPRINT("write manager configuration"),
write_manager_conf(ConfDir),
Opts1 = [{versions, [v1]},
{inform_request_behaviour, user},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("start manager config"),
+ ?IPRINT("start manager config"),
?line {ok, _Pid1} = snmpm_config:start_link(Opts1),
- p("get some manager config"),
+ ?IPRINT("get some manager config"),
{ok, {user, _}} = snmpm_config:system_info(net_if_irb),
- p("stop manager config"),
+ ?IPRINT("stop manager config"),
?line ok = snmpm_config:stop(),
- await_config_not_running(),
+ config_ensure_not_running(),
IRB_TO = 15322,
Opts2 = [{versions, [v1]},
{inform_request_behaviour, {user, IRB_TO}},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("start manager config"),
+ ?IPRINT("start manager config"),
?line {ok, _Pid2} = snmpm_config:start_link(Opts2),
- p("get some manager config"),
+ ?IPRINT("get some manager config"),
{ok, {user, IRB_TO}} = snmpm_config:system_info(net_if_irb),
- p("stop manager config"),
+ ?IPRINT("stop manager config"),
?line ok = snmpm_config:stop(),
- await_config_not_running(),
+ config_ensure_not_running(),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -2452,8 +2519,8 @@ otp_8395_1(suite) -> [];
otp_8395_1(doc) ->
"OTP-8395(1)";
otp_8395_1(Conf) when is_list(Conf) ->
- put(tname, otp_8395_1),
- p("start"),
+ put(tname, "OTP-8395-1"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
otp8395(Conf, false, ok),
ok.
@@ -2462,8 +2529,8 @@ otp_8395_2(suite) -> [];
otp_8395_2(doc) ->
"OTP-8395(2)";
otp_8395_2(Conf) when is_list(Conf) ->
- put(tname, otp_8395_2),
- p("start"),
+ put(tname, "OTP-8395-2"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
otp8395(Conf, true, ok),
ok.
@@ -2472,8 +2539,8 @@ otp_8395_3(suite) -> [];
otp_8395_3(doc) ->
"OTP-8395(3)";
otp_8395_3(Conf) when is_list(Conf) ->
- put(tname, otp_8395_3),
- p("start"),
+ put(tname, "OTP-8395-3"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
otp8395(Conf, gurka, error),
ok.
@@ -2487,7 +2554,7 @@ otp8395(Conf, SeqNoVal, Expect) ->
write_manager_conf(ConfDir),
%% Third set of options (no versions):
- p("all options"),
+ ?IPRINT("all options"),
NetIfOpts = [{module, snmpm_net_if},
{verbosity, trace},
{options, [{recbuf, 30000},
@@ -2526,7 +2593,7 @@ otp8395(Conf, SeqNoVal, Expect) ->
Error when (Expect =:= ok) ->
exit({unexpected_failed_starting_config, SeqNoVal, Error})
end,
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -2534,8 +2601,8 @@ otp_8395_4(suite) -> [];
otp_8395_4(doc) ->
"OTP-8395(4)";
otp_8395_4(Conf) when is_list(Conf) ->
- put(tname, otp_8395_4),
- p("start"),
+ put(tname, "OTP-8395-4"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
snmp:print_version_info(),
@@ -2548,7 +2615,7 @@ otp_8395_4(Conf) when is_list(Conf) ->
write_manager_conf(ConfDir),
%% Third set of options (no versions):
- p("all options"),
+ ?IPRINT("all options"),
NetIfOpts = [{module, snmpm_net_if},
{verbosity, trace},
{options, [{recbuf, 30000},
@@ -2595,7 +2662,7 @@ otp_8395_4(Conf) when is_list(Conf) ->
?line ok = config_stop(),
- p("done"),
+ ?IPRINT("done"),
ok.
@@ -2607,52 +2674,17 @@ otp8395_incr_counter(Counter, Initial, Increment, Max) ->
%% Internal functions
%%======================================================================
-await_config_not_running() ->
- await_not_running(snmpm_config, 5).
-
-await_not_running(Name, 0) ->
- p("await_not_running -> done waiting for ~w to die - try kill it", [Name]),
- %% Ok, we tried it the nice way, now use brute force
- await_killed(Name, 5);
-await_not_running(Name, N) when N > 0 ->
- p("await_not_running -> is process ~w still running (~w)", [Name, N]),
- case erlang:whereis(Name) of
- undefined ->
- p("await_not_running -> no such (~w) process - sleep some",[Name]),
- ?SLEEP(1000),
- p("await_not_running -> no such (~w) process - done", [Name]),
- ok;
- Pid when is_pid(Pid) ->
- p("~w process still running", [Name]),
- ?SLEEP(500),
- await_not_running(Name, N-1)
- end.
-
-await_killed(Name, 0) ->
- p("await_killed -> could not kill ~w => giving up", [Name]),
- exit({error, {failed_terminating, Name}});
-await_killed(Name, N) when N > 0 ->
- p("await_killed -> is process ~w still running (~w)", [Name, N]),
- case whereis(Name) of
- undefined ->
- p("await_killed -> no such (~w) process - sleep some", [Name]),
- ?SLEEP(1000),
- p("await_killed -> no such (~w) process - done", [Name]),
- ok;
- Pid when is_pid(Pid) ->
- p("await_killed -> ~w still running - try kill it", [Name]),
- exit(Pid, kill),
- ?SLEEP(1000),
- await_killed(Name, N-1)
- end.
-
-
config_start(Opts) ->
(catch snmpm_config:start_link(Opts)).
config_stop() ->
(catch snmpm_config:stop()).
+config_ensure_not_running() ->
+ ?ENSURE_NOT_RUNNING(snmpm_config,
+ fun() -> snmpm_config:stop() end,
+ 1000).
+
%% ------
@@ -2809,20 +2841,5 @@ verify_dir_existing(DirName, Dir) ->
%% ------
str(X) ->
- lists:flatten(io_lib:format("~w", [X])).
-
-
-%% ------
-
-p(F) ->
- p(F, []).
-
-p(F, A) ->
- p(get(tname), F, A).
-
-p(TName, F, A) ->
- io:format("*** [~s] ***"
- " ~w -> " ++ F ++ "~n", [formated_timestamp(),TName|A]).
+ ?F("~w", [X]).
-formated_timestamp() ->
- snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_manager_user_SUITE.erl b/lib/snmp/test/snmp_manager_user_SUITE.erl
index 353f1b21f3..eca0d8a4f9 100644
--- a/lib/snmp/test/snmp_manager_user_SUITE.erl
+++ b/lib/snmp/test/snmp_manager_user_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -143,8 +143,8 @@ tickets_cases() ->
init_per_suite(Config0) when is_list(Config0) ->
- p("init_per_suite -> entry with"
- "~n Config0: ~p", [Config0]),
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config0: ~p", [Config0]),
case ?LIB:init_per_suite(Config0) of
{skip, _} = SKIP ->
@@ -153,19 +153,23 @@ init_per_suite(Config0) when is_list(Config0) ->
snmp_test_sys_monitor:start(),
Config2 = snmp_test_lib:init_suite_top_dir(?MODULE, Config1),
- p("init_per_suite -> done when"
- "~n Config: ~p", [Config2]),
+ ?IPRINT("init_per_suite -> done when"
+ "~n Config: ~p", [Config2]),
Config2
end.
end_per_suite(Config) when is_list(Config) ->
- p("end_per_suite -> entry with"
- "~n Config: ~p", [Config]),
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config: ~p", [Config]),
snmp_test_sys_monitor:stop(),
- ?LIB:end_per_suite(Config).
+ Config1 = ?LIB:end_per_suite(Config),
+
+ ?IPRINT("end_per_suite -> end"),
+
+ Config1.
@@ -186,14 +190,15 @@ end_per_group(_GroupName, Config) ->
%%
init_per_testcase(Case, Config) when is_list(Config) ->
- p("init_per_testcase -> Case: ~p", [Case]),
+ ?IPRINT("init_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
snmp_test_global_sys_monitor:reset_events(),
SuiteTopDir = ?config(snmp_suite_top_dir, Config),
CaseTopDir = filename:join(SuiteTopDir, atom_to_list(Case)),
?line ok = file:make_dir(CaseTopDir),
- p("init_per_testcase -> CaseTopDir: ~p", [CaseTopDir]),
+ ?IPRINT("init_per_testcase -> CaseTopDir: ~p", [CaseTopDir]),
MgrTopDir = filename:join(CaseTopDir, "manager/"),
?line ok = file:make_dir(MgrTopDir),
MgrConfDir = filename:join(MgrTopDir, "conf/"),
@@ -202,18 +207,27 @@ init_per_testcase(Case, Config) when is_list(Config) ->
?line ok = file:make_dir(MgrDbDir),
MgrLogDir = filename:join(MgrTopDir, "log/"),
?line ok = file:make_dir(MgrLogDir),
- [{case_top_dir, CaseTopDir},
- {manager_dir, MgrTopDir},
- {manager_conf_dir, MgrConfDir},
- {manager_db_dir, MgrDbDir},
- {manager_log_dir, MgrLogDir} | Config].
+ Config1 = [{case_top_dir, CaseTopDir},
+ {manager_dir, MgrTopDir},
+ {manager_conf_dir, MgrConfDir},
+ {manager_db_dir, MgrDbDir},
+ {manager_log_dir, MgrLogDir} | Config],
+
+ ?IPRINT("init_per_testcase -> done when"
+ "~n Config: ~p", [Config1]),
+
+ Config1.
+
+
+end_per_testcase(_Case, Config) when is_list(Config) ->
-end_per_testcase(Case, Config) when is_list(Config) ->
- p("end_per_testcase -> Case: ~p", [Case]),
+ ?IPRINT("end_per_testcase -> entry with"
+ "~n Config: ~p",
+ [Config]),
- p("system events during test: "
- "~n ~p~n", [snmp_test_global_sys_monitor:events()]),
+ ?IPRINT("system events during test: ~p",
+ [snmp_test_global_sys_monitor:events()]),
Config.
@@ -228,7 +242,7 @@ simple_register_and_unregister1(doc) ->
"Start a user, register and unregister the user.";
simple_register_and_unregister1(Conf) when is_list(Conf) ->
put(tname,srar1),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -241,7 +255,7 @@ simple_register_and_unregister1(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -251,23 +265,23 @@ simple_register_and_unregister1(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user(Pid, Id),
?line [Id] = Users2 = which_users(),
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = unregister_user(Pid),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
?line stop_user(Pid),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -279,7 +293,7 @@ simple_register_and_unregister2(doc) ->
"register 2 users (per that process) and unregister the 2 users.";
simple_register_and_unregister2(Conf) when is_list(Conf) ->
put(tname,srar2),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -292,7 +306,7 @@ simple_register_and_unregister2(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -303,7 +317,7 @@ simple_register_and_unregister2(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user(Pid, Id1),
?line ok = register_user(Pid, Id2),
@@ -316,20 +330,20 @@ simple_register_and_unregister2(Conf) when is_list(Conf) ->
Else ->
?FAIL({invalid_users, Else})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = unregister_user(Pid, Id1),
?line ok = unregister_user(Pid, Id2),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
?line stop_user(Pid),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -341,7 +355,7 @@ simple_register_and_unregister3(doc) ->
"register one users per process and unregister the 2 users.";
simple_register_and_unregister3(Conf) when is_list(Conf) ->
put(tname,srar2),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -354,7 +368,7 @@ simple_register_and_unregister3(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -366,7 +380,7 @@ simple_register_and_unregister3(Conf) when is_list(Conf) ->
?line Pid2 = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user(Pid1, Id1),
?line ok = register_user(Pid2, Id2),
@@ -379,21 +393,21 @@ simple_register_and_unregister3(Conf) when is_list(Conf) ->
Else ->
?FAIL({invalid_users, Else})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = unregister_user(Pid1, Id1),
?line ok = unregister_user(Pid2, Id2),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
?line stop_user(Pid1),
?line stop_user(Pid2),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -404,7 +418,7 @@ register_and_crash1(doc) ->
"Start a user, register and crash user.";
register_and_crash1(Conf) when is_list(Conf) ->
put(tname,racau1),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -417,7 +431,7 @@ register_and_crash1(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
?line ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -427,22 +441,22 @@ register_and_crash1(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user(Pid, Id),
?line [Id] = Users2 = which_users(),
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = simulate_crash(Pid),
?line [Id] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -454,7 +468,7 @@ register_and_crash2(doc) ->
"register 2 users (per that process) and crash the process.";
register_and_crash2(Conf) when is_list(Conf) ->
put(tname,racau2),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -467,7 +481,7 @@ register_and_crash2(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
?line ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -478,7 +492,7 @@ register_and_crash2(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user(Pid, Id1),
?line ok = register_user(Pid, Id2),
@@ -491,7 +505,7 @@ register_and_crash2(Conf) when is_list(Conf) ->
Else1 ->
?FAIL({invalid_users, Else1})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = simulate_crash(Pid),
@@ -503,12 +517,12 @@ register_and_crash2(Conf) when is_list(Conf) ->
Else2 ->
?FAIL({invalid_users, Else2})
end,
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -521,7 +535,7 @@ register_and_crash3(doc) ->
"crash the first user process.";
register_and_crash3(Conf) when is_list(Conf) ->
%% put(tname,rac3),
- %% p("start"),
+ %% ?IPRINT("start"),
%% process_flag(trap_exit, true),
?SKIP(not_yet_implemented).
@@ -534,7 +548,7 @@ register_request_and_crash1(doc) ->
"register user, send request and crash user.";
register_request_and_crash1(Conf) when is_list(Conf) ->
%% put(tname,rrac1),
- %% p("start"),
+ %% ?IPRINT("start"),
%% process_flag(trap_exit, true),
?SKIP(not_yet_implemented).
@@ -548,7 +562,7 @@ register_request_and_crash2(doc) ->
"send a request for each user and crash the single user process.";
register_request_and_crash2(Conf) when is_list(Conf) ->
%% put(tname,rrac2),
- %% p("start"),
+ %% ?IPRINT("start"),
%% process_flag(trap_exit, true),
?SKIP(not_yet_implemented).
@@ -562,7 +576,7 @@ register_request_and_crash3(doc) ->
"send a request for each user and crash the first user process.";
register_request_and_crash3(Conf) when is_list(Conf) ->
%% put(tname,rrac3),
- %% p("start"),
+ %% ?IPRINT("start"),
%% process_flag(trap_exit, true),
?SKIP(not_yet_implemented).
@@ -574,7 +588,7 @@ simple_register_monitor_and_unregister1(doc) ->
"Start a user, register-link and unregister the user.";
simple_register_monitor_and_unregister1(Conf) when is_list(Conf) ->
put(tname,srlau1),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -587,41 +601,41 @@ simple_register_monitor_and_unregister1(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start_link(Opts),
?SLEEP(1000),
Id = make_ref(),
- p("start user"),
+ ?IPRINT("start user"),
?line Pid = start_user(),
- p("get users (=0)"),
+ ?IPRINT("get users (=0)"),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
- p("register monitored user"),
+ ?IPRINT("register monitored user"),
?line ok = register_user_monitor(Pid, Id),
- p("get users (=1)"),
+ ?IPRINT("get users (=1)"),
?line [Id] = Users2 = which_users(),
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
- p("unregister monitored user"),
+ ?IPRINT("unregister monitored user"),
?line unregister_user(Pid),
- p("get users (=0)"),
+ ?IPRINT("get users (=0)"),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
- p("start user"),
+ ?IPRINT("start user"),
?line stop_user(Pid),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -634,7 +648,7 @@ simple_register_monitor_and_unregister2(doc) ->
"unregister the 2 users.";
simple_register_monitor_and_unregister2(Conf) when is_list(Conf) ->
put(tname,srlau2),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -647,7 +661,7 @@ simple_register_monitor_and_unregister2(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -658,7 +672,7 @@ simple_register_monitor_and_unregister2(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user_monitor(Pid, Id1),
?line ok = register_user_monitor(Pid, Id2),
@@ -671,19 +685,19 @@ simple_register_monitor_and_unregister2(Conf) when is_list(Conf) ->
Else ->
?FAIL({invalid_users, Else})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = unregister_user(Pid, Id1),
?line ok = unregister_user(Pid, Id2),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
?line stop_user(Pid),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -697,7 +711,7 @@ simple_register_monitor_and_unregister3(doc) ->
"unregister the 2 users.";
simple_register_monitor_and_unregister3(Conf) when is_list(Conf) ->
put(tname,srlau3),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -710,7 +724,7 @@ simple_register_monitor_and_unregister3(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -721,7 +735,7 @@ simple_register_monitor_and_unregister3(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user(Pid, Id1),
?line ok = register_user_monitor(Pid, Id2),
@@ -734,18 +748,18 @@ simple_register_monitor_and_unregister3(Conf) when is_list(Conf) ->
Else ->
?FAIL({invalid_users, Else})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line unregister_user(Pid),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
?line stop_user(Pid),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -756,7 +770,7 @@ register_monitor_and_crash1(doc) ->
"Start a user, register-monitor and crash the user.";
register_monitor_and_crash1(Conf) when is_list(Conf) ->
put(tname,rlac1),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -769,7 +783,7 @@ register_monitor_and_crash1(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
?line ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -779,24 +793,24 @@ register_monitor_and_crash1(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user_monitor(Pid, Id),
?line [Id] = Users2 = which_users(),
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = simulate_crash(Pid),
?SLEEP(1000),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -809,7 +823,7 @@ register_monitor_and_crash2(doc) ->
"and crash the single user process.";
register_monitor_and_crash2(Conf) when is_list(Conf) ->
put(tname,rlac2),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -822,7 +836,7 @@ register_monitor_and_crash2(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
?line ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -833,7 +847,7 @@ register_monitor_and_crash2(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user_monitor(Pid, Id1),
?line ok = register_user_monitor(Pid, Id2),
@@ -846,19 +860,19 @@ register_monitor_and_crash2(Conf) when is_list(Conf) ->
Else ->
?FAIL({invalid_users, Else})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = simulate_crash(Pid),
?SLEEP(1000),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -901,7 +915,7 @@ register_monitor_and_crash3(Conf) when is_list(Conf) ->
?NON_PC_TC_MAYBE_SKIP(Conf, Condition),
%% </CONDITIONAL-SKIP>
- p("start"),
+ ?IPRINT("start"),
ConfDir = ?config(manager_conf_dir, Conf),
DbDir = ?config(manager_db_dir, Conf),
@@ -913,7 +927,7 @@ register_monitor_and_crash3(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
?line ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -924,7 +938,7 @@ register_monitor_and_crash3(Conf) when is_list(Conf) ->
?line Pid = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user(Pid, Id1),
?line ok = register_user_monitor(Pid, Id2),
@@ -937,19 +951,19 @@ register_monitor_and_crash3(Conf) when is_list(Conf) ->
Else ->
?FAIL({invalid_users, Else})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = simulate_crash(Pid),
?SLEEP(1000),
?line [Id1] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -962,7 +976,7 @@ register_monitor_and_crash4(doc) ->
"and crash the first user process.";
register_monitor_and_crash4(Conf) when is_list(Conf) ->
put(tname,rlac4),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -975,7 +989,7 @@ register_monitor_and_crash4(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("start manager"),
+ ?IPRINT("start manager"),
?line ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -983,12 +997,12 @@ register_monitor_and_crash4(Conf) when is_list(Conf) ->
Id1 = make_ref(),
Id2 = make_ref(),
- p("start user processes"),
+ ?IPRINT("start user processes"),
?line Pid1 = start_user(),
?line Pid2 = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user_monitor(Pid1, Id1),
?line ok = register_user_monitor(Pid2, Id2),
@@ -1001,21 +1015,21 @@ register_monitor_and_crash4(Conf) when is_list(Conf) ->
Else ->
?FAIL({invalid_users, Else})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = simulate_crash(Pid1),
?SLEEP(1000),
?line [Id2] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
?line stop_user(Pid2),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -1030,7 +1044,7 @@ register_monitor_and_crash5(doc) ->
"and crash the first user process.";
register_monitor_and_crash5(Conf) when is_list(Conf) ->
put(tname,rlac4),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -1043,7 +1057,7 @@ register_monitor_and_crash5(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("start manager"),
+ ?IPRINT("start manager"),
?line ok = snmpm:start_link(Opts),
?SLEEP(1000),
@@ -1051,12 +1065,12 @@ register_monitor_and_crash5(Conf) when is_list(Conf) ->
Id1 = gurka, %% make_ref(),
Id2 = tomat, %% make_ref(),
- p("start user processes"),
+ ?IPRINT("start user processes"),
?line Pid1 = start_user(),
?line Pid2 = start_user(),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = register_user_monitor(Pid1, Id1),
?line ok = register_user_monitor(Pid2, Id2),
@@ -1090,9 +1104,9 @@ register_monitor_and_crash5(Conf) when is_list(Conf) ->
U3 ->
?FAIL({invalid_users, U3})
end,
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
- p("verify all agent(s): expect 2"),
+ ?IPRINT("verify all agent(s): expect 2"),
?line Agents1 = case which_agents() of
[TargetName1, TargetName2] = A1 ->
A1;
@@ -1101,25 +1115,25 @@ register_monitor_and_crash5(Conf) when is_list(Conf) ->
A3 ->
?FAIL({invalid_agents, A3})
end,
- p("Agents1: ~p", [Agents1]),
+ ?IPRINT("Agents1: ~p", [Agents1]),
?line ok = simulate_crash(Pid1),
- p("wait some time"),
+ ?IPRINT("wait some time"),
?SLEEP(1000),
?line [Id2] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
?line [TargetName2] = Agents2 = which_agents(),
- p("Agents2: ~p", [Agents2]),
+ ?IPRINT("Agents2: ~p", [Agents2]),
?line stop_user(Pid2),
- p("stop manager"),
+ ?IPRINT("stop manager"),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -1132,7 +1146,7 @@ register_monitor_request_and_crash1(doc) ->
"send request and crash the user.";
register_monitor_request_and_crash1(Conf) when is_list(Conf) ->
%% put(tname,rlrac1),
- %% p("start"),
+ %% ?IPRINT("start"),
%% process_flag(trap_exit, true),
?SKIP(not_yet_implemented).
@@ -1146,7 +1160,7 @@ register_monitor_request_and_crash2(doc) ->
"send a request for each user and crash the single user process.";
register_monitor_request_and_crash2(Conf) when is_list(Conf) ->
%% put(tname,rlrac2),
- %% p("start"),
+ %% ?IPRINT("start"),
%% process_flag(trap_exit, true),
?SKIP(not_yet_implemented).
@@ -1160,7 +1174,7 @@ register_monitor_request_and_crash3(doc) ->
"send a request for each user and crash the single user process.";
register_monitor_request_and_crash3(Conf) when is_list(Conf) ->
%% put(tname,rlrac3),
- %% p("start"),
+ %% ?IPRINT("start"),
%% process_flag(trap_exit, true),
?SKIP(not_yet_implemented).
@@ -1176,7 +1190,7 @@ register_monitor_request_and_crash4(doc) ->
"crash the first user process.";
register_monitor_request_and_crash4(Conf) when is_list(Conf) ->
%% put(tname,rlrac4),
- %% p("start"),
+ %% ?IPRINT("start"),
%% process_flag(trap_exit, true),
?SKIP(not_yet_implemented).
@@ -1189,7 +1203,7 @@ otp7902(doc) ->
"OTP-7902 - Start old user and make sure it wors.";
otp7902(Conf) when is_list(Conf) ->
put(tname, otp7902),
- p("start"),
+ ?IPRINT("start"),
process_flag(trap_exit, true),
ConfDir = ?config(manager_conf_dir, Conf),
@@ -1202,27 +1216,27 @@ otp7902(Conf) when is_list(Conf) ->
{note_store, [{verbosity, trace}]},
{config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
- p("try starting manager"),
+ ?IPRINT("try starting manager"),
ok = snmpm:start_link(Opts),
?SLEEP(1000),
?line [] = Users1 = which_users(),
- p("Users1: ~p", [Users1]),
+ ?IPRINT("Users1: ~p", [Users1]),
?line ok = snmp_manager_user_old:start(),
?line [_] = Users2 = which_users(),
- p("Users2: ~p", [Users2]),
+ ?IPRINT("Users2: ~p", [Users2]),
?line ok = snmp_manager_user_old:stop(),
?line [] = Users3 = which_users(),
- p("Users3: ~p", [Users3]),
+ ?IPRINT("Users3: ~p", [Users3]),
?line ok = snmpm:stop(),
- p("end"),
+ ?IPRINT("end"),
ok.
@@ -1306,15 +1320,3 @@ write_conf_file(Dir, File, Str) ->
?line ok = io:format(Fd, "~s", [Str]),
file:close(Fd).
-
-%% ------
-
-p(F) ->
- p(F, []).
-
-p(F, A) ->
- p(get(tname), F, A).
-
-p(TName, F, A) ->
- io:format("~w -> " ++ F ++ "~n", [TName|A]).
-
diff --git a/lib/snmp/test/snmp_note_store_SUITE.erl b/lib/snmp/test/snmp_note_store_SUITE.erl
index 832c03029e..3b6d9f9fcd 100644
--- a/lib/snmp/test/snmp_note_store_SUITE.erl
+++ b/lib/snmp/test/snmp_note_store_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2004-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2004-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -81,11 +81,34 @@ groups() ->
%% -----
%%
-init_per_suite(Config) when is_list(Config) ->
- Config.
+init_per_suite(Config0) when is_list(Config0) ->
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config: ~p", [Config0]),
-end_per_suite(Config) when is_list(Config) ->
- Config.
+ case ?LIB:init_per_suite(Config0) of
+ {skip, _} = SKIP ->
+ SKIP;
+
+ Config1 when is_list(Config1) ->
+ %% We need a monitor on this node also
+ snmp_test_sys_monitor:start(),
+
+ ?IPRINT("init_per_suite -> end when"
+ "~n Config1: ~p", [Config1]),
+
+ Config1
+ end.
+
+end_per_suite(Config0) when is_list(Config0) ->
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config: ~p", [Config0]),
+
+ snmp_test_sys_monitor:stop(),
+ Config1 = ?LIB:end_per_suite(Config0),
+
+ ?IPRINT("end_per_suite -> end"),
+
+ Config1.
@@ -106,9 +129,24 @@ end_per_group(_GroupName, Config) ->
%%
init_per_testcase(_Case, Config) when is_list(Config) ->
+ ?IPRINT("init_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
+
+ snmp_test_global_sys_monitor:reset_events(),
+
+ ?IPRINT("init_per_testcase -> end"),
+
Config.
end_per_testcase(_Case, Config) when is_list(Config) ->
+
+ ?IPRINT("end_per_testcase -> entry with"
+ "~n Config: ~p",
+ [Config]),
+
+ ?IPRINT("system events during test: ~p",
+ [snmp_test_global_sys_monitor:events()]),
+
Config.
@@ -143,42 +181,55 @@ notes(doc) ->
["Testing that it does what it is actually supposed to do, "
"namilly to handle notes. "];
notes(Config) when is_list(Config) ->
-
- {ok, Handler, Pid} = note_store_handler_start(),
-
- io:format("sleep some before we begin the tests~n", []),
- ?SLEEP(timer:seconds(1)),
+ Pre = fun() ->
+ ?IPRINT("try start note-store"),
+ case note_store_handler_start() of
+ {ok, Handler, Pid} ->
+ ?IPRINT("started - sleep some before we begin the tests"),
+ ?SLEEP(?SECS(1)),
+ {Handler, Pid};
+ {error, Reason} ->
+ {skip, ?F("Failed starting note-store: ~p", [Reason])}
+ end
+ end,
+ Case = fun(State) -> do_notes(State, Config) end,
+ Post = fun({Handler, _Pid}) ->
+ note_store_handler_stop(Handler)
+ end,
+ ?TC_TRY(notes, Pre, Case, Post).
+
+do_notes({_, Pid}, _Config) ->
%% Default lifetime is infinity. A note with lifetime
%% infinity is permanent
- io:format("create permanent note sune~n", []),
+ ?IPRINT("create permanent note: sune"),
true = snmp_note_store:set_note(Pid, sune, 10),
10 = snmp_note_store:get_note(Pid, sune),
10 = snmp_note_store:get_note(Pid, sune),
%% Lifetime is in 1/100 sec ticks, so 500 equals 5 seconds
- io:format("create 5 sec note kalle~n", []),
+ ?IPRINT("create 5 sec note kalle"),
true = snmp_note_store:set_note(Pid, 500, kalle, hobbe),
- io:format("wait 1 sec~n", []),
+ ?IPRINT("wait 1 sec"),
?SLEEP(timer:seconds(1)),
- io:format("get note kalle~n", []),
+ ?IPRINT("get note kalle"),
hobbe = snmp_note_store:get_note(Pid, kalle),
- io:format("wait 5 sec~n", []),
+ ?IPRINT("wait 5 sec"),
?SLEEP(timer:seconds(5)),
- io:format("get note kalle again (now it should not exist)~n", []),
+ ?IPRINT("get note kalle again (now it should not exist)"),
undefined = snmp_note_store:get_note(Pid, kalle),
- io:format("create 5 sec note kalle~n", []),
+ ?IPRINT("create 5 sec note kalle"),
true = snmp_note_store:set_note(Pid, 500, kalle, hobbe),
- io:format("wait 6 sec (to allow timer to clean up note)~n", []),
+ ?IPRINT("wait 6 sec (to allow timer to clean up note)"),
?SLEEP(timer:seconds(6)),
- io:format("get note kalle - should not exist~n", []),
+ ?IPRINT("get note kalle - should not exist"),
undefined = snmp_note_store:get_note(Pid, kalle),
- io:format("read the permanent note sune again~n", []),
+ ?IPRINT("read the permanent note sune again"),
10 = snmp_note_store:get_note(Pid, sune),
- note_store_handler_stop(Handler),
+ ?IPRINT("done"),
ok.
@@ -190,47 +241,65 @@ info(suite) ->
info(doc) ->
["Testing that we can retreive process info."];
info(Config) when is_list(Config) ->
-
- Prio = normal,
- Mod = ?MODULE,
- Opts = [{verbosity, trace}],
- {ok, Pid} = snmp_note_store:start_link(Prio, Mod, Opts),
+ Pre = fun() ->
+ ?IPRINT("try start note-store"),
+ Prio = normal,
+ Mod = ?MODULE,
+ Opts = [{verbosity, trace}],
+ case snmp_note_store:start_link(Prio, Mod, Opts) of
+ {ok, Pid} ->
+ ?IPRINT("note-store started: ~p", [Pid]),
+ Pid;
+ {error, Reason} ->
+ {skip, ?F("Failed starting note-store: ~p", [Reason])}
+ end
+ end,
+ Case = fun(State) -> do_info(State, Config) end,
+ Post = fun(Pid) ->
+ ?IPRINT("attempt stop note-store"),
+ snmp_note_store:stop(Pid)
+ end,
+ ?TC_TRY(info, Pre, Case, Post).
+
+do_info(Pid, _Config) ->
%% Get the info:
+ ?IPRINT("get initial info"),
Info = snmp_note_store:info(Pid),
- io:format("Info: ~p~n", [Info]),
+ ?IPRINT("Info: "
+ "~n ~p", [Info]),
%% Verify content
- io:format("get process memory~n", []),
+ ?IPRINT("verify content: get notes process memory"),
{value, {process_memory, ProcMem}} =
lists:keysearch(process_memory, 1, Info),
- io:format("get notes process memory~n", []),
+ ?IPRINT("get notes process memory"),
{value, {notes, NotesProcMem}} =
lists:keysearch(notes, 1, ProcMem),
- io:format("verify notes process memory~n", []),
+ ?IPRINT("verify notes process memory"),
if
is_integer(NotesProcMem) andalso (NotesProcMem > 0) ->
ok;
true ->
throw({error, {bad_notes_proc_memery, NotesProcMem}})
end,
- io:format("get timer process memory~n", []),
+ ?IPRINT("verify content: get timer process memory"),
{value, {timer, TmrProcMem}} =
lists:keysearch(timer, 1, ProcMem),
- io:format("verify timer process memory~n", []),
+ ?IPRINT("verify content: timer process memory"),
if
is_integer(TmrProcMem) andalso (TmrProcMem > 0) ->
ok;
true ->
throw({error, {bad_timer_proc_memery, TmrProcMem}})
end,
- io:format("get db memory~n", []),
+ ?IPRINT("verify content: get db memory"),
{value, {db_memory, DbMem}} =
lists:keysearch(db_memory, 1, Info),
- io:format("get notes db memory~n", []),
+ ?IPRINT("verify content: get notes db memory"),
{value, {notes, NotesDbMem}} =
lists:keysearch(notes, 1, DbMem),
- io:format("verify notes db memory~n", []),
+ ?IPRINT("verify content: notes db memory"),
if
is_integer(NotesDbMem) andalso (NotesDbMem > 0) ->
ok;
@@ -238,9 +307,7 @@ info(Config) when is_list(Config) ->
throw({error, {bad_notes_db_memery, NotesDbMem}})
end,
-
- snmp_note_store:stop(Pid),
-
+ ?IPRINT("done"),
ok.
@@ -251,23 +318,38 @@ garbage_in(suite) ->
garbage_in(doc) ->
["Test that the process handles garbage sent to it."];
garbage_in(Config) when is_list(Config) ->
-
- io:format("start note_store server~n", []),
- Prio = normal,
- Mod = ?MODULE,
- Opts = [{verbosity, trace}],
- {ok, Pid} = snmp_note_store:start_link(Prio, Mod, Opts),
-
- io:format("issue bad request~n", []),
+ Pre = fun() ->
+ ?IPRINT("try start note-store"),
+ Prio = normal,
+ Mod = ?MODULE,
+ Opts = [{verbosity, trace}],
+ case snmp_note_store:start_link(Prio, Mod, Opts) of
+ {ok, Pid} ->
+ ?IPRINT("note-store started: ~p", [Pid]),
+ Pid;
+ {error, Reason} ->
+ {skip, ?F("Failed starting note-store: ~p", [Reason])}
+ end
+ end,
+ Case = fun(State) -> do_garbage_in(State, Config) end,
+ Post = fun(Pid) ->
+ ?IPRINT("attempt stop note-store"),
+ snmp_note_store:stop(Pid)
+ end,
+ ?TC_TRY(garbage_in, Pre, Case, Post).
+
+do_garbage_in(Pid, _Config) ->
+
+ ?IPRINT("issue bad request"),
{error, _} = gen_server:call(Pid, bad_request),
- io:format("cast bad message~n", []),
+ ?IPRINT("cast bad message"),
gen_server:cast(Pid, bad_message),
- io:format("bang bad info~n", []),
+ ?IPRINT("bang bad info"),
Pid ! bad_info,
- io:format("verify note_Store server still alive and kicking~n", []),
+ ?IPRINT("verify note-store server still alive and kicking"),
Info = snmp_note_store:info(Pid),
if
is_list(Info) andalso (length(Info) > 0) ->
@@ -276,10 +358,7 @@ garbage_in(Config) when is_list(Config) ->
throw({error, {bad_info, Info}})
end,
- io:format("stop note_store server~n", []),
- snmp_note_store:stop(Pid),
-
- io:format("done~n", []),
+ ?IPRINT("done"),
ok.
diff --git a/lib/snmp/test/snmp_pdus_SUITE.erl b/lib/snmp/test/snmp_pdus_SUITE.erl
index f49e2eb602..d70e7aebd0 100644
--- a/lib/snmp/test/snmp_pdus_SUITE.erl
+++ b/lib/snmp/test/snmp_pdus_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2003-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2003-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -75,11 +75,34 @@ tickets_cases() ->
%% -----
%%
-init_per_suite(Config) when is_list(Config) ->
- Config.
+init_per_suite(Config0) when is_list(Config0) ->
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config: ~p", [Config0]),
-end_per_suite(Config) when is_list(Config) ->
- Config.
+ case ?LIB:init_per_suite(Config0) of
+ {skip, _} = SKIP ->
+ SKIP;
+
+ Config1 when is_list(Config1) ->
+ %% We need a monitor on this node also
+ snmp_test_sys_monitor:start(),
+
+ ?IPRINT("init_per_suite -> end when"
+ "~n Config1: ~p", [Config1]),
+
+ Config1
+ end.
+
+end_per_suite(Config0) when is_list(Config0) ->
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config: ~p", [Config0]),
+
+ snmp_test_sys_monitor:stop(),
+ Config1 = ?LIB:end_per_suite(Config0),
+
+ ?IPRINT("end_per_suite -> end"),
+
+ Config1.
@@ -100,9 +123,24 @@ end_per_group(_GroupName, Config) ->
%%
init_per_testcase(_Case, Config) when is_list(Config) ->
+ ?IPRINT("init_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
+
+ snmp_test_global_sys_monitor:reset_events(),
+
+ ?IPRINT("init_per_testcase -> end"),
+
Config.
end_per_testcase(_Case, Config) when is_list(Config) ->
+
+ ?IPRINT("end_per_testcase -> entry with"
+ "~n Config: ~p",
+ [Config]),
+
+ ?IPRINT("system events during test: ~p",
+ [snmp_test_global_sys_monitor:events()]),
+
Config.
@@ -114,7 +152,7 @@ end_per_testcase(_Case, Config) when is_list(Config) ->
otp7575(suite) -> [];
otp7575(doc) -> ["OTP-7575 - Message version"];
otp7575(Config) when is_list(Config) ->
- io:format("attempt to decode message with valid version~n", []),
+ ?IPRINT("attempt to decode message with valid version"),
MsgWithOkVersion = <<48,39,2,1,0,4,6,112,117,98,108,105,99,160,26,2,2,1,49,2,1,0,2,1,0,48,14,48,12,6,8,43,6,1,2,1,1,5,0,5,0>>,
case (catch dec_message(MsgWithOkVersion)) of
Msg when is_record(Msg, message) ->
@@ -123,7 +161,7 @@ otp7575(Config) when is_list(Config) ->
exit({unexpected_decode_result, 1, Unexpected1})
end,
- io:format("attempt to decode message with bad version~n", []),
+ ?IPRINT("attempt to decode message with bad version"),
MsgWithBadVersion = <<48,48,2,10,1,1,1,1,1,1,1,1,1,1,4,6,112,117,98,108,105,99,160,26,2,2,1,49,2,1,0,2,1,0,48,14,48,12,6,8,43,6,1,2,1,1,5,0,5,0>>,
case (catch dec_message(MsgWithBadVersion)) of
{'EXIT', {bad_version, BadVersion}} when is_integer(BadVersion) ->
@@ -132,7 +170,7 @@ otp7575(Config) when is_list(Config) ->
exit({unexpected_decode_result, 2, Unexpected2})
end,
- io:format("attempt to decode message with very bad version~n", []),
+ ?IPRINT("attempt to decode message with very bad version"),
MsgWithVeryBadVersion = <<48,49,2,11,1,1,1,1,1,1,1,1,1,1,1,4,6,112,117,98,108,105,99,160,26,2,2,1,49,2,1,0,2,1,0,48,14,48,12,6,8,43,6,1,2,1,1,5,0,5,0>>,
case (catch dec_message(MsgWithVeryBadVersion)) of
{'EXIT', {bad_version, {VersionSize, MaxVersionSize}}} when (VersionSize > MaxVersionSize) ->
@@ -140,7 +178,7 @@ otp7575(Config) when is_list(Config) ->
Unexpected3 ->
exit({unexpected_decode_result, 3, Unexpected3})
end,
- io:format("done~n", []),
+ ?IPRINT("done"),
ok.
@@ -148,52 +186,52 @@ otp8563(suite) -> [];
otp8563(doc) -> ["OTP-8563 - Counter64"];
otp8563(Config) when is_list(Config) ->
Val1 = 16#7fffffffffffffff,
- io:format("try encode and decode value 1: ~w (0x~.16b)~n", [Val1, Val1]),
+ ?IPRINT("try encode and decode value 1: ~w (0x~.16b)", [Val1, Val1]),
Enc1 = snmp_pdus:enc_value('Counter64', Val1),
- io:format(" => ~w~n", [Enc1]),
+ ?IPRINT(" => ~w", [Enc1]),
{{'Counter64', Val1}, []} = snmp_pdus:dec_value(Enc1),
Val2 = Val1 + 1,
- io:format("try encode and decode value 2: ~w (0x~.16b)~n", [Val2, Val2]),
+ ?IPRINT("try encode and decode value 2: ~w (0x~.16b)", [Val2, Val2]),
Enc2 = snmp_pdus:enc_value('Counter64', Val2),
- io:format(" => ~w~n", [Enc2]),
+ ?IPRINT(" => ~w", [Enc2]),
{{'Counter64', Val2}, []} = snmp_pdus:dec_value(Enc2),
Val3 = Val2 + 1,
- io:format("try encode and decode value 3: ~w (0x~.16b)~n", [Val3, Val3]),
+ ?IPRINT("try encode and decode value 3: ~w (0x~.16b)", [Val3, Val3]),
Enc3 = snmp_pdus:enc_value('Counter64', Val3),
- io:format(" => ~w~n", [Enc3]),
+ ?IPRINT(" => ~w", [Enc3]),
{{'Counter64', Val3}, []} = snmp_pdus:dec_value(Enc3),
Val4 = 16#fffffffffffffffe,
- io:format("try encode and decode value 4: ~w (0x~.16b)~n", [Val4, Val4]),
+ ?IPRINT("try encode and decode value 4: ~w (0x~.16b)", [Val4, Val4]),
Enc4 = snmp_pdus:enc_value('Counter64', Val4),
- io:format(" => ~w~n", [Enc4]),
+ ?IPRINT(" => ~w", [Enc4]),
{{'Counter64', Val4}, []} = snmp_pdus:dec_value(Enc4),
Val5 = Val4 + 1,
- io:format("try encode and decode value 5: ~w (0x~.16b)~n", [Val5, Val5]),
+ ?IPRINT("try encode and decode value 5: ~w (0x~.16b)", [Val5, Val5]),
Enc5 = snmp_pdus:enc_value('Counter64', Val5),
- io:format(" => ~w~n", [Enc5]),
+ ?IPRINT(" => ~w", [Enc5]),
{{'Counter64', Val5}, []} = snmp_pdus:dec_value(Enc5),
Val6 = 16#ffffffffffffffff + 1,
- io:format("try and fail to encode value 6: ~w (0x~.16b)~n", [Val6, Val6]),
+ ?IPRINT("try and fail to encode value 6: ~w (0x~.16b)", [Val6, Val6]),
case (catch snmp_pdus:enc_value('Counter64', Val6)) of
{'EXIT', {error, {bad_counter64, Val6}}} ->
ok;
Unexpected6 ->
- io:format(" => ~w~n", [Unexpected6]),
+ ?IPRINT(" => ~w", [Unexpected6]),
exit({unexpected_encode_result, Unexpected6, Val6})
end,
Val7 = -1,
- io:format("try and fail to encode value 7: ~w~n", [Val7]),
+ ?IPRINT("try and fail to encode value 7: ~w", [Val7]),
case (catch snmp_pdus:enc_value('Counter64', Val7)) of
{'EXIT', {error, {bad_counter64, Val7}}} ->
ok;
Unexpected7 ->
- io:format(" => ~w~n", [Unexpected7]),
+ ?IPRINT(" => ~w", [Unexpected7]),
exit({unexpected_encode_result, Unexpected7, Val7})
end,
@@ -204,70 +242,70 @@ otp9022(suite) -> [];
otp9022(doc) -> ["OTP-9022 - Counter32"];
otp9022(Config) when is_list(Config) ->
Val0 = 2908389204,
- io:format("try encode and decode value 0: ~w (0x~.16b)~n", [Val0, Val0]),
+ ?IPRINT("try encode and decode value 0: ~w (0x~.16b)", [Val0, Val0]),
Enc0 = snmp_pdus:enc_value('Counter32', Val0),
- io:format(" => ~w~n", [Enc0]),
+ ?IPRINT(" => ~w", [Enc0]),
{{'Counter32', Val0}, []} = snmp_pdus:dec_value(Enc0),
Val1 = 0,
- io:format("try encode and decode value 1: ~w (0x~.16b)~n", [Val1, Val1]),
+ ?IPRINT("try encode and decode value 1: ~w (0x~.16b)", [Val1, Val1]),
Enc1 = snmp_pdus:enc_value('Counter32', Val1),
- io:format(" => ~w~n", [Enc1]),
+ ?IPRINT(" => ~w", [Enc1]),
{{'Counter32', Val1}, []} = snmp_pdus:dec_value(Enc1),
Val2 = Val1 + 1,
- io:format("try encode and decode value 2: ~w (0x~.16b)~n", [Val2, Val2]),
+ ?IPRINT("try encode and decode value 2: ~w (0x~.16b)", [Val2, Val2]),
Enc2 = snmp_pdus:enc_value('Counter32', Val2),
- io:format(" => ~w~n", [Enc2]),
+ ?IPRINT(" => ~w", [Enc2]),
{{'Counter32', Val2}, []} = snmp_pdus:dec_value(Enc2),
Val3 = 16#7ffffffe,
- io:format("try encode and decode value 3: ~w (0x~.16b)~n", [Val3, Val3]),
+ ?IPRINT("try encode and decode value 3: ~w (0x~.16b)", [Val3, Val3]),
Enc3 = snmp_pdus:enc_value('Counter32', Val3),
- io:format(" => ~w~n", [Enc3]),
+ ?IPRINT(" => ~w", [Enc3]),
{{'Counter32', Val3}, []} = snmp_pdus:dec_value(Enc3),
Val4 = Val3 + 1,
- io:format("try encode and decode value 4: ~w (0x~.16b)~n", [Val4, Val4]),
+ ?IPRINT("try encode and decode value 4: ~w (0x~.16b)", [Val4, Val4]),
Enc4 = snmp_pdus:enc_value('Counter32', Val4),
- io:format(" => ~w~n", [Enc4]),
+ ?IPRINT(" => ~w", [Enc4]),
{{'Counter32', Val4}, []} = snmp_pdus:dec_value(Enc4),
Val5 = Val4 + 1,
- io:format("try encode and decode value 5: ~w (0x~.16b)~n", [Val5, Val5]),
+ ?IPRINT("try encode and decode value 5: ~w (0x~.16b)", [Val5, Val5]),
Enc5 = snmp_pdus:enc_value('Counter32', Val5),
- io:format(" => ~w~n", [Enc5]),
+ ?IPRINT(" => ~w", [Enc5]),
{{'Counter32', Val5}, []} = snmp_pdus:dec_value(Enc5),
Val6 = 16#fffffffe,
- io:format("try encode and decode value 6: ~w (0x~.16b)~n", [Val6, Val6]),
+ ?IPRINT("try encode and decode value 6: ~w (0x~.16b)", [Val6, Val6]),
Enc6 = snmp_pdus:enc_value('Counter32', Val6),
- io:format(" => ~w~n", [Enc6]),
+ ?IPRINT(" => ~w", [Enc6]),
{{'Counter32', Val6}, []} = snmp_pdus:dec_value(Enc6),
Val7 = Val6 + 1,
- io:format("try encode and decode value 7: ~w (0x~.16b)~n", [Val7, Val7]),
+ ?IPRINT("try encode and decode value 7: ~w (0x~.16b)", [Val7, Val7]),
Enc7 = snmp_pdus:enc_value('Counter32', Val7),
- io:format(" => ~w~n", [Enc7]),
+ ?IPRINT(" => ~w", [Enc7]),
{{'Counter32', Val7}, []} = snmp_pdus:dec_value(Enc7),
Val8 = 16#ffffffff + 1,
- io:format("try and fail to encode value 8: ~w (0x~.16b)~n", [Val8, Val8]),
+ ?IPRINT("try and fail to encode value 8: ~w (0x~.16b)", [Val8, Val8]),
case (catch snmp_pdus:enc_value('Counter32', Val8)) of
{'EXIT', {error, {bad_counter32, Val8}}} ->
ok;
Unexpected8 ->
- io:format(" => ~w~n", [Unexpected8]),
+ ?IPRINT(" => ~w", [Unexpected8]),
exit({unexpected_encode_result, Unexpected8, Val8})
end,
Val9 = -1,
- io:format("try and fail to encode value 9: ~w~n", [Val9]),
+ ?IPRINT("try and fail to encode value 9: ~w", [Val9]),
case (catch snmp_pdus:enc_value('Counter32', Val9)) of
{'EXIT', {error, {bad_counter32, Val9}}} ->
ok;
Unexpected9 ->
- io:format(" => ~w~n", [Unexpected9]),
+ ?IPRINT(" => ~w", [Unexpected9]),
exit({unexpected_encode_result, Unexpected9, Val9})
end,
@@ -278,74 +316,74 @@ otp10132(suite) -> [];
otp10132(doc) -> ["OTP-10132 - TimeTicks"];
otp10132(Config) when is_list(Config) ->
Val0 = 2159001034,
- io:format("try encode and decode value 0: ~w (0x~.16b)~n", [Val0, Val0]),
+ ?IPRINT("try encode and decode value 0: ~w (0x~.16b)", [Val0, Val0]),
Enc0 = snmp_pdus:enc_value('TimeTicks', Val0),
- io:format(" => ~w~n", [Enc0]),
+ ?IPRINT(" => ~w", [Enc0]),
{{'TimeTicks', Val0}, []} = snmp_pdus:dec_value(Enc0),
Val1 = 0,
- io:format("try encode and decode value 1: ~w (0x~.16b)~n", [Val1, Val1]),
+ ?IPRINT("try encode and decode value 1: ~w (0x~.16b)", [Val1, Val1]),
Enc1 = snmp_pdus:enc_value('TimeTicks', Val1),
- io:format(" => ~w~n", [Enc1]),
+ ?IPRINT(" => ~w", [Enc1]),
{{'TimeTicks', Val1}, []} = snmp_pdus:dec_value(Enc1),
Val2 = Val1 + 1,
- io:format("try encode and decode value 2: ~w (0x~.16b)~n", [Val2, Val2]),
+ ?IPRINT("try encode and decode value 2: ~w (0x~.16b)", [Val2, Val2]),
Enc2 = snmp_pdus:enc_value('TimeTicks', Val2),
- io:format(" => ~w~n", [Enc2]),
+ ?IPRINT(" => ~w", [Enc2]),
{{'TimeTicks', Val2}, []} = snmp_pdus:dec_value(Enc2),
Val3 = 16#7ffffffe,
- io:format("try encode and decode value 3: ~w (0x~.16b)~n", [Val3, Val3]),
+ ?IPRINT("try encode and decode value 3: ~w (0x~.16b)", [Val3, Val3]),
Enc3 = snmp_pdus:enc_value('TimeTicks', Val3),
- io:format(" => ~w~n", [Enc3]),
+ ?IPRINT(" => ~w", [Enc3]),
{{'TimeTicks', Val3}, []} = snmp_pdus:dec_value(Enc3),
Val4 = Val3 + 1,
- io:format("try encode and decode value 4: ~w (0x~.16b)~n", [Val4, Val4]),
+ ?IPRINT("try encode and decode value 4: ~w (0x~.16b)", [Val4, Val4]),
Enc4 = snmp_pdus:enc_value('TimeTicks', Val4),
- io:format(" => ~w~n", [Enc4]),
+ ?IPRINT(" => ~w", [Enc4]),
{{'TimeTicks', Val4}, []} = snmp_pdus:dec_value(Enc4),
Val5 = Val4 + 1,
- io:format("try encode and decode value 5: ~w (0x~.16b)~n", [Val5, Val5]),
+ ?IPRINT("try encode and decode value 5: ~w (0x~.16b)", [Val5, Val5]),
Enc5 = snmp_pdus:enc_value('TimeTicks', Val5),
- io:format(" => ~w~n", [Enc5]),
+ ?IPRINT(" => ~w", [Enc5]),
{{'TimeTicks', Val5}, []} = snmp_pdus:dec_value(Enc5),
Val6 = 16#fffffffe,
- io:format("try encode and decode value 6: ~w (0x~.16b)~n", [Val6, Val6]),
+ ?IPRINT("try encode and decode value 6: ~w (0x~.16b)", [Val6, Val6]),
Enc6 = snmp_pdus:enc_value('TimeTicks', Val6),
- io:format(" => ~w~n", [Enc6]),
+ ?IPRINT(" => ~w", [Enc6]),
{{'TimeTicks', Val6}, []} = snmp_pdus:dec_value(Enc6),
Val7 = Val6 + 1,
- io:format("try encode and decode value 7: ~w (0x~.16b)~n", [Val7, Val7]),
+ ?IPRINT("try encode and decode value 7: ~w (0x~.16b)", [Val7, Val7]),
Enc7 = snmp_pdus:enc_value('TimeTicks', Val7),
- io:format(" => ~w~n", [Enc7]),
+ ?IPRINT(" => ~w", [Enc7]),
{{'TimeTicks', Val7}, []} = snmp_pdus:dec_value(Enc7),
Val8 = Val7 + 1,
- io:format("try and fail to encode value 8: ~w (0x~.16b)~n", [Val8, Val8]),
+ ?IPRINT("try and fail to encode value 8: ~w (0x~.16b)", [Val8, Val8]),
case (catch snmp_pdus:enc_value('TimeTicks', Val8)) of
{'EXIT', {error, {bad_timeticks, Val8}}} ->
ok;
Unexpected8 ->
- io:format(" => ~w~n", [Unexpected8]),
+ ?IPRINT(" => ~w", [Unexpected8]),
exit({unexpected_encode_result, Unexpected8, Val8})
end,
Val9 = -1,
- io:format("try and fail to encode value 9: ~w~n", [Val9]),
+ ?IPRINT("try and fail to encode value 9: ~w", [Val9]),
case (catch snmp_pdus:enc_value('TimeTicks', Val9)) of
{'EXIT', {error, {bad_timeticks, Val9}}} ->
ok;
Unexpected9 ->
- io:format(" => ~w~n", [Unexpected9]),
+ ?IPRINT(" => ~w", [Unexpected9]),
exit({unexpected_encode_result, Unexpected9, Val9})
end,
- io:format("done~n", []),
+ ?IPRINT("done"),
ok.
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
index d2edd636cc..3e445174ba 100644
--- a/lib/snmp/test/snmp_test_lib.erl
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -23,12 +23,14 @@
-include_lib("kernel/include/file.hrl").
--export([tc_try/2, tc_try/3]).
+-export([tc_try/2, tc_try/3,
+ tc_try/4, tc_try/5]).
-export([hostname/0, hostname/1, localhost/0, localhost/1, os_type/0, sz/1,
display_suite_info/1]).
--export([non_pc_tc_maybe_skip/4, os_based_skip/1,
- has_support_ipv6/0, has_support_ipv6/1,
- is_ipv6_host/0, is_ipv6_host/1]).
+-export([non_pc_tc_maybe_skip/4,
+ os_based_skip/1,
+ has_support_ipv6/0
+ ]).
-export([init_per_suite/1, end_per_suite/1,
init_suite_top_dir/2, init_group_top_dir/2, init_testcase_top_dir/2,
fix_data_dir/1,
@@ -40,57 +42,136 @@
-export([ping/1, local_nodes/0, nodes_on/1]).
-export([start_node/2, stop_node/1]).
-export([is_app_running/1,
- is_crypto_running/0, is_mnesia_running/0, is_snmp_running/0]).
+ is_crypto_running/0, is_mnesia_running/0, is_snmp_running/0,
+ ensure_not_running/3]).
-export([crypto_start/0, crypto_support/0]).
-export([watchdog/3, watchdog_start/1, watchdog_start/2, watchdog_stop/1]).
-export([del_dir/1]).
--export([cover/1]).
--export([f/2, p/2, print1/2, print2/2, print/5, formated_timestamp/0]).
+-export([f/2, formated_timestamp/0]).
+-export([p/2, print1/2, print2/2, print/5]).
+-export([eprint/2, wprint/2, nprint/2, iprint/2]).
+
+
+-define(SKIP(R), skip(R, ?MODULE, ?LINE)).
%% ----------------------------------------------------------------------
%% Run test-case
%%
-%% *** tc_try/2,3 ***
-%% Case: Basically the test case name
-%% TCCondFun: A fun that is evaluated before the actual test case
-%% The point of this is that it can performs checks to
-%% see if we shall run the test case at all.
-%% For instance, the test case may only work in specific
-%% conditions.
-%% FCFun: The test case fun
-tc_try(Case, TCFun) ->
- tc_try(Case, fun() -> ok end, TCFun).
-
-tc_try(Case, TCCondFun, TCFun)
- when is_atom(Case) andalso
- is_function(TCCondFun, 0) andalso
- is_function(TCFun, 0) ->
+%% *** tc_try/2,3,4,5 ***
+%% Case: Basically the test case name
+%% TCCond: A fun that is evaluated before the actual test case
+%% The point of this is that it can performs checks to
+%% see if we shall run the test case at all.
+%% For instance, the test case may only work in specific
+%% conditions.
+%% Pre: A fun that is nominally part of the test case
+%% but is an initiation that must be "undone". This is
+%% done by the Post fun (regardless if the TC is successfull
+%% or not). Example: Starts a couple of nodes,
+%% TC: The test case fun
+%% Post: A fun that undo what was done by the Pre fun.
+%% Example: Stops the nodes created by the Pre function.
+tc_try(Case, TC) ->
+ tc_try(Case, fun() -> ok end, TC).
+
+tc_try(Case, TCCond, TC0) when is_function(TC0, 0) ->
+ Pre = fun() -> undefined end,
+ TC = fun(_) -> TC0() end,
+ Post = fun(_) -> ok end,
+ tc_try(Case, TCCond, Pre, TC, Post).
+
+tc_try(Case, Pre, TC, Post)
+ when is_atom(Case) andalso
+ is_function(Pre, 0) andalso
+ is_function(TC, 1) andalso
+ is_function(Post, 1) ->
+ TCCond = fun() -> ok end,
+ tc_try(Case, TCCond, Pre, TC, Post).
+
+tc_try(Case, TCCond, Pre, TC, Post)
+ when is_atom(Case) andalso
+ is_function(TCCond, 0) andalso
+ is_function(Pre, 0) andalso
+ is_function(TC, 1) andalso
+ is_function(Post, 1) ->
tc_begin(Case),
- try TCCondFun() of
+ try TCCond() of
ok ->
- try
- begin
- TCFun(),
- sleep(seconds(1)),
- tc_end("ok")
- end
+ tc_print("starting: try pre"),
+ try Pre() of
+ State ->
+ tc_print("pre done: try test case"),
+ try
+ begin
+ TC(State),
+ sleep(seconds(1)),
+ tc_print("test case done: try post"),
+ (catch Post(State)),
+ tc_end("ok")
+ end
+ catch
+ C:{skip, _} = SKIP when (C =:= throw) orelse
+ (C =:= exit) ->
+ tc_print("test case (~w) skip: try post", [C]),
+ (catch Post(State)),
+ tc_end( f("skipping(catched,~w,tc)", [C]) ),
+ SKIP;
+ C:E:S ->
+ %% We always check the system events
+ %% before we accept a failure.
+ %% We do *not* run the Post here because it might
+ %% generate sys events itself...
+ case snmp_test_global_sys_monitor:events() of
+ [] ->
+ tc_print("test case failed: try post"),
+ (catch Post(State)),
+ tc_end( f("failed(catched,~w,tc)", [C]) ),
+ erlang:raise(C, E, S);
+ SysEvs ->
+ tc_print("System Events received during tc: "
+ "~n ~p"
+ "~nwhen tc failed:"
+ "~n C: ~p"
+ "~n E: ~p"
+ "~n S: ~p",
+ [SysEvs, C, E, S]),
+ (catch Post(State)),
+ tc_end( f("skipping(catched-sysevs,~w,tc)",
+ [C]) ),
+ SKIP = {skip, "TC failure with system events"},
+ SKIP
+ end
+ end
catch
- C:{skip, _} = SKIP when ((C =:= throw) orelse (C =:= exit)) ->
- tc_end( f("skipping(catched,~w,tc)", [C]) ),
+ C:{skip, _} = SKIP when (C =:= throw) orelse
+ (C =:= exit) ->
+ tc_end( f("skipping(catched,~w,tc-pre)", [C]) ),
SKIP;
C:E:S ->
- %% We always check the system events before we accept a failure
+ %% We always check the system events
+ %% before we accept a failure
case snmp_test_global_sys_monitor:events() of
[] ->
- tc_end( f("failed(catched,~w,tc)", [C]) ),
- erlang:raise(C, E, S);
+ tc_print("tc-pre failed: auto-skip"
+ "~n C: ~p"
+ "~n E: ~p"
+ "~n S: ~p",
+ [C, E, S]),
+ tc_end( f("auto-skip(catched,~w,tc-pre)", [C]) ),
+ SKIP = {skip, f("TC-Pre failure (~w)", [C])},
+ SKIP;
SysEvs ->
- tc_print("System Events received: "
- "~n ~p", [SysEvs], "", ""),
- tc_end( f("skipping(catched-sysevs,~w,tc)", [C]) ),
- SKIP = {skip, "TC failure with system events"},
+ tc_print("System Events received: "
+ "~n ~p"
+ "~nwhen tc-pre failed:"
+ "~n C: ~p"
+ "~n E: ~p"
+ "~n S: ~p",
+ [SysEvs, C, E, S], "", ""),
+ tc_end( f("skipping(catched-sysevs,~w,tc-pre)", [C]) ),
+ SKIP = {skip, "TC-Pre failure with system events"},
SKIP
end
end;
@@ -142,14 +223,21 @@ tc_end(Result) when is_list(Result) ->
"", "----------------------------------------------------~n~n"),
ok.
+tc_print(F) ->
+ tc_print(F, [], "", "").
+
+tc_print(F, A) ->
+ tc_print(F, A, "", "").
+
tc_print(F, Before, After) ->
tc_print(F, [], Before, After).
tc_print(F, A, Before, After) ->
Name = tc_which_name(),
FStr = f("*** [~s][~s][~p] " ++ F ++ "~n",
- [formated_timestamp(),Name,self()|A]),
- io:format(user, Before ++ FStr ++ After, []).
+ [formated_timestamp(), Name, self() | A]),
+ io:format(user, Before ++ FStr ++ After, []),
+ io:format(standard_io, Before ++ FStr ++ After, []).
tc_which_name() ->
case tc_get_name() of
@@ -406,37 +494,113 @@ os_based_skip_check(OsName, OsNames) ->
end.
-%% A basic test to check if current host supports IPv6
+%% A modern take on the "Check if our host handle IPv6" question.
+%%
has_support_ipv6() ->
- case inet:gethostname() of
- {ok, Hostname} ->
- has_support_ipv6(Hostname);
+ case os:type() of
+ {win32, _} ->
+ %% We do not yet have support for windows in the socket nif,
+ %% so for windows we need to use the old style...
+ old_has_support_ipv6();
_ ->
- false
+ socket:supports(ipv6) andalso has_valid_ipv6_address()
end.
-has_support_ipv6(Hostname) ->
- case inet:getaddr(Hostname, inet6) of
- {ok, Addr} when (size(Addr) =:= 8) andalso
- (element(1, Addr) =/= 0) andalso
- (element(1, Addr) =/= 16#fe80) ->
- true;
+has_valid_ipv6_address() ->
+ case net:getifaddrs(fun(#{addr := #{family := inet6},
+ flags := Flags}) ->
+ not lists:member(loopback, Flags);
+ (_) ->
+ false
+ end) of
+ {ok, [#{addr := #{addr := LocalAddr}}|_]} ->
+ %% At least one valid address, we pick the first...
+ try validate_ipv6_address(LocalAddr)
+ catch
+ _:_:_ ->
+ false
+ end;
{ok, _} ->
false;
{error, _} ->
false
end.
-
-is_ipv6_host() ->
+validate_ipv6_address(LocalAddr) ->
+ Domain = inet6,
+ ServerSock =
+ case socket:open(Domain, dgram, udp) of
+ {ok, SS} ->
+ SS;
+ {error, R2} ->
+ ?SKIP(f("(server) socket open failed: ~p", [R2]))
+ end,
+ LocalSA = #{family => Domain, addr => LocalAddr},
+ ServerPort =
+ case socket:bind(ServerSock, LocalSA) of
+ {ok, P1} ->
+ P1;
+ {error, R3} ->
+ socket:close(ServerSock),
+ ?SKIP(f("(server) socket bind failed: ~p", [R3]))
+ end,
+ ServerSA = LocalSA#{port => ServerPort},
+ ClientSock =
+ case socket:open(Domain, dgram, udp) of
+ {ok, CS} ->
+ CS;
+ {error, R4} ->
+ ?SKIP(f("(client) socket open failed: ~p", [R4]))
+ end,
+ case socket:bind(ClientSock, LocalSA) of
+ {ok, _} ->
+ ok;
+ {error, R5} ->
+ socket:close(ServerSock),
+ socket:close(ClientSock),
+ ?SKIP(f("(client) socket bind failed: ~p", [R5]))
+ end,
+ case socket:sendto(ClientSock, <<"hejsan">>, ServerSA) of
+ ok ->
+ ok;
+ {error, R6} ->
+ socket:close(ServerSock),
+ socket:close(ClientSock),
+ ?SKIP(f("failed socket sendto test: ~p", [R6]))
+ end,
+ case socket:recvfrom(ServerSock) of
+ {ok, {_, <<"hejsan">>}} ->
+ socket:close(ServerSock),
+ socket:close(ClientSock),
+ true;
+ {error, R7} ->
+ socket:close(ServerSock),
+ socket:close(ClientSock),
+ ?SKIP(f("failed socket recvfrom test: ~p", [R7]))
+ end.
+
+
+
+
+old_has_support_ipv6() ->
case inet:gethostname() of
{ok, Hostname} ->
- is_ipv6_host(Hostname);
- {error, _} ->
+ old_has_support_ipv6(Hostname) andalso old_is_ipv6_host(Hostname);
+ _ ->
false
end.
-is_ipv6_host(Hostname) ->
+old_has_support_ipv6(Hostname) ->
+ case inet:getaddr(Hostname, inet6) of
+ {ok, Addr} when (size(Addr) =:= 8) andalso
+ (element(1, Addr) =/= 0) andalso
+ (element(1, Addr) =/= 16#fe80) ->
+ true;
+ _ ->
+ false
+ end.
+
+old_is_ipv6_host(Hostname) ->
case ct:require(ipv6_hosts) of
ok ->
lists:member(list_to_atom(Hostname), ct:get_config(ipv6_hosts));
@@ -445,6 +609,7 @@ is_ipv6_host(Hostname) ->
end.
+
%% ----------------------------------------------------------------
%% Test suite utility functions
%%
@@ -486,8 +651,9 @@ init_per_suite(Config) ->
true ->
{skip, "Unstable host and/or os (or combo thererof)"};
false ->
+ Factor = analyze_and_print_host_info(),
snmp_test_global_sys_monitor:start(),
- Config
+ [{snmp_factor, Factor} | Config]
end.
@@ -625,6 +791,692 @@ skip(Reason, Module, Line) ->
exit({skip, String}).
+%% This function prints various host info, which might be usefull
+%% when analyzing the test suite (results).
+%% It also returns a "factor" that can be used when deciding
+%% the load for some test cases. Such as run time or number of
+%% iteraions. This only works for some OSes.
+%%
+%% We make some calculations on Linux, OpenBSD and FreeBSD.
+%% On SunOS we always set the factor to 2 (just to be on the safe side)
+%% On all other os:es (mostly windows) we check the number of schedulers,
+%% but at least the factor will be 2.
+analyze_and_print_host_info() ->
+ {OsFam, OsName} = os:type(),
+ Version =
+ case os:version() of
+ {Maj, Min, Rel} ->
+ f("~w.~w.~w", [Maj, Min, Rel]);
+ VStr ->
+ VStr
+ end,
+ case {OsFam, OsName} of
+ {unix, linux} ->
+ analyze_and_print_linux_host_info(Version);
+ {unix, openbsd} ->
+ analyze_and_print_openbsd_host_info(Version);
+ {unix, freebsd} ->
+ analyze_and_print_freebsd_host_info(Version);
+ {unix, sunos} ->
+ analyze_and_print_solaris_host_info(Version);
+ {win32, nt} ->
+ analyze_and_print_win_host_info(Version);
+ _ ->
+ io:format("OS Family: ~p"
+ "~n OS Type: ~p"
+ "~n Version: ~p"
+ "~n Num Schedulers: ~s"
+ "~n", [OsFam, OsName, Version, str_num_schedulers()]),
+ try erlang:system_info(schedulers) of
+ 1 ->
+ 10;
+ 2 ->
+ 5;
+ N when (N =< 6) ->
+ 2;
+ _ ->
+ 1
+ catch
+ _:_:_ ->
+ 10
+ end
+ end.
+
+analyze_and_print_linux_host_info(Version) ->
+ case file:read_file_info("/etc/issue") of
+ {ok, _} ->
+ io:format("Linux: ~s"
+ "~n ~s"
+ "~n",
+ [Version, string:trim(os:cmd("cat /etc/issue"))]);
+ _ ->
+ io:format("Linux: ~s"
+ "~n", [Version])
+ end,
+ Factor =
+ case (catch linux_which_cpuinfo()) of
+ {ok, {CPU, BogoMIPS}} ->
+ io:format("CPU: "
+ "~n Model: ~s"
+ "~n BogoMIPS: ~s"
+ "~n", [CPU, BogoMIPS]),
+ %% We first assume its a float, and if not try integer
+ try list_to_float(string:trim(BogoMIPS)) of
+ F when F > 1000 ->
+ 1;
+ F when F > 1000 ->
+ 2;
+ _ ->
+ 3
+ catch
+ _:_:_ ->
+ %%
+ try list_to_integer(string:trim(BogoMIPS)) of
+ I when I > 1000 ->
+ 1;
+ I when I > 1000 ->
+ 2;
+ _ ->
+ 3
+ catch
+ _:_:_ ->
+ 1
+ end
+ end;
+ _ ->
+ 1
+ end,
+ %% Check if we need to adjust the factor because of the memory
+ try linux_which_meminfo() of
+ AddFactor ->
+ io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]),
+ Factor + AddFactor
+ catch
+ _:_:_ ->
+ io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]),
+ Factor
+ end.
+
+linux_which_cpuinfo() ->
+ %% Check for x86 (Intel or AMD)
+ CPU =
+ try [string:trim(S) || S <- string:tokens(os:cmd("grep \"model name\" /proc/cpuinfo"), [$:,$\n])] of
+ ["model name", ModelName | _] ->
+ ModelName;
+ _ ->
+ %% ARM (at least some distros...)
+ try [string:trim(S) || S <- string:tokens(os:cmd("grep \"Processor\" /proc/cpuinfo"), [$:,$\n])] of
+ ["Processor", Proc | _] ->
+ Proc;
+ _ ->
+ %% Ok, we give up
+ throw(noinfo)
+ catch
+ _:_:_ ->
+ throw(noinfo)
+ end
+ catch
+ _:_:_ ->
+ throw(noinfo)
+ end,
+ try [string:trim(S) || S <- string:tokens(os:cmd("grep -i \"bogomips\" /proc/cpuinfo"), [$:,$\n])] of
+ [_, BMips | _] ->
+ {ok, {CPU, BMips}};
+ _ ->
+ {ok, CPU}
+ catch
+ _:_:_ ->
+ {ok, CPU}
+ end.
+
+%% We *add* the value this return to the Factor.
+linux_which_meminfo() ->
+ try [string:trim(S) || S <- string:tokens(os:cmd("grep MemTotal /proc/meminfo"), [$:])] of
+ [_, MemTotal] ->
+ io:format("Memory:"
+ "~n ~s"
+ "~n", [MemTotal]),
+ case string:tokens(MemTotal, [$ ]) of
+ [MemSzStr, MemUnit] ->
+ MemSz2 = list_to_integer(MemSzStr),
+ MemSz3 =
+ case string:to_lower(MemUnit) of
+ "kb" ->
+ MemSz2;
+ "mb" ->
+ MemSz2*1024;
+ "gb" ->
+ MemSz2*1024*1024;
+ _ ->
+ throw(noinfo)
+ end,
+ if
+ (MemSz3 >= 8388608) ->
+ 0;
+ (MemSz3 >= 4194304) ->
+ 1;
+ (MemSz3 >= 2097152) ->
+ 2;
+ true ->
+ 3
+ end;
+ _X ->
+ 0
+ end;
+ _ ->
+ 0
+ catch
+ _:_:_ ->
+ 0
+ end.
+
+
+%% Just to be clear: This is ***not*** scientific...
+analyze_and_print_openbsd_host_info(Version) ->
+ io:format("OpenBSD:"
+ "~n Version: ~p"
+ "~n", [Version]),
+ Extract =
+ fun(Key) ->
+ string:tokens(string:trim(os:cmd("sysctl " ++ Key)), [$=])
+ end,
+ try
+ begin
+ CPU =
+ case Extract("hw.model") of
+ ["hw.model", Model] ->
+ string:trim(Model);
+ _ ->
+ "-"
+ end,
+ CPUSpeed =
+ case Extract("hw.cpuspeed") of
+ ["hw.cpuspeed", Speed] ->
+ list_to_integer(Speed);
+ _ ->
+ -1
+ end,
+ NCPU =
+ case Extract("hw.ncpufound") of
+ ["hw.ncpufound", N] ->
+ list_to_integer(N);
+ _ ->
+ -1
+ end,
+ Memory =
+ case Extract("hw.physmem") of
+ ["hw.physmem", PhysMem] ->
+ list_to_integer(PhysMem) div 1024;
+ _ ->
+ -1
+ end,
+ io:format("CPU:"
+ "~n Model: ~s"
+ "~n Speed: ~w"
+ "~n N: ~w"
+ "~nMemory:"
+ "~n ~w KB"
+ "~n", [CPU, CPUSpeed, NCPU, Memory]),
+ io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]),
+ CPUFactor =
+ if
+ (CPUSpeed =:= -1) ->
+ 1;
+ (CPUSpeed >= 2000) ->
+ if
+ (NCPU >= 4) ->
+ 1;
+ (NCPU >= 2) ->
+ 2;
+ true ->
+ 3
+ end;
+ true ->
+ if
+ (NCPU >= 4) ->
+ 2;
+ (NCPU >= 2) ->
+ 3;
+ true ->
+ 4
+ end
+ end,
+ MemAddFactor =
+ if
+ (Memory =:= -1) ->
+ 0;
+ (Memory >= 8388608) ->
+ 0;
+ (Memory >= 4194304) ->
+ 1;
+ (Memory >= 2097152) ->
+ 2;
+ true ->
+ 3
+ end,
+ CPUFactor + MemAddFactor
+ end
+ catch
+ _:_:_ ->
+ io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]),
+ 1
+ end.
+
+
+analyze_and_print_freebsd_host_info(Version) ->
+ io:format("FreeBSD:"
+ "~n Version: ~p"
+ "~n", [Version]),
+ %% This test require that the program 'sysctl' is in the path.
+ %% First test with 'which sysctl', if that does not work
+ %% try with 'which /sbin/sysctl'. If that does not work either,
+ %% we skip the test...
+ try
+ begin
+ SysCtl =
+ case string:trim(os:cmd("which sysctl")) of
+ [] ->
+ case string:trim(os:cmd("which /sbin/sysctl")) of
+ [] ->
+ throw(sysctl);
+ SC2 ->
+ SC2
+ end;
+ SC1 ->
+ SC1
+ end,
+ Extract =
+ fun(Key) ->
+ string:tokens(string:trim(os:cmd(SysCtl ++ " " ++ Key)),
+ [$:])
+ end,
+ CPU = analyze_freebsd_cpu(Extract),
+ CPUSpeed = analyze_freebsd_cpu_speed(Extract),
+ NCPU = analyze_freebsd_ncpu(Extract),
+ Memory = analyze_freebsd_memory(Extract),
+ io:format("CPU:"
+ "~n Model: ~s"
+ "~n Speed: ~w"
+ "~n N: ~w"
+ "~n Num Schedulers: ~s"
+ "~nMemory:"
+ "~n ~w KB"
+ "~n",
+ [CPU, CPUSpeed, NCPU, str_num_schedulers(), Memory]),
+ io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]),
+ CPUFactor =
+ if
+ (CPUSpeed =:= -1) ->
+ 1;
+ (CPUSpeed >= 2000) ->
+ if
+ (NCPU >= 4) ->
+ 1;
+ (NCPU >= 2) ->
+ 2;
+ true ->
+ 3
+ end;
+ true ->
+ if
+ (NCPU =:= -1) ->
+ 1;
+ (NCPU >= 4) ->
+ 2;
+ (NCPU >= 2) ->
+ 3;
+ true ->
+ 4
+ end
+ end,
+ MemAddFactor =
+ if
+ (Memory =:= -1) ->
+ 0;
+ (Memory >= 8388608) ->
+ 0;
+ (Memory >= 4194304) ->
+ 1;
+ (Memory >= 2097152) ->
+ 2;
+ true ->
+ 3
+ end,
+ CPUFactor + MemAddFactor
+ end
+ catch
+ _:_:_ ->
+ io:format("CPU:"
+ "~n Num Schedulers: ~s"
+ "~n", [str_num_schedulers()]),
+ io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]),
+ case erlang:system_info(schedulers) of
+ 1 ->
+ 10;
+ 2 ->
+ 5;
+ _ ->
+ 2
+ end
+ end.
+
+
+analyze_freebsd_cpu(Extract) ->
+ analyze_freebsd_item(Extract, "hw.model", fun(X) -> X end, "-").
+
+analyze_freebsd_cpu_speed(Extract) ->
+ analyze_freebsd_item(Extract,
+ "hw.clockrate",
+ fun(X) -> list_to_integer(X) end,
+ -1).
+
+analyze_freebsd_ncpu(Extract) ->
+ analyze_freebsd_item(Extract,
+ "hw.ncpu",
+ fun(X) -> list_to_integer(X) end,
+ -1).
+
+analyze_freebsd_memory(Extract) ->
+ analyze_freebsd_item(Extract,
+ "hw.physmem",
+ fun(X) -> list_to_integer(X) div 1024 end,
+ -1).
+
+analyze_freebsd_item(Extract, Key, Process, Default) ->
+ try
+ begin
+ case Extract(Key) of
+ [Key, Model] ->
+ Process(string:trim(Model));
+ _ ->
+ Default
+ end
+ end
+ catch
+ _:_:_ ->
+ Default
+ end.
+
+
+analyze_and_print_solaris_host_info(Version) ->
+ Release =
+ case file:read_file_info("/etc/release") of
+ {ok, _} ->
+ case [string:trim(S) || S <- string:tokens(os:cmd("cat /etc/release"), [$\n])] of
+ [Rel | _] ->
+ Rel;
+ _ ->
+ "-"
+ end;
+ _ ->
+ "-"
+ end,
+ %% Display the firmware device tree root properties (prtconf -b)
+ Props = [list_to_tuple([string:trim(PS) || PS <- Prop]) ||
+ Prop <- [string:tokens(S, [$:]) ||
+ S <- string:tokens(os:cmd("prtconf -b"), [$\n])]],
+ BannerName = case lists:keysearch("banner-name", 1, Props) of
+ {value, {_, BN}} ->
+ string:trim(BN);
+ _ ->
+ "-"
+ end,
+ InstructionSet =
+ case string:trim(os:cmd("isainfo -k")) of
+ "Pseudo-terminal will not" ++ _ ->
+ "-";
+ IS ->
+ IS
+ end,
+ PtrConf = [list_to_tuple([string:trim(S) || S <- Items]) || Items <- [string:tokens(S, [$:]) || S <- string:tokens(os:cmd("prtconf"), [$\n])], length(Items) > 1],
+ SysConf =
+ case lists:keysearch("System Configuration", 1, PtrConf) of
+ {value, {_, SC}} ->
+ SC;
+ _ ->
+ "-"
+ end,
+ %% Because we count the lines of the output (which may contain
+ %% any number of extra crap lines) we need to ensure we only
+ %% count the "proper" stdout. So send it to a tmp file first
+ %% and then count its number of lines...
+ NumPhysCPU =
+ try
+ begin
+ File1 = f("/tmp/psrinfo_p.~s.~w", [os:getpid(), os:system_time()]),
+ os:cmd("psrinfo -p > " ++ File1),
+ string:trim(os:cmd("cat " ++ File1))
+ end
+ catch
+ _:_:_ ->
+ "-"
+ end,
+ %% Because we count the lines of the output (which may contain
+ %% any number of extra crap lines) we need to ensure we only
+ %% count the "proper" stdout. So send it to a tmp file first
+ %% and then count its number of lines...
+ NumVCPU =
+ try
+ begin
+ File2 = f("/tmp/psrinfo.~s.~w", [os:getpid(), os:system_time()]),
+ os:cmd("psrinfo > " ++ File2),
+ [NumVCPUStr | _] = string:tokens(os:cmd("wc -l " ++ File2), [$\ ]),
+ NumVCPUStr
+ end
+ catch
+ _:_:_ ->
+ "-"
+ end,
+ MemSz =
+ case lists:keysearch("Memory size", 1, PtrConf) of
+ {value, {_, MS}} ->
+ MS;
+ _ ->
+ "-"
+ end,
+ io:format("Solaris: ~s"
+ "~n Release: ~s"
+ "~n Banner Name: ~s"
+ "~n Instruction Set: ~s"
+ "~n CPUs: ~s (~s)"
+ "~n System Config: ~s"
+ "~n Memory Size: ~s"
+ "~n Num Schedulers: ~s"
+ "~n~n", [Version, Release, BannerName, InstructionSet,
+ NumPhysCPU, NumVCPU,
+ SysConf, MemSz,
+ str_num_schedulers()]),
+ io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]),
+ MemFactor =
+ try string:tokens(MemSz, [$ ]) of
+ [SzStr, "Mega" ++ _] ->
+ try list_to_integer(SzStr) of
+ Sz when Sz > 8192 ->
+ 0;
+ Sz when Sz > 4096 ->
+ 1;
+ Sz when Sz > 2048 ->
+ 2;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 10
+ end;
+ [SzStr, "Giga" ++ _] ->
+ try list_to_integer(SzStr) of
+ Sz when Sz > 8 ->
+ 0;
+ Sz when Sz > 4 ->
+ 1;
+ Sz when Sz > 2 ->
+ 2;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 10
+ end;
+ _ ->
+ 10
+ catch
+ _:_:_ ->
+ 10
+ end,
+ try erlang:system_info(schedulers) of
+ 1 ->
+ 10;
+ 2 ->
+ 5;
+ N when (N =< 6) ->
+ 2;
+ _ ->
+ 1
+ catch
+ _:_:_ ->
+ 10
+ end + MemFactor.
+
+
+
+analyze_and_print_win_host_info(Version) ->
+ SysInfo = which_win_system_info(),
+ OsName = win_sys_info_lookup(os_name, SysInfo),
+ OsVersion = win_sys_info_lookup(os_version, SysInfo),
+ SysMan = win_sys_info_lookup(system_manufacturer, SysInfo),
+ SysMod = win_sys_info_lookup(system_model, SysInfo),
+ NumProcs = win_sys_info_lookup(num_processors, SysInfo),
+ TotPhysMem = win_sys_info_lookup(total_phys_memory, SysInfo),
+ io:format("Windows: ~s"
+ "~n OS Version: ~s (~p)"
+ "~n System Manufacturer: ~s"
+ "~n System Model: ~s"
+ "~n Number of Processor(s): ~s"
+ "~n Total Physical Memory: ~s"
+ "~n Num Schedulers: ~s"
+ "~n~n", [OsName, OsVersion, Version,
+ SysMan, SysMod, NumProcs, TotPhysMem,
+ str_num_schedulers()]),
+ io:format("TS Scale Factor: ~w~n", [timetrap_scale_factor()]),
+ MemFactor =
+ try
+ begin
+ [MStr, MUnit|_] =
+ string:tokens(lists:delete($,, TotPhysMem), [$\ ]),
+ case string:to_lower(MUnit) of
+ "gb" ->
+ try list_to_integer(MStr) of
+ M when M > 8 ->
+ 0;
+ M when M > 4 ->
+ 1;
+ M when M > 2 ->
+ 2;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 10
+ end;
+ "mb" ->
+ try list_to_integer(MStr) of
+ M when M > 8192 ->
+ 0;
+ M when M > 4096 ->
+ 1;
+ M when M > 2048 ->
+ 2;
+ _ ->
+ 5
+ catch
+ _:_:_ ->
+ 10
+ end;
+ _ ->
+ 10
+ end
+ end
+ catch
+ _:_:_ ->
+ 10
+ end,
+ CPUFactor =
+ case erlang:system_info(schedulers) of
+ 1 ->
+ 10;
+ 2 ->
+ 5;
+ _ ->
+ 2
+ end,
+ CPUFactor + MemFactor.
+
+win_sys_info_lookup(Key, SysInfo) ->
+ win_sys_info_lookup(Key, SysInfo, "-").
+
+win_sys_info_lookup(Key, SysInfo, Def) ->
+ case lists:keysearch(Key, 1, SysInfo) of
+ {value, {Key, Value}} ->
+ Value;
+ false ->
+ Def
+ end.
+
+%% This function only extracts the prop we actually care about!
+which_win_system_info() ->
+ SysInfo = os:cmd("systeminfo"),
+ try process_win_system_info(string:tokens(SysInfo, [$\r, $\n]), [])
+ catch
+ _:_:_ ->
+ io:format("Failed process System info: "
+ "~s~n", [SysInfo]),
+ []
+ end.
+
+process_win_system_info([], Acc) ->
+ Acc;
+process_win_system_info([H|T], Acc) ->
+ case string:tokens(H, [$:]) of
+ [Key, Value] ->
+ case string:to_lower(Key) of
+ "os name" ->
+ process_win_system_info(T,
+ [{os_name, string:trim(Value)}|Acc]);
+ "os version" ->
+ process_win_system_info(T,
+ [{os_version, string:trim(Value)}|Acc]);
+ "system manufacturer" ->
+ process_win_system_info(T,
+ [{system_manufacturer, string:trim(Value)}|Acc]);
+ "system model" ->
+ process_win_system_info(T,
+ [{system_model, string:trim(Value)}|Acc]);
+ "processor(s)" ->
+ [NumProcStr|_] = string:tokens(Value, [$\ ]),
+ T2 = lists:nthtail(list_to_integer(NumProcStr), T),
+ process_win_system_info(T2,
+ [{num_processors, NumProcStr}|Acc]);
+ "total physical memory" ->
+ process_win_system_info(T,
+ [{total_phys_memory, string:trim(Value)}|Acc]);
+ _ ->
+ process_win_system_info(T, Acc)
+ end;
+ _ ->
+ process_win_system_info(T, Acc)
+ end.
+
+
+
+str_num_schedulers() ->
+ try erlang:system_info(schedulers) of
+ N -> f("~w", [N])
+ catch
+ _:_:_ -> "-"
+ end.
+
+
+
%% ----------------------------------------------------------------
%% Time related function
%%
@@ -717,15 +1569,16 @@ is_snmp_running() ->
is_app_running(snmp).
crypto_start() ->
- case (catch crypto:start()) of
+ try crypto:start() of
ok ->
ok;
{error, {already_started,crypto}} ->
- ok;
- {'EXIT', Reason} ->
- {error, {exit, Reason}};
- Else ->
- Else
+ ok
+ catch
+ exit:{undef, [{crypto, start, [], []} | _]}:_ ->
+ {error, no_crypto};
+ C:E:S ->
+ {error, {C, E, S}}
end.
crypto_support() ->
@@ -745,8 +1598,74 @@ crypto_support([Func|Funcs], Acc) ->
is_crypto_supported(Func) ->
snmp_misc:is_crypto_supported(Func).
-
-
+
+
+%% This function ensures that a *named* process on the local node is not running.
+%% It does so by:
+%% 1) Wait for 'Timeout' msec
+%% 2) If 1 did not work, issue 'stop' and then wait 'Timeout' msec
+%% 3) And finally, if 2 did not work, issue exit(kill).
+ensure_not_running(Name, Stopper, Timeout)
+ when is_atom(Name) andalso
+ is_function(Stopper, 0) andalso
+ is_integer(Timeout) ->
+ ensure_not_running(whereis(Name), Name, Stopper, Timeout).
+
+ensure_not_running(Pid, Name, Stopper, Timeout) when is_pid(Pid) ->
+ MRef = erlang:monitor(process, Pid),
+ try
+ begin
+ ensure_not_running_wait(Pid, MRef, Timeout),
+ ensure_not_running_stop(Pid, MRef, Stopper, Timeout),
+ ensure_not_running_kill(Pid, MRef, Timeout),
+ exit({failed_ensure_not_running, Name})
+ end
+ catch
+ throw:ok ->
+ sleep(1000),
+ ok
+ end;
+ensure_not_running(_, _, _, _) ->
+ iprint("ensure_not_running -> not running", []),
+ sleep(1000), % This should not actually be necessary!
+ ok.
+
+
+ensure_not_running_wait(Pid, MRef, Timeout) ->
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ iprint("ensure_not_running_wait -> died peacefully", []),
+ throw(ok)
+ after Timeout ->
+ wprint("ensure_not_running_wait -> giving up", []),
+ ok
+ end.
+
+ensure_not_running_stop(Pid, MRef, Stopper, Timeout) ->
+ %% Spawn a stop'er process
+ StopPid = spawn(Stopper),
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ nprint("ensure_not_running_stop -> dead (stopped)", []),
+ throw(ok)
+ after Timeout ->
+ wprint("ensure_not_running_stop -> giving up", []),
+ exit(StopPid, kill),
+ ok
+ end.
+
+ensure_not_running_kill(Pid, MRef, Timeout) ->
+ exit(Pid, kill),
+ receive
+ {'DOWN', MRef, process, Pid, _Info} ->
+ nprint("ensure_not_running_kill -> dead (killed)", []),
+ throw(ok)
+ after Timeout ->
+ wprint("ensure_not_running_kill -> giving up", []),
+ ok
+ end.
+
+
%% ----------------------------------------------------------------
%% Watchdog functions
%%
@@ -875,19 +1794,6 @@ del_file_or_dir(FileOrDir) ->
%% ----------------------------------------------------------------------
-%% cover functions
-%%
-
-cover([Suite, Case] = Args) when is_atom(Suite) andalso is_atom(Case) ->
- Mods0 = cover:compile_directory("../src"),
- Mods1 = [Mod || {ok, Mod} <- Mods0],
- snmp_test_server:t(Args),
- Files0 = [cover:analyse_to_file(Mod) || Mod <- Mods1],
- [io:format("Cover output: ~s~n", [File]) || {ok, File} <- Files0],
- ok.
-
-
-%% ----------------------------------------------------------------------
%% (debug) Print functions
%%
@@ -933,3 +1839,49 @@ print(Prefix, Module, Line, Format, Args) ->
formated_timestamp() ->
snmp_misc:formated_timestamp().
+
+%% ----------------------------------------------------------------------
+%%
+%% General purpose print functions
+%% ERROR, WARNING and NOTICE are written both to 'user' and 'standard_io'.
+%% INFO only to 'standard_io'.
+%%
+%% Should we also allow for (optional) a "short name" (sname)?
+%%
+
+%% ERROR print (both to user and standard_io)
+eprint(F, A) ->
+ Str = format_print("ERROR", F, A),
+ io:format(user, "~s~n", [Str]),
+ io:format(standard_io, "~s~n", [Str]).
+
+%% WARNING print (both to user and standard_io)
+wprint(F, A) ->
+ Str = format_print("WARNING", F, A),
+ io:format(user, "~s~n", [Str]),
+ io:format(standard_io, "~s~n", [Str]).
+
+%% NOTICE print (both to user and standard_io)
+nprint(F, A) ->
+ Str = format_print("NOTICE", F, A),
+ io:format(user, "~s~n", [Str]),
+ io:format(standard_io, "~s~n", [Str]).
+
+%% INFO print (only to user)
+iprint(F, A) ->
+ Str = format_print("INFO", F, A),
+ io:format(standard_io, "~s~n", [Str]).
+
+format_print(Prefix, F, A) ->
+ format_print(get(tname), Prefix, F, A).
+
+format_print(undefined, Prefix, F, A) ->
+ f("*** [~s] ~s ~p ~p *** ~n" ++ F ++ "~n",
+ [formated_timestamp(), Prefix, node(), self() | A]);
+format_print(TName, Prefix, F, A) when is_atom(TName) ->
+ format_print(atom_to_list(TName), Prefix, F, A);
+format_print(TName, Prefix, F, A) when is_list(TName) ->
+ f("*** [~s] ~s ~s ~p ~p *** ~n" ++ F ++ "~n",
+ [formated_timestamp(), Prefix, TName, node(), self() | A]).
+
+
diff --git a/lib/snmp/test/snmp_test_lib.hrl b/lib/snmp/test/snmp_test_lib.hrl
index c91b6d1859..f4863c9a1e 100644
--- a/lib/snmp/test/snmp_test_lib.hrl
+++ b/lib/snmp/test/snmp_test_lib.hrl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2002-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2002-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -43,17 +43,18 @@
%% - Test case macros -
--define(TC_TRY(C, TC), ?LIB:tc_try(C, TC)).
--define(TC_TRY(C, TCCond, TC), ?LIB:tc_try(C, TCCond, TC)).
+
+-define(TC_TRY(C, TC), ?LIB:tc_try(C, TC)).
+-define(TC_TRY(C, TCCond, TC), ?LIB:tc_try(C, TCCond, TC)).
+-define(TC_TRY(C, Pre, TC, Post), ?LIB:tc_try(C, Pre, TC, Post)).
+-define(TC_TRY(C, TCCond, Pre, TC, Post), ?LIB:tc_try(C, TCCond, Pre, TC, Post)).
+
-define(OS_BASED_SKIP(Skippable), ?LIB:os_based_skip(Skippable)).
-define(NON_PC_TC_MAYBE_SKIP(Config, Condition),
?LIB:non_pc_tc_maybe_skip(Config, Condition, ?MODULE, ?LINE)).
-define(SKIP(Reason), ?LIB:skip(Reason, ?MODULE, ?LINE)).
-define(FAIL(Reason), ?LIB:fail(Reason, ?MODULE, ?LINE)).
--define(IS_IPV6_HOST(), ?LIB:is_ipv6_host()).
--define(IS_IPV6_HOST(H), ?LIB:is_ipv6_host(H)).
-define(HAS_SUPPORT_IPV6(), ?LIB:has_support_ipv6()).
--define(HAS_SUPPORT_IPV6(H), ?LIB:has_support_ipv6(H)).
%% - Time macros -
@@ -83,6 +84,10 @@
-define(FLUSH(), ?LIB:flush_mqueue()).
-define(ETRAP_GET(), ?LIB:trap_exit()).
-define(ETRAP_SET(O), ?LIB:trap_exit(O)).
+-define(PINFO(__P__), try process_info(__P__)
+ catch _:_:_ ->
+ {not_running, __P__}
+ end).
%% - Node utility macros -
@@ -104,6 +109,9 @@
-define(CRYPTO_SUPPORT(), ?LIB:crypto_support()).
+-define(ENSURE_NOT_RUNNING(N, S, T), ?LIB:ensure_not_running(N, S, T)).
+
+
%% - Dir macros -
-define(DEL_DIR(D), ?LIB:del_dir(D)).
@@ -111,55 +119,33 @@
%% - Print macros
+%% Used for indicating the start of a test case
-define(P(C), ?LIB:p(?MODULE, C)).
--define(P1(F), ?LIB:p(F, [])).
--define(P2(F, A), ?LIB:p(F, A)).
--define(F(F, A), ?LIB:f(F, A)).
--ifdef(snmp_debug).
--ifndef(snmp_log).
--define(snmp_log,true).
--endif.
--ifndef(snmp_error).
--define(snmp_error,true).
--endif.
--else.
--ifdef(snmp_log).
--ifndef(snmp_error).
--define(snmp_error,true).
--endif.
--endif.
--endif.
+%% Takes a format call (such as io:format) and produces a printable string
+-define(F(F, A), ?LIB:f(F, A)).
-ifdef(snmp_debug).
--define(DBG(F,A), ?PRINT("DBG", F, A)).
+-define(DBG(F,A), ?IPRINT(F, A)).
-else.
-define(DBG(F,A), ok).
-endif.
--ifdef(snmp_log).
--define(LOG(F,A), ?PRINT("LOG", F, A)).
--else.
--define(LOG(F,A), ok).
--endif.
-
--ifdef(snmp_error).
--define(ERR(F,A), ?PRINT("ERR", F, A)).
--else.
--define(ERR(F,A), ok).
--endif.
-
--define(INF(F,A), ?PRINT("INF", F, A)).
+%% ERROR print
+-define(EPRINT(F), ?LIB:eprint(F, [])).
+-define(EPRINT(F, A), ?LIB:eprint(F, A)).
--define(PRINT(P,F,A), ?LIB:print(P, ?MODULE, ?LINE, F, A)).
+%% WARNING print
+-define(WPRINT(F), ?LIB:wprint(F, [])).
+-define(WPRINT(F, A), ?LIB:wprint(F, A)).
--define(PRINT1(F, A), ?LIB:print1(F, A)).
--define(PRINT1(F), ?PRINT1(F, [])).
--define(EPRINT1(F, A), ?PRINT1("<ERROR> " ++ F, A)).
+%% NOTICE print
+-define(NPRINT(F), ?LIB:nprint(F, [])).
+-define(NPRINT(F, A), ?LIB:nprint(F, A)).
--define(PRINT2(F, A), ?LIB:print2(F, A)).
--define(PRINT2(F), ?PRINT2(F, [])).
--define(EPRINT2(F, A), ?PRINT2("<ERROR> " ++ F, A)).
+%% INFO print
+-define(IPRINT(F), ?LIB:iprint(F, [])).
+-define(IPRINT(F, A), ?LIB:iprint(F, A)).
-define(FTS(), snmp_misc:formated_timestamp()).
-define(FTS(TS), snmp_misc:format_timestamp(TS)).
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
index f50147a852..0a80860ed1 100644
--- a/lib/snmp/test/snmp_test_mgr.erl
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -191,40 +191,41 @@ receive_trap(Timeout) ->
%% {mibs, List of Filenames}, {trap_udp, UDPPort (default 5000)},
%%----------------------------------------------------------------------
init({Options, CallerPid}) ->
+ %% This causes "verbosity printouts" to print (from level debug)
+ %% in the modules we "borrow" from the agent code (burr,,,)
+ %% With "our" name (mgr).
put(sname, mgr),
- put(verbosity, debug),
+ put(verbosity, debug),
+ %% Make use of the "test name" print "feature"
+ put(tname, "MGR"),
?SNMP_RAND_SEED(),
- %% rand:seed(exrop,
- %% {erlang:phash2([node()]),
- %% erlang:monotonic_time(),
- %% erlang:unique_integer()}),
case (catch is_options_ok(Options)) of
true ->
put(debug, get_value(debug, Options, false)),
- d("init -> (~p) extract options",[self()]),
+ d("init -> extract options"),
PacksDbg = get_value(packet_server_debug, Options, false),
- print("[~w] ~p -> PacksDbg: ~p~n", [?MODULE, self(), PacksDbg]),
+ ?IPRINT("init -> PacksDbg: ~p", [PacksDbg]),
RecBufSz = get_value(recbuf, Options, 1024),
- print("[~w] ~p -> RecBufSz: ~p~n", [?MODULE, self(), RecBufSz]),
+ ?IPRINT("init -> RecBufSz: ~p", [RecBufSz]),
Mibs = get_value(mibs, Options, []),
- print("[~w] ~p -> Mibs: ~p~n", [?MODULE, self(), Mibs]),
+ ?IPRINT("init -> Mibs: ~p", [Mibs]),
Udp = get_value(agent_udp, Options, 4000),
- print("[~w] ~p -> Udp: ~p~n", [?MODULE, self(), Udp]),
+ ?IPRINT("init -> Udp: ~p", [Udp]),
User = get_value(user, Options, "initial"),
- print("[~w] ~p -> User: ~p~n", [?MODULE, self(), User]),
+ ?IPRINT("init -> User: ~p", [User]),
EngineId = get_value(engine_id, Options, "agentEngine"),
- print("[~w] ~p -> EngineId: ~p~n", [?MODULE, self(), EngineId]),
+ ?IPRINT("init -> EngineId: ~p", [EngineId]),
CtxEngineId = get_value(context_engine_id, Options, EngineId),
- print("[~w] ~p -> CtxEngineId: ~p~n", [?MODULE, self(), CtxEngineId]),
+ ?IPRINT("init -> CtxEngineId: ~p", [CtxEngineId]),
TrapUdp = get_value(trap_udp, Options, 5000),
- print("[~w] ~p -> TrapUdp: ~p~n", [?MODULE, self(), TrapUdp]),
+ ?IPRINT("init -> TrapUdp: ~p", [TrapUdp]),
Dir = get_value(dir, Options, "."),
- print("[~w] ~p -> Dir: ~p~n", [?MODULE, self(), Dir]),
+ ?IPRINT("init -> Dir: ~p", [Dir]),
SecLevel = get_value(sec_level, Options, noAuthNoPriv),
- print("[~w] ~p -> SecLevel: ~p~n", [?MODULE, self(), SecLevel]),
+ ?IPRINT("init -> SecLevel: ~p", [SecLevel]),
MiniMIB = snmp_mini_mib:create(Mibs),
- d("[~w] ~p -> MiniMIB: "
- "~n ~p", [?MODULE, self(), MiniMIB]),
+ d("init -> MiniMIB: "
+ "~n ~p", [MiniMIB]),
Version = case lists:member(v2, Options) of
true -> 'version-2';
false ->
@@ -233,41 +234,38 @@ init({Options, CallerPid}) ->
false -> 'version-1'
end
end,
- print("[~w] ~p -> Version: ~p~n", [?MODULE, self(), Version]),
+ ?IPRINT("init -> Version: ~p", [Version]),
Com = case Version of
'version-3' ->
get_value(context, Options, "");
_ ->
get_value(community, Options, "public")
end,
- print("[~w] ~p -> Com: ~p~n", [?MODULE, self(), Com]),
+ ?IPRINT("init -> Com: ~p", [Com]),
VsnHdrD =
{Com, User, EngineId, CtxEngineId, mk_seclevel(SecLevel)},
- print("[~w] ~p -> VsnHdrD: ~p~n", [?MODULE, self(), VsnHdrD]),
+ ?IPRINT("init -> VsnHdrD: ~p", [VsnHdrD]),
IpFamily = get_value(ipfamily, Options, inet),
- print("[~w] ~p -> IpFamily: ~p~n", [?MODULE, self(), IpFamily]),
+ ?IPRINT("init -> IpFamily: ~p", [IpFamily]),
AgIp = case snmp_misc:assq(agent, Options) of
{value, Addr} when is_tuple(Addr) andalso
(size(Addr) =:= 4) andalso
(IpFamily =:= inet) ->
- print("[~w] ~p -> Addr: ~p~n",
- [?MODULE, self(), Addr]),
+ ?IPRINT("init -> Addr: ~p", [Addr]),
Addr;
{value, Addr} when is_tuple(Addr) andalso
(size(Addr) =:= 8) andalso
(IpFamily =:= inet6) ->
- print("[~w] ~p -> Addr: ~p~n",
- [?MODULE, self(), Addr]),
+ ?IPRINT("init -> Addr: ~p", [Addr]),
Addr;
{value, Host} when is_list(Host) ->
- print("[~w] ~p -> Host: ~p~n",
- [?MODULE, self(), Host]),
+ ?IPRINT("init -> Host: ~p", [Host]),
{ok, Ip} = snmp_misc:ip(Host, IpFamily),
Ip
end,
- print("[~w] ~p -> AgIp: ~p~n", [?MODULE, self(), AgIp]),
+ ?IPRINT("init -> AgIp: ~p", [AgIp]),
Quiet = lists:member(quiet, Options),
- print("[~w] ~p -> Quiet: ~p~n", [?MODULE, self(), Quiet]),
+ ?IPRINT("init -> Quiet: ~p", [Quiet]),
PackServ =
start_packet_server(
Quiet, Options, CallerPid, AgIp, Udp, TrapUdp,
@@ -692,16 +690,16 @@ echo_pdu(PDU, MiniMIB) ->
%% Test Sequence
%%----------------------------------------------------------------------
echo_errors({error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}})->
- io:format("* Unexpected Behaviour * Id: ~w.~n"
- " Expected: " ++ ExpectedFormat ++ "~n"
- " Got: " ++ Format ++ "~n",
- [Id] ++ ExpectedData ++ Data),
+ ?IPRINT("*** Unexpected Behaviour *** Id: ~w.~n"
+ " Expected: " ++ ExpectedFormat ++ "~n"
+ " Got: " ++ Format ++ "~n",
+ [Id] ++ ExpectedData ++ Data),
{error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}};
echo_errors(ok) -> ok;
echo_errors({ok, Val}) -> {ok, Val}.
get_response_impl(Id, ExpVars) ->
- ?PRINT2("await response ~w with"
+ ?IPRINT("await response ~w with"
"~n Expected Varbinds: ~p",
[Id, ExpVars]),
PureVars = find_pure_oids2(ExpVars),
@@ -710,7 +708,7 @@ get_response_impl(Id, ExpVars) ->
error_status = noError,
error_index = 0,
varbinds = VBs} ->
- ?PRINT2("received expected response pdu (~w) - match vars"
+ ?IPRINT("received expected response pdu (~w) - match vars"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[Id, PureVars, VBs]),
@@ -720,10 +718,10 @@ get_response_impl(Id, ExpVars) ->
request_id = ReqId,
error_status = Err2,
error_index = Index2} ->
- ?EPRINT2("received unexpected response pdu: ~w, ~w, ~w"
- "~n Received Error: ~p"
- "~n Received Index: ~p",
- [Type2, Id, ReqId, Err2, Index2]),
+ ?EPRINT("received unexpected response pdu: ~w, ~w, ~w"
+ "~n Received Error: ~p"
+ "~n Received Index: ~p",
+ [Type2, Id, ReqId, Err2, Index2]),
{error,
Id,
{"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
@@ -732,8 +730,8 @@ get_response_impl(Id, ExpVars) ->
[Type2, Err2, Index2]}};
{error, Reason} ->
- ?EPRINT2("unexpected receive pdu error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive pdu error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end.
@@ -743,81 +741,81 @@ get_response_impl(Id, ExpVars) ->
%% Returns: ok | {error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}}
%%----------------------------------------------------------------------
expect_impl(Id, any) ->
- ?PRINT2("await ~w pdu (any)", [Id]),
+ ?IPRINT("await ~w pdu (any)", [Id]),
case receive_response() of
PDU when is_record(PDU, pdu) ->
- ?PRINT2("received expected pdu (~w)", [Id]),
+ ?IPRINT("received expected pdu (~w)", [Id]),
ok;
{error, Reason} ->
- ?EPRINT1("unexpected receive error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end;
expect_impl(Id, return) ->
- ?PRINT2("await ~w pdu", [Id]),
+ ?IPRINT("await ~w pdu", [Id]),
case receive_response() of
PDU when is_record(PDU, pdu) ->
- ?PRINT2("received expected pdu (~w)", [Id]),
+ ?IPRINT("received expected pdu (~w)", [Id]),
{ok, PDU};
{error, Reason} ->
- ?EPRINT1("unexpected receive error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end;
expect_impl(Id, trap) ->
- ?PRINT2("await ~w trap", [Id]),
+ ?IPRINT("await ~w trap", [Id]),
case receive_trap(3500) of
PDU when is_record(PDU, trappdu) ->
- ?PRINT2("received expected trap (~w)", [Id]),
+ ?IPRINT("received expected trap (~w)", [Id]),
ok;
{error, Reason} ->
- ?EPRINT1("unexpected receive error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end;
expect_impl(Id, timeout) ->
- ?PRINT2("await ~w nothing", [Id]),
+ ?IPRINT("await ~w nothing", [Id]),
receive
X ->
- ?EPRINT1("received unexpected message: ~w"
- "~n ~p",
- [Id, X]),
+ ?EPRINT("received unexpected message: ~w"
+ "~n ~p",
+ [Id, X]),
{error, Id, {"Timeout", []}, {"Message ~w", [X]}}
after 3500 ->
ok
end;
expect_impl(Id, Err) when is_atom(Err) ->
- ?PRINT2("await ~w with"
+ ?IPRINT("await ~w with"
"~n Err: ~p",
[Id, Err]),
case receive_response() of
#pdu{error_status = Err} ->
- ?PRINT2("received pdu with expected error status (~w, ~w)",
+ ?IPRINT("received pdu with expected error status (~w, ~w)",
[Id, Err]),
ok;
#pdu{type = Type2,
request_id = ReqId,
error_status = Err2} ->
- ?EPRINT1("received pdu with unexpected error status: ~w, ~w, ~w"
- "~n Expected Error: ~p"
- "~n Received Error: ~p",
- [Type2, Id, ReqId, Err, Err2]),
+ ?EPRINT("received pdu with unexpected error status: ~w, ~w, ~w"
+ "~n Expected Error: ~p"
+ "~n Received Error: ~p",
+ [Type2, Id, ReqId, Err, Err2]),
{error, Id, {"ErrorStatus: ~w, RequestId: ~w", [Err,ReqId]},
{"ErrorStatus: ~w", [Err2]}};
{error, Reason} ->
- ?EPRINT1("unexpected receive error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end;
expect_impl(Id, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
- ?PRINT2("await ~w with"
+ ?IPRINT("await ~w with"
"~n ExpectedVarbinds: ~p",
[Id, ExpectedVarbinds]),
PureVars = find_pure_oids(ExpectedVarbinds),
@@ -826,7 +824,7 @@ expect_impl(Id, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
error_status = noError,
error_index = 0,
varbinds = VBs} ->
- ?PRINT2("received expected response pdu (~w) - check varbinds"
+ ?IPRINT("received expected response pdu (~w) - check varbinds"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[Id, PureVars, VBs]),
@@ -836,22 +834,22 @@ expect_impl(Id, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
request_id = ReqId,
error_status = Err2,
error_index = Index2} ->
- ?EPRINT1("received unexpected pdu: ~w, ~w, ~w"
- "~n Received Error: ~p"
- "~n Received Index: ~p",
+ ?EPRINT("received unexpected pdu: ~w, ~w, ~w"
+ "~n Received Error: ~p"
+ "~n Received Index: ~p",
[Type2, Id, ReqId, Err2, Index2]),
{error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
['get-response', noError, 0, ReqId]},
{"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
{error, Reason} ->
- ?EPRINT1("unexpected receive error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end.
expect_impl(Id, v2trap, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
- ?PRINT2("await v2 trap ~w with"
+ ?IPRINT("await v2 trap ~w with"
"~n ExpectedVarbinds: ~p",
[Id, ExpectedVarbinds]),
PureVars = find_pure_oids(ExpectedVarbinds),
@@ -860,7 +858,7 @@ expect_impl(Id, v2trap, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
error_status = noError,
error_index = 0,
varbinds = VBs} ->
- ?PRINT2("received expected v2 trap (~w) - check varbinds"
+ ?IPRINT("received expected v2 trap (~w) - check varbinds"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[Id, PureVars, VBs]),
@@ -870,22 +868,22 @@ expect_impl(Id, v2trap, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
request_id = ReqId,
error_status = Err2,
error_index = Index2} ->
- ?EPRINT1("received unexpected pdu: ~w, ~w, ~w"
- "~n Received Error: ~p"
- "~n Received Index: ~p",
- [Type2, Id, ReqId, Err2, Index2]),
+ ?EPRINT("received unexpected pdu: ~w, ~w, ~w"
+ "~n Received Error: ~p"
+ "~n Received Index: ~p",
+ [Type2, Id, ReqId, Err2, Index2]),
{error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
['snmpv2-trap', noError, 0, ReqId]},
{"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
{error, Reason} ->
- ?EPRINT1("unexpected receive error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end;
expect_impl(Id, report, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
- ?PRINT2("await report ~w with"
+ ?IPRINT("await report ~w with"
"~n ExpectedVarbinds: ~p",
[Id, ExpectedVarbinds]),
PureVBs = find_pure_oids(ExpectedVarbinds),
@@ -894,7 +892,7 @@ expect_impl(Id, report, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
error_status = noError,
error_index = 0,
varbinds = VBs} ->
- ?PRINT2("received expected report (~w) - check varbinds"
+ ?IPRINT("received expected report (~w) - check varbinds"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[Id, PureVBs, VBs]),
@@ -904,23 +902,23 @@ expect_impl(Id, report, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
request_id = ReqId,
error_status = Err2,
error_index = Index2} ->
- ?EPRINT1("received unexpected pdu: ~w, ~w, ~w"
- "~n Received Error: ~p"
- "~n Received Index: ~p",
- [Type2, Id, ReqId, Err2, Index2]),
+ ?EPRINT("received unexpected pdu: ~w, ~w, ~w"
+ "~n Received Error: ~p"
+ "~n Received Index: ~p",
+ [Type2, Id, ReqId, Err2, Index2]),
{error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
[report, noError, 0, ReqId]},
{"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
{error, Reason} ->
- ?EPRINT1("unexpected receive error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end;
expect_impl(Id, {inform, Reply}, ExpectedVarbinds)
when is_list(ExpectedVarbinds) ->
- ?PRINT2("await inform ~w with"
+ ?IPRINT("await inform ~w with"
"~n Reply: ~p"
"~n ExpectedVarbinds: ~p",
[Id, Reply, ExpectedVarbinds]),
@@ -931,20 +929,20 @@ expect_impl(Id, {inform, Reply}, ExpectedVarbinds)
error_status = noError,
error_index = 0,
varbinds = VBs} ->
- ?PRINT2("received inform (~w) - check varbinds"
+ ?IPRINT("received inform (~w) - check varbinds"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[Id, PureVBs, VBs]),
case check_vars(Id, PureVBs, VBs) of
ok when (Reply == true) ->
- ?PRINT2("varbinds ok (~w) - send ok inform response", [Id]),
+ ?IPRINT("varbinds ok (~w) - send ok inform response", [Id]),
RespPDU = Resp#pdu{type = 'get-response',
error_status = noError,
error_index = 0},
?MODULE:rpl(RespPDU),
ok;
ok when (element(1, Reply) == error) ->
- ?PRINT2("varbinds ok (~w) - send error inform response", [Id]),
+ ?IPRINT("varbinds ok (~w) - send error inform response", [Id]),
{error, Status, Index} = Reply,
RespPDU = Resp#pdu{type = 'get-response',
error_status = Status,
@@ -952,13 +950,12 @@ expect_impl(Id, {inform, Reply}, ExpectedVarbinds)
?MODULE:rpl(RespPDU),
ok;
ok when (Reply == false) ->
- ?PRINT2("varbinds ok (~w) - don't send inform response", [Id]),
+ ?IPRINT("varbinds ok (~w) - don't send inform response", [Id]),
ok;
Else ->
- ?EPRINT1("unexpected varbinds (~w)", [Id]),
- io:format("expect_impl(~w, inform) -> "
- "~n Else: ~p"
- "~n", [Id, Else]),
+ ?EPRINT("unexpected (inform) varbinds (~w):"
+ "~n VBs: ~p"
+ "~n ~p", [Id, VBs, Else]),
Else
end;
@@ -966,22 +963,22 @@ expect_impl(Id, {inform, Reply}, ExpectedVarbinds)
request_id = ReqId,
error_status = Err2,
error_index = Index2} ->
- ?EPRINT1("received unexpected pdu: ~w, ~w, ~w"
- "~n Received Error: ~p"
- "~n Received Index: ~p",
- [Type2, Id, ReqId, Err2, Index2]),
+ ?EPRINT("received unexpected pdu: ~w, ~w, ~w"
+ "~n Received Error: ~p"
+ "~n Received Index: ~p",
+ [Type2, Id, ReqId, Err2, Index2]),
{error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
['inform-request', noError, 0, ReqId]},
{"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
{error, Reason} ->
- ?EPRINT1("unexpected receive error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end.
expect_impl(Id, Err, Index, any = _ExpectedVarbinds) ->
- ?PRINT2("await response ~w with"
+ ?IPRINT("await response ~w with"
"~n Err: ~p"
"~n Index: ~p"
"~n ExpectedVarbinds: ~p",
@@ -990,13 +987,13 @@ expect_impl(Id, Err, Index, any = _ExpectedVarbinds) ->
#pdu{type = 'get-response',
error_status = Err,
error_index = Index} ->
- ?PRINT2("received expected response pdu (~w, ~w, ~w)",
+ ?IPRINT("received expected response pdu (~w, ~w, ~w)",
[Id, Err, Index]),
ok;
#pdu{type = 'get-response',
error_status = Err} when (Index == any) ->
- ?PRINT2("received expected response pdu (~w, ~w)",
+ ?IPRINT("received expected response pdu (~w, ~w)",
[Id, Err]),
ok;
@@ -1006,14 +1003,14 @@ expect_impl(Id, Err, Index, any = _ExpectedVarbinds) ->
error_index = Idx} when is_list(Index) ->
case lists:member(Idx, Index) of
true ->
- ?PRINT2("received expected response pdu (~w, ~w, ~w)",
+ ?IPRINT("received expected response pdu (~w, ~w, ~w)",
[Id, Err, Idx]),
ok;
false ->
- ?EPRINT1("received response pdu with unexpected index (~w, ~w):"
- "~n Expected Index: ~p"
- "~n Received Index: ~p",
- [Id, Err, Index, Idx]),
+ ?EPRINT("received response pdu with unexpected index (~w, ~w):"
+ "~n Expected Index: ~p"
+ "~n Received Index: ~p",
+ [Id, Err, Index, Idx]),
{error, Id, {"ErrStat: ~w, Idx: ~w, RequestId: ~w",
[Err, Index, ReqId]},
{"ErrStat: ~w, Idx: ~w", [Err, Idx]}}
@@ -1023,22 +1020,24 @@ expect_impl(Id, Err, Index, any = _ExpectedVarbinds) ->
request_id = ReqId,
error_status = Err2,
error_index = Index2} ->
- ?EPRINT1("received unexpected response pdu: ~w, ~w, ~w"
- "~n Expected Error: ~p"
- "~n Received Error: ~p"
- "~n Expected Index: ~p"
- "~n Received Index: ~p",
- [Type2, Id, ReqId, Err, Err2, Index, Index2]),
+ ?EPRINT("received unexpected response pdu: ~w, ~w, ~w"
+ "~n Expected Error: ~p"
+ "~n Received Error: ~p"
+ "~n Expected Index: ~p"
+ "~n Received Index: ~p",
+ [Type2, Id, ReqId, Err, Err2, Index, Index2]),
{error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
['get-response', Err, Index, ReqId]},
{"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
{error, Reason} ->
+ ?EPRINT("unexpected (receive) response: "
+ "~n ~p", [Reason]),
format_reason(Id, Reason)
end;
expect_impl(Id, Err, Index, ExpectedVarbinds) ->
- ?PRINT2("await response ~w with"
+ ?IPRINT("await response ~w with"
"~n Err: ~p"
"~n Index: ~p"
"~n ExpectedVarbinds: ~p",
@@ -1049,7 +1048,7 @@ expect_impl(Id, Err, Index, ExpectedVarbinds) ->
error_status = Err,
error_index = Index,
varbinds = VBs} ->
- ?PRINT2("received expected response pdu (~w, ~w, ~w) - check varbinds"
+ ?IPRINT("received expected response pdu (~w, ~w, ~w) - check varbinds"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[Id, Err, Index, PureVBs, VBs]),
@@ -1058,7 +1057,7 @@ expect_impl(Id, Err, Index, ExpectedVarbinds) ->
#pdu{type = 'get-response',
error_status = Err,
varbinds = VBs} when (Index == any) ->
- ?PRINT2("received expected response pdu (~w, ~w) - check varbinds"
+ ?IPRINT("received expected response pdu (~w, ~w) - check varbinds"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[Id, Err, PureVBs, VBs]),
@@ -1071,18 +1070,18 @@ expect_impl(Id, Err, Index, ExpectedVarbinds) ->
varbinds = VBs} when is_list(Index) ->
case lists:member(Idx, Index) of
true ->
- ?PRINT2("received expected pdu (~w, ~w, ~w) - check varbinds"
+ ?IPRINT("received expected pdu (~w, ~w, ~w) - check varbinds"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[Id, Err, Idx, PureVBs, VBs]),
check_vars(Id, PureVBs, VBs);
false ->
- ?EPRINT1("received response pdu with unexpected index (~w, ~w):"
- "~n Expected Index: ~p"
- "~n Received Index: ~p"
- "~n Expected VBs: ~p"
- "~n Received VBs: ~p",
- [Id, Err, Index, Idx, PureVBs, VBs]),
+ ?EPRINT("received response pdu with unexpected index (~w, ~w):"
+ "~n Expected Index: ~p"
+ "~n Received Index: ~p"
+ "~n Expected VBs: ~p"
+ "~n Received VBs: ~p",
+ [Id, Err, Index, Idx, PureVBs, VBs]),
{error,Id,
{"ErrStat: ~w, Idx: ~w, Varbinds: ~w, RequestId: ~w",
[Err,Index,PureVBs,ReqId]},
@@ -1095,15 +1094,15 @@ expect_impl(Id, Err, Index, ExpectedVarbinds) ->
error_status = Err2,
error_index = Index2,
varbinds = VBs} ->
- ?EPRINT1("received unexpected response pdu: ~w, ~w, ~w"
- "~n Expected Error: ~p"
- "~n Received Error: ~p"
- "~n Expected Index: ~p"
- "~n Received Index: ~p"
- "~n Expected VBs: ~p"
- "~n Received VBs: ~p",
- [Type2, Id, ReqId,
- Err, Err2, Index, Index2, PureVBs, VBs]),
+ ?EPRINT("received unexpected response pdu: ~w, ~w, ~w"
+ "~n Expected Error: ~p"
+ "~n Received Error: ~p"
+ "~n Expected Index: ~p"
+ "~n Received Index: ~p"
+ "~n Expected VBs: ~p"
+ "~n Received VBs: ~p",
+ [Type2, Id, ReqId,
+ Err, Err2, Index, Index2, PureVBs, VBs]),
{error,Id,
{"Type: ~w, ErrStat: ~w, Idx: ~w, Varbinds: ~w, RequestId: ~w",
['get-response',Err,Index,PureVBs,ReqId]},
@@ -1111,13 +1110,13 @@ expect_impl(Id, Err, Index, ExpectedVarbinds) ->
[Type2,Err2,Index2,VBs]}};
{error, Reason} ->
- ?EPRINT1("unexpected receive pdu error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive pdu error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end.
expect_impl(Id, trap, Enterp, Generic, Specific, ExpectedVarbinds) ->
- ?PRINT2("await trap pdu ~w with"
+ ?IPRINT("await trap pdu ~w with"
"~n Enterprise: ~p"
"~n Generic: ~p"
"~n Specific: ~p"
@@ -1130,7 +1129,7 @@ expect_impl(Id, trap, Enterp, Generic, Specific, ExpectedVarbinds) ->
generic_trap = Generic,
specific_trap = Specific,
varbinds = VBs} ->
- ?PRINT2("received expected trap pdu - check varbinds"
+ ?IPRINT("received expected trap pdu - check varbinds"
"~n Expected VBs: ~p"
"~n Received VBs: ~p",
[PureVBs, VBs]),
@@ -1140,20 +1139,20 @@ expect_impl(Id, trap, Enterp, Generic, Specific, ExpectedVarbinds) ->
generic_trap = G2,
specific_trap = Spec2,
varbinds = VBs} ->
- ?EPRINT1("received unexpected trap pdu: ~w"
- "~n Expected Enterprise: ~p"
- "~n Received Enterprise: ~p"
- "~n Expected Generic: ~p"
- "~n Received Generic: ~p"
- "~n Expected Specific: ~p"
- "~n Received Specific: ~p"
- "~n Expected VBs: ~p"
- "~n Received VBs: ~p",
- [Id,
- PureE, Ent2,
- Generic, G2,
- Specific, Spec2,
- PureVBs, VBs]),
+ ?EPRINT("received unexpected trap pdu: ~w"
+ "~n Expected Enterprise: ~p"
+ "~n Received Enterprise: ~p"
+ "~n Expected Generic: ~p"
+ "~n Received Generic: ~p"
+ "~n Expected Specific: ~p"
+ "~n Received Specific: ~p"
+ "~n Expected VBs: ~p"
+ "~n Received VBs: ~p",
+ [Id,
+ PureE, Ent2,
+ Generic, G2,
+ Specific, Spec2,
+ PureVBs, VBs]),
{error, Id,
{"Enterprise: ~w, Generic: ~w, Specific: ~w, Varbinds: ~w",
[PureE, Generic, Specific, ExpectedVarbinds]},
@@ -1161,8 +1160,8 @@ expect_impl(Id, trap, Enterp, Generic, Specific, ExpectedVarbinds) ->
[Ent2, G2, Spec2, VBs]}};
{error, Reason} ->
- ?EPRINT1("unexpected receive trap pdu error: ~w"
- "~n ~p", [Id, Reason]),
+ ?EPRINT("unexpected receive trap pdu error: ~w"
+ "~n ~p", [Id, Reason]),
format_reason(Id, Reason)
end.
@@ -1252,15 +1251,11 @@ sizeOf(L) when is_list(L) ->
sizeOf(B) when is_binary(B) ->
size(B).
+d(F) -> d(F, []).
d(F, A) -> d(get(debug), F, A).
d(true, F, A) ->
- print(F, A);
+ ?IPRINT(F, A);
d(_,_F,_A) ->
ok.
-print(F, A) ->
- ?PRINT2("MGR " ++ F, A).
-
-%% formated_timestamp() ->
-%% snmp_test_lib:formated_timestamp().
diff --git a/lib/snmp/test/snmp_test_mgr_misc.erl b/lib/snmp/test/snmp_test_mgr_misc.erl
index 6608a88c00..738f45a1b0 100644
--- a/lib/snmp/test/snmp_test_mgr_misc.erl
+++ b/lib/snmp/test/snmp_test_mgr_misc.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -102,13 +102,21 @@ init_packet(
Parent,
SnmpMgr, AgentIp, UdpPort, TrapUdp, VsnHdr, Version, Dir, BufSz,
DbgOptions, IpFamily) ->
+ %% This causes "verbosity printouts" to print (from the
+ %% specified level) in the modules we "borrow" from the
+ %% agent code (burr,,,).
+ %% With "our" name (mgr_misc).
put(sname, mgr_misc),
init_debug(DbgOptions),
+ %% Make use of the "test name" print "feature"
+ put(tname, "MGR-MISC"),
+ ?IPRINT("starting"),
UdpOpts = [{recbuf,BufSz}, {reuseaddr, true}, IpFamily],
{ok, UdpId} = gen_udp:open(TrapUdp, UdpOpts),
put(msg_id, 1),
init_usm(Version, Dir),
proc_lib:init_ack(Parent, self()),
+ ?IPRINT("started"),
packet_loop(SnmpMgr, UdpId, AgentIp, UdpPort, VsnHdr, Version, []).
init_debug(Dbg) when is_atom(Dbg) ->
@@ -601,43 +609,51 @@ set_pdu(Msg, RePdu) ->
Msg#message{data = RePdu}.
+%% Disgustingly, we borrow stuff from the agent, including the
+%% local-db. Also, disgustingly, the local-db may actually not
+%% have died yet. But since we actually *need* a clean local-db,
+%% we must make sure its dead before we try to start the new
+%% instance...
init_usm('version-3', Dir) ->
- ?vlog("init_usm -> create (and init) fake \"agent\" table", []),
+ ?IPRINT("init_usm -> create (and init) fake \"agent\" table", []),
ets:new(snmp_agent_table, [set, public, named_table]),
ets:insert(snmp_agent_table, {agent_mib_storage, persistent}),
%% The local-db process may *still* be running (from a previous
%% test case), on the way down, but not yet dead.
- %% Either way, before we start it, make sure its dead and *gone*!
+ %% Either way, before we try to start it, make sure its old instance
+ %% dead and *gone*!
%% How do we do that without getting hung up? Calling the stop
%% function, will not do since it uses Timeout=infinity.
- ?vlog("init_usm -> ensure (old) fake local-db is dead", []),
+ ?IPRINT("init_usm -> ensure (old) fake local-db is dead", []),
ensure_local_db_dead(),
- ?vlog("init_usm -> try start fake local-db", []),
+ ?IPRINT("init_usm -> try start fake local-db", []),
case snmpa_local_db:start_link(normal, Dir,
[{sname, "MGR-LOCAL-DB"},
{verbosity, trace}]) of
{ok, Pid} ->
- ?vlog("started: ~p"
- "~n ~p", [Pid, process_info(Pid)]);
+ ?IPRINT("init_usm -> local-db started: ~p"
+ "~n ~p", [Pid, process_info(Pid)]);
{error, {already_started, Pid}} ->
LDBInfo = process_info(Pid),
- ?vlog("already started: ~p"
- "~n ~p", [Pid, LDBInfo]),
+ ?EPRINT("init_usm -> local-db already started: ~p"
+ "~n ~p", [Pid, LDBInfo]),
?FAIL({still_running, snmpa_local_db, LDBInfo});
{error, Reason} ->
+ ?EPRINT("init_usm -> failed start local-db: "
+ "~n ~p", [Reason]),
?FAIL({failed_starting, snmpa_local_db, Reason})
end,
NameDb = snmpa_agent:db(snmpEngineID),
- ?vlog("init_usm -> try set manager engine-id", []),
+ ?IPRINT("init_usm -> try set manager engine-id"),
R = snmp_generic:variable_set(NameDb, "mgrEngine"),
snmp_verbosity:print(info, info, "init_usm -> engine-id set result: ~p", [R]),
- ?vlog("init_usm -> try set engine boots (framework-mib)", []),
+ ?IPRINT("init_usm -> try set engine boots (framework-mib)"),
snmp_framework_mib:set_engine_boots(1),
- ?vlog("init_usm -> try set engine time (framework-mib)", []),
+ ?IPRINT("init_usm -> try set engine time (framework-mib)"),
snmp_framework_mib:set_engine_time(1),
- ?vlog("init_usm -> try usm (mib) reconfigure", []),
+ ?IPRINT("init_usm -> try usm (mib) reconfigure"),
snmp_user_based_sm_mib:reconfigure(Dir),
- ?vlog("init_usm -> done", []),
+ ?IPRINT("init_usm -> done"),
ok;
init_usm(_Vsn, _Dir) ->
ok.
@@ -659,27 +675,28 @@ ensure_dead(Pid, Timeout) when is_pid(Pid) ->
ok
end;
ensure_dead(_, _) ->
- ?vlog("ensure_dead -> already dead", []),
+ ?IPRINT("ensure_dead -> already dead", []),
ok.
ensure_dead_wait(Pid, MRef, Timeout) ->
receive
{'DOWN', MRef, process, Pid, _Info} ->
- ?vlog("ensure_dead_wait -> died peacefully", []),
+ ?IPRINT("ensure_dead_wait -> died peacefully"),
throw(ok)
after Timeout ->
- ?vlog("ensure_dead_wait -> giving up", []),
+ ?WPRINT("ensure_dead_wait -> giving up"),
ok
end.
ensure_dead_stop(Pid, MRef, Timeout) ->
+ %% Spawn a stop'er process
StopPid = spawn(fun() -> snmpa_local_db:stop() end),
receive
{'DOWN', MRef, process, Pid, _Info} ->
- ?vlog("ensure_dead -> dead (stopped)", []),
+ ?NPRINT("ensure_dead -> dead (stopped)"),
throw(ok)
after Timeout ->
- ?vlog("ensure_dead_stop -> giving up", []),
+ ?WPRINT("ensure_dead_stop -> giving up"),
exit(StopPid, kill),
ok
end.
@@ -688,10 +705,10 @@ ensure_dead_kill(Pid, MRef, Timeout) ->
exit(Pid, kill),
receive
{'DOWN', MRef, process, Pid, _Info} ->
- ?vlog("ensure_dead -> dead (killed)", []),
+ ?NPRINT("ensure_dead -> dead (killed)"),
throw(ok)
after Timeout ->
- ?vlog("ensure_dead_kill -> giving up", []),
+ ?WPRINT("ensure_dead_kill -> giving up"),
ok
end.
@@ -891,10 +908,7 @@ d(F) -> d(F, []).
d(F,A) -> d(get(debug), F, A).
d(true, F, A) ->
- print(F, A);
+ ?IPRINT(F, A);
d(_,_F,_A) ->
ok.
-print(F, A) ->
- ?PRINT2("MGR_PS " ++ F, A).
-
diff --git a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
index 09f20ad48a..76a1967513 100644
--- a/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
+++ b/lib/snmp/test/snmp_to_snmpnet_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2014-2018. All Rights Reserved.
+%% Copyright Ericsson AB 2014-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -130,16 +130,27 @@ snmpd_cases() ->
%% -----
%%
-init_per_suite(Config) ->
- try
- begin
- Config2 = ?LIB:init_per_suite(netsnmp_init(Config)),
- snmp_test_sys_monitor:start(),
- Config2
- end
- catch
- throw:{skip, _} = SKIP ->
- SKIP
+init_per_suite(Config0) ->
+ ?IPRINT("init_per_suite -> entry with"
+ "~n Config: ~p", [Config0]),
+
+ case netsnmp_init(Config0) of
+ {skip, _} = SKIP ->
+ SKIP;
+
+ Config1 ->
+ case ?LIB:init_per_suite(Config1) of
+ {skip, _} = SKIP ->
+ SKIP;
+
+ Config2 when is_list(Config2) ->
+ snmp_test_sys_monitor:start(),
+
+ ?IPRINT("init_per_suite -> end when"
+ "~n Config: ~p", [Config2]),
+
+ Config2
+ end
end.
netsnmp_init(Config) ->
@@ -150,10 +161,10 @@ netsnmp_init(Config) ->
[{agent_port, ?AGENT_PORT},
{manager_port, ?MANAGER_PORT} | Config];
false ->
- throw({skip, "Buggy NetSNMP"})
+ {skip, "Buggy NetSNMP"}
end;
false ->
- throw({skip, "No NetSNMP"})
+ {skip, "No NetSNMP"}
end.
has_netsnmp() ->
@@ -172,9 +183,15 @@ netsnmp_check(RE) ->
end_per_suite(Config) ->
+ ?IPRINT("end_per_suite -> entry with"
+ "~n Config: ~p", [Config]),
+
snmp_test_sys_monitor:stop(),
- ?LIB:end_per_suite(Config).
+ ?LIB:end_per_suite(Config),
+ ?IPRINT("end_per_suite -> end"),
+
+ Config.
%%
%% -----
@@ -208,7 +225,7 @@ init_per_group(_, Config) ->
Config.
init_per_group_ipv6(Families, Config) ->
- case ?LIB:has_support_ipv6() of
+ case ?HAS_SUPPORT_IPV6() of
true ->
init_per_group_ip(Families, Config);
false ->
@@ -256,17 +273,27 @@ end_per_group(_GroupName, Config) ->
%%
init_per_testcase(_Case, Config) ->
+ ?IPRINT("init_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
snmp_test_global_sys_monitor:reset_events(),
- Dog = ct:timetrap(20000),
+ Dog = ct:timetrap(?SECS(20)),
application:stop(snmp),
application:unload(snmp),
- [{watchdog, Dog} | Config].
+ Config1 = [{watchdog, Dog} | Config],
+
+ ?IPRINT("init_per_testcase -> done when"
+ "~n Config: ~p", [Config1]),
+
+ Config1.
end_per_testcase(_, Config) ->
- ?PRINT2("system events during test: "
+ ?IPRINT("end_per_testcase -> entry with"
+ "~n Config: ~p", [Config]),
+
+ ?IPRINT("system events during test: "
"~n ~p", [snmp_test_global_sys_monitor:events()]),
case application:stop(snmp) of
@@ -281,6 +308,10 @@ end_per_testcase(_, Config) ->
E2 ->
ct:pal("application:unload(snmp) -> ~p", [E2])
end,
+
+ ?IPRINT("end_per_testcase -> done with"
+ "~n Config: ~p", [Config]),
+
Config.
find_executable(Exec, Config) ->
diff --git a/lib/ssh/doc/src/notes.xml b/lib/ssh/doc/src/notes.xml
index b5a718c0b9..e79cbaa336 100644
--- a/lib/ssh/doc/src/notes.xml
+++ b/lib/ssh/doc/src/notes.xml
@@ -30,6 +30,35 @@
<file>notes.xml</file>
</header>
+<section><title>Ssh 4.8.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed that <c>ssh_connection:send</c> could allocate a
+ large amount of memory if given an iolist() as input
+ data.</p>
+ <p>
+ Own Id: OTP-16373</p>
+ </item>
+ <item>
+ <p>
+ Safe atom conversions.</p>
+ <p>
+ Own Id: OTP-16375</p>
+ </item>
+ <item>
+ <p>
+ Constant time comparisons added.</p>
+ <p>
+ Own Id: OTP-16376</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.8.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -235,6 +264,35 @@
</section>
+<section><title>Ssh 4.7.6.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed that <c>ssh_connection:send</c> could allocate a
+ large amount of memory if given an iolist() as input
+ data.</p>
+ <p>
+ Own Id: OTP-16373</p>
+ </item>
+ <item>
+ <p>
+ Safe atom conversions.</p>
+ <p>
+ Own Id: OTP-16375</p>
+ </item>
+ <item>
+ <p>
+ Constant time comparisons added.</p>
+ <p>
+ Own Id: OTP-16376</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.7.6.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -610,6 +668,50 @@
</section>
</section>
+<section><title>Ssh 4.6.9.7</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed possible hanging in <c>ssh_sftp:stop_channel/1</c>.</p>
+ <p>
+ Own Id: OTP-16507 Aux Id: ERIERL-470 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>Ssh 4.6.9.6</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fixed that <c>ssh_connection:send</c> could allocate a
+ large amount of memory if given an iolist() as input
+ data.</p>
+ <p>
+ Own Id: OTP-16373</p>
+ </item>
+ <item>
+ <p>
+ Safe atom conversions.</p>
+ <p>
+ Own Id: OTP-16375</p>
+ </item>
+ <item>
+ <p>
+ Constant time comparisons added.</p>
+ <p>
+ Own Id: OTP-16376</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>Ssh 4.6.9.5</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssh/doc/src/ssh.xml b/lib/ssh/doc/src/ssh.xml
index aa0fbe376c..862f79ac56 100644
--- a/lib/ssh/doc/src/ssh.xml
+++ b/lib/ssh/doc/src/ssh.xml
@@ -1196,6 +1196,41 @@
</desc>
</func>
+<!-- SET_SOCK_OPTS/2 -->
+ <func>
+ <name name="set_sock_opts" arity="2" since=""/>
+ <fsummary>Set tcp socket options on connections</fsummary>
+ <desc>
+ <p>Sets tcp socket options on the tcp-socket below an ssh connection.</p>
+ <p>This function calls the
+ <seealso marker="kernel:inet#setopts/2">inet:setopts/2</seealso>, read that documentation and
+ for <seealso marker="kernel:gen_tcp#type-option">gen_tcp:option()</seealso>.
+ All gen_tcp socket options except <c>active</c>, <c>deliver</c>, <c>mode</c> and <c>packet</c>
+ are allowed. The excluded options are reserved by the SSH application.
+ </p>
+ <warning>
+ <p>This is an extremly dangerous function. You use it on your own risk.</p>
+ <p>Some options are OS and OS version dependent.
+ Do not use it unless you know what effect your option values will have
+ on an TCP stream.</p>
+ <p>Some values may destroy the functionality of the SSH protocol.
+ </p>
+ </warning>
+ </desc>
+ </func>
+
+<!-- GET_SOCK_OPTS/2 -->
+ <func>
+ <name name="get_sock_opts" arity="2" since=""/>
+ <fsummary>Get tcp socket options on connections</fsummary>
+ <desc>
+ <p>Get tcp socket option values of the tcp-socket below an ssh connection.</p>
+ <p>This function calls the
+ <seealso marker="kernel:inet#getopts/2">inet:getopts/2</seealso>, read that documentation.
+ </p>
+ </desc>
+ </func>
+
<!-- DEAMON/1,2,3 -->
<func>
<name since="">daemon(Port | TcpSocket) -> Result</name>
diff --git a/lib/ssh/src/Makefile b/lib/ssh/src/Makefile
index 9627b70eeb..f5c520f2f0 100644
--- a/lib/ssh/src/Makefile
+++ b/lib/ssh/src/Makefile
@@ -39,7 +39,13 @@ RELSYSDIR = $(RELEASE_PATH)/lib/ssh-$(VSN)
# Behaviour (api) modules are first so they are compiled when
# the compiler reaches a callback module using them.
-BEHAVIOUR_MODULES= \
+# The $(BEHAVIOUR_MODULES_1) has a behaviour used in one or more
+# of the $(BEHAVIOUR_MODULES_2)
+
+BEHAVIOUR_MODULES_1= \
+ ssh_dbg
+
+BEHAVIOUR_MODULES_2= \
ssh_client_key_api \
ssh_daemon_channel \
ssh_server_channel \
@@ -59,7 +65,6 @@ MODULES= \
ssh_connection \
ssh_connection_handler \
ssh_connection_sup \
- ssh_dbg \
ssh_file \
ssh_info \
ssh_io \
@@ -83,12 +88,15 @@ HRL_FILES =
ERL_FILES= \
$(MODULES:%=%.erl) \
- $(BEHAVIOUR_MODULES:%=%.erl)
+ $(BEHAVIOUR_MODULES_1:%=%.erl) \
+ $(BEHAVIOUR_MODULES_2:%=%.erl)
TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR))
-BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_MODULES:%=$(EBIN)/%.$(EMULATOR))
+BEHAVIOUR_TARGET_FILES_1= $(BEHAVIOUR_MODULES_1:%=$(EBIN)/%.$(EMULATOR))
+BEHAVIOUR_TARGET_FILES_2= $(BEHAVIOUR_MODULES_2:%=$(EBIN)/%.$(EMULATOR))
+BEHAVIOUR_TARGET_FILES= $(BEHAVIOUR_TARGET_FILES_1) $(BEHAVIOUR_TARGET_FILES_2)
APP_FILE= ssh.app
APPUP_FILE= ssh.appup
@@ -115,7 +123,8 @@ ERL_COMPILE_FLAGS += -I$(ERL_TOP)/lib/kernel/src \
# Targets
# ----------------------------------------------------
-$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES)
+$(TARGET_FILES): $(BEHAVIOUR_TARGET_FILES_2)
+$(BEHAVIOUR_TARGET_FILES_2): $(BEHAVIOUR_TARGET_FILES_1)
debug opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
diff --git a/lib/ssh/src/ssh.app.src b/lib/ssh/src/ssh.app.src
index 2193c14611..21e3604400 100644
--- a/lib/ssh/src/ssh.app.src
+++ b/lib/ssh/src/ssh.app.src
@@ -44,10 +44,9 @@
{env, []},
{mod, {ssh_app, []}},
{runtime_dependencies, [
- "crypto-4.5",
+ "crypto-4.6.4",
"erts-9.0",
"kernel-5.3",
"public_key-1.6.1",
"stdlib-3.4.1"
]}]}.
-
diff --git a/lib/ssh/src/ssh.erl b/lib/ssh/src/ssh.erl
index c93b796078..355b40eea8 100644
--- a/lib/ssh/src/ssh.erl
+++ b/lib/ssh/src/ssh.erl
@@ -35,6 +35,7 @@
channel_info/3,
daemon/1, daemon/2, daemon/3,
daemon_info/1, daemon_info/2,
+ set_sock_opts/2, get_sock_opts/2,
default_algorithms/0,
chk_algos_opts/1,
stop_listener/1, stop_listener/2, stop_listener/3,
@@ -560,6 +561,25 @@ chk_algos_opts(Opts) ->
{error, {non_algo_opts_found,OtherOps}}
end.
+
+%%--------------------------------------------------------------------
+-spec set_sock_opts(ConnectionRef, SocketOptions) ->
+ ok | {error, inet:posix()} when
+ ConnectionRef :: connection_ref(),
+ SocketOptions :: [gen_tcp:option()] .
+%%--------------------------------------------------------------------
+set_sock_opts(ConnectionRef, SocketOptions) ->
+ ssh_connection_handler:set_sock_opts(ConnectionRef, SocketOptions).
+
+%%--------------------------------------------------------------------
+-spec get_sock_opts(ConnectionRef, SocketGetOptions) ->
+ ok | {error, inet:posix()} when
+ ConnectionRef :: connection_ref(),
+ SocketGetOptions :: [gen_tcp:option_name()] .
+%%--------------------------------------------------------------------
+get_sock_opts(ConnectionRef, SocketGetOptions) ->
+ ssh_connection_handler:get_sock_opts(ConnectionRef, SocketGetOptions).
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
diff --git a/lib/ssh/src/ssh.hrl b/lib/ssh/src/ssh.hrl
index 86c447f695..a9d81f7252 100644
--- a/lib/ssh/src/ssh.hrl
+++ b/lib/ssh/src/ssh.hrl
@@ -87,6 +87,9 @@
-define(Empint(X), (ssh_bits:mpint(X))/binary ).
-define(Ebinary(X), ?STRING(X) ).
+%% Other macros
+-define(to_binary(X), (try iolist_to_binary(X) catch _:_ -> unicode:characters_to_binary(X) end) ).
+
%% Cipher details
-define(SSH_CIPHER_NONE, 0).
-define(SSH_CIPHER_3DES, 3).
diff --git a/lib/ssh/src/ssh_acceptor.erl b/lib/ssh/src/ssh_acceptor.erl
index 11ce80354e..dae34f858f 100644
--- a/lib/ssh/src/ssh_acceptor.erl
+++ b/lib/ssh/src/ssh_acceptor.erl
@@ -33,7 +33,8 @@
%% spawn export
-export([acceptor_init/5, acceptor_loop/6]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
-define(SLEEP_TIME, 200).
@@ -202,18 +203,21 @@ handle_error(Reason) ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [connections];
+ssh_dbg_trace_points() -> [connections].
-dbg_trace(flags, connections, _) -> [c];
-dbg_trace(on, connections, _) -> dbg:tp(?MODULE, acceptor_init, 5, x),
- dbg:tpl(?MODULE, handle_connection, 5, x);
-dbg_trace(off, connections, _) -> dbg:ctp(?MODULE, acceptor_init, 5),
- dbg:ctp(?MODULE, handle_connection, 5);
-dbg_trace(format, connections, {call, {?MODULE,acceptor_init,
- [_Parent, Port, Address, _Opts, _AcceptTimeout]}}) ->
+ssh_dbg_flags(connections) -> [c].
+
+ssh_dbg_on(connections) -> dbg:tp(?MODULE, acceptor_init, 5, x),
+ dbg:tpl(?MODULE, handle_connection, 5, x).
+
+ssh_dbg_off(connections) -> dbg:ctp(?MODULE, acceptor_init, 5),
+ dbg:ctp(?MODULE, handle_connection, 5).
+
+ssh_dbg_format(connections, {call, {?MODULE,acceptor_init,
+ [_Parent, Port, Address, _Opts, _AcceptTimeout]}}) ->
[io_lib:format("Starting LISTENER on ~s:~p\n", [ntoa(Address),Port])
];
-dbg_trace(format, connections, {return_from, {?MODULE,handle_connection,5}, {error,Error}}) ->
+ssh_dbg_format(connections, {return_from, {?MODULE,handle_connection,5}, {error,Error}}) ->
["Starting connection to server failed:\n",
io_lib:format("Error = ~p", [Error])
].
diff --git a/lib/ssh/src/ssh_auth.erl b/lib/ssh/src/ssh_auth.erl
index 9632168e65..b9813b6b5c 100644
--- a/lib/ssh/src/ssh_auth.erl
+++ b/lib/ssh/src/ssh_auth.erl
@@ -462,7 +462,7 @@ check_password(User, Password, Opts, Ssh) ->
case ?GET_OPT(pwdfun, Opts) of
undefined ->
Static = get_password_option(Opts, User),
- {Password == Static, Ssh};
+ {crypto:equal_const_time(Password,Static), Ssh};
Checker when is_function(Checker,2) ->
{Checker(User, Password), Ssh};
diff --git a/lib/ssh/src/ssh_cli.erl b/lib/ssh/src/ssh_cli.erl
index 7f04fcb804..0345eaf0eb 100644
--- a/lib/ssh/src/ssh_cli.erl
+++ b/lib/ssh/src/ssh_cli.erl
@@ -33,7 +33,8 @@
%% ssh_server_channel callbacks
-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
%% state
-record(state, {
@@ -651,12 +652,15 @@ not_zero(A, _) ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [terminate];
+ssh_dbg_trace_points() -> [terminate].
-dbg_trace(flags, terminate, _) -> [c];
-dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
-dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
-dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ssh_dbg_flags(terminate) -> [c].
+
+ssh_dbg_on(terminate) -> dbg:tp(?MODULE, terminate, 2, x).
+
+ssh_dbg_off(terminate) -> dbg:ctpg(?MODULE, terminate, 2).
+
+ssh_dbg_format(terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
["Cli Terminating:\n",
io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
].
diff --git a/lib/ssh/src/ssh_client_channel.erl b/lib/ssh/src/ssh_client_channel.erl
index 3bd1e1fdf1..605f71b8ac 100644
--- a/lib/ssh/src/ssh_client_channel.erl
+++ b/lib/ssh/src/ssh_client_channel.erl
@@ -72,7 +72,8 @@
cache_info/2, cache_find/2,
get_print_info/1]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
-record(state, {
cm,
@@ -388,64 +389,64 @@ adjust_window(_) ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [terminate, channels, channel_events];
+ssh_dbg_trace_points() -> [terminate, channels, channel_events].
+ssh_dbg_flags(channels) -> [c];
+ssh_dbg_flags(terminate) -> [c];
+ssh_dbg_flags(channel_events) -> [c].
-dbg_trace(flags, channels, A) -> [c] ++ dbg_trace(flags, terminate, A);
-dbg_trace(on, channels, A) -> dbg:tp(?MODULE, init, 1, x),
- dbg_trace(on, terminate, A);
-dbg_trace(off, channels, A) -> dbg:ctpg(?MODULE, init, 1),
- dbg_trace(off, terminate, A);
-dbg_trace(format, channels, {call, {?MODULE,init, [[KVs]]}}) ->
+ssh_dbg_on(terminate) -> dbg:tp(?MODULE, terminate, 2, x);
+ssh_dbg_on(channels) -> dbg:tp(?MODULE, init, 1, x),
+ ssh_dbg_on(terminate);
+ssh_dbg_on(channel_events) -> dbg:tp(?MODULE, handle_call, 3, x),
+ dbg:tp(?MODULE, handle_cast, 2, x),
+ dbg:tp(?MODULE, handle_info, 2, x).
+
+ssh_dbg_off(terminate) -> dbg:ctpg(?MODULE, terminate, 2);
+ssh_dbg_off(channels) -> dbg:ctpg(?MODULE, init, 1),
+ ssh_dbg_off(terminate);
+ssh_dbg_off(channel_events) -> dbg:ctpg(?MODULE, handle_call, 3),
+ dbg:ctpg(?MODULE, handle_cast, 2),
+ dbg:ctpg(?MODULE, handle_info, 2).
+
+ssh_dbg_format(channels, {call, {?MODULE,init, [[KVs]]}}) ->
["Server Channel Starting:\n",
io_lib:format("Connection: ~p, ChannelId: ~p, CallBack: ~p\nCallBack init args = ~p",
[proplists:get_value(K,KVs) || K <- [cm, channel_id, channel_cb]]
++ [channel_cb_init_args(KVs)])
];
-dbg_trace(format, channels, {return_from, {?MODULE,init,1}, {stop,Reason}}) ->
+ssh_dbg_format(channels, {return_from, {?MODULE,init,1}, {stop,Reason}}) ->
["Server Channel Start FAILED!\n",
io_lib:format("Reason = ~p", [Reason])
];
-dbg_trace(format, channels, F) ->
- dbg_trace(format, terminate, F);
-
-
-dbg_trace(flags, terminate, _) -> [c];
-dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
-dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
-dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ssh_dbg_format(channels, F) ->
+ ssh_dbg_format(terminate, F);
+ssh_dbg_format(terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
["Server Channel Terminating:\n",
io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
];
-dbg_trace(flags, channel_events, _) -> [c];
-dbg_trace(on, channel_events, _) -> dbg:tp(?MODULE, handle_call, 3, x),
- dbg:tp(?MODULE, handle_cast, 2, x),
- dbg:tp(?MODULE, handle_info, 2, x);
-dbg_trace(off, channel_events, _) -> dbg:ctpg(?MODULE, handle_call, 3),
- dbg:ctpg(?MODULE, handle_cast, 2),
- dbg:ctpg(?MODULE, handle_info, 2);
-dbg_trace(format, channel_events, {call, {?MODULE,handle_call, [Call,From,State]}}) ->
+ssh_dbg_format(channel_events, {call, {?MODULE,handle_call, [Call,From,State]}}) ->
[hdr("is called", State),
io_lib:format("From: ~p~nCall: ~p~n", [From, Call])
];
-dbg_trace(format, channel_events, {return_from, {?MODULE,handle_call,3}, Ret}) ->
+ssh_dbg_format(channel_events, {return_from, {?MODULE,handle_call,3}, Ret}) ->
["Server Channel call returned:\n",
io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)])
];
-dbg_trace(format, channel_events, {call, {?MODULE,handle_cast, [Cast,State]}}) ->
+ssh_dbg_format(channel_events, {call, {?MODULE,handle_cast, [Cast,State]}}) ->
[hdr("got cast", State),
io_lib:format("Cast: ~p~n", [Cast])
];
-dbg_trace(format, channel_events, {return_from, {?MODULE,handle_cast,2}, Ret}) ->
+ssh_dbg_format(channel_events, {return_from, {?MODULE,handle_cast,2}, Ret}) ->
["Server Channel cast returned:\n",
io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)])
];
-dbg_trace(format, channel_events, {call, {?MODULE,handle_info, [Info,State]}}) ->
+ssh_dbg_format(channel_events, {call, {?MODULE,handle_info, [Info,State]}}) ->
[hdr("got info", State),
io_lib:format("Info: ~p~n", [Info])
];
-dbg_trace(format, channel_events, {return_from, {?MODULE,handle_info,2}, Ret}) ->
+ssh_dbg_format(channel_events, {return_from, {?MODULE,handle_info,2}, Ret}) ->
["Server Channel info returned:\n",
io_lib:format("~p~n", [ssh_dbg:reduce_state(Ret)])
].
diff --git a/lib/ssh/src/ssh_connection.erl b/lib/ssh/src/ssh_connection.erl
index 73aeda8efc..380faeb11e 100644
--- a/lib/ssh/src/ssh_connection.erl
+++ b/lib/ssh/src/ssh_connection.erl
@@ -417,12 +417,7 @@ channel_data(ChannelId, DataType, Data0,
From) ->
case ssh_client_channel:cache_lookup(Cache, ChannelId) of
#channel{remote_id = Id, sent_close = false} = Channel0 ->
- Data =
- try iolist_to_binary(Data0)
- catch
- _:_ ->
- unicode:characters_to_binary(Data0)
- end,
+ Data = ?to_binary(Data0),
{SendList, Channel} =
update_send_window(Channel0#channel{flow_control = From}, DataType,
Data, Connection),
diff --git a/lib/ssh/src/ssh_connection_handler.erl b/lib/ssh/src/ssh_connection_handler.erl
index ad5a54a2e2..e8c0d88e59 100644
--- a/lib/ssh/src/ssh_connection_handler.erl
+++ b/lib/ssh/src/ssh_connection_handler.erl
@@ -57,7 +57,8 @@
channel_info/3,
adjust_window/3, close/2,
disconnect/4,
- get_print_info/1
+ get_print_info/1,
+ set_sock_opts/2, get_sock_opts/2
]).
-type connection_ref() :: ssh:connection_ref().
@@ -74,7 +75,8 @@
renegotiate/1, alg/1 % Export intended for test cases
]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
-define(send_disconnect(Code, DetailedText, StateName, State),
@@ -320,6 +322,31 @@ close(ConnectionHandler, ChannelId) ->
ok
end.
+
+%%--------------------------------------------------------------------
+%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+set_sock_opts(ConnectionRef, SocketOptions) ->
+ try lists:foldr(fun({Name,_Val}, Acc) ->
+ case lists:member(Name, [active, deliver, mode, packet]) of
+ true -> [Name|Acc];
+ false -> Acc
+ end
+ end, [], SocketOptions)
+ of
+ [] ->
+ call(ConnectionRef, {set_sock_opts,SocketOptions});
+ Bad ->
+ {error, {not_allowed,Bad}}
+ catch
+ _:_ ->
+ {error, badarg}
+ end.
+
+%%--------------------------------------------------------------------
+%% . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
+get_sock_opts(ConnectionRef, SocketGetOptions) ->
+ call(ConnectionRef, {get_sock_opts,SocketGetOptions}).
+
%%====================================================================
%% Test support
%%====================================================================
@@ -1204,6 +1231,20 @@ handle_event({call,From}, {info, ChannelPid}, _, D) ->
end, [], cache(D)),
{keep_state_and_data, [{reply, From, {ok,Result}}]};
+handle_event({call,From}, {set_sock_opts,SocketOptions}, _StateName, D) ->
+ Result = try inet:setopts(D#data.socket, SocketOptions)
+ catch
+ _:_ -> {error, badarg}
+ end,
+ {keep_state_and_data, [{reply,From,Result}]};
+
+handle_event({call,From}, {get_sock_opts,SocketGetOptions}, _StateName, D) ->
+ Result = try inet:getopts(D#data.socket, SocketGetOptions)
+ catch
+ _:_ -> {error, badarg}
+ end,
+ {keep_state_and_data, [{reply,From,Result}]};
+
handle_event({call,From}, stop, _StateName, D0) ->
{Repls,D} = send_replies(ssh_connection:handle_stop(D0#data.connection_state), D0),
{stop_and_reply, normal, [{reply,From,ok}|Repls], D};
@@ -2284,14 +2325,37 @@ update_inet_buffers(Socket) ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [terminate, disconnect, connections, connection_events, renegotiation];
-
-dbg_trace(flags, connections, A) -> [c] ++ dbg_trace(flags, terminate, A);
-dbg_trace(on, connections, A) -> dbg:tp(?MODULE, init_connection_handler, 3, x),
- dbg_trace(on, terminate, A);
-dbg_trace(off, connections, A) -> dbg:ctpg(?MODULE, init_connection_handler, 3),
- dbg_trace(off, terminate, A);
-dbg_trace(format, connections, {call, {?MODULE,init_connection_handler, [Role, Sock, Opts]}}) ->
+ssh_dbg_trace_points() -> [terminate, disconnect, connections, connection_events, renegotiation].
+
+ssh_dbg_flags(connections) -> [c | ssh_dbg_flags(terminate)];
+ssh_dbg_flags(renegotiation) -> [c];
+ssh_dbg_flags(connection_events) -> [c];
+ssh_dbg_flags(terminate) -> [c];
+ssh_dbg_flags(disconnect) -> [c].
+
+ssh_dbg_on(connections) -> dbg:tp(?MODULE, init_connection_handler, 3, x),
+ ssh_dbg_on(terminate);
+ssh_dbg_on(connection_events) -> dbg:tp(?MODULE, handle_event, 4, x);
+ssh_dbg_on(renegotiation) -> dbg:tpl(?MODULE, init_renegotiate_timers, 2, x),
+ dbg:tpl(?MODULE, pause_renegotiate_timers, 2, x),
+ dbg:tpl(?MODULE, check_data_rekeying_dbg, 2, x),
+ dbg:tpl(?MODULE, start_rekeying, 2, x);
+ssh_dbg_on(terminate) -> dbg:tp(?MODULE, terminate, 3, x);
+ssh_dbg_on(disconnect) -> dbg:tpl(?MODULE, send_disconnect, 7, x).
+
+
+ssh_dbg_off(disconnect) -> dbg:ctpl(?MODULE, send_disconnect, 7);
+ssh_dbg_off(terminate) -> dbg:ctpg(?MODULE, terminate, 3);
+ssh_dbg_off(renegotiation) -> dbg:ctpl(?MODULE, init_renegotiate_timers, 2),
+ dbg:ctpl(?MODULE, pause_renegotiate_timers, 2),
+ dbg:ctpl(?MODULE, check_data_rekeying_dbg, 2),
+ dbg:ctpl(?MODULE, start_rekeying, 2);
+ssh_dbg_off(connection_events) -> dbg:ctpg(?MODULE, handle_event, 4);
+ssh_dbg_off(connections) -> dbg:ctpg(?MODULE, init_connection_handler, 3),
+ ssh_dbg_off(terminate).
+
+
+ssh_dbg_format(connections, {call, {?MODULE,init_connection_handler, [Role, Sock, Opts]}}) ->
DefaultOpts = ssh_options:handle_options(Role,[]),
ExcludedKeys = [internal_options, user_options],
NonDefaultOpts =
@@ -2312,41 +2376,29 @@ dbg_trace(format, connections, {call, {?MODULE,init_connection_handler, [Role, S
[Sock,inet:ntoa(IPp),Portp,inet:ntoa(IPs),Ports,
NonDefaultOpts])
];
-dbg_trace(format, connections, F) ->
- dbg_trace(format, terminate, F);
+ssh_dbg_format(connections, F) ->
+ ssh_dbg_format(terminate, F);
-dbg_trace(flags, connection_events, _) -> [c];
-dbg_trace(on, connection_events, _) -> dbg:tp(?MODULE, handle_event, 4, x);
-dbg_trace(off, connection_events, _) -> dbg:ctpg(?MODULE, handle_event, 4);
-dbg_trace(format, connection_events, {call, {?MODULE,handle_event, [EventType, EventContent, State, _Data]}}) ->
+ssh_dbg_format(connection_events, {call, {?MODULE,handle_event, [EventType, EventContent, State, _Data]}}) ->
["Connection event\n",
io_lib:format("EventType: ~p~nEventContent: ~p~nState: ~p~n", [EventType, EventContent, State])
];
-dbg_trace(format, connection_events, {return_from, {?MODULE,handle_event,4}, Ret}) ->
+ssh_dbg_format(connection_events, {return_from, {?MODULE,handle_event,4}, Ret}) ->
["Connection event result\n",
io_lib:format("~p~n", [event_handler_result(Ret)])
];
-dbg_trace(flags, renegotiation, _) -> [c];
-dbg_trace(on, renegotiation, _) -> dbg:tpl(?MODULE, init_renegotiate_timers, 2, x),
- dbg:tpl(?MODULE, pause_renegotiate_timers, 2, x),
- dbg:tpl(?MODULE, check_data_rekeying_dbg, 2, x),
- dbg:tpl(?MODULE, start_rekeying, 2, x);
-dbg_trace(off, renegotiation, _) -> dbg:ctpl(?MODULE, init_renegotiate_timers, 2),
- dbg:ctpl(?MODULE, pause_renegotiate_timers, 2),
- dbg:ctpl(?MODULE, check_data_rekeying_dbg, 2),
- dbg:ctpl(?MODULE, start_rekeying, 2);
-dbg_trace(format, renegotiation, {call, {?MODULE,init_renegotiate_timers,[_State,D]}}) ->
+ssh_dbg_format(renegotiation, {call, {?MODULE,init_renegotiate_timers,[_State,D]}}) ->
["Renegotiation init\n",
io_lib:format("rekey_limit: ~p ({ms,bytes})~ncheck_data_size: ~p (ms)~n",
[?GET_OPT(rekey_limit, (D#data.ssh_params)#ssh.opts),
?REKEY_DATA_TIMOUT])
];
-dbg_trace(format, renegotiation, {call, {?MODULE,pause_renegotiate_timers,[_State,_D]}}) ->
+ssh_dbg_format(renegotiation, {call, {?MODULE,pause_renegotiate_timers,[_State,_D]}}) ->
["Renegotiation pause\n"];
-dbg_trace(format, renegotiation, {call, {?MODULE,start_rekeying,[_Role,_D]}}) ->
+ssh_dbg_format(renegotiation, {call, {?MODULE,start_rekeying,[_Role,_D]}}) ->
["Renegotiation start rekeying\n"];
-dbg_trace(format, renegotiation, {call, {?MODULE,check_data_rekeying_dbg,[SentSinceRekey, MaxSent]}}) ->
+ssh_dbg_format(renegotiation, {call, {?MODULE,check_data_rekeying_dbg,[SentSinceRekey, MaxSent]}}) ->
["Renegotiation check data sent\n",
io_lib:format("TotalSentSinceRekey: ~p~nMaxBeforeRekey: ~p~nStartRekey: ~p~n",
[SentSinceRekey, MaxSent, SentSinceRekey >= MaxSent])
@@ -2354,10 +2406,7 @@ dbg_trace(format, renegotiation, {call, {?MODULE,check_data_rekeying_dbg,[SentSi
-dbg_trace(flags, terminate, _) -> [c];
-dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 3, x);
-dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 3);
-dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, StateName, D]}}) ->
+ssh_dbg_format(terminate, {call, {?MODULE,terminate, [Reason, StateName, D]}}) ->
ExtraInfo =
try
{conn_info(peer,D),
@@ -2390,11 +2439,8 @@ dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, StateName, D]}}
]
end;
-dbg_trace(flags, disconnect, _) -> [c];
-dbg_trace(on, disconnect, _) -> dbg:tpl(?MODULE, send_disconnect, 7, x);
-dbg_trace(off, disconnect, _) -> dbg:ctpl(?MODULE, send_disconnect, 7);
-dbg_trace(format, disconnect, {call,{?MODULE,send_disconnect,
- [Code, Reason, DetailedText, Module, Line, StateName, _D]}}) ->
+ssh_dbg_format(disconnect, {call,{?MODULE,send_disconnect,
+ [Code, Reason, DetailedText, Module, Line, StateName, _D]}}) ->
["Disconnecting:\n",
io_lib:format(" Module = ~p, Line = ~p, StateName = ~p,~n"
" Code = ~p, Reason = ~p,~n"
diff --git a/lib/ssh/src/ssh_dbg.erl b/lib/ssh/src/ssh_dbg.erl
index 43ac4c0ccf..7b7f9909ac 100644
--- a/lib/ssh/src/ssh_dbg.erl
+++ b/lib/ssh/src/ssh_dbg.erl
@@ -80,6 +80,15 @@
-define(CALL_TIMEOUT, 15000). % 3x the default
+-type trace_point() :: atom().
+-type trace_points() :: [trace_point()].
+
+-callback ssh_dbg_trace_points() -> trace_points().
+-callback ssh_dbg_flags(trace_point()) -> [atom()].
+-callback ssh_dbg_on(trace_point() | trace_points()) -> term().
+-callback ssh_dbg_off(trace_point() | trace_points()) -> term().
+-callback ssh_dbg_format(trace_point(), term()) -> iolist().
+
%%%================================================================
-define(ALL_DBG_TYPES, get_all_dbg_types()).
@@ -170,13 +179,13 @@ init(_) ->
%%%----------------------------------------------------------------
handle_call({switch,on,Types}, _From, D) ->
NowOn = lists:usort(Types ++ D#data.types_on),
- call_modules(on, Types, NowOn),
+ call_modules(on, Types),
{reply, {ok,NowOn}, D#data{types_on = NowOn}};
handle_call({switch,off,Types}, _From, D) ->
StillOn = D#data.types_on -- Types,
- call_modules(off, Types, StillOn),
- call_modules(on, StillOn, StillOn),
+ call_modules(off, Types),
+ call_modules(on, StillOn),
{reply, {ok,StillOn}, D#data{types_on = StillOn}};
handle_call(get_on, _From, D) ->
@@ -202,52 +211,54 @@ handle_info(C, D) ->
ssh_modules_with_trace() ->
{ok,AllSshModules} = application:get_key(ssh, modules),
[M || M <- AllSshModules,
- lists:member({dbg_trace,3}, M:module_info(exports))].
+ {behaviour,Bs} <- M:module_info(attributes),
+ lists:member(?MODULE, Bs)
+ ].
%%%----------------------------------------------------------------
get_all_trace_flags() ->
- get_all_trace_flags(ssh_modules_with_trace()).
-
-get_all_trace_flags(Modules) ->
lists:usort(
- lists:flatten(
- lists:foldl(
- fun(Type, Acc) ->
- call_modules(flags, Type, undefined, Acc, Modules)
- end, [timestamp], ?ALL_DBG_TYPES))).
+ lists:flatten([timestamp | call_modules(flags, ?ALL_DBG_TYPES)]
+ )).
%%%----------------------------------------------------------------
get_all_dbg_types() ->
lists:usort(
lists:flatten(
- call_modules(points, undefined) )).
+ call_modules(points) )).
%%%----------------------------------------------------------------
-call_modules(Cmnd, Type) ->
- call_modules(Cmnd, Type, undefined).
-
-call_modules(Cmnd, Type, Arg) ->
- call_modules(Cmnd, Type, Arg, []).
+call_modules(points) ->
+ F = fun(Mod) -> Mod:ssh_dbg_trace_points() end,
+ fold_modules(F, [], ssh_modules_with_trace()).
+
+call_modules(Cmnd, Types) when is_list(Types) ->
+ F = case Cmnd of
+ flags -> fun(Type) ->
+ fun(Mod) -> Mod:ssh_dbg_flags(Type) end
+ end;
+ on -> fun(Type) ->
+ fun(Mod) -> Mod:ssh_dbg_on(Type) end
+ end;
+ off -> fun(Type) ->
+ fun(Mod) -> Mod:ssh_dbg_off(Type) end
+ end
+ end,
+ lists:foldl(fun(T, Acc) ->
+ fold_modules(F(T), Acc, ssh_modules_with_trace())
+ end, [], Types).
-call_modules(Cmnd, Type, Arg, Acc0) ->
- call_modules(Cmnd, Type, Arg, Acc0, ssh_modules_with_trace()).
-call_modules(Cmnd, Types, Arg, Acc0, Modules) when is_list(Types) ->
- lists:foldl(
- fun(Type, Acc) ->
- call_modules(Cmnd, Type, Arg, Acc, Modules)
- end, Acc0, Types);
-call_modules(Cmnd, Type, Arg, Acc0, Modules) ->
- lists:foldl(
- fun(Mod, Acc) ->
- try Mod:dbg_trace(Cmnd, Type, Arg)
- of
- Result -> [Result|Acc]
- catch
- _:_ -> Acc
- end
- end, Acc0, Modules).
+fold_modules(F, Acc0, Modules) ->
+ lists:foldl(
+ fun(Mod, Acc) ->
+ try F(Mod) of
+ Result -> [Result|Acc]
+ catch
+ _:_ -> Acc
+ end
+ end, Acc0, Modules).
%%%----------------------------------------------------------------
switch(X, Type) when is_atom(Type) ->
@@ -314,7 +325,9 @@ try_all_types_in_all_modules(TypesOn, Arg, WriteFun, Acc0) ->
lists:foldl(
fun(SshMod,Acc) ->
try WriteFun("~n~s ~p ~s~n",
- [lists:flatten(TS), PID, lists:flatten(SshMod:dbg_trace(format,Type,INFO))],
+ [lists:flatten(TS),
+ PID,
+ lists:flatten(SshMod:ssh_dbg_format(Type, INFO))],
Acc)
catch
_:_ -> Acc
diff --git a/lib/ssh/src/ssh_message.erl b/lib/ssh/src/ssh_message.erl
index 7c86a81108..47cbec1513 100644
--- a/lib/ssh/src/ssh_message.erl
+++ b/lib/ssh/src/ssh_message.erl
@@ -32,7 +32,9 @@
-export([encode/1, decode/1, decode_keyboard_interactive_prompts/2]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
+
ucl(B) ->
try unicode:characters_to_list(B) of
@@ -606,34 +608,36 @@ encode_signature({ed_pub, ed448,_}, _SigAlg, Signature) ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [ssh_messages, raw_messages];
+ssh_dbg_trace_points() -> [ssh_messages, raw_messages].
+
+ssh_dbg_flags(ssh_messages) -> [c];
+ssh_dbg_flags(raw_messages) -> [c].
-dbg_trace(flags, ssh_messages, _) -> [c];
-dbg_trace(on, ssh_messages, _) -> dbg:tp(?MODULE,encode,1,x),
- dbg:tp(?MODULE,decode,1,x);
-dbg_trace(off, ssh_messages, _) -> dbg:ctpg(?MODULE,encode,1),
- dbg:ctpg(?MODULE,decode,1);
+ssh_dbg_on(P) when P==ssh_messages ;
+ P==raw_messages ->
+ dbg:tp(?MODULE,encode,1,x),
+ dbg:tp(?MODULE,decode,1,x).
-dbg_trace(flags, raw_messages, A) -> dbg_trace(flags, ssh_messages, A);
-dbg_trace(on, raw_messages, A) -> dbg_trace(on, ssh_messages, A);
-dbg_trace(off, raw_messages, A) -> dbg_trace(off, ssh_messages, A);
+ssh_dbg_off(P) when P==ssh_messages ;
+ P==raw_messages ->
+ dbg:ctpg(?MODULE,encode,1),
+ dbg:ctpg(?MODULE,decode,1).
-dbg_trace(format, ssh_messages, {call,{?MODULE,encode,[Msg]}}) ->
+ssh_dbg_format(ssh_messages, {call,{?MODULE,encode,[Msg]}}) ->
Name = string:to_upper(atom_to_list(element(1,Msg))),
["Going to send ",Name,":\n",
wr_record(ssh_dbg:shrink_bin(Msg))
];
-dbg_trace(format, ssh_messages, {return_from,{?MODULE,decode,1},Msg}) ->
+ssh_dbg_format(ssh_messages, {return_from,{?MODULE,decode,1},Msg}) ->
Name = string:to_upper(atom_to_list(element(1,Msg))),
["Received ",Name,":\n",
wr_record(ssh_dbg:shrink_bin(Msg))
];
-
-dbg_trace(format, raw_messages, {call,{?MODULE,decode,[BytesPT]}}) ->
+ssh_dbg_format(raw_messages, {call,{?MODULE,decode,[BytesPT]}}) ->
["Received plain text bytes (shown after decryption):\n",
io_lib:format("~p",[BytesPT])
];
-dbg_trace(format, raw_messages, {return_from,{?MODULE,encode,1},BytesPT}) ->
+ssh_dbg_format(raw_messages, {return_from,{?MODULE,encode,1},BytesPT}) ->
["Going to send plain text bytes (shown before encryption):\n",
io_lib:format("~p",[BytesPT])
].
diff --git a/lib/ssh/src/ssh_sftp.erl b/lib/ssh/src/ssh_sftp.erl
index 28df85dfa4..11d48bb1e5 100644
--- a/lib/ssh/src/ssh_sftp.erl
+++ b/lib/ssh/src/ssh_sftp.erl
@@ -52,7 +52,8 @@
%% TODO: Should be placed elsewhere ssh_sftpd should not call functions in ssh_sftp!
-export([info_to_attr/1, attr_to_info/1]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
-record(state,
{
@@ -818,7 +819,7 @@ write_file(Pid, Name, List) ->
Timeout :: timeout(),
Error :: {error, reason()}.
write_file(Pid, Name, List, FileOpTimeout) when is_list(List) ->
- write_file(Pid, Name, list_to_binary(List), FileOpTimeout);
+ write_file(Pid, Name, to_bin(List), FileOpTimeout);
write_file(Pid, Name, Bin, FileOpTimeout) ->
case open(Pid, Name, [write, binary], FileOpTimeout) of
{ok, Handle} ->
@@ -1621,7 +1622,7 @@ lseek_pos(_, _, _) ->
%%%================================================================
%%%
-to_bin(Data) when is_list(Data) -> list_to_binary(Data);
+to_bin(Data) when is_list(Data) -> ?to_binary(Data);
to_bin(Data) when is_binary(Data) -> Data.
@@ -1833,12 +1834,15 @@ format_channel_start_error(Reason) ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [terminate];
+ssh_dbg_trace_points() -> [terminate].
-dbg_trace(flags, terminate, _) -> [c];
-dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
-dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
-dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ssh_dbg_flags(terminate) -> [c].
+
+ssh_dbg_on(terminate) -> dbg:tp(?MODULE, terminate, 2, x).
+
+ssh_dbg_off(terminate) -> dbg:ctpg(?MODULE, terminate, 2).
+
+ssh_dbg_format(terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
["Sftp Terminating:\n",
io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
].
diff --git a/lib/ssh/src/ssh_sftpd.erl b/lib/ssh/src/ssh_sftpd.erl
index bf921f0ff3..b8dc905d4d 100644
--- a/lib/ssh/src/ssh_sftpd.erl
+++ b/lib/ssh/src/ssh_sftpd.erl
@@ -38,7 +38,9 @@
-export([init/1, handle_ssh_msg/2, handle_msg/2, terminate/2]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
+
-record(state, {
xf, % [{channel,ssh_xfer states}...]
@@ -950,12 +952,15 @@ maybe_increase_recv_window(ConnectionManager, ChannelId, Options) ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [terminate];
+ssh_dbg_trace_points() -> [terminate].
+
+ssh_dbg_flags(terminate) -> [c].
+
+ssh_dbg_on(terminate) -> dbg:tp(?MODULE, terminate, 2, x).
+
+ssh_dbg_off(terminate) -> dbg:ctpg(?MODULE, terminate, 2).
-dbg_trace(flags, terminate, _) -> [c];
-dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
-dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
-dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ssh_dbg_format(terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
["SftpD Terminating:\n",
io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
].
diff --git a/lib/ssh/src/ssh_shell.erl b/lib/ssh/src/ssh_shell.erl
index cdc9a6df5b..39329875d8 100644
--- a/lib/ssh/src/ssh_shell.erl
+++ b/lib/ssh/src/ssh_shell.erl
@@ -35,7 +35,8 @@
%% Spawn export
-export([input_loop/2]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
-record(state,
{
@@ -188,12 +189,15 @@ get_ancestors() ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [terminate];
+ssh_dbg_trace_points() -> [terminate].
-dbg_trace(flags, terminate, _) -> [c];
-dbg_trace(on, terminate, _) -> dbg:tp(?MODULE, terminate, 2, x);
-dbg_trace(off, terminate, _) -> dbg:ctpg(?MODULE, terminate, 2);
-dbg_trace(format, terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
+ssh_dbg_flags(terminate) -> [c].
+
+ssh_dbg_on(terminate) -> dbg:tp(?MODULE, terminate, 2, x).
+
+ssh_dbg_off(terminate) -> dbg:ctpg(?MODULE, terminate, 2).
+
+ssh_dbg_format(terminate, {call, {?MODULE,terminate, [Reason, State]}}) ->
["Shell Terminating:\n",
io_lib:format("Reason: ~p,~nState:~n~s", [Reason, wr_record(State)])
].
diff --git a/lib/ssh/src/ssh_transport.erl b/lib/ssh/src/ssh_transport.erl
index d1a3d513d1..9a4ae5bbc6 100644
--- a/lib/ssh/src/ssh_transport.erl
+++ b/lib/ssh/src/ssh_transport.erl
@@ -55,7 +55,8 @@
get_host_key/2,
call_KeyCb/3]).
--export([dbg_trace/3]).
+-behaviour(ssh_dbg).
+-export([ssh_dbg_trace_points/0, ssh_dbg_flags/1, ssh_dbg_on/1, ssh_dbg_off/1, ssh_dbg_format/2]).
%%% For test suites
-export([pack/3, adjust_algs_for_peer_version/2]).
@@ -233,7 +234,7 @@ is_valid_mac(_, _ , #ssh{recv_mac_size = 0}) ->
true;
is_valid_mac(Mac, Data, #ssh{recv_mac = Algorithm,
recv_mac_key = Key, recv_sequence = SeqNum}) ->
- Mac == mac(Algorithm, Key, SeqNum, Data).
+ crypto:equal_const_time(Mac, mac(Algorithm, Key, SeqNum, Data)).
format_version({Major,Minor}, SoftwareVersion) ->
"SSH-" ++ integer_to_list(Major) ++ "." ++
@@ -1097,9 +1098,21 @@ alg_final(rcv, SSH0) ->
select_all(CL, SL) when length(CL) + length(SL) < ?MAX_NUM_ALGORITHMS ->
- A = CL -- SL, %% algortihms only used by client
+ %% algortihms only used by client
+ %% NOTE: an algorithm occuring more than once in CL will still be present
+ %% in CLonly. This is not a problem for nice clients.
+ CLonly = CL -- SL,
+
%% algorithms used by client and server (client pref)
- lists:map(fun(ALG) -> list_to_atom(ALG) end, (CL -- A));
+ lists:foldr(fun(ALG, Acc) ->
+ try [list_to_existing_atom(ALG) | Acc]
+ catch
+ %% If an malicious client uses the same non-existing algorithm twice,
+ %% we will end up here
+ _:_ -> Acc
+ end
+ end, [], (CL -- CLonly));
+
select_all(CL, SL) ->
Error = lists:concat(["Received too many algorithms (",length(CL),"+",length(SL)," >= ",?MAX_NUM_ALGORITHMS,")."]),
?DISCONNECT(?SSH_DISCONNECT_PROTOCOL_ERROR,
@@ -1548,7 +1561,7 @@ decrypt(#ssh{decrypt = 'chacha20-poly1305@openssh.com',
%% The length is already decrypted and used to divide the input
%% Check the mac (important that it is timing-safe):
PolyKey = crypto:crypto_one_time(chacha20, K2, <<0:8/unit:8,Seq:8/unit:8>>, <<0:32/unit:8>>, false),
- case equal_const_time(Ctag, crypto:poly1305(PolyKey, <<AAD/binary,Ctext/binary>>)) of
+ case crypto:equal_const_time(Ctag, crypto:poly1305(PolyKey, <<AAD/binary,Ctext/binary>>)) of
true ->
%% MAC is ok, decode
IV2 = <<1:8/little-unit:8, Seq:8/unit:8>>,
@@ -1800,7 +1813,10 @@ valid_key_sha_alg(_, _) -> false.
valid_key_sha_alg_ec(OID, Alg) ->
Curve = public_key:oid2ssh_curvename(OID),
- Alg == list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
+ try Alg == list_to_existing_atom("ecdsa-sha2-" ++ binary_to_list(Curve))
+ catch
+ _:_ -> false
+ end.
-dialyzer({no_match, public_algo/1}).
@@ -1811,7 +1827,10 @@ public_algo({ed_pub, ed25519,_}) -> 'ssh-ed25519';
public_algo({ed_pub, ed448,_}) -> 'ssh-ed448';
public_algo({#'ECPoint'{},{namedCurve,OID}}) ->
Curve = public_key:oid2ssh_curvename(OID),
- list_to_atom("ecdsa-sha2-" ++ binary_to_list(Curve)).
+ try list_to_existing_atom("ecdsa-sha2-" ++ binary_to_list(Curve))
+ catch
+ _:_ -> undefined
+ end.
sha('ssh-rsa') -> sha;
@@ -1845,7 +1864,7 @@ sha('curve25519-sha256@libssh.org' ) -> sha256;
sha('curve448-sha512') -> sha512;
sha(x25519) -> sha256;
sha(x448) -> sha512;
-sha(Str) when is_list(Str), length(Str)<50 -> sha(list_to_atom(Str)).
+sha(Str) when is_list(Str), length(Str)<50 -> sha(list_to_existing_atom(Str)).
mac_key_bytes('hmac-sha1') -> 20;
@@ -1953,18 +1972,6 @@ same(Algs) -> [{client2server,Algs}, {server2client,Algs}].
%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Compare two binaries in a timing safe maner.
-%%% The time spent in comparing should not be different depending on where in the binaries they differ.
-%%% This is to avoid a certain side-channel attac.
-equal_const_time(X1, X2) -> equal_const_time(X1, X2, true).
-
-equal_const_time(<<B1,R1/binary>>, <<B2,R2/binary>>, Truth) ->
- equal_const_time(R1, R2, Truth and (B1 == B2));
-equal_const_time(<<>>, <<>>, Truth) ->
- Truth;
-equal_const_time(_, _, _) ->
- false.
-
%%%-------- Remove CR, LF and following characters from a line
trim_tail(Str) ->
@@ -1977,34 +1984,43 @@ trim_tail(Str) ->
%%%# Tracing
%%%#
-dbg_trace(points, _, _) -> [alg, ssh_messages, raw_messages, hello];
+ssh_dbg_trace_points() -> [alg, ssh_messages, raw_messages, hello].
+
+ssh_dbg_flags(alg) -> [c];
+ssh_dbg_flags(hello) -> [c];
+ssh_dbg_flags(raw_messages) -> ssh_dbg_flags(hello);
+ssh_dbg_flags(ssh_messages) -> ssh_dbg_flags(hello).
+
+
+ssh_dbg_on(alg) -> dbg:tpl(?MODULE,select_algorithm,4,x);
+ssh_dbg_on(hello) -> dbg:tp(?MODULE,hello_version_msg,1,x),
+ dbg:tp(?MODULE,handle_hello_version,1,x);
+ssh_dbg_on(raw_messages) -> ssh_dbg_on(hello);
+ssh_dbg_on(ssh_messages) -> ssh_dbg_on(hello).
-dbg_trace(flags, hello, _) -> [c];
-dbg_trace(on, hello, _) -> dbg:tp(?MODULE,hello_version_msg,1,x),
- dbg:tp(?MODULE,handle_hello_version,1,x);
-dbg_trace(off, hello, _) -> dbg:ctpg(?MODULE,hello_version_msg,1),
- dbg:ctpg(?MODULE,handle_hello_version,1);
-dbg_trace(C, raw_messages, A) -> dbg_trace(C, hello, A);
-dbg_trace(C, ssh_messages, A) -> dbg_trace(C, hello, A);
+ssh_dbg_off(alg) -> dbg:ctpl(?MODULE,select_algorithm,4);
+ssh_dbg_off(hello) -> dbg:ctpg(?MODULE,hello_version_msg,1),
+ dbg:ctpg(?MODULE,handle_hello_version,1);
+ssh_dbg_off(raw_messages) -> ssh_dbg_off(hello);
+ssh_dbg_off(ssh_messages) -> ssh_dbg_off(hello).
-dbg_trace(flags, alg, _) -> [c];
-dbg_trace(on, alg, _) -> dbg:tpl(?MODULE,select_algorithm,4,x);
-dbg_trace(off, alg, _) -> dbg:ctpl(?MODULE,select_algorithm,4);
-dbg_trace(format, hello, {return_from,{?MODULE,hello_version_msg,1},Hello}) ->
+
+ssh_dbg_format(hello, {return_from,{?MODULE,hello_version_msg,1},Hello}) ->
["Going to send hello message:\n",
Hello
];
-dbg_trace(format, hello, {call,{?MODULE,handle_hello_version,[Hello]}}) ->
+ssh_dbg_format(hello, {call,{?MODULE,handle_hello_version,[Hello]}}) ->
["Received hello message:\n",
Hello
];
-
-dbg_trace(format, alg, {return_from,{?MODULE,select_algorithm,4},{ok,Alg}}) ->
+ssh_dbg_format(alg, {return_from,{?MODULE,select_algorithm,4},{ok,Alg}}) ->
["Negotiated algorithms:\n",
wr_record(Alg)
- ].
+ ];
+ssh_dbg_format(raw_messages, X) -> ssh_dbg_format(hello, X);
+ssh_dbg_format(ssh_messages, X) -> ssh_dbg_format(hello, X).
?wr_record(alg).
diff --git a/lib/ssh/src/ssh_xfer.erl b/lib/ssh/src/ssh_xfer.erl
index b071b38be2..2292beaf68 100644
--- a/lib/ssh/src/ssh_xfer.erl
+++ b/lib/ssh/src/ssh_xfer.erl
@@ -93,7 +93,7 @@ write(XF,ReqID, Handle, Offset, Data) ->
is_binary(Data) ->
Data;
is_list(Data) ->
- unicode:characters_to_binary(Data)
+ ?to_binary(Data)
end,
xf_request(XF,?SSH_FXP_WRITE,
[?uint32(ReqID),
@@ -233,7 +233,7 @@ xf_request(XF, Op, Arg) ->
is_binary(Arg) ->
Arg;
is_list(Arg) ->
- list_to_binary(Arg)
+ ?to_binary(Arg)
end,
Size = 1+size(Data),
ssh_connection:send(CM, Channel, [<<?UINT32(Size), Op, Data/binary>>]).
@@ -243,7 +243,7 @@ xf_send_reply(#ssh_xfer{cm = CM, channel = Channel}, Op, Arg) ->
is_binary(Arg) ->
Arg;
is_list(Arg) ->
- list_to_binary(Arg)
+ ?to_binary(Arg)
end,
Size = 1 + size(Data),
ssh_connection:send(CM, Channel, [<<?UINT32(Size), Op, Data/binary>>]).
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
index f4b521356f..dfc94f830c 100644
--- a/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_client_info_timing.erl
@@ -23,37 +23,7 @@
-compile(export_all).
--proptest(eqc).
--proptest([triq,proper]).
-
--ifndef(EQC).
--ifndef(PROPER).
--ifndef(TRIQ).
--define(EQC,true).
-%%-define(PROPER,true).
-%%-define(TRIQ,true).
--endif.
--endif.
--endif.
-
--ifdef(EQC).
--include_lib("eqc/include/eqc.hrl").
--define(MOD_eqc,eqc).
-
--else.
--ifdef(PROPER).
--include_lib("proper/include/proper.hrl").
--define(MOD_eqc,proper).
-
--else.
--ifdef(TRIQ).
--define(MOD_eqc,triq).
--include_lib("triq/include/triq.hrl").
-
--endif.
--endif.
--endif.
-
+-include_lib("common_test/include/ct_property_test.hrl").
%%% Properties:
diff --git a/lib/ssh/test/property_test/ssh_eqc_client_server.erl b/lib/ssh/test/property_test/ssh_eqc_client_server.erl
index acb0faa0c7..4c890c9dd2 100644
--- a/lib/ssh/test/property_test/ssh_eqc_client_server.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_client_server.erl
@@ -23,8 +23,6 @@
-compile(export_all).
--proptest([proper]).
-
-ifndef(PROPER).
-else.
%% Only use proper
@@ -35,10 +33,9 @@
%% However, with access to eqc it ought to be quite easy to re-enable eqc by
%% studying the diff.
--include_lib("proper/include/proper.hrl").
--define(MOD_eqc,proper).
-
-include_lib("common_test/include/ct.hrl").
+-include_lib("common_test/include/ct_property_test.hrl").
+
%% Limit the testing time on CI server... this needs to be improved in % from total budget.
-define(TESTINGTIME(Prop), eqc:testing_time(30,Prop)).
@@ -102,20 +99,20 @@
%% To be called as eqc:quickcheck( ssh_eqc_client_server:prop_seq() ).
prop_seq() ->
error_logger:tty(false),
- ?TESTINGTIME(do_prop_seq(?SSH_DIR)).
+ ?TESTINGTIME(do_prop_seq(?SSH_DIR,[])).
%% To be called from a common_test test suite
prop_seq(CT_Config) ->
error_logger:tty(false),
- do_prop_seq(full_path(?SSH_DIR, CT_Config)).
+ do_prop_seq(full_path(?SSH_DIR, CT_Config), CT_Config).
-do_prop_seq(DataDir) ->
+do_prop_seq(DataDir, CT_Config) ->
setup_rsa(DataDir),
?FORALL(Cmds,commands(?MODULE),
begin
{H,Sf,Result} = run_commands(?MODULE,Cmds,[{data_dir,DataDir}]),
- present_result(?MODULE, Cmds, {H,Sf,Result}, Result==ok)
+ ct_property_test:present_result(?MODULE, Cmds, {H,Sf,Result}, CT_Config, [])
end).
full_path(SSHdir, CT_Config) ->
@@ -124,37 +121,37 @@ full_path(SSHdir, CT_Config) ->
%%%----
prop_parallel() ->
error_logger:tty(false),
- ?TESTINGTIME(do_prop_parallel(?SSH_DIR)).
+ ?TESTINGTIME(do_prop_parallel(?SSH_DIR,[])).
%% To be called from a common_test test suite
prop_parallel(CT_Config) ->
error_logger:tty(false),
- do_prop_parallel(full_path(?SSH_DIR, CT_Config)).
+ do_prop_parallel(full_path(?SSH_DIR, CT_Config), CT_Config).
-do_prop_parallel(DataDir) ->
+do_prop_parallel(DataDir, CT_Config) ->
setup_rsa(DataDir),
?FORALL(Cmds,parallel_commands(?MODULE),
begin
{H,Sf,Result} = run_parallel_commands(?MODULE,Cmds,[{data_dir,DataDir}]),
- present_result(?MODULE, Cmds, {H,Sf,Result}, Result==ok)
+ ct_property_test:present_result(?MODULE, Cmds, {H,Sf,Result}, CT_Config, [])
end).
%%%----
%% prop_parallel_multi() ->
-%% ?TESTINGTIME(do_prop_parallel_multi(?SSH_DIR)).
+%% ?TESTINGTIME(do_prop_parallel_multi(?SSH_DIR, [])).
%% %% To be called from a common_test test suite
%% prop_parallel_multi(CT_Config) ->
-%% do_prop_parallel_multi(full_path(?SSH_DIR, CT_Config)).
+%% do_prop_parallel_multi(full_path(?SSH_DIR, CT_Config), CT_Config).
-%% do_prop_parallel_multi(DataDir) ->
+%% do_prop_parallel_multi(DataDir, CT_Config) ->
%% setup_rsa(DataDir),
%% ?FORALL(Repetitions,?SHRINK(1,[10]),
%% ?FORALL(Cmds,parallel_commands(?MODULE),
%% ?ALWAYS(Repetitions,
%% begin
%% {H,Sf,Result} = run_parallel_commands(?MODULE,Cmds,[{data_dir,DataDir}]),
-%% present_result(?MODULE, Cmds, {H,Sf,Result}, Result==ok)
+%% ct_property_test:present_result(?MODULE, Cmds, {H,Sf,Result}, CT_Config, [])
%% end))).
%%%================================================================
@@ -476,178 +473,6 @@ is_ok(_) -> true.
ensure_string({A,B,C,D}) -> lists:flatten(io_lib:format("~w.~w.~w.~w",[A,B,C,D]));
ensure_string(X) -> X.
-%%%----------------------------------------------------------------
-present_result(_Module, Cmds, _Triple, true) ->
- aggregate(with_title("Distribution sequential/parallel"), sequential_parallel(Cmds),
- aggregate(with_title("Function calls"), cmnd_names(Cmds),
- aggregate(with_title("Message sizes"), empty_msgs(Cmds),
- aggregate(print_frequencies(), message_sizes(Cmds),
- aggregate(title("Length of command sequences",print_frequencies()), num_calls(Cmds),
- true)))));
-
-present_result(Module, Cmds, Triple, false) ->
- pretty_comands(Module, Cmds, Triple, [{show_states,true}], false),
- false. % Proper dislikes non-boolean results while eqc treats non-true as false.
-
-pretty_comands(Module, Cmds, Triple, Opts, Bool) ->
- ct:log("Module = ~p,~n Cmds = ~p,~n Triple = ~p,~n Opts = ~p,~n Bool = ~p",[Module, Cmds, Triple, Opts, Bool]).
-
-
-
-cmnd_names(Cs) -> traverse_commands(fun cmnd_name/1, Cs).
-cmnd_name(L) -> [F || {set,_Var,{call,_Mod,F,_As}} <- L].
-
-empty_msgs(Cs) -> traverse_commands(fun empty_msg/1, Cs).
-empty_msg(L) -> [empty || {set,_,{call,_,ssh_send,[_,_,Msg]}} <- L,
- size(Msg)==0].
-
-message_sizes(Cs) -> traverse_commands(fun message_size/1, Cs).
-message_size(L) -> [size(Msg) || {set,_,{call,_,ssh_send,[_,_,Msg]}} <- L].
-
-num_calls(Cs) -> traverse_commands(fun num_call/1, Cs).
-num_call(L) -> [length(L)].
-
-sequential_parallel(Cs) ->
- traverse_commands(fun(L) -> dup_module(L, sequential) end,
- fun(L) -> [dup_module(L1, mkmod("parallel",num(L1,L))) || L1<-L] end,
- Cs).
-dup_module(L, ModName) -> lists:duplicate(length(L), ModName).
-mkmod(PfxStr,N) -> list_to_atom(PfxStr++"_"++integer_to_list(N)).
-
-%% Meta functions for the aggregate functions
-traverse_commands(Fun, L) when is_list(L) -> Fun(L);
-traverse_commands(Fun, {Seq, ParLs}) -> Fun(lists:append([Seq|ParLs])).
-
-traverse_commands(Fseq, _Fpar, L) when is_list(L) -> Fseq(L);
-traverse_commands(Fseq, Fpar, {Seq, ParLs}) -> lists:append([Fseq(Seq)|Fpar(ParLs)]).
-
-%%%----------------
-%% PrintMethod([{term(), int()}]) -> any().
-print_frequencies() -> print_frequencies(10).
-
-print_frequencies(Ngroups) -> fun([]) -> io:format('Empty list!~n',[]);
- (L ) ->
- try
- M = lists:last(L),
- Max = if is_integer(M) -> M;
- is_tuple(M) -> element(1,L)
- end,
- print_frequencies(L,Ngroups,0,Max)
- catch
- C:E:S ->
- ct:pal("~p:~p ~p:~p~n~p~n~p",[?MODULE,?LINE,C,E,S,L])
- end
- end.
-
-
-print_frequencies(Ngroups, MaxValue) -> fun(L) -> print_frequencies(L,Ngroups,0,MaxValue) end.
-
-print_frequencies(L, N, Min, Max) when N>Max -> print_frequencies(L++[{N,0}], N, Min, N);
-print_frequencies(L, N, Min, Max0) ->
- try
- Interval = round((Max0-Min)/N),
- Max = Max0 + (Max0 rem Interval),
- IntervalUpperLimits =
- lists:reverse(
- [Max | tl(lists:reverse(lists:seq(Min,Max,Interval)))]
- ),
- {Acc0,_} = lists:mapfoldl(fun(Upper,Lower) ->
- {{{Lower,Upper},0}, Upper+1}
- end, hd(IntervalUpperLimits), tl(IntervalUpperLimits)),
- Fs0 = get_frequencies(L, Acc0),
- SumVal = lists:sum([V||{_,V}<-Fs0]),
- Fs = with_percentage(Fs0, SumVal),
- Mean = mean(L),
- Median = median(L),
- Npos_value = num_digits(SumVal),
- Npos_range = num_digits(Max),
- io:format("Range~*s: ~s~n",[2*Npos_range-2,"", "Number in range"]),
- io:format("~*c:~*c~n",[2*Npos_range+3,$-, max(16,Npos_value+10),$- ]),
- [begin
- io:format("~*w - ~*w: ~*w ~5.1f%",[Npos_range,Rlow,
- Npos_range,Rhigh,
- Npos_value,Val,
- Percent]),
- [io:format(" <-- mean=~.1f",[Mean]) || in_interval(Mean, Interval)],
- [io:format(" <-- median=" ++
- if
- is_float(Median) -> "~.1f";
- true -> "~p"
- end, [Median]) || in_interval(Median, Interval)],
- io:nl()
- end
- || {Interval={Rlow,Rhigh},Val,Percent} <- Fs],
- io:format('~*c ~*c~n',[2*Npos_range,32,Npos_value+2,$-]),
- io:format('~*c ~*w~n',[2*Npos_range,32,Npos_value,SumVal])
- catch
- C:E ->
- io:format('*** Faild printing (~p:~p) for~n~p~n',[C,E,L])
- end.
-
-get_frequencies([{I,Num}|T], [{{Lower,Upper},Cnt}|Acc]) when Lower=<I,I=<Upper ->
- get_frequencies(T, [{{Lower,Upper},Cnt+Num}|Acc]);
-get_frequencies(L=[{I,_Num}|_], [Ah={{_Lower,Upper},_Cnt}|Acc]) when I>Upper ->
- [Ah | get_frequencies(L,Acc)];
-get_frequencies([I|T], Acc) when is_integer(I) ->
- get_frequencies([{I,1}|T], Acc);
-get_frequencies([], Acc) ->
- Acc.
-
-with_percentage(Fs, Sum) ->
- [{Rng,Val,100*Val/Sum} || {Rng,Val} <- Fs].
-
-
-title(Str, Fun) ->
- fun(L) ->
- io:format('~s~n',[Str]),
- Fun(L)
- end.
-
-num_digits(I) -> 1+trunc(math:log(I)/math:log(10)).
-
-num(Elem, List) -> length(lists:takewhile(fun(E) -> E /= Elem end, List)) + 1.
-
-%%%---- Just for naming an operation for readability
-is_odd(I) -> (I rem 2) == 1.
-
-in_interval(Value, {Rlow,Rhigh}) ->
- try
- Rlow=<round(Value) andalso round(Value)=<Rhigh
- catch
- _:_ -> false
- end.
-
-%%%================================================================
-%%% Statistical functions
-
-%%%---- Mean value
-mean(L = [X|_]) when is_number(X) ->
- lists:sum(L) / length(L);
-mean(L = [{_Value,_Weight}|_]) ->
- SumOfWeights = lists:sum([W||{_,W}<-L]),
- WeightedSum = lists:sum([W*V||{V,W}<-L]),
- WeightedSum / SumOfWeights;
-mean(_) ->
- undefined.
-
-%%%---- Median
-median(L = [X|_]) when is_number(X) ->
- case is_odd(length(L)) of
- true ->
- hd(lists:nthtail(length(L) div 2, L));
- false ->
- %% 1) L has at least on element (the when test).
- %% 2) Length is even.
- %% => Length >= 2
- [M1,M2|_] = lists:nthtail((length(L) div 2)-1, L),
- (M1+M2) / 2
- end;
-%% integer Weights...
-median(L = [{_Value,_Weight}|_]) ->
- median( lists:append([lists:duplicate(W,V) || {V,W} <- L]) );
-median(_) ->
- undefined.
-
%%%================================================================
%%% The rest is taken and modified from ssh_test_lib.erl
setup_rsa(Dir) ->
diff --git a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
index 165274241c..6470fa5f3d 100644
--- a/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
+++ b/lib/ssh/test/property_test/ssh_eqc_encode_decode.erl
@@ -23,36 +23,7 @@
-compile(export_all).
--proptest(eqc).
--proptest([triq,proper]).
-
--ifndef(EQC).
--ifndef(PROPER).
--ifndef(TRIQ).
--define(EQC,true).
-%%-define(PROPER,true).
-%%-define(TRIQ,true).
--endif.
--endif.
--endif.
-
--ifdef(EQC).
--include_lib("eqc/include/eqc.hrl").
--define(MOD_eqc,eqc).
-
--else.
--ifdef(PROPER).
--include_lib("proper/include/proper.hrl").
--define(MOD_eqc,proper).
-
--else.
--ifdef(TRIQ).
--define(MOD_eqc,triq).
--include_lib("triq/include/triq.hrl").
-
--endif.
--endif.
--endif.
+-include_lib("common_test/include/ct_property_test.hrl").
%% Public key records:
-include_lib("public_key/include/public_key.hrl").
diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl
index 30d03f842f..386730af17 100644
--- a/lib/ssh/test/ssh_basic_SUITE.erl
+++ b/lib/ssh/test/ssh_basic_SUITE.erl
@@ -79,7 +79,8 @@ groups() ->
packet_size,
ssh_info_print,
{group, login_bad_pwd_no_retry},
- shell_exit_status
+ shell_exit_status,
+ setopts_getopts
]},
{ssh_renegotiate_SUITE, [?PARALLEL], [rekey0,
@@ -866,7 +867,7 @@ daemon_already_started(Config) when is_list(Config) ->
%%% Test that a failed daemon start does not leave the port open
daemon_error_closes_port(Config) ->
GoodSystemDir = proplists:get_value(data_dir, Config),
- Port = ssh_test_lib:inet_port(),
+ Port = inet_port(),
{error,_} = ssh_test_lib:daemon(Port, []), % No system dir
case ssh_test_lib:daemon(Port, [{system_dir, GoodSystemDir}]) of
{error,eaddrinuse} ->
@@ -1440,6 +1441,42 @@ shell_exit_status(Config) when is_list(Config) ->
%%----------------------------------------------------------------------------
+setopts_getopts(Config) ->
+ process_flag(trap_exit, true),
+ SystemDir = proplists:get_value(data_dir, Config),
+ UserDir = proplists:get_value(priv_dir, Config),
+
+ ShellFun = fun (_User) -> spawn(fun() -> ok end) end,
+ {Pid, Host, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {user_dir, UserDir},
+ {user_passwords, [{"vego", "morot"}]},
+ {shell, ShellFun},
+ {failfun, fun ssh_test_lib:failfun/2}]),
+ ConnectionRef =
+ ssh_test_lib:connect(Host, Port, [{silently_accept_hosts, true},
+ {user_dir, UserDir},
+ {user, "vego"},
+ {password, "morot"},
+ {user_interaction, false}]),
+ %% Test get_sock_opts
+ {ok,[{active,once},{deliver,term},{mode,binary},{packet,0}]} =
+ ssh:get_sock_opts(ConnectionRef, [active, deliver, mode, packet]),
+
+ %% Test to set forbidden opts
+ {error,{not_allowed,[active,deliver,mode,packet]}} =
+ ssh:set_sock_opts(ConnectionRef, [{active,once},{deliver,term},{mode,binary},{packet,0}]),
+
+ %% Test to set some other opt
+ {ok,[{delay_send,DS0}]} =
+ ssh:get_sock_opts(ConnectionRef, [delay_send]),
+ DS1 = not DS0,
+ ok = ssh:set_sock_opts(ConnectionRef, [{delay_send,DS1}]),
+ {ok,[{delay_send,DS1}]} =
+ ssh:get_sock_opts(ConnectionRef, [delay_send]),
+
+ ssh:stop_daemon(Pid).
+
+%%----------------------------------------------------------------------------
%%% Idle timeout test
rekey0() -> [{timetrap,{seconds,90}}].
rekey1() -> [{timetrap,{seconds,90}}].
@@ -1681,9 +1718,7 @@ renegotiate1(Config) ->
{Pid, Host, DPort} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
{preferred_algorithms,Algs}]),
- RPort = ssh_test_lib:inet_port(),
- {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort),
-
+ {ok,RelayPid,_,RPort} = ssh_relay:start_link({0,0,0,0}, 0, Host, DPort),
ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
{ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
@@ -1721,8 +1756,7 @@ renegotiate2(Config) ->
{Pid, Host, DPort} = ssh_test_lib:std_daemon(Config,[{max_random_length_padding,0},
{preferred_algorithms,Algs}]),
- RPort = ssh_test_lib:inet_port(),
- {ok,RelayPid} = ssh_relay:start_link({0,0,0,0}, RPort, Host, DPort),
+ {ok,RelayPid,_,RPort} = ssh_relay:start_link({0,0,0,0}, 0, Host, DPort),
ConnectionRef = ssh_test_lib:std_connect(Config, Host, RPort, [{max_random_length_padding,0}]),
{ok, SftpPid} = ssh_sftp:start_channel(ConnectionRef),
@@ -1931,3 +1965,8 @@ new_do_shell_prompt(IO, N, Op, Str, More) ->
new_do_shell(IO, N, [{Op,Str}|More]).
%%--------------------------------------------------------------------
+inet_port() ->
+ {ok, Socket} = gen_tcp:listen(0, [{reuseaddr, true}]),
+ {ok, Port} = inet:port(Socket),
+ gen_tcp:close(Socket),
+ Port.
diff --git a/lib/ssh/test/ssh_connection_SUITE.erl b/lib/ssh/test/ssh_connection_SUITE.erl
index c187a5e4b5..42d5c736c8 100644
--- a/lib/ssh/test/ssh_connection_SUITE.erl
+++ b/lib/ssh/test/ssh_connection_SUITE.erl
@@ -95,7 +95,10 @@ sock() ->
%%--------------------------------------------------------------------
init_per_suite(Config) ->
- ?CHECK_CRYPTO(Config).
+ ?CHECK_CRYPTO(
+ [{ptty_supported, ssh_test_lib:ptty_supported()}
+ | Config]
+ ).
end_per_suite(_Config) ->
catch ssh:stop(),
@@ -117,7 +120,7 @@ end_per_group(_, Config) ->
Config.
%%--------------------------------------------------------------------
-init_per_testcase(_TestCase, Config) ->
+init_per_testcase(TestCase, Config) ->
%% To make sure we start clean as it is not certain that
%% end_per_testcase will be run!
end_per_testcase(Config),
@@ -347,7 +350,11 @@ ptty_alloc_default(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId, []),
+ Expect = case proplists:get_value(ptty_supported, Config) of
+ true -> success;
+ false -> failure
+ end,
+ Expect = ssh_connection:ptty_alloc(ConnectionRef, ChannelId, []),
ssh:close(ConnectionRef).
%%--------------------------------------------------------------------
@@ -358,8 +365,12 @@ ptty_alloc(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId,
- [{term, os:getenv("TERM", ?DEFAULT_TERMINAL)}, {width, 70}, {height, 20}]),
+ Expect = case proplists:get_value(ptty_supported, Config) of
+ true -> success;
+ false -> failure
+ end,
+ Expect = ssh_connection:ptty_alloc(ConnectionRef, ChannelId,
+ [{term, os:getenv("TERM", ?DEFAULT_TERMINAL)}, {width, 70}, {height, 20}]),
ssh:close(ConnectionRef).
@@ -371,8 +382,12 @@ ptty_alloc_pixel(Config) when is_list(Config) ->
ConnectionRef = ssh_test_lib:connect(?SSH_DEFAULT_PORT, [{silently_accept_hosts, true},
{user_interaction, false}]),
{ok, ChannelId} = ssh_connection:session_channel(ConnectionRef, infinity),
- success = ssh_connection:ptty_alloc(ConnectionRef, ChannelId,
- [{term, os:getenv("TERM", ?DEFAULT_TERMINAL)}, {pixel_widh, 630}, {pixel_hight, 470}]),
+ Expect = case proplists:get_value(ptty_supported, Config) of
+ true -> success;
+ false -> failure
+ end,
+ Expect = ssh_connection:ptty_alloc(ConnectionRef, ChannelId,
+ [{term, os:getenv("TERM", ?DEFAULT_TERMINAL)}, {pixel_widh, 630}, {pixel_hight, 470}]),
ssh:close(ConnectionRef).
%%--------------------------------------------------------------------
diff --git a/lib/ssh/test/ssh_relay.erl b/lib/ssh/test/ssh_relay.erl
index 763130358b..3bb4cb2071 100644
--- a/lib/ssh/test/ssh_relay.erl
+++ b/lib/ssh/test/ssh_relay.erl
@@ -28,8 +28,7 @@
}).
-record(state, {
- local_addr,
- local_port,
+ sockname,
peer_addr,
peer_port,
lpid,
@@ -92,11 +91,17 @@ release_next(Srv, Dir, TriggerDir) ->
%% @doc
%% Starts the server
%%
-%% @spec start_link() -> {ok, Pid} | ignore | {error, Error}
+%% @spec start_link() -> {ok, Pid, Host, Port} | ignore | {error, Error}
%% @end
%%--------------------------------------------------------------------
start_link(ListenAddr, ListenPort, PeerAddr, PeerPort) ->
- gen_server:start_link(?MODULE, [ListenAddr, ListenPort, PeerAddr, PeerPort], []).
+ case gen_server:start_link(?MODULE, [ListenAddr, ListenPort, PeerAddr, PeerPort], []) of
+ {ok,Pid} ->
+ {ok,{Host,Port}} = gen_server:call(Pid, get_sockname),
+ {ok, Pid, Host, Port};
+ Other ->
+ Other
+ end.
stop(Srv) ->
unlink(Srv),
@@ -126,11 +131,11 @@ init([ListenAddr, ListenPort, PeerAddr, PeerPort | _Options]) ->
end,
case gen_tcp:listen(ListenPort, [{reuseaddr, true}, {backlog, 1}, {active, false}, binary | IfAddr]) of
{ok, LSock} ->
+ {ok, SName} = inet:sockname(LSock),
Parent = self(),
{LPid, _LMod} = spawn_monitor(fun() -> listen(Parent, LSock) end),
- S = #state{local_addr = ListenAddr,
- local_port = ListenPort,
- lpid = LPid,
+ S = #state{sockname = SName,
+ lpid = LPid,
peer_addr = ssh_test_lib:ntoa(
ssh_test_lib:mangle_connect_address(PeerAddr)),
peer_port = PeerPort
@@ -174,6 +179,8 @@ handle_call({release, Dir}, _From, State) ->
end;
handle_call({release_next, _Dir, _TriggerDir}, _From, State) ->
{reply, {error, nyi}, State};
+handle_call(get_sockname, _From, State) ->
+ {reply, {ok,State#state.sockname}, State};
handle_call(Request, _From, State) ->
Reply = {unhandled, Request},
diff --git a/lib/ssh/test/ssh_sftp_SUITE.erl b/lib/ssh/test/ssh_sftp_SUITE.erl
index c2f9c0eba8..4ecec4e79d 100644
--- a/lib/ssh/test/ssh_sftp_SUITE.erl
+++ b/lib/ssh/test/ssh_sftp_SUITE.erl
@@ -100,29 +100,32 @@ groups() ->
init_per_group(not_unicode, Config) ->
ct:comment("Begin ~p",[grps(Config)]),
- DataDir = proplists:get_value(data_dir, Config),
+ {ok,TestDataDir} =
+ make_data_sub_dir(Config, "test_data", "test_data_not_unicode"),
[{user, "Alladin"},
{passwd, "Sesame"},
{data, <<"Hello world!">>},
+ {data_pos, ["Hej ","hopp"]},
{filename, "sftp.txt"},
{testfile, "test.txt"},
{linktest, "link_test.txt"},
{tar_filename, "sftp_tar_test.tar"},
{tar_F1_txt, "f1.txt"},
- {datadir_tar, filename:join(DataDir,"sftp_tar_test_data")}
+ {datadir_tar, TestDataDir}
| Config];
init_per_group(unicode, Config) ->
- case (file:native_name_encoding() == utf8)
- andalso ("四" == [22235])
- of
+ case have_unicode_support() of
true ->
ct:comment("Begin ~p",[grps(Config)]),
- DataDir = proplists:get_value(data_dir, Config),
+ {ok,TestDataDir} =
+ make_data_sub_dir(Config, "test_data", "test_data_高兴_unicöde"),
+ populate_non_unicode(TestDataDir),
NewConfig =
[{user, "åke高兴"},
{passwd, "ärlig日本じん"},
- {data, <<"foobar å 一二三四いちにさんち">>},
+ {data, "foobar å 一二三四いちにさんち"},
+ {data_pos, ["中","国"]},
{filename, "sftp瑞点.txt"},
{testfile, "testハンス.txt"},
{linktest, "link_test語.txt"},
@@ -130,14 +133,14 @@ init_per_group(unicode, Config) ->
{tar_F1_txt, "F一.txt"},
{tar_F3_txt, "f3.txt"},
{tar_F4_txt, "g四.txt"},
- {datadir_tar, filename:join(DataDir,"sftp_tar_test_data_高兴")}
- | lists:foldl(fun(K,Cf) -> lists:keydelete(K,1,Cf) end,
- Config,
- [user, passwd, data,
- filename, testfile, linktest,
- tar_filename, tar_F1_txt, datadir_tar
- ]
- )
+ {datadir_tar, TestDataDir}
+ | Config %% lists:foldl(fun(K,Cf) -> lists:keydelete(K,1,Cf) end,
+ %% Config,
+ %% [user, passwd, data,
+ %% filename, testfile, linktest,
+ %% tar_filename, tar_F1_txt, datadir_tar
+ %% ]
+ %% )
],
FN = fn(proplists:get_value(tar_F1_txt,NewConfig), NewConfig),
case catch file:read_file(FN) of
@@ -178,7 +181,8 @@ init_per_group(openssh_server, Config) ->
{ok, _ChannelPid, Connection} ->
[{peer, {_HostName,{IPx,Portx}}}] = ssh:connection_info(Connection,[peer]),
ssh:close(Connection),
- [{peer, {fmt_host(IPx),Portx}}, {group, openssh_server} | Config];
+ [{w2l, fun w2l/1},
+ {peer, {fmt_host(IPx),Portx}}, {group, openssh_server} | Config];
{error,"Key exchange failed"} ->
{skip, "openssh server doesn't support the tested kex algorithm"};
Other ->
@@ -330,15 +334,16 @@ open_close_file() ->
[{doc, "Test API functions open/3 and close/2"}].
open_close_file(Config) when is_list(Config) ->
FileName = proplists:get_value(filename, Config),
-
+ SftpFileName = w2l(Config, FileName),
+ ct:log("FileName = ~p~nSftpFileName = ~p", [FileName, SftpFileName]),
{Sftp, _} = proplists:get_value(sftp, Config),
- ok = open_close_file(Sftp, FileName, [read]),
- ok = open_close_file(Sftp, FileName, [write]),
- ok = open_close_file(Sftp, FileName, [write, creat]),
- ok = open_close_file(Sftp, FileName, [write, trunc]),
- ok = open_close_file(Sftp, FileName, [append]),
- ok = open_close_file(Sftp, FileName, [read, binary]).
+ ok = open_close_file(Sftp, SftpFileName, [read]),
+ ok = open_close_file(Sftp, SftpFileName, [write]),
+ ok = open_close_file(Sftp, SftpFileName, [write, creat]),
+ ok = open_close_file(Sftp, SftpFileName, [write, trunc]),
+ ok = open_close_file(Sftp, SftpFileName, [append]),
+ ok = open_close_file(Sftp, SftpFileName, [read, binary]).
open_close_file(Server, File, Mode) ->
{ok, Handle} = ssh_sftp:open(Server, File, Mode),
@@ -349,21 +354,24 @@ open_close_dir() ->
[{doc, "Test API functions opendir/2 and close/2"}].
open_close_dir(Config) when is_list(Config) ->
PrivDir = proplists:get_value(sftp_priv_dir, Config),
+ SftpPrivDir = w2l(Config, PrivDir),
{Sftp, _} = proplists:get_value(sftp, Config),
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
- {ok, Handle} = ssh_sftp:opendir(Sftp, PrivDir),
+ {ok, Handle} = ssh_sftp:opendir(Sftp, SftpPrivDir),
ok = ssh_sftp:close(Sftp, Handle),
- {error, _} = ssh_sftp:opendir(Sftp, FileName).
+ {error, _} = ssh_sftp:opendir(Sftp, SftpFileName).
%%--------------------------------------------------------------------
read_file() ->
[{doc, "Test API funtion read_file/2"}].
read_file(Config) when is_list(Config) ->
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- {ok, Data} = ssh_sftp:read_file(Sftp, FileName),
- {ok, Data} = ssh_sftp:read_file(Sftp, FileName),
+ {ok, Data} = ssh_sftp:read_file(Sftp, SftpFileName),
+ {ok, Data} = ssh_sftp:read_file(Sftp, SftpFileName),
{ok, Data} = file:read_file(FileName).
%%--------------------------------------------------------------------
@@ -371,8 +379,10 @@ read_dir() ->
[{doc,"Test API function list_dir/2"}].
read_dir(Config) when is_list(Config) ->
PrivDir = proplists:get_value(sftp_priv_dir, Config),
+ SftpPrivDir = w2l(Config, PrivDir),
+
{Sftp, _} = proplists:get_value(sftp, Config),
- {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir),
+ {ok, Files} = ssh_sftp:list_dir(Sftp, SftpPrivDir),
ct:log("sftp list dir: ~p~n", [Files]).
%%--------------------------------------------------------------------
@@ -380,31 +390,34 @@ write_file() ->
[{doc, "Test API function write_file/2"}].
write_file(Config) when is_list(Config) ->
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
-
- Data = list_to_binary("Hej hopp!"),
- ok = ssh_sftp:write_file(Sftp, FileName, [Data]),
- {ok, Data} = file:read_file(FileName).
+ Data = proplists:get_value(data, Config),
+ Expected = unicode:characters_to_binary(Data),
+ ok = ssh_sftp:write_file(Sftp, SftpFileName, [Data]),
+ {ok, Expected} = file:read_file(FileName).
%%--------------------------------------------------------------------
write_file_iolist() ->
[{doc, "Test API function write_file/2 with iolists"}].
write_file_iolist(Config) when is_list(Config) ->
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- Data = list_to_binary("Hej hopp!"),
+ Data = proplists:get_value(data, Config),
+ DataB = unicode:characters_to_binary(Data),
lists:foreach(
fun(D) ->
- ok = ssh_sftp:write_file(Sftp, FileName, [D]),
- Expected = if is_binary(D) -> D;
- is_list(D) -> list_to_binary(D)
+ ok = ssh_sftp:write_file(Sftp, SftpFileName, [D]),
+ Expected = try iolist_to_binary(D)
+ catch _:_ -> unicode:characters_to_binary(D)
end,
{ok, Expected} = file:read_file(FileName)
end,
[Data, [Data,Data], [[Data],[Data]], [[[Data]],[[[[Data]],Data]]],
- [[[[Data]],Data],binary_to_list(Data)],
- [[[[Data]],Data],[[binary_to_list(Data)],[[binary_to_list(Data)]]]]
+ [[[[Data]],Data],DataB],
+ [[[[Data]],Data],[[DataB],[[DataB]]]]
]).
%%--------------------------------------------------------------------
@@ -412,53 +425,63 @@ write_big_file() ->
[{doc, "Test API function write_file/2 with big data"}].
write_big_file(Config) when is_list(Config) ->
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- Data = list_to_binary(lists:duplicate(750000,"a")),
- ok = ssh_sftp:write_file(Sftp, FileName, [Data]),
- {ok, Data} = file:read_file(FileName).
+ Data = [lists:duplicate(750000,"a"),
+ proplists:get_value(data, Config)],
+ ok = ssh_sftp:write_file(Sftp, SftpFileName, Data),
+ Expected = unicode:characters_to_binary(Data),
+ {ok, Expected} = file:read_file(FileName).
%%--------------------------------------------------------------------
sftp_read_big_file() ->
[{doc, "Test API function read_file/2 with big data"}].
sftp_read_big_file(Config) when is_list(Config) ->
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- Data = list_to_binary(lists:duplicate(750000,"a")),
- ct:log("Data size to write is ~p bytes",[size(Data)]),
- ok = ssh_sftp:write_file(Sftp, FileName, [Data]),
- {ok, Data} = ssh_sftp:read_file(Sftp, FileName).
+ Data = [lists:duplicate(750000,"a"),
+ proplists:get_value(data, Config)],
+ ok = ssh_sftp:write_file(Sftp, SftpFileName, Data),
+ Expected = unicode:characters_to_binary(Data),
+ {ok, Expected} = ssh_sftp:read_file(Sftp, SftpFileName).
%%--------------------------------------------------------------------
remove_file() ->
[{doc,"Test API function delete/2"}].
remove_file(Config) when is_list(Config) ->
PrivDir = proplists:get_value(sftp_priv_dir, Config),
+ SftpPrivDir = w2l(Config, PrivDir),
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir),
+ {ok, Files} = ssh_sftp:list_dir(Sftp, SftpPrivDir),
true = lists:member(filename:basename(FileName), Files),
- ok = ssh_sftp:delete(Sftp, FileName),
- {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir),
+ ok = ssh_sftp:delete(Sftp, SftpFileName),
+ {ok, NewFiles} = ssh_sftp:list_dir(Sftp, SftpPrivDir),
false = lists:member(filename:basename(FileName), NewFiles),
- {error, no_such_file} = ssh_sftp:delete(Sftp, FileName).
+ {error, no_such_file} = ssh_sftp:delete(Sftp, SftpFileName).
%%--------------------------------------------------------------------
rename_file() ->
[{doc, "Test API function rename_file/2"}].
rename_file(Config) when is_list(Config) ->
PrivDir = proplists:get_value(sftp_priv_dir, Config),
+ SftpPrivDir = w2l(Config, PrivDir),
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
NewFileName = proplists:get_value(testfile, Config),
+ SftpNewFileName = w2l(Config, NewFileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- {ok, Files} = ssh_sftp:list_dir(Sftp, PrivDir),
+ {ok, Files} = ssh_sftp:list_dir(Sftp, SftpPrivDir),
ct:log("FileName: ~p, Files: ~p~n", [FileName, Files]),
true = lists:member(filename:basename(FileName), Files),
false = lists:member(filename:basename(NewFileName), Files),
- ok = ssh_sftp:rename(Sftp, FileName, NewFileName),
- {ok, NewFiles} = ssh_sftp:list_dir(Sftp, PrivDir),
+ ok = ssh_sftp:rename(Sftp, SftpFileName, SftpNewFileName),
+ {ok, NewFiles} = ssh_sftp:list_dir(Sftp, SftpPrivDir),
ct:log("FileName: ~p, Files: ~p~n", [FileName, NewFiles]),
false = lists:member(filename:basename(FileName), NewFiles),
@@ -469,14 +492,17 @@ mk_rm_dir() ->
[{doc,"Test API functions make_dir/2, del_dir/2"}].
mk_rm_dir(Config) when is_list(Config) ->
PrivDir = proplists:get_value(sftp_priv_dir, Config),
+ SftpPrivDir = w2l(Config, PrivDir),
{Sftp, _} = proplists:get_value(sftp, Config),
DirName = filename:join(PrivDir, "test"),
- ok = ssh_sftp:make_dir(Sftp, DirName),
- ok = ssh_sftp:del_dir(Sftp, DirName),
+ SftpDirName = w2l(Config, DirName),
+ ok = ssh_sftp:make_dir(Sftp, SftpDirName),
+ ok = ssh_sftp:del_dir(Sftp, SftpDirName),
NewDirName = filename:join(PrivDir, "foo/bar"),
- {error, _} = ssh_sftp:make_dir(Sftp, NewDirName),
- {error, _} = ssh_sftp:del_dir(Sftp, PrivDir).
+ SftpNewDirName = w2l(Config, NewDirName),
+ {error, _} = ssh_sftp:make_dir(Sftp, SftpNewDirName),
+ {error, _} = ssh_sftp:del_dir(Sftp, SftpPrivDir).
%%--------------------------------------------------------------------
links() ->
@@ -488,10 +514,12 @@ links(Config) when is_list(Config) ->
_ ->
{Sftp, _} = proplists:get_value(sftp, Config),
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
LinkFileName = proplists:get_value(linktest, Config),
+ SftpLinkFileName = w2l(Config, LinkFileName),
- ok = ssh_sftp:make_symlink(Sftp, LinkFileName, FileName),
- {ok, FileName} = ssh_sftp:read_link(Sftp, LinkFileName)
+ ok = ssh_sftp:make_symlink(Sftp, SftpLinkFileName, SftpFileName),
+ {ok, FileName} = ssh_sftp:read_link(Sftp, SftpLinkFileName)
end.
%%--------------------------------------------------------------------
@@ -499,9 +527,10 @@ retrieve_attributes() ->
[{doc, "Test API function read_file_info/3"}].
retrieve_attributes(Config) when is_list(Config) ->
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- {ok, FileInfo} = ssh_sftp:read_file_info(Sftp, FileName),
+ {ok, FileInfo} = ssh_sftp:read_file_info(Sftp, SftpFileName),
{ok, NewFileInfo} = file:read_file_info(FileName),
%% TODO comparison. There are some differences now is that ok?
@@ -512,13 +541,14 @@ set_attributes() ->
[{doc,"Test API function write_file_info/3"}].
set_attributes(Config) when is_list(Config) ->
FileName = proplists:get_value(testfile, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
{ok,Fd} = file:open(FileName, write),
io:put_chars(Fd,"foo"),
- ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#400}),
+ ok = ssh_sftp:write_file_info(Sftp, SftpFileName, #file_info{mode=8#400}),
{error, eacces} = file:write_file(FileName, "hello again"),
- ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#600}),
+ ok = ssh_sftp:write_file_info(Sftp, SftpFileName, #file_info{mode=8#600}),
ok = file:write_file(FileName, "hello again").
%%--------------------------------------------------------------------
@@ -530,23 +560,24 @@ file_owner_access(Config) when is_list(Config) ->
{skip, "Not a relevant test on Windows"};
_ ->
FileName = proplists:get_value(filename, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
{ok, #file_info{mode = InitialMode}} = ssh_sftp:read_file_info(Sftp, FileName),
- ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#000}),
- {ok, #file_info{access = none}} = ssh_sftp:read_file_info(Sftp, FileName),
+ ok = ssh_sftp:write_file_info(Sftp, SftpFileName, #file_info{mode=8#000}),
+ {ok, #file_info{access = none}} = ssh_sftp:read_file_info(Sftp, SftpFileName),
- ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#400}),
- {ok, #file_info{access = read}} = ssh_sftp:read_file_info(Sftp, FileName),
+ ok = ssh_sftp:write_file_info(Sftp, SftpFileName, #file_info{mode=8#400}),
+ {ok, #file_info{access = read}} = ssh_sftp:read_file_info(Sftp, SftpFileName),
- ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#200}),
- {ok, #file_info{access = write}} = ssh_sftp:read_file_info(Sftp, FileName),
+ ok = ssh_sftp:write_file_info(Sftp, SftpFileName, #file_info{mode=8#200}),
+ {ok, #file_info{access = write}} = ssh_sftp:read_file_info(Sftp, SftpFileName),
- ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=8#600}),
- {ok, #file_info{access = read_write}} = ssh_sftp:read_file_info(Sftp, FileName),
+ ok = ssh_sftp:write_file_info(Sftp, SftpFileName, #file_info{mode=8#600}),
+ {ok, #file_info{access = read_write}} = ssh_sftp:read_file_info(Sftp, SftpFileName),
- ok = ssh_sftp:write_file_info(Sftp, FileName, #file_info{mode=InitialMode}),
+ ok = ssh_sftp:write_file_info(Sftp, SftpFileName, #file_info{mode=InitialMode}),
ok
end.
@@ -558,7 +589,8 @@ async_read(Config) when is_list(Config) ->
{Sftp, _} = proplists:get_value(sftp, Config),
FileName = proplists:get_value(filename, Config),
- {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]),
+ SftpFileName = w2l(Config, FileName),
+ {ok, Handle} = ssh_sftp:open(Sftp, SftpFileName, [read]),
{async, Ref} = ssh_sftp:aread(Sftp, Handle, 20),
receive
@@ -576,13 +608,15 @@ async_write() ->
async_write(Config) when is_list(Config) ->
{Sftp, _} = proplists:get_value(sftp, Config),
FileName = proplists:get_value(testfile, Config),
- {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]),
- Data = list_to_binary("foobar"),
+ SftpFileName = w2l(Config, FileName),
+ {ok, Handle} = ssh_sftp:open(Sftp, SftpFileName, [write]),
+ Data = proplists:get_value(data, Config),
+ Expected = unicode:characters_to_binary(Data),
{async, Ref} = ssh_sftp:awrite(Sftp, Handle, Data),
receive
{async_reply, Ref, ok} ->
- {ok, Data} = file:read_file(FileName);
+ {ok, Expected} = file:read_file(FileName);
Msg ->
ct:fail(Msg)
end.
@@ -593,11 +627,12 @@ position() ->
[{doc, "Test API functions position/3"}].
position(Config) when is_list(Config) ->
FileName = proplists:get_value(testfile, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
Data = list_to_binary("1234567890"),
- ok = ssh_sftp:write_file(Sftp, FileName, [Data]),
- {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]),
+ ok = ssh_sftp:write_file(Sftp, SftpFileName, Data),
+ {ok, Handle} = ssh_sftp:open(Sftp, SftpFileName, [read]),
{ok, 3} = ssh_sftp:position(Sftp, Handle, {bof, 3}),
{ok, "4"} = ssh_sftp:read(Sftp, Handle, 1),
@@ -622,17 +657,21 @@ pos_read() ->
[{doc,"Test API functions pread/3 and apread/3"}].
pos_read(Config) when is_list(Config) ->
FileName = proplists:get_value(testfile, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- Data = list_to_binary("Hej hopp!"),
- ok = ssh_sftp:write_file(Sftp, FileName, [Data]),
+ Data = proplists:get_value(data_pos, Config),
+ [Expect1,Expect2] = Es = [binary_to_list(unicode:characters_to_binary(D)) || D <- Data],
+ [Len1,Len2] = [length(E) || E <- Es],
+ ok = ssh_sftp:write_file(Sftp, SftpFileName, Data),
- {ok, Handle} = ssh_sftp:open(Sftp, FileName, [read]),
- {async, Ref} = ssh_sftp:apread(Sftp, Handle, {bof, 5}, 4),
+ {ok,Read} = file:read_file(FileName),
+ ct:log("File: <~ts>~n<~p>~nExpect1: <~p>~nExpect2: <~p>", [Read, Read, Expect1, Expect2]),
- NewData = "opp!",
+ {ok,Handle} = ssh_sftp:open(Sftp, SftpFileName, [read]),
+ {async,Ref} = ssh_sftp:apread(Sftp, Handle, {bof, Len1}, Len2),
receive
- {async_reply, Ref, {ok, NewData}} ->
+ {async_reply, Ref, {ok,Expect2}} ->
ok;
Msg ->
ct:fail(Msg)
@@ -640,21 +679,20 @@ pos_read(Config) when is_list(Config) ->
30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
end,
- NewData1 = "hopp",
-
- {ok, NewData1} = ssh_sftp:pread(Sftp, Handle, {bof, 4}, 4).
+ {ok,Expect1} = ssh_sftp:pread(Sftp, Handle, {bof,0}, Len1).
%%--------------------------------------------------------------------
pos_write() ->
[{doc,"Test API functions pwrite/4 and apwrite/4"}].
pos_write(Config) when is_list(Config) ->
FileName = proplists:get_value(testfile, Config),
+ SftpFileName = w2l(Config, FileName),
{Sftp, _} = proplists:get_value(sftp, Config),
- {ok, Handle} = ssh_sftp:open(Sftp, FileName, [write]),
+ {ok, Handle} = ssh_sftp:open(Sftp, SftpFileName, [write]),
Data = list_to_binary("Bye,"),
- ok = ssh_sftp:write_file(Sftp, FileName, [Data]),
+ ok = ssh_sftp:write_file(Sftp, SftpFileName, [Data]),
NewData = list_to_binary(" see you tomorrow"),
{async, Ref} = ssh_sftp:apwrite(Sftp, Handle, {bof, 4}, NewData),
@@ -667,10 +705,11 @@ pos_write(Config) when is_list(Config) ->
30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
end,
- ok = ssh_sftp:pwrite(Sftp, Handle, eof, list_to_binary("!")),
+ LastData = proplists:get_value(data, Config),
+ ok = ssh_sftp:pwrite(Sftp, Handle, eof, LastData),
- NewData1 = list_to_binary("Bye, see you tomorrow!"),
- {ok, NewData1} = ssh_sftp:read_file(Sftp, FileName).
+ NewData1 = unicode:characters_to_binary("Bye, see you tomorrow" ++ LastData),
+ {ok, NewData1} = ssh_sftp:read_file(Sftp, SftpFileName).
%%--------------------------------------------------------------------
start_channel_sock(Config) ->
@@ -697,25 +736,27 @@ start_channel_sock(Config) ->
%% Test that the channel is usable
FileName = proplists:get_value(filename, Config),
- ok = open_close_file(ChPid1, FileName, [read]),
- ok = open_close_file(ChPid1, FileName, [write]),
+ SftpFileName = w2l(Config, FileName),
+
+ ok = open_close_file(ChPid1, SftpFileName, [read]),
+ ok = open_close_file(ChPid1, SftpFileName, [write]),
%% Try to open a second channel on the Connection
{ok, ChPid2} = ssh_sftp:start_channel(Conn, Opts),
- ok = open_close_file(ChPid1, FileName, [read]),
- ok = open_close_file(ChPid2, FileName, [read]),
+ ok = open_close_file(ChPid1, SftpFileName, [read]),
+ ok = open_close_file(ChPid2, SftpFileName, [read]),
%% Test that the second channel still works after closing the first one
ok = ssh_sftp:stop_channel(ChPid1),
- ok = open_close_file(ChPid2, FileName, [write]),
+ ok = open_close_file(ChPid2, SftpFileName, [write]),
%% Test the Connection survives that all channels are closed
ok = ssh_sftp:stop_channel(ChPid2),
{ok, ChPid3} = ssh_sftp:start_channel(Conn, Opts),
- ok = open_close_file(ChPid3, FileName, [write]),
+ ok = open_close_file(ChPid3, SftpFileName, [write]),
%% Test that a closed channel really is closed
- {error, closed} = ssh_sftp:open(ChPid2, FileName, [write]),
+ {error, closed} = ssh_sftp:open(ChPid2, SftpFileName, [write]),
ok = ssh_sftp:stop_channel(ChPid3),
%% Test that the socket is closed when the Connection closes
@@ -749,17 +790,19 @@ version_option(Config) when is_list(Config) ->
create_empty_tar(Config) ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
erl_tar:close(Handle),
{ChPid,_} = proplists:get_value(sftp,Config),
{ok, #file_info{type=regular}} =
- ssh_sftp:read_file_info(ChPid, TarFileName).
+ ssh_sftp:read_file_info(ChPid, SftpTarFileName).
%%--------------------------------------------------------------------
files_to_tar(Config) ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
F1 = proplists:get_value(tar_F1_txt, Config),
ok = erl_tar:add(Handle, fn(F1,Config), F1, [verbose]),
ok = erl_tar:add(Handle, fn("f2.txt",Config), "f2.txt", [verbose]),
@@ -770,7 +813,8 @@ files_to_tar(Config) ->
ascii_filename_ascii_contents_to_tar(Config) ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
ok = erl_tar:add(Handle, fn("f2.txt",Config), "f2.txt", [verbose]),
ok = erl_tar:close(Handle),
chk_tar(["f2.txt"], Config).
@@ -783,7 +827,8 @@ ascii_filename_unicode_contents_to_tar(Config) ->
Fn ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
ok = erl_tar:add(Handle, fn(Fn,Config), Fn, [verbose]),
ok = erl_tar:close(Handle),
chk_tar([Fn], Config)
@@ -797,7 +842,8 @@ unicode_filename_ascii_contents_to_tar(Config) ->
Fn ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
ok = erl_tar:add(Handle, fn(Fn,Config), Fn, [verbose]),
ok = erl_tar:close(Handle),
chk_tar([Fn], Config)
@@ -807,7 +853,8 @@ unicode_filename_ascii_contents_to_tar(Config) ->
big_file_to_tar(Config) ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
ok = erl_tar:add(Handle, fn("big.txt",Config), "big.txt", [verbose]),
ok = erl_tar:close(Handle),
chk_tar(["big.txt"], Config).
@@ -817,7 +864,8 @@ big_file_to_tar(Config) ->
files_chunked_to_tar(Config) ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
F1 = proplists:get_value(tar_F1_txt, Config),
ok = erl_tar:add(Handle, fn(F1,Config), F1, [verbose,{chunks,2}]),
ok = erl_tar:close(Handle),
@@ -827,7 +875,8 @@ files_chunked_to_tar(Config) ->
directory_to_tar(Config) ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
ok = erl_tar:add(Handle, fn("d1",Config), "d1", [verbose]),
ok = erl_tar:close(Handle),
chk_tar(["d1"], Config).
@@ -836,7 +885,8 @@ directory_to_tar(Config) ->
binaries_to_tar(Config) ->
ChPid2 = proplists:get_value(channel_pid2, Config),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
Bin = <<"A binary">>,
ok = erl_tar:add(Handle, Bin, "b1", [verbose]),
ok = erl_tar:close(Handle),
@@ -850,7 +900,8 @@ null_crypto_tar(Config) ->
Cend = fun(Bin,_CState) -> {ok,Bin} end,
C = {Cinit,Cenc,Cend},
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,C}]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write,{crypto,C}]),
Bin = <<"A binary">>,
F1 = proplists:get_value(tar_F1_txt, Config),
ok = erl_tar:add(Handle, Bin, "b1", [verbose]),
@@ -868,7 +919,8 @@ simple_crypto_tar_small(Config) ->
Cend = fun(Bin,_CState) -> {ok,stuff(Bin)} end,
C = {Cinit,Cenc,Cend},
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,C}]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write,{crypto,C}]),
Bin = <<"A binary">>,
F1 = proplists:get_value(tar_F1_txt, Config),
ok = erl_tar:add(Handle, Bin, "b1", [verbose]),
@@ -885,7 +937,8 @@ simple_crypto_tar_big(Config) ->
Cend = fun(Bin,_CState) -> {ok,stuff(Bin)} end,
C = {Cinit,Cenc,Cend},
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,Handle} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,C}]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,Handle} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write,{crypto,C}]),
Bin = <<"A binary">>,
F1 = proplists:get_value(tar_F1_txt, Config),
ok = erl_tar:add(Handle, Bin, "b1", [verbose]),
@@ -906,7 +959,8 @@ read_tar(Config) ->
{"b2",list_to_binary(lists:duplicate(750000,"a"))}
]),
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write]),
[ok = erl_tar:add(HandleWrite, Bin, Name, [verbose])
|| {Name,Bin} <- NameBins],
ok = erl_tar:close(HandleWrite),
@@ -929,7 +983,8 @@ read_null_crypto_tar(Config) ->
Cr = {Cinitr,Cdec},
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,Cw}]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write,{crypto,Cw}]),
[ok = erl_tar:add(HandleWrite, Bin, Name, [verbose])
|| {Name,Bin} <- NameBins],
ok = erl_tar:close(HandleWrite),
@@ -953,7 +1008,8 @@ read_crypto_tar(Config) ->
Cr = {Cinitr,Cdec},
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,Cw}]),
+ SftpTarFileName = w2l(Config, TarFileName),
+ {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write,{crypto,Cw}]),
[ok = erl_tar:add(HandleWrite, Bin, Name, [verbose])
|| {Name,Bin} <- NameBins],
ok = erl_tar:close(HandleWrite),
@@ -993,7 +1049,9 @@ aes_cbc256_crypto_tar(Config) ->
Cw = {Cinitw,Cenc,Cendw},
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,Cw}]),
+ SftpTarFileName = w2l(Config, TarFileName),
+
+ {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write,{crypto,Cw}]),
[ok = erl_tar:add(HandleWrite, Bin, Name, [verbose]) || {Name,Bin} <- NameBins],
ok = erl_tar:close(HandleWrite),
@@ -1036,7 +1094,9 @@ aes_ctr_stream_crypto_tar(Config) ->
Cw = {Cinitw,Cenc,Cendw},
TarFileName = proplists:get_value(tar_filename, Config),
- {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, TarFileName, [write,{crypto,Cw}]),
+ SftpTarFileName = w2l(Config, TarFileName),
+
+ {ok,HandleWrite} = ssh_sftp:open_tar(ChPid2, SftpTarFileName, [write,{crypto,Cw}]),
[ok = erl_tar:add(HandleWrite, Bin, Name, [verbose]) || {Name,Bin} <- NameBins],
ok = erl_tar:close(HandleWrite),
@@ -1046,41 +1106,27 @@ aes_ctr_stream_crypto_tar(Config) ->
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
-oldprep(Config) ->
- DataDir = proplists:get_value(data_dir, Config),
- TestFile = proplists:get_value(filename, Config),
- TestFile1 = proplists:get_value(testfile, Config),
- TestLink = proplists:get_value(linktest, Config),
- TarFileName = proplists:get_value(tar_filename, Config),
-
- file:delete(TestFile),
- file:delete(TestFile1),
- file:delete(TestLink),
- file:delete(TarFileName),
-
- %% Initial config
- FileName = filename:join(DataDir, "sftp.txt"),
- file:copy(FileName, TestFile),
- Mode = 8#00400 bor 8#00200 bor 8#00040, % read & write owner, read group
- {ok, FileInfo} = file:read_file_info(TestFile),
- ok = file:write_file_info(TestFile,
- FileInfo#file_info{mode = Mode}).
-
-prepare(Config0) ->
+old_prepare(Config0) ->
PrivDir = proplists:get_value(priv_dir, Config0),
Dir = filename:join(PrivDir, ssh_test_lib:random_chars(10)),
file:make_dir(Dir),
+ ct:log("~p:~p created the directory~nsftp_priv_dir = ~p", [?MODULE,?LINE,Dir]),
Keys = [filename,
testfile,
linktest,
tar_filename],
Config1 = foldl_keydelete(Keys, Config0),
Config2 = lists:foldl(fun({Key,Name}, ConfAcc) ->
- [{Key, filename:join(Dir,Name)} | ConfAcc]
+ [{Key, filename:join(Dir,Name)} | ConfAcc]
end,
Config1,
lists:zip(Keys, [proplists:get_value(K,Config0) || K<-Keys])),
+ catch ct:log("~p:~p Prepared filenames (Key -> Value):~n~ts",
+ [?MODULE,?LINE,
+ [io_lib:format("~p -> ~ts~n", [K,V]) || {K,V} <- Config2,
+ lists:member(K, Keys)]]),
+
DataDir = proplists:get_value(data_dir, Config2),
FilenameSrc = filename:join(DataDir, "sftp.txt"),
FilenameDst = proplists:get_value(filename, Config2),
@@ -1088,6 +1134,49 @@ prepare(Config0) ->
[{sftp_priv_dir,Dir} | Config2].
+have_unicode_support() -> (file:native_name_encoding() == utf8) andalso ("四" == [22235]).
+
+
+make_data_sub_dir(Config, SubDir) ->
+ make_data_sub_dir(Config, SubDir, SubDir).
+
+make_data_sub_dir(Config, SubDirSrc, SubDirDst) ->
+ SrcDir = filename:join(proplists:get_value(data_dir, Config),
+ SubDirSrc
+ ),
+ DstDir = filename:join(proplists:get_value(data_dir, Config),
+ SubDirDst),
+ ssh_test_lib:copy_recursive(SrcDir, DstDir),
+ {ok,DstDir}.
+
+
+prepare(Config0) ->
+ SrcDir = proplists:get_value(datadir_tar,Config0),
+ DstDir = filename:join(proplists:get_value(priv_dir,Config0), ssh_test_lib:random_chars(10)),
+ ssh_test_lib:copy_recursive(SrcDir, DstDir),
+ Keys = [filename,
+ testfile,
+ linktest,
+ tar_filename],
+ Config1 = foldl_keydelete(Keys, Config0),
+ Config2 = lists:foldl(fun({Key,Name}, ConfAcc) ->
+ [{Key, filename:join(DstDir,Name)} | ConfAcc]
+ end,
+ Config1,
+ lists:zip(Keys, [proplists:get_value(K,Config0) || K<-Keys])),
+
+ catch ct:log("~p:~p Prepared filenames (Key -> Value):~n~ts",
+ [?MODULE,?LINE,
+ [io_lib:format("~p -> ~ts~n", [K,V]) || {K,V} <- Config2,
+ lists:member(K, Keys)]]),
+
+ DataDir = proplists:get_value(data_dir, Config2),
+ FilenameSrc = filename:join(DataDir, "sftp.txt"),
+ FilenameDst = proplists:get_value(filename, Config2),
+ {ok,_} = file:copy(FilenameSrc, FilenameDst),
+ [{sftp_priv_dir,DstDir} | Config2].
+
+
foldl_keydelete(Keys, L) ->
lists:foldl(fun(K,E) -> lists:keydelete(K,1,E) end,
L,
@@ -1102,9 +1191,10 @@ chk_tar(Items, Config, Opts) ->
chk_tar(Items, TarFileName, Config, Opts).
chk_tar(Items, TarFileName, Config, Opts) when is_list(Opts) ->
+ SftpTarFileName = w2l(Config, TarFileName),
tar_size(TarFileName, Config),
{ChPid,_} = proplists:get_value(sftp,Config),
- {ok,HandleRead} = ssh_sftp:open_tar(ChPid, TarFileName, [read|Opts]),
+ {ok,HandleRead} = ssh_sftp:open_tar(ChPid, SftpTarFileName, [read|Opts]),
{ok,NameValueList} = erl_tar:extract(HandleRead,[memory,verbose]),
ok = erl_tar:close(HandleRead),
case {lists:sort(expand_items(Items,Config)), lists:sort(NameValueList)} of
@@ -1145,8 +1235,9 @@ analyze_report([], []) ->
"".
tar_size(TarFileName, Config) ->
+ SftpTarFileName = w2l(Config, TarFileName),
{ChPid,_} = proplists:get_value(sftp,Config),
- {ok,Data} = ssh_sftp:read_file(ChPid, TarFileName),
+ {ok,Data} = ssh_sftp:read_file(ChPid, SftpTarFileName),
io:format('Tar file ~p is~n ~p bytes.~n',[TarFileName, size(Data)]).
expand_items(Items, Config) ->
@@ -1178,3 +1269,22 @@ fn(Name, Config) ->
fmt_host({A,B,C,D}) -> lists:concat([A,".",B,".",C,".",D]);
fmt_host(S) -> S.
+
+%%%----------------------------------------------------------------
+populate_non_unicode(Dir) ->
+ file:delete("f1.txt"),
+ ok = file:write_file(filename:join(Dir,"f3.txt"),
+ unicode:characters_to_binary("你好")),
+ ok = file:write_file(filename:join(Dir,"F一.txt"),
+ unicode:characters_to_binary("你好")),
+ ok = file:write_file(filename:join(Dir,"g四.txt"),
+ <<"How are you?">>).
+
+w2l(P) ->
+ ssh_test_lib:winpath_to_linuxpath(P).
+
+w2l(Config, P) ->
+ W2L = proplists:get_value(w2l, Config, fun(X) -> X end),
+ W2L(P).
+
+
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/F一.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/F一.txt
deleted file mode 100644
index e6076a05b5..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/F一.txt
+++ /dev/null
@@ -1 +0,0 @@
-你好
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/big.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/big.txt
deleted file mode 100644
index f597b69d4c..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/big.txt
+++ /dev/null
@@ -1,16384 +0,0 @@
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
-All work and no play makes Jack a dull boy.
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f1 b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f1
deleted file mode 100644
index 1bafa9761e..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f1
+++ /dev/null
@@ -1 +0,0 @@
-And hi from the subdirectory too!
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f2 b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f2
deleted file mode 100644
index 8566adaeef..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/d1/f2
+++ /dev/null
@@ -1 +0,0 @@
-one more file
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f2.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f2.txt
deleted file mode 100644
index d18c6b11fc..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f2.txt
+++ /dev/null
@@ -1 +0,0 @@
-How are you?
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f3.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f3.txt
deleted file mode 100644
index e6076a05b5..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/f3.txt
+++ /dev/null
@@ -1 +0,0 @@
-你好
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/g四.txt b/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/g四.txt
deleted file mode 100644
index d18c6b11fc..0000000000
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data_高兴/g四.txt
+++ /dev/null
@@ -1 +0,0 @@
-How are you?
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/big.txt b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/big.txt
index f597b69d4c..f597b69d4c 100644
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/big.txt
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/big.txt
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/d1/f1 b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/d1/f1
index 1bafa9761e..1bafa9761e 100644
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/d1/f1
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/d1/f1
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/d1/f2 b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/d1/f2
index 8566adaeef..8566adaeef 100644
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/d1/f2
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/d1/f2
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/f1.txt b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/f1.txt
index 137d409d7b..137d409d7b 100644
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/f1.txt
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/f1.txt
diff --git a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/f2.txt b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/f2.txt
index d18c6b11fc..d18c6b11fc 100644
--- a/lib/ssh/test/ssh_sftp_SUITE_data/sftp_tar_test_data/f2.txt
+++ b/lib/ssh/test/ssh_sftp_SUITE_data/test_data/f2.txt
diff --git a/lib/ssh/test/ssh_sup_SUITE.erl b/lib/ssh/test/ssh_sup_SUITE.erl
index a0e3d809be..73bfc13eef 100644
--- a/lib/ssh/test/ssh_sup_SUITE.erl
+++ b/lib/ssh/test/ssh_sup_SUITE.erl
@@ -58,11 +58,10 @@ end_per_group(_GroupName, Config) ->
init_per_suite(Config) ->
?CHECK_CRYPTO(
begin
- Port = ssh_test_lib:inet_port(node()),
PrivDir = proplists:get_value(priv_dir, Config),
UserDir = filename:join(PrivDir, nopubkey), % to make sure we don't use public-key-auth
file:make_dir(UserDir),
- [{userdir, UserDir},{port, Port}, {host, "localhost"}, {host_ip, any} | Config]
+ [{userdir, UserDir} | Config]
end).
end_per_suite(_) ->
@@ -136,13 +135,11 @@ sshc_subtree(Config) when is_list(Config) ->
sshd_subtree() ->
[{doc, "Make sure the sshd subtree is correct"}].
sshd_subtree(Config) when is_list(Config) ->
- HostIP = proplists:get_value(host_ip, Config),
- Port = proplists:get_value(port, Config),
SystemDir = proplists:get_value(data_dir, Config),
- {ok,Daemon} = ssh:daemon(HostIP, Port, [{system_dir, SystemDir},
- {failfun, fun ssh_test_lib:failfun/2},
- {user_passwords,
- [{?USER, ?PASSWD}]}]),
+ {Daemon, HostIP, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {user_passwords,
+ [{?USER, ?PASSWD}]}]),
ct:log("Expect HostIP=~p, Port=~p, Daemon=~p",[HostIP,Port,Daemon]),
?wait_match([{{server,ssh_system_sup, ListenIP, Port, ?DEFAULT_PROFILE},
@@ -151,7 +148,7 @@ sshd_subtree(Config) when is_list(Config) ->
supervisor:which_children(sshd_sup),
[ListenIP,Daemon]),
true = ssh_test_lib:match_ip(HostIP, ListenIP),
- check_sshd_system_tree(Daemon, Config),
+ check_sshd_system_tree(Daemon, HostIP, Port, Config),
ssh:stop_daemon(HostIP, Port),
ct:sleep(?WAIT_FOR_SHUTDOWN),
?wait_match([], supervisor:which_children(sshd_sup)).
@@ -160,16 +157,14 @@ sshd_subtree(Config) when is_list(Config) ->
sshd_subtree_profile() ->
[{doc, "Make sure the sshd subtree using profile option is correct"}].
sshd_subtree_profile(Config) when is_list(Config) ->
- HostIP = proplists:get_value(host_ip, Config),
- Port = proplists:get_value(port, Config),
Profile = proplists:get_value(profile, Config),
SystemDir = proplists:get_value(data_dir, Config),
- {ok, Daemon} = ssh:daemon(HostIP, Port, [{system_dir, SystemDir},
- {failfun, fun ssh_test_lib:failfun/2},
- {user_passwords,
- [{?USER, ?PASSWD}]},
- {profile, Profile}]),
+ {Daemon, HostIP, Port} = ssh_test_lib:daemon([{system_dir, SystemDir},
+ {failfun, fun ssh_test_lib:failfun/2},
+ {user_passwords,
+ [{?USER, ?PASSWD}]},
+ {profile, Profile}]),
ct:log("Expect HostIP=~p, Port=~p, Profile=~p, Daemon=~p",[HostIP,Port,Profile,Daemon]),
?wait_match([{{server,ssh_system_sup, ListenIP,Port,Profile},
Daemon, supervisor,
@@ -177,7 +172,7 @@ sshd_subtree_profile(Config) when is_list(Config) ->
supervisor:which_children(sshd_sup),
[ListenIP,Daemon]),
true = ssh_test_lib:match_ip(HostIP, ListenIP),
- check_sshd_system_tree(Daemon, Config),
+ check_sshd_system_tree(Daemon, HostIP, Port, Config),
ssh:stop_daemon(HostIP, Port, Profile),
ct:sleep(?WAIT_FOR_SHUTDOWN),
?wait_match([], supervisor:which_children(sshd_sup)).
@@ -354,9 +349,7 @@ chk_empty_con_daemon(Daemon) ->
%%-------------------------------------------------------------------------
%% Help functions
%%-------------------------------------------------------------------------
-check_sshd_system_tree(Daemon, Config) ->
- Host = proplists:get_value(host, Config),
- Port = proplists:get_value(port, Config),
+check_sshd_system_tree(Daemon, Host, Port, Config) ->
UserDir = proplists:get_value(userdir, Config),
{ok, Client} = ssh:connect(Host, Port, [{silently_accept_hosts, true},
{user_interaction, false},
diff --git a/lib/ssh/test/ssh_test_lib.erl b/lib/ssh/test/ssh_test_lib.erl
index 036820fa8d..83481e6c33 100644
--- a/lib/ssh/test/ssh_test_lib.erl
+++ b/lib/ssh/test/ssh_test_lib.erl
@@ -28,6 +28,7 @@
-include_lib("public_key/include/public_key.hrl").
-include_lib("common_test/include/ct.hrl").
-include_lib("ssh/src/ssh_transport.hrl").
+-include_lib("kernel/include/file.hrl").
-include("ssh_test_lib.hrl").
%%%----------------------------------------------------------------
@@ -353,12 +354,6 @@ receive_exec_result(Data, ConnectionRef, ChannelId) ->
expected = receive_exec_result(Closed).
-inet_port()->
- {ok, Socket} = gen_tcp:listen(0, [{reuseaddr, true}]),
- {ok, Port} = inet:port(Socket),
- gen_tcp:close(Socket),
- Port.
-
setup_ssh_auth_keys(RSAFile, DSAFile, Dir) ->
Entries = ssh_file_entry(RSAFile) ++ ssh_file_entry(DSAFile),
AuthKeys = public_key:ssh_encode(Entries , auth_keys),
@@ -611,19 +606,12 @@ del_dirs(Dir) ->
ok
end.
-inet_port(Node) ->
- {Port, Socket} = do_inet_port(Node),
- rpc:call(Node, gen_tcp, close, [Socket]),
- Port.
-
-do_inet_port(Node) ->
- {ok, Socket} = rpc:call(Node, gen_tcp, listen, [0, [{reuseaddr, true}]]),
- {ok, Port} = rpc:call(Node, inet, port, [Socket]),
- {Port, Socket}.
-
openssh_sanity_check(Config) ->
ssh:start(),
- case ssh:connect("localhost", 22, [{password,""}]) of
+ case ssh:connect("localhost", 22, [{password,""},
+ {silently_accept_hosts, true},
+ {user_interaction, false}
+ ]) of
{ok, Pid} ->
ssh:close(Pid),
ssh:stop(),
@@ -1124,3 +1112,68 @@ report(Comment, Line) ->
crypto:info_lib(),
crypto:info_fips(),
crypto:supports()]).
+
+%%%----------------------------------------------------------------
+lc_name_in(Names) ->
+ case inet:gethostname() of
+ {ok,Name} ->
+ lists:member(string:to_lower(Name), Names);
+ Other ->
+ ct:log("~p:~p inet:gethostname() returned ~p", [?MODULE,?LINE,Other]),
+ false
+ end.
+
+ptty_supported() -> not lc_name_in([]). %%["fobi"]).
+
+%%%----------------------------------------------------------------
+has_WSL() ->
+ os:getenv("WSLENV") =/= false. % " =/= false" =/= "== true" :)
+
+winpath_to_linuxpath(Path) ->
+ case {has_WSL(), Path} of
+ {true, [_,$:|WithoutWinInit]} ->
+ "/mnt/c" ++ WithoutWinInit;
+ _ ->
+ Path
+ end.
+
+%%%----------------------------------------------------------------
+copy_recursive(Src, Dst) ->
+ {ok,S} = file:read_file_info(Src),
+ case S#file_info.type of
+ directory ->
+ %%ct:log("~p:~p copy dir ~ts -> ~ts", [?MODULE,?LINE,Src,Dst]),
+ {ok,Names} = file:list_dir(Src),
+ mk_dir_path(Dst),
+ %%ct:log("~p:~p Names = ~p", [?MODULE,?LINE,Names]),
+ lists:foreach(fun(Name) ->
+ copy_recursive(filename:join(Src, Name),
+ filename:join(Dst, Name))
+ end, Names);
+ _ ->
+ %%ct:log("~p:~p copy file ~ts -> ~ts", [?MODULE,?LINE,Src,Dst]),
+ {ok,_NumBytesCopied} = file:copy(Src, Dst)
+ end.
+
+%%%----------------------------------------------------------------
+%% Make a directory even if parts of the path does not exist
+
+mk_dir_path(DirPath) ->
+ case file:make_dir(DirPath) of
+ {error,eexist} ->
+ %%ct:log("~p:~p dir exists ~ts", [?MODULE,?LINE,DirPath]),
+ ok;
+ {error,enoent} ->
+ %%ct:log("~p:~p try make dirname of ~ts", [?MODULE,?LINE,DirPath]),
+ case mk_dir_path( filename:dirname(DirPath) ) of
+ ok ->
+ %%ct:log("~p:~p redo ~ts", [?MODULE,?LINE,DirPath]),
+ file:make_dir(DirPath);
+ Error ->
+ %%ct:log("~p:~p return Error ~p ~ts", [?MODULE,?LINE,Error,DirPath]),
+ Error
+ end;
+ Other ->
+ %%ct:log("~p:~p return Other ~p ~ts", [?MODULE,?LINE,Other,DirPath]),
+ Other
+ end.
diff --git a/lib/ssh/test/ssh_to_openssh_SUITE.erl b/lib/ssh/test/ssh_to_openssh_SUITE.erl
index cf64ac8dab..4f06bd3d65 100644
--- a/lib/ssh/test/ssh_to_openssh_SUITE.erl
+++ b/lib/ssh/test/ssh_to_openssh_SUITE.erl
@@ -62,7 +62,10 @@ init_per_suite(Config) ->
{error,econnrefused} ->
{skip,"No openssh deamon (econnrefused)"};
_ ->
- ssh_test_lib:openssh_sanity_check(Config)
+ ssh_test_lib:openssh_sanity_check(
+ [{ptty_supported, ssh_test_lib:ptty_supported()}
+ | Config]
+ )
end
).
@@ -118,14 +121,26 @@ erlang_shell_client_openssh_server(Config) when is_list(Config) ->
Prev = lists:usort(supervisor:which_children(sshc_sup)),
Shell = ssh_test_lib:start_shell(?SSH_DEFAULT_PORT, IO),
IO ! {input, self(), "echo Hej\n"},
- receive_data("Hej", undefined),
- IO ! {input, self(), "exit\n"},
- receive_logout(),
- receive_normal_exit(Shell),
- %% Check that the connection is closed:
- ct:log("Expects ~p", [Prev]),
- ?wait_match(Prev, lists:usort(supervisor:which_children(sshc_sup))).
-
+ case proplists:get_value(ptty_supported, Config) of
+ true ->
+ ct:log("~p:~p ptty supported", [?MODULE,?LINE]),
+ receive_data("Hej", undefined),
+ IO ! {input, self(), "exit\n"},
+ receive_logout(),
+ receive_normal_exit(Shell),
+ %% Check that the connection is closed:
+ ct:log("Expects ~p", [Prev]),
+ ?wait_match(Prev, lists:usort(supervisor:which_children(sshc_sup)));
+ false ->
+ ct:log("~p:~p ptty unsupported", [?MODULE,?LINE]),
+ receive_exit(Shell,
+ fun({{badmatch,failure},
+ [{ssh,shell,_,_} | _]}) -> true;
+ (_) ->
+ false
+ end)
+ end.
+
%%--------------------------------------------------------------------
%% Test that the server could redirect stdin and stdout from/to an
%% OpensSSH client when handling an exec request
@@ -168,6 +183,7 @@ exec_direct_with_io_in_sshc(Config) when is_list(Config) ->
ct:pal("Cmd = ~p~n",[Cmd]),
case os:cmd(Cmd) of
"? {ciao,\"oaic\"}" -> ok;
+ "'? '{ciao,\"oaic\"}" -> ok; % WSL
"{ciao,\"oaic\"}? " -> ok; % Could happen if the client sends the piped
% input before receiving the prompt ("? ").
Other -> ct:fail("Received ~p",[Other])
@@ -239,14 +255,14 @@ receive_data(Data, Conn) ->
Lines = string:tokens(binary_to_list(Info), "\r\n "),
case lists:member(Data, Lines) of
true ->
- ct:log("Expected result ~p found in lines: ~p~n", [Data,Lines]),
+ ct:log("~p:~p Expected result ~p found in lines: ~p~n", [?MODULE,?LINE,Data,Lines]),
ok;
false ->
- ct:log("Extra info: ~p~n", [Info]),
+ ct:log("~p:~p Extra info: ~p~n", [?MODULE,?LINE,Info]),
receive_data(Data, Conn)
end;
Other ->
- ct:log("Unexpected: ~p",[Other]),
+ ct:log("~p:~p Unexpected: ~p",[?MODULE,?LINE,Other]),
receive_data(Data, Conn)
after
30000 ->
@@ -275,18 +291,32 @@ receive_logout() ->
30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
end.
+
receive_normal_exit(Shell) ->
+ receive_exit(Shell, fun(Reason) -> Reason == normal end).
+
+
+receive_exit(Shell, F) when is_function(F,1) ->
receive
- {'EXIT', Shell, normal} ->
- ok;
- <<"\r\n">> ->
- receive_normal_exit(Shell);
- Other ->
- ct:fail({unexpected_msg, Other})
- after
+ {'EXIT', Shell, Reason} ->
+ case F(Reason) of
+ true ->
+ ok;
+ false ->
+ ct:fail({unexpected_exit, Reason})
+ end;
+
+ <<"\r\n">> ->
+ receive_normal_exit(Shell);
+
+ Other ->
+ ct:fail({unexpected_msg, Other})
+
+ after
30000 -> ct:fail("timeout ~p:~p",[?MODULE,?LINE])
end.
+
extra_logout() ->
receive
<<"logout">> ->
diff --git a/lib/ssh/test/ssh_upgrade_SUITE.erl b/lib/ssh/test/ssh_upgrade_SUITE.erl
index 7b9b109fa1..de9d7b2b1c 100644
--- a/lib/ssh/test/ssh_upgrade_SUITE.erl
+++ b/lib/ssh/test/ssh_upgrade_SUITE.erl
@@ -149,8 +149,7 @@ setup_server_client(#state{config=Config} = State) ->
SFTP = ssh_sftpd:subsystem_spec([{root,FtpRootDir},{cwd,FtpRootDir}]),
- {Server,Host,Port} = ssh_test_lib:daemon(ssh_test_lib:inet_port(), % when lower rel is 18.x
- [{system_dir,DataDir},
+ {Server,Host,Port} = ssh_test_lib:daemon([{system_dir,DataDir},
{user_passwords,[{"hej","hopp"}]},
{subsystems,[SFTP]}]),
diff --git a/lib/ssh/vsn.mk b/lib/ssh/vsn.mk
index a205da67fc..64b0bda0b4 100644
--- a/lib/ssh/vsn.mk
+++ b/lib/ssh/vsn.mk
@@ -1,4 +1,4 @@
#-*-makefile-*- ; force emacs to enter makefile-mode
-SSH_VSN = 4.8.1
+SSH_VSN = 4.8.2
APP_VSN = "ssh-$(SSH_VSN)"
diff --git a/lib/ssl/doc/src/notes.xml b/lib/ssl/doc/src/notes.xml
index 3671bfbdb6..6360f5977e 100644
--- a/lib/ssl/doc/src/notes.xml
+++ b/lib/ssl/doc/src/notes.xml
@@ -27,6 +27,65 @@
</header>
<p>This document describes the changes made to the SSL application.</p>
+<section><title>SSL 9.5.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Enhance error handling, all ALERTS shall be handled
+ gracefully and not cause a crash.</p>
+ <p>
+ Own Id: OTP-16413 Aux Id: ERL-1136 </p>
+ </item>
+ <item>
+ <p>
+ Enhance alert logging, in some places the role indication
+ of the alert origin was missing. So the log would say
+ undefined instead of client or server.</p>
+ <p>
+ Own Id: OTP-16424</p>
+ </item>
+ <item>
+ <p>
+ Two different optimizations did not work together and
+ resulted in the possible breakage of connections using
+ stream ciphers (that is RC4). Reworked the implementation
+ to avoid this.</p>
+ <p>
+ Own Id: OTP-16426 Aux Id: ERL-1136 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>SSL 9.5.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ Fix the handling of GREASE values sent by web browsers
+ when establishing TLS 1.3 connections. This change
+ improves handling of GREASE values in various protocol
+ elements sent in a TLS 1.3 ClientHello.</p>
+ <p>
+ Own Id: OTP-16388 Aux Id: ERL-1130 </p>
+ </item>
+ <item>
+ <p>
+ Correct DTLS listen emulation, could cause problems with
+ opening a new DTLS listen socket for a port previously
+ used by a now closed DTLS listen socket.</p>
+ <p>
+ Own Id: OTP-16396 Aux Id: ERL-1118 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>SSL 9.5.1</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/ssl/doc/src/ssl.xml b/lib/ssl/doc/src/ssl.xml
index 7424566adb..27b8a3f457 100644
--- a/lib/ssl/doc/src/ssl.xml
+++ b/lib/ssl/doc/src/ssl.xml
@@ -348,20 +348,35 @@
<datatype>
<name name="cipher_suites"/>
<desc>
- <p>Supported cipher suites. The function
- <c>cipher_suites/2</c> can be used to find all ciphers that
- are supported by default. <c>cipher_suites(all, 'tlsv1.2')</c> can be
- called to find all available cipher suites. Pre-Shared Key
- (<url href="http://www.ietf.org/rfc/rfc4279.txt">RFC
- 4279</url> and <url
- href="http://www.ietf.org/rfc/rfc5487.txt">RFC 5487</url>),
- Secure Remote Password (<url
- href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</url>),
- RC4, 3DES, DES cipher suites, and anonymous cipher suites only work if
- explicitly enabled by this option; they are supported/enabled
- by the peer also. Anonymous cipher suites are supported for
- testing purposes only and are not be used when security
- matters.</p>
+ <p>A list of cipher suites that should be supported</p>
+
+ <p>The function <seealso
+ marker="#cipher_suites-2"> ssl:cipher_suites/2 </seealso>
+ can be used to find all cipher suites that
+ are supported by default and all cipher suites that may be configured.</p>
+
+ <p>If you compose your own <c>cipher_suites()</c> make
+ sure they are filtered for cryptolib support
+ <seealso
+ marker="#filter_cipher_suites-2"> ssl:filter_cipher_suites/2 </seealso>
+ Additionaly the functions <seealso
+ marker="#append_cipher_suites-2"> ssl:append_cipher_suites/2 </seealso>
+ , <seealso
+ marker="#prepend_cipher_suites-2"> ssl:prepend_cipher_suites/2</seealso>,
+ <seealso marker="#suite_to_str/1">ssl:suite_to_str/1</seealso>,
+ <seealso marker="#str_to_suite/1">ssl:str_to_suite/1</seealso>,
+ and <seealso marker="#suite_to_openssl_str/1">ssl:suite_to_openssl_str/1</seealso>
+ also exist to help creating customized cipher suite lists.</p>
+
+ <note><p>Note that TLS-1.3 and TLS-1.2 cipher suites are not overlapping
+ sets of cipher suites so to support both these versions cipher
+ suites from both versions need to be included. If supporting
+ TLS-1.3 versions prior to TLS-1.2 can not be supported. </p></note>
+
+ <p>Non-default cipher suites including anonymous cipher suites (PRE TLS-1.3) are supported for
+ interop/testing purposes and may be used by adding them to your cipher suite list.
+ Note that they must also be supported/enabled by the peer to actually be used.
+ </p>
</desc>
</datatype>
@@ -747,6 +762,21 @@ fun(srp, Username :: string(), UserState :: term()) ->
</desc>
</datatype>
+ <datatype>
+ <name name="key_update_at"/>
+ <desc><p>Configures the maximum amount of bytes that can be sent on a TLS 1.3 connection
+ before an automatic key update is performed.</p>
+ <p>There are cryptographic limits on the amount of plaintext which can be safely
+ encrypted under a given set of keys. The current default ensures that data integrity
+ will not be breached with probability greater than 1/2^57. For more information see
+ <url href="http://www.isg.rhul.ac.uk/~kp/TLS-AEbounds.pdf">Limits on Authenticated
+ Encryption Use in TLS</url>.</p>
+ <warning><p>The default value of this option shall provide the above mentioned security
+ guarantees and it shall be reasonable for most applications (~353 TB).</p>
+ </warning>
+ </desc>
+ </datatype>
+
<datatype_title>TLS/DTLS OPTION DESCRIPTIONS - CLIENT</datatype_title>
<datatype>
@@ -1258,6 +1288,17 @@ fun(srp, Username :: string(), UserState :: term()) ->
<desc><p>Returns all default or all supported (except anonymous),
or all anonymous cipher suites for a
TLS version</p>
+
+ <note><p>The cipher suites returned by this function are the
+ cipher suites that the OTP ssl application can support provided
+ that they are supported by the cryptolib linked with the OTP
+ crypto application. Use <seealso
+ marker="#filter_cipher_suites-2"> ssl:filter_cipher_suites(Suites,
+ []).</seealso> to filter the list for the current
+ cryptolib. Note that cipher suites may be filtered out because
+ they are too old or too new depending on the
+ cryptolib</p></note>
+
</desc>
</func>
@@ -1424,10 +1465,17 @@ fun(srp, Username :: string(), UserState :: term()) ->
<name since="OTP 20.3" name="filter_cipher_suites" arity="2" />
<fsummary></fsummary>
<desc><p>Removes cipher suites if any of the filter functions
- returns false for any part of the cipher suite. This function
- also calls default filter functions to make sure the cipher
- suites are supported by crypto. If no filter function is supplied for some
- part the default behaviour is fun(Algorithm) -> true.</p>
+ returns false for any part of the cipher suite. If no filter function is supplied for some
+ part the default behaviour regards it as if there was a filter function that returned true.
+
+ For examples see <seealso marker="ssl:using_ssl#customizing-cipher-suits"> Customizing cipher suits </seealso>
+
+ Additionaly this function also filters the cipher suites to
+ exclude cipher suites not supported by the cryptolib used by the
+ OTP crypto application. That is calling
+ ssl:filter_cipher_suites(Suites, []) will be equivalent to only
+ applying the filters for cryptolib support.
+ </p>
</desc>
</func>
@@ -1624,7 +1672,21 @@ fun(srp, Username :: string(), UserState :: term()) ->
is still active using the previously negotiated session.</p>
</desc>
</func>
-
+
+ <func>
+ <name since="OTP 22.3" name="update_keys" arity="2" />
+ <fsummary>Initiates a key update.</fsummary>
+ <desc><p>There are cryptographic limits on the amount of plaintext which can be safely
+ encrypted under a given set of keys. If the amount of data surpasses those limits, a key
+ update is triggered and a new set of keys are installed.
+ See also the option <seealso marker="ssl:ssl#type-key_update_at">key_update_at</seealso>.</p>
+ <p>This function can be used to explicitly start a key update on a TLS 1.3 connection.
+ There are two types of the key update: if <em>Type</em> is set to <em>write</em>, only the writing
+ key is updated; if <em>Type</em> is set to <em>read_write</em>, both the reading and writing keys
+ are updated.</p>
+ </desc>
+ </func>
+
<func>
<name since="" name="send" arity="2" />
<fsummary>Writes data to a socket.</fsummary>
diff --git a/lib/ssl/doc/src/standards_compliance.xml b/lib/ssl/doc/src/standards_compliance.xml
index 98542a797b..553ee79a39 100644
--- a/lib/ssl/doc/src/standards_compliance.xml
+++ b/lib/ssl/doc/src/standards_compliance.xml
@@ -1721,14 +1721,14 @@
</url>
</cell>
<cell align="left" valign="middle"><em>Client</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.3</em></cell>
</row>
<row>
<cell align="left" valign="middle"></cell>
<cell align="left" valign="middle"><em>Server</em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.3</em></cell>
</row>
<row>
@@ -1824,8 +1824,8 @@
</url>
</cell>
<cell align="left" valign="middle"><em></em></cell>
- <cell align="left" valign="middle"><em>NC</em></cell>
- <cell align="left" valign="middle"><em></em></cell>
+ <cell align="left" valign="middle"><em>C</em></cell>
+ <cell align="left" valign="middle"><em>22.3</em></cell>
</row>
<row>
diff --git a/lib/ssl/src/dtls_connection.erl b/lib/ssl/src/dtls_connection.erl
index a658fe0306..85ba4f0556 100644
--- a/lib/ssl/src/dtls_connection.erl
+++ b/lib/ssl/src/dtls_connection.erl
@@ -908,12 +908,13 @@ handle_client_hello(#client_hello{client_version = ClientVersion} = Hello,
%% raw data from socket, unpack records
handle_info({Protocol, _, _, _, Data}, StateName,
- #state{static_env = #static_env{data_tag = Protocol}} = State0) ->
+ #state{static_env = #static_env{role = Role,
+ data_tag = Protocol}} = State0) ->
case next_dtls_record(Data, StateName, State0) of
{Record, State} ->
next_event(StateName, Record, State);
#alert{} = Alert ->
- ssl_connection:handle_normal_shutdown(Alert, StateName, State0),
+ ssl_connection:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State0),
{stop, {shutdown, own_alert}, State0}
end;
@@ -925,8 +926,10 @@ handle_info({PassiveTag, Socket}, StateName,
State#state{protocol_specific = PS#{active_n_toggle => true}});
handle_info({CloseTag, Socket}, StateName,
- #state{static_env = #static_env{socket = Socket,
- close_tag = CloseTag},
+ #state{static_env = #static_env{
+ role = Role,
+ socket = Socket,
+ close_tag = CloseTag},
connection_env = #connection_env{negotiated_version = Version},
socket_options = #socket_options{active = Active},
protocol_buffers = #protocol_buffers{dtls_cipher_texts = CTs},
@@ -947,7 +950,8 @@ handle_info({CloseTag, Socket}, StateName,
%%invalidate_session(Role, Host, Port, Session)
ok
end,
- ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, transport_closed),
+ ssl_connection:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
{stop, {shutdown, transport_closed}, State};
true ->
%% Fixes non-delivery of final DTLS record in {active, once}.
diff --git a/lib/ssl/src/dtls_listener_sup.erl b/lib/ssl/src/dtls_listener_sup.erl
index 2c43c215be..dae7e48487 100644
--- a/lib/ssl/src/dtls_listener_sup.erl
+++ b/lib/ssl/src/dtls_listener_sup.erl
@@ -52,7 +52,7 @@ lookup_listner(Port) ->
[{Port, {Owner, Handler}}] ->
case erlang:is_process_alive(Handler) of
true ->
- case erlang:is_process_alive(Owner) of
+ case (Owner =/= undefined) andalso erlang:is_process_alive(Owner) of
true ->
{error, already_listening};
false ->
@@ -75,7 +75,7 @@ register_listner(OwnerAndListner, Port) ->
%%% Supervisor callback
%%%=========================================================================
init(_O) ->
- ets:new(dtls_listener_sup, [named_table, public]),
+ ets:new(dtls_listener_sup, [named_table, public, set]),
RestartStrategy = simple_one_for_one,
MaxR = 0,
MaxT = 3600,
diff --git a/lib/ssl/src/dtls_packet_demux.erl b/lib/ssl/src/dtls_packet_demux.erl
index cc3efa33ed..11ad659ff5 100644
--- a/lib/ssl/src/dtls_packet_demux.erl
+++ b/lib/ssl/src/dtls_packet_demux.erl
@@ -32,6 +32,7 @@
accept/2,
sockname/1,
close/1,
+ new_owner/1,
get_all_opts/1,
set_all_opts/2,
get_sock_opts/2,
@@ -76,16 +77,23 @@ accept(PacketSocket, Accepter) ->
sockname(PacketSocket) ->
call(PacketSocket, sockname).
+
close(PacketSocket) ->
call(PacketSocket, close).
+
+new_owner(PacketSocket) ->
+ call(PacketSocket, new_owner).
+
get_sock_opts(PacketSocket, SplitSockOpts) ->
call(PacketSocket, {get_sock_opts, SplitSockOpts}).
get_all_opts(PacketSocket) ->
call(PacketSocket, get_all_opts).
+
set_sock_opts(PacketSocket, Opts) ->
call(PacketSocket, {set_sock_opts, Opts}).
set_all_opts(PacketSocket, Opts) ->
call(PacketSocket, {set_all_opts, Opts}).
+
getstat(PacketSocket, Opts) ->
call(PacketSocket, {getstat, Opts}).
@@ -143,6 +151,8 @@ handle_call(close, _, #state{dtls_processes = Processes,
end, queue:to_list(Accepters)),
{reply, ok, State#state{close = true, accepters = queue:new()}}
end;
+handle_call(new_owner, _, State) ->
+ {reply, ok, State#state{close = false, first = true}};
handle_call({get_sock_opts, {SocketOptNames, EmOptNames}}, _, #state{listener = Socket,
emulated_options = EmOpts} = State) ->
case get_socket_opts(Socket, SocketOptNames) of
diff --git a/lib/ssl/src/dtls_socket.erl b/lib/ssl/src/dtls_socket.erl
index 81d9f3dcca..7c72c45bca 100644
--- a/lib/ssl/src/dtls_socket.erl
+++ b/lib/ssl/src/dtls_socket.erl
@@ -33,7 +33,9 @@
peername/2,
sockname/2,
port/2,
- close/2]).
+ close/2,
+ close/1
+ ]).
-export([emulated_options/0,
emulated_options/1,
@@ -56,6 +58,7 @@ listen(Port, #config{transport_info = TransportInfo,
dtls_listener_sup:register_listner({self(), Listner0}, Port),
Result0;
{ok, Listner0} = Result0 ->
+ dtls_packet_demux:new_owner(Listner0),
dtls_packet_demux:set_all_opts(Listner0, {Options, emulated_socket_options(EmOpts0, #socket_options{}), SslOpts}),
dtls_listener_sup:register_listner({self(), Listner0}, Port),
Result0;
@@ -96,6 +99,10 @@ connect(Address, Port, #config{transport_info = {Transport, _, _, _, _} = CbInfo
Error
end.
+close(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, Port}}}}) ->
+ dtls_listener_sup:register_listner({undefined, Pid}, Port),
+ dtls_packet_demux:close(Pid).
+
close(_, dtls) ->
ok;
close(gen_udp, {_Client, _Socket}) ->
diff --git a/lib/ssl/src/ssl.app.src b/lib/ssl/src/ssl.app.src
index c45e6bcf9a..63ccaabd74 100644
--- a/lib/ssl/src/ssl.app.src
+++ b/lib/ssl/src/ssl.app.src
@@ -74,5 +74,5 @@
{applications, [crypto, public_key, kernel, stdlib]},
{env, []},
{mod, {ssl_app, []}},
- {runtime_dependencies, ["stdlib-3.5","public_key-1.5","kernel-6.0",
+ {runtime_dependencies, ["stdlib-3.5","public_key-@OTP-16528@","kernel-6.0",
"erts-10.0","crypto-4.2", "inets-5.10.7"]}]}.
diff --git a/lib/ssl/src/ssl.erl b/lib/ssl/src/ssl.erl
index af6c50f0c1..ee1664a82f 100644
--- a/lib/ssl/src/ssl.erl
+++ b/lib/ssl/src/ssl.erl
@@ -87,6 +87,7 @@
groups/1,
format_error/1,
renegotiate/1,
+ update_keys/2,
prf/5,
negotiated_protocol/1,
connection_information/1,
@@ -313,7 +314,8 @@
{padding_check, padding_check()} |
{beast_mitigation, beast_mitigation()} |
{ssl_imp, ssl_imp()} |
- {session_tickets, session_tickets()}.
+ {session_tickets, session_tickets()} |
+ {key_update_at, key_update_at()}.
-type protocol() :: tls | dtls.
-type handshake_completion() :: hello | full.
@@ -356,6 +358,7 @@
-type client_session_tickets() :: disabled | manual | auto.
-type server_session_tickets() :: disabled | stateful | stateless.
-type session_tickets() :: client_session_tickets() | server_session_tickets().
+-type key_update_at() :: pos_integer().
-type bloom_filter_window_size() :: integer().
-type bloom_filter_hash_functions() :: integer().
-type bloom_filter_bits() :: integer().
@@ -786,8 +789,8 @@ handshake_cancel(Socket) ->
%%--------------------------------------------------------------------
close(#sslsocket{pid = [Pid|_]}) when is_pid(Pid) ->
ssl_connection:close(Pid, {close, ?DEFAULT_TIMEOUT});
-close(#sslsocket{pid = {dtls, #config{dtls_handler = {Pid, _}}}}) ->
- dtls_packet_demux:close(Pid);
+close(#sslsocket{pid = {dtls, #config{dtls_handler = {_, _}}}} = DTLSListen) ->
+ dtls_socket:close(DTLSListen);
close(#sslsocket{pid = {ListenSocket, #config{transport_info={Transport,_,_,_,_}}}}) ->
Transport:close(ListenSocket).
@@ -1351,6 +1354,28 @@ renegotiate(#sslsocket{pid = {dtls,_}}) ->
renegotiate(#sslsocket{pid = {Listen,_}}) when is_port(Listen) ->
{error, enotconn}.
+
+%%---------------------------------------------------------------
+-spec update_keys(SslSocket, Type) -> ok | {error, reason()} when
+ SslSocket :: sslsocket(),
+ Type :: write | read_write.
+%%
+%% Description: Initiate a key update.
+%%--------------------------------------------------------------------
+update_keys(#sslsocket{pid = [Pid, Sender |_]}, Type0) when is_pid(Pid) andalso
+ is_pid(Sender) andalso
+ (Type0 =:= write orelse
+ Type0 =:= read_write) ->
+ Type = case Type0 of
+ write ->
+ update_not_requested;
+ read_write ->
+ update_requested
+ end,
+ tls_connection:send_key_update(Sender, Type);
+update_keys(_, Type) ->
+ {error, {illegal_parameter, Type}}.
+
%%--------------------------------------------------------------------
-spec prf(SslSocket, Secret, Label, Seed, WantedLength) ->
{ok, binary()} | {error, reason()} when
@@ -1643,6 +1668,13 @@ handle_option(honor_ecc_order = Option, Value0, OptionsMap, #{role := Role}) ->
handle_option(keyfile = Option, unbound, #{certfile := CertFile} = OptionsMap, _Env) ->
Value = validate_option(Option, CertFile),
OptionsMap#{Option => Value};
+handle_option(key_update_at = Option, unbound, OptionsMap, #{rules := Rules}) ->
+ Value = validate_option(Option, default_value(Option, Rules)),
+ OptionsMap#{Option => Value};
+handle_option(key_update_at = Option, Value0, #{versions := Versions} = OptionsMap, _Env) ->
+ assert_option_dependency(Option, versions, Versions, ['tlsv1.3']),
+ Value = validate_option(Option, Value0),
+ OptionsMap#{Option => Value};
handle_option(next_protocol_selector = Option, unbound, OptionsMap, #{rules := Rules}) ->
Value = default_value(Option, Rules),
OptionsMap#{Option => Value};
@@ -1973,6 +2005,9 @@ validate_option(keyfile, Value) when is_binary(Value) ->
Value;
validate_option(keyfile, Value) when is_list(Value), Value =/= "" ->
binary_filename(Value);
+validate_option(key_update_at, Value) when is_integer(Value) andalso
+ Value > 0 ->
+ Value;
validate_option(password, Value) when is_list(Value) ->
Value;
@@ -2540,7 +2575,8 @@ include_security_info([Item | Items]) ->
end.
server_name_indication_default(Host) when is_list(Host) ->
- Host;
+ %% SNI should not contain a trailing dot that a hostname may
+ string:strip(Host, right, $.);
server_name_indication_default(_) ->
undefined.
diff --git a/lib/ssl/src/ssl_alert.erl b/lib/ssl/src/ssl_alert.erl
index d4b0cb1f14..33b91b09e7 100644
--- a/lib/ssl/src/ssl_alert.erl
+++ b/lib/ssl/src/ssl_alert.erl
@@ -201,8 +201,8 @@ description_txt(?UNSUPPORTED_EXTENSION) ->
"Unsupported Extension";
description_txt(?CERTIFICATE_UNOBTAINABLE) ->
"Certificate Unobtainable";
-description_txt(?UNRECOGNISED_NAME) ->
- "Unrecognised Name";
+description_txt(?UNRECOGNIZED_NAME) ->
+ "Unrecognized Name";
description_txt(?BAD_CERTIFICATE_STATUS_RESPONSE) ->
"Bad Certificate Status Response";
description_txt(?BAD_CERTIFICATE_HASH_VALUE) ->
@@ -272,8 +272,8 @@ description_atom(?UNSUPPORTED_EXTENSION) ->
unsupported_extension;
description_atom(?CERTIFICATE_UNOBTAINABLE) ->
certificate_unobtainable;
-description_atom(?UNRECOGNISED_NAME) ->
- unrecognised_name;
+description_atom(?UNRECOGNIZED_NAME) ->
+ unrecognized_name;
description_atom(?BAD_CERTIFICATE_STATUS_RESPONSE) ->
bad_certificate_status_response;
description_atom(?BAD_CERTIFICATE_HASH_VALUE) ->
diff --git a/lib/ssl/src/ssl_alert.hrl b/lib/ssl/src/ssl_alert.hrl
index 0edc4bf8e4..6e562f0f33 100644
--- a/lib/ssl/src/ssl_alert.hrl
+++ b/lib/ssl/src/ssl_alert.hrl
@@ -107,7 +107,7 @@
-define(MISSING_EXTENSION, 109).
-define(UNSUPPORTED_EXTENSION, 110).
-define(CERTIFICATE_UNOBTAINABLE, 111).
--define(UNRECOGNISED_NAME, 112).
+-define(UNRECOGNIZED_NAME, 112).
-define(BAD_CERTIFICATE_STATUS_RESPONSE, 113).
-define(BAD_CERTIFICATE_HASH_VALUE, 114).
-define(UNKNOWN_PSK_IDENTITY, 115).
diff --git a/lib/ssl/src/ssl_connection.erl b/lib/ssl/src/ssl_connection.erl
index 20a080dc2b..b62a1c4546 100644
--- a/lib/ssl/src/ssl_connection.erl
+++ b/lib/ssl/src/ssl_connection.erl
@@ -53,7 +53,8 @@
%% Alert and close handling
-export([handle_own_alert/4, handle_alert/3,
handle_normal_shutdown/3,
- handle_trusted_certs_db/1]).
+ handle_trusted_certs_db/1,
+ maybe_invalidate_session/6]).
%% Data handling
-export([read_application_data/2, internal_renegotiation/2]).
@@ -325,6 +326,7 @@ dist_handshake_complete(ConnectionPid, DHandle) ->
prf(ConnectionPid, Secret, Label, Seed, WantedLength) ->
call(ConnectionPid, {prf, Secret, Label, Seed, WantedLength}).
+
%%====================================================================
%% Alert and close handling
%%====================================================================
@@ -442,6 +444,13 @@ handle_alert(#alert{level = ?WARNING} = Alert, StateName,
Alert#alert{role = opposite_role(Role)}),
Connection:next_event(StateName, no_record, State).
+maybe_invalidate_session(undefined,_, _, _, _, _) ->
+ ok;
+maybe_invalidate_session({3, 4},_, _, _, _, _) ->
+ ok;
+maybe_invalidate_session({3, N}, Type, Role, Host, Port, Session) when N < 4 ->
+ maybe_invalidate_session(Type, Role, Host, Port, Session).
+
%%====================================================================
%% Data handling
%%====================================================================
@@ -1342,18 +1351,22 @@ handle_common_event(internal, {handshake, {#hello_request{}, _}}, StateName,
when StateName =/= connection ->
keep_state_and_data;
handle_common_event(internal, {handshake, {Handshake, Raw}}, StateName,
- #state{handshake_env = #handshake_env{tls_handshake_history = Hist0}} = State0,
+ #state{handshake_env = #handshake_env{tls_handshake_history = Hist0},
+ connection_env = #connection_env{negotiated_version = Version}} = State0,
Connection) ->
PossibleSNI = Connection:select_sni_extension(Handshake),
%% This function handles client SNI hello extension when Handshake is
%% a client_hello, which needs to be determined by the connection callback.
%% In other cases this is a noop
- State = #state{handshake_env = HsEnv} = handle_sni_extension(PossibleSNI, State0),
-
- Hist = ssl_handshake:update_handshake_history(Hist0, Raw),
- {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}},
- [{next_event, internal, Handshake}]};
+ case handle_sni_extension(PossibleSNI, State0) of
+ #state{handshake_env = HsEnv} = State ->
+ Hist = ssl_handshake:update_handshake_history(Hist0, Raw),
+ {next_state, StateName, State#state{handshake_env = HsEnv#handshake_env{tls_handshake_history = Hist}},
+ [{next_event, internal, Handshake}]};
+ #alert{} = Alert ->
+ handle_own_alert(Alert, Version, StateName, State0)
+ end;
handle_common_event(internal, {protocol_record, TLSorDTLSRecord}, StateName, State, Connection) ->
Connection:handle_protocol_record(TLSorDTLSRecord, StateName, State);
handle_common_event(timeout, hibernate, _, _, _) ->
@@ -1492,24 +1505,34 @@ handle_call(_,_,_,_,_) ->
handle_info({ErrorTag, Socket, econnaborted}, StateName,
#state{static_env = #static_env{role = Role,
+ host = Host,
+ port = Port,
socket = Socket,
transport_cb = Transport,
error_tag = ErrorTag,
trackers = Trackers,
protocol_cb = Connection},
- start_or_recv_from = StartFrom
- } = State) when StateName =/= connection ->
+ handshake_env = #handshake_env{renegotiation = Type},
+ connection_env = #connection_env{negotiated_version = Version},
+ session = Session,
+ start_or_recv_from = StartFrom
+ } = State) when StateName =/= connection ->
+
+ maybe_invalidate_session(Version, Type, Role, Host, Port, Session),
Pids = Connection:pids(State),
alert_user(Pids, Transport, Trackers,Socket,
- StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, StateName, Connection),
+ StartFrom, ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), Role, StateName, Connection),
{stop, {shutdown, normal}, State};
-handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{socket = Socket,
- error_tag = ErrorTag},
+handle_info({ErrorTag, Socket, Reason}, StateName, #state{static_env = #static_env{
+ role = Role,
+ socket = Socket,
+ error_tag = ErrorTag},
ssl_options = #{log_level := Level}} = State) ->
ssl_logger:log(info, Level, #{description => "Socket error",
reason => [{error_tag, ErrorTag}, {description, Reason}]}, ?LOCATION),
- handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, {transport_error, Reason}),
+ handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
{stop, {shutdown,normal}, State};
handle_info({'DOWN', MonitorRef, _, _, Reason}, _,
@@ -2797,9 +2820,11 @@ ssl_options_list([{Key, Value}|T], Acc) ->
handle_active_option(false, connection = StateName, To, Reply, State) ->
hibernate_after(StateName, State, [{reply, To, Reply}]);
-handle_active_option(_, connection = StateName, To, _Reply, #state{connection_env = #connection_env{terminated = true},
+handle_active_option(_, connection = StateName, To, _Reply, #state{static_env = #static_env{role = Role},
+ connection_env = #connection_env{terminated = true},
user_data_buffer = {_,0,_}} = State) ->
- handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, all_data_deliverd), StateName,
+ Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, all_data_deliverd),
+ handle_normal_shutdown(Alert#alert{role = Role}, StateName,
State#state{start_or_recv_from = To}),
{stop,{shutdown, peer_close}, State};
handle_active_option(_, connection = StateName0, To, Reply, #state{static_env = #static_env{protocol_cb = Connection},
@@ -3004,6 +3029,11 @@ log_alert(Level, Role, ProtocolName, StateName, Alert) ->
alert => Alert,
alerter => peer}, Alert#alert.where).
+maybe_invalidate_session({false, first}, server = Role, Host, Port, Session) ->
+ invalidate_session(Role, Host, Port, Session);
+maybe_invalidate_session(_, _, _, _, _) ->
+ ok.
+
invalidate_session(client, Host, Port, Session) ->
ssl_manager:invalidate_session(Host, Port, Session);
invalidate_session(server, _, Port, Session) ->
@@ -3011,9 +3041,16 @@ invalidate_session(server, _, Port, Session) ->
handle_sni_extension(undefined, State) ->
State;
-handle_sni_extension(#sni{hostname = Hostname}, #state{static_env = #static_env{role = Role} = InitStatEnv0,
- handshake_env = HsEnv,
- connection_env = CEnv} = State0) ->
+handle_sni_extension(#sni{hostname = Hostname}, State) ->
+ case is_sni_value(Hostname) of
+ true ->
+ handle_sni_extension(Hostname, State);
+ false ->
+ ?ALERT_REC(?FATAL, ?UNRECOGNIZED_NAME, {sni_included_trailing_dot, Hostname})
+ end;
+handle_sni_extension(Hostname, #state{static_env = #static_env{role = Role} = InitStatEnv0,
+ handshake_env = HsEnv,
+ connection_env = CEnv} = State0) ->
NewOptions = update_ssl_options_from_sni(State0#state.ssl_options, Hostname),
case NewOptions of
undefined ->
@@ -3070,3 +3107,11 @@ no_records(Extensions) ->
maps:map(fun(_, Value) ->
ssl_handshake:extension_value(Value)
end, Extensions).
+
+is_sni_value(Hostname) ->
+ case hd(lists:reverse(Hostname)) of
+ $. ->
+ false;
+ _ ->
+ true
+ end.
diff --git a/lib/ssl/src/ssl_handshake.erl b/lib/ssl/src/ssl_handshake.erl
index ecbe905d28..3b33af95d0 100644
--- a/lib/ssl/src/ssl_handshake.erl
+++ b/lib/ssl/src/ssl_handshake.erl
@@ -402,6 +402,12 @@ certificate_verify(Signature, PublicKeyInfo, Version,
%%--------------------------------------------------------------------
verify_signature(_Version, _Hash, {_HashAlgo, anon}, _Signature, _) ->
true;
+verify_signature({3, Minor}, Hash, {HashAlgo, rsa_pss_rsae}, Signature, {?rsaEncryption, PubKey, _PubKeyParams})
+ when Minor >= 3 ->
+ public_key:verify({digest, Hash}, HashAlgo, Signature, PubKey,
+ [{rsa_padding, rsa_pkcs1_pss_padding},
+ {rsa_pss_saltlen, -1},
+ {rsa_mgf1_md, HashAlgo}]);
verify_signature({3, Minor}, Hash, {HashAlgo, rsa}, Signature, {?rsaEncryption, PubKey, _PubKeyParams})
when Minor >= 3 ->
public_key:verify({digest, Hash}, HashAlgo, Signature, PubKey);
@@ -2356,6 +2362,20 @@ dec_server_key_params(Len, Keys, Version) ->
<<Params:Len/bytes, Signature/binary>> = Keys,
dec_server_key_signature(Params, Signature, Version).
+dec_server_key_signature(Params, <<?BYTE(8), ?BYTE(SignAlgo),
+ ?UINT16(0)>>, {Major, Minor})
+ when Major == 3, Minor >= 3 ->
+ <<?UINT16(Scheme0)>> = <<?BYTE(8), ?BYTE(SignAlgo)>>,
+ Scheme = ssl_cipher:signature_scheme(Scheme0),
+ {Hash, Sign, _} = ssl_cipher:scheme_to_components(Scheme),
+ {Params, {Hash, Sign}, <<>>};
+dec_server_key_signature(Params, <<?BYTE(8), ?BYTE(SignAlgo),
+ ?UINT16(Len), Signature:Len/binary>>, {Major, Minor})
+ when Major == 3, Minor >= 3 ->
+ <<?UINT16(Scheme0)>> = <<?BYTE(8), ?BYTE(SignAlgo)>>,
+ Scheme = ssl_cipher:signature_scheme(Scheme0),
+ {Hash, Sign, _} = ssl_cipher:scheme_to_components(Scheme),
+ {Params, {Hash, Sign}, Signature};
dec_server_key_signature(Params, <<?BYTE(HashAlgo), ?BYTE(SignAlgo),
?UINT16(0)>>, {Major, Minor})
when Major == 3, Minor >= 3 ->
@@ -2464,8 +2484,17 @@ decode_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_EXT), ?UINT16(Len),
when Version =:= {3,4} ->
SignSchemeListLen = Len - 2,
<<?UINT16(SignSchemeListLen), SignSchemeList/binary>> = ExtData,
- SignSchemes = [ssl_cipher:signature_scheme(SignScheme) ||
- <<?UINT16(SignScheme)>> <= SignSchemeList],
+ %% Ignore unknown signature algorithms
+ Fun = fun(Elem) ->
+ case ssl_cipher:signature_scheme(Elem) of
+ unassigned ->
+ false;
+ Value ->
+ {true, Value}
+ end
+ end,
+ SignSchemes= lists:filtermap(Fun, [SignScheme ||
+ <<?UINT16(SignScheme)>> <= SignSchemeList]),
decode_extensions(Rest, Version, MessageType,
Acc#{signature_algs =>
#signature_algorithms{
@@ -2475,8 +2504,17 @@ decode_extensions(<<?UINT16(?SIGNATURE_ALGORITHMS_CERT_EXT), ?UINT16(Len),
ExtData:Len/binary, Rest/binary>>, Version, MessageType, Acc) ->
SignSchemeListLen = Len - 2,
<<?UINT16(SignSchemeListLen), SignSchemeList/binary>> = ExtData,
- SignSchemes = [ssl_cipher:signature_scheme(SignScheme) ||
- <<?UINT16(SignScheme)>> <= SignSchemeList],
+ %% Ignore unknown signature algorithms
+ Fun = fun(Elem) ->
+ case ssl_cipher:signature_scheme(Elem) of
+ unassigned ->
+ false;
+ Value ->
+ {true, Value}
+ end
+ end,
+ SignSchemes= lists:filtermap(Fun, [SignScheme ||
+ <<?UINT16(SignScheme)>> <= SignSchemeList]),
decode_extensions(Rest, Version, MessageType,
Acc#{signature_algs_cert =>
#signature_algorithms_cert{
@@ -2651,11 +2689,18 @@ decode_client_shares(ClientShares) ->
%%
decode_client_shares(<<>>, Acc) ->
lists:reverse(Acc);
-decode_client_shares(<<?UINT16(Group),?UINT16(Len),KeyExchange:Len/binary,Rest/binary>>, Acc) ->
- decode_client_shares(Rest, [#key_share_entry{
- group = tls_v1:enum_to_group(Group),
- key_exchange= KeyExchange
- }|Acc]).
+decode_client_shares(<<?UINT16(Group0),?UINT16(Len),KeyExchange:Len/binary,Rest/binary>>, Acc) ->
+ case tls_v1:enum_to_group(Group0) of
+ undefined ->
+ %% Ignore key_share with unknown group
+ decode_client_shares(Rest, Acc);
+ Group ->
+ decode_client_shares(Rest, [#key_share_entry{
+ group = Group,
+ key_exchange= KeyExchange
+ }|Acc])
+ end.
+
decode_next_protocols({next_protocol_negotiation, Protocols}) ->
decode_protocols(Protocols, []).
@@ -2681,7 +2726,10 @@ decode_psk_key_exchange_modes(<<>>, Acc) ->
decode_psk_key_exchange_modes(<<?BYTE(?PSK_KE), Rest/binary>>, Acc) ->
decode_psk_key_exchange_modes(Rest, [psk_ke|Acc]);
decode_psk_key_exchange_modes(<<?BYTE(?PSK_DHE_KE), Rest/binary>>, Acc) ->
- decode_psk_key_exchange_modes(Rest, [psk_dhe_ke|Acc]).
+ decode_psk_key_exchange_modes(Rest, [psk_dhe_ke|Acc]);
+%% Ignore unknown PskKeyExchangeModes
+decode_psk_key_exchange_modes(<<?BYTE(_), Rest/binary>>, Acc) ->
+ decode_psk_key_exchange_modes(Rest, Acc).
decode_psk_identities(Identities) ->
diff --git a/lib/ssl/src/ssl_internal.hrl b/lib/ssl/src/ssl_internal.hrl
index ceca206605..d661de323c 100644
--- a/lib/ssl/src/ssl_internal.hrl
+++ b/lib/ssl/src/ssl_internal.hrl
@@ -109,6 +109,12 @@
-define('24H_in_msec', 86400000).
-define('24H_in_sec', 86400).
+%% https://tools.ietf.org/html/rfc8446#section-5.5
+%% Limits on Key Usage
+%% http://www.isg.rhul.ac.uk/~kp/TLS-AEbounds.pdf
+%% Number of records * Record length
+%% 2^24.5 * 2^14 = 2^38.5
+-define(KEY_USAGE_LIMIT_AES_GCM, 388736063997).
%% This map stores all supported options with default values and
%% list of dependencies:
@@ -144,6 +150,7 @@
key => {undefined, [versions]},
keyfile => {undefined, [versions,
certfile]},
+ key_update_at => {?KEY_USAGE_LIMIT_AES_GCM, [versions]},
log_level => {notice, [versions]},
max_handshake_size => {?DEFAULT_MAX_HANDSHAKE_SIZE, [versions]},
next_protocol_selector => {undefined, [versions]},
diff --git a/lib/ssl/src/ssl_logger.erl b/lib/ssl/src/ssl_logger.erl
index 9ee0c23aaa..66de98c53a 100644
--- a/lib/ssl/src/ssl_logger.erl
+++ b/lib/ssl/src/ssl_logger.erl
@@ -244,6 +244,11 @@ parse_handshake(Direction, #new_session_ticket{} = NewSessionTicket) ->
Header = io_lib:format("~s Post-Handshake, NewSessionTicket",
[header_prefix(Direction)]),
Message = io_lib:format("~p", [?rec_info(new_session_ticket, NewSessionTicket)]),
+ {Header, Message};
+parse_handshake(Direction, #key_update{} = KeyUpdate) ->
+ Header = io_lib:format("~s Post-Handshake, KeyUpdate",
+ [header_prefix(Direction)]),
+ Message = io_lib:format("~p", [?rec_info(key_update, KeyUpdate)]),
{Header, Message}.
diff --git a/lib/ssl/src/ssl_record.hrl b/lib/ssl/src/ssl_record.hrl
index e37e3f714f..fb2f31b83c 100644
--- a/lib/ssl/src/ssl_record.hrl
+++ b/lib/ssl/src/ssl_record.hrl
@@ -67,6 +67,7 @@
compression_algorithm, % unit 8
master_secret, % opaque 48
resumption_master_secret,
+ application_traffic_secret,
client_random, % opaque 32
server_random, % opaque 32
exportable % boolean
@@ -74,7 +75,7 @@
-define(INITIAL_BYTES, 5).
--define(MAX_SEQENCE_NUMBER, 18446744073709551615). %% (1 bsl 64) - 1 = 18446744073709551615
+-define(MAX_SEQUENCE_NUMBER, 18446744073709551615). %% (1 bsl 64) - 1 = 18446744073709551615
%% Sequence numbers cannot wrap so when max is about to be reached we should renegotiate.
%% We will renegotiate a little before so that there will be sequence numbers left
%% for the rehandshake and a little data. Currently we decided to renegotiate a little more
@@ -152,6 +153,7 @@
-define(MAX_PLAIN_TEXT_LENGTH, 16384).
-define(MAX_COMPRESSED_LENGTH, (?MAX_PLAIN_TEXT_LENGTH+1024)).
-define(MAX_CIPHER_TEXT_LENGTH, (?MAX_PLAIN_TEXT_LENGTH+2048)).
+-define(TLS13_MAX_CIPHER_TEXT_LENGTH, (?MAX_PLAIN_TEXT_LENGTH+256)).
%% -record(protocol_version, {
%% major, % unit 8
diff --git a/lib/ssl/src/tls_client_ticket_store.erl b/lib/ssl/src/tls_client_ticket_store.erl
index 6343b9cf0b..7386b0363f 100644
--- a/lib/ssl/src/tls_client_ticket_store.erl
+++ b/lib/ssl/src/tls_client_ticket_store.erl
@@ -294,7 +294,7 @@ store_ticket(#state{db = Db0, max = Max} = State, Ticket, HKDF, SNI, PSK) ->
true ->
Db0
end,
- Key = erlang:monotonic_time(),
+ Key = {erlang:monotonic_time(), erlang:unique_integer([monotonic])},
Db = gb_trees:insert(Key,
#data{hkdf = HKDF,
sni = SNI,
diff --git a/lib/ssl/src/tls_connection.erl b/lib/ssl/src/tls_connection.erl
index ed11cfd985..7257e1dea5 100644
--- a/lib/ssl/src/tls_connection.erl
+++ b/lib/ssl/src/tls_connection.erl
@@ -88,7 +88,7 @@
%% gen_statem callbacks
-export([callback_mode/0, terminate/3, code_change/4, format_status/2]).
--export([encode_handshake/4]).
+-export([encode_handshake/4, send_key_update/2, update_cipher_key/2]).
-define(DIST_CNTRL_SPAWN_OPTS, [{priority, max}]).
@@ -221,7 +221,7 @@ activate_socket(#state{protocol_specific = #{active_n_toggle := true, active_n :
next_record(State, CipherTexts, ConnectionStates, Check) ->
next_record(State, CipherTexts, ConnectionStates, Check, []).
%%
-next_record(#state{connection_env = #connection_env{negotiated_version = Version}} = State,
+next_record(#state{connection_env = #connection_env{negotiated_version = {3,4} = Version}} = State,
[CT|CipherTexts], ConnectionStates0, Check, Acc) ->
case tls_record:decode_cipher_text(Version, CT, ConnectionStates0, Check) of
{#ssl_tls{type = ?APPLICATION_DATA, fragment = Fragment}, ConnectionStates} ->
@@ -242,10 +242,41 @@ next_record(#state{connection_env = #connection_env{negotiated_version = Version
%% Not ?APPLICATION_DATA but we have accumulated fragments
%% -> build an ?APPLICATION_DATA record with concatenated fragments
%% and forget about decrypting this record - we'll decrypt it again next time
+ %% Will not work for stream ciphers
next_record_done(State, [CT|CipherTexts], ConnectionStates0,
#ssl_tls{type = ?APPLICATION_DATA, fragment = iolist_to_binary(lists:reverse(Acc))});
#alert{} = Alert ->
Alert
+ end;
+next_record(#state{connection_env = #connection_env{negotiated_version = Version}} = State,
+ [#ssl_tls{type = ?APPLICATION_DATA} = CT |CipherTexts], ConnectionStates0, Check, Acc) ->
+ case tls_record:decode_cipher_text(Version, CT, ConnectionStates0, Check) of
+ {#ssl_tls{type = ?APPLICATION_DATA, fragment = Fragment}, ConnectionStates} ->
+ case CipherTexts of
+ [] ->
+ %% End of cipher texts - build and deliver an ?APPLICATION_DATA record
+ %% from the accumulated fragments
+ next_record_done(State, [], ConnectionStates,
+ #ssl_tls{type = ?APPLICATION_DATA,
+ fragment = iolist_to_binary(lists:reverse(Acc, [Fragment]))});
+ [_|_] ->
+ next_record(State, CipherTexts, ConnectionStates, Check, [Fragment|Acc])
+ end;
+ #alert{} = Alert ->
+ Alert
+ end;
+next_record(State, CipherTexts, ConnectionStates, _, [_|_] = Acc) ->
+ next_record_done(State, CipherTexts, ConnectionStates,
+ #ssl_tls{type = ?APPLICATION_DATA,
+ fragment = iolist_to_binary(lists:reverse(Acc))});
+next_record(#state{connection_env = #connection_env{negotiated_version = Version}} = State,
+ [CT|CipherTexts], ConnectionStates0, Check, []) ->
+ case tls_record:decode_cipher_text(Version, CT, ConnectionStates0, Check) of
+ {Record, ConnectionStates} ->
+ %% Singelton non-?APPLICATION_DATA record - deliver
+ next_record_done(State, CipherTexts, ConnectionStates, Record);
+ #alert{} = Alert ->
+ Alert
end.
next_record_done(#state{protocol_buffers = Buffers} = State, CipherTexts, ConnectionStates, Record) ->
@@ -256,14 +287,14 @@ next_record_done(#state{protocol_buffers = Buffers} = State, CipherTexts, Connec
next_event(StateName, Record, State) ->
next_event(StateName, Record, State, []).
%%
-next_event(StateName, no_record, State0, Actions) ->
+next_event(StateName, no_record, #state{static_env = #static_env{role = Role}} = State0, Actions) ->
case next_record(StateName, State0) of
{no_record, State} ->
ssl_connection:hibernate_after(StateName, State, Actions);
{Record, State} ->
next_event(StateName, Record, State, Actions);
#alert{} = Alert ->
- ssl_connection:handle_normal_shutdown(Alert, StateName, State0),
+ ssl_connection:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State0),
{stop, {shutdown, own_alert}, State0}
end;
next_event(StateName, #ssl_tls{} = Record, State, Actions) ->
@@ -278,23 +309,21 @@ handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, Stat
case ssl_connection:read_application_data(Data, State0) of
{stop, _, _} = Stop->
Stop;
- {Record, #state{start_or_recv_from = Caller} = State1} ->
+ {Record, #state{start_or_recv_from = Caller} = State} ->
TimerAction = case Caller of
undefined -> %% Passive recv complete cancel timer
[{{timeout, recv}, infinity, timeout}];
_ ->
[]
end,
- {next_state, StateName, State, Actions} = next_event(StateName, Record, State1, TimerAction),
- ssl_connection:hibernate_after(StateName, State, Actions)
+ next_event(StateName, Record, State, TimerAction)
end;
handle_protocol_record(#ssl_tls{type = ?APPLICATION_DATA, fragment = Data}, StateName, State0) ->
case ssl_connection:read_application_data(Data, State0) of
{stop, _, _} = Stop->
Stop;
- {Record, State1} ->
- {next_state, StateName, State, Actions} = next_event(StateName, Record, State1),
- ssl_connection:hibernate_after(StateName, State, Actions)
+ {Record, State} ->
+ next_event(StateName, Record, State)
end;
%%% TLS record protocol level handshake messages
handle_protocol_record(#ssl_tls{type = ?HANDSHAKE, fragment = Data},
@@ -387,7 +416,6 @@ renegotiate(#state{static_env = #static_env{role = server,
send_handshake(Handshake, State) ->
send_handshake_flight(queue_handshake(Handshake, State)).
-
queue_handshake(Handshake, #state{handshake_env = #handshake_env{tls_handshake_history = Hist0} = HsEnv,
connection_env = #connection_env{negotiated_version = Version},
flight_buffer = Flight0,
@@ -706,7 +734,7 @@ hello(internal, #server_hello{} = Hello,
[{next_event, internal, Hello}]}
end;
hello(info, Event, State) ->
- gen_info(Event, ?FUNCTION_NAME, State);
+ handle_info(Event, ?FUNCTION_NAME, State);
hello(Type, Event, State) ->
gen_handshake(?FUNCTION_NAME, Type, Event, State).
@@ -753,15 +781,19 @@ connection({call, From}, {user_renegotiate, WriteState},
[{next_event,{call, From}, renegotiate}]};
connection({call, From},
{close, {Pid, _Timeout}},
- #state{connection_env = #connection_env{terminated = closed} =CEnv} = State) ->
+ #state{connection_env = #connection_env{terminated = closed} = CEnv,
+ protocol_specific = PS} = State) ->
{next_state, downgrade, State#state{connection_env =
- CEnv#connection_env{terminated = true,
- downgrade = {Pid, From}}},
+ CEnv#connection_env{terminated = true,
+ downgrade = {Pid, From}},
+ protocol_specific = PS#{active_n_toggle => true,
+ active_n => 1}
+ },
[{next_event, internal, ?ALERT_REC(?WARNING, ?CLOSE_NOTIFY)}]};
connection({call, From},
{close,{Pid, Timeout}},
#state{connection_states = ConnectionStates,
- protocol_specific = #{sender := Sender},
+ protocol_specific = #{sender := Sender} = PS,
connection_env = CEnv
} = State0) ->
case tls_sender:downgrade(Sender, Timeout) of
@@ -775,7 +807,10 @@ connection({call, From},
ConnectionStates#{current_write => Write}}),
{next_state, downgrade, State#state{connection_env =
CEnv#connection_env{downgrade = {Pid, From},
- terminated = true}},
+ terminated = true},
+ protocol_specific = PS#{active_n_toggle => true,
+ active_n => 1}
+ },
[{timeout, Timeout, downgrade}]};
{error, timeout} ->
{stop_and_reply, {shutdown, downgrade_fail}, [{reply, From, {error, timeout}}]}
@@ -850,6 +885,16 @@ connection(internal, #new_session_ticket{} = NewSessionTicket, State) ->
handle_new_session_ticket(NewSessionTicket, State),
next_event(?FUNCTION_NAME, no_record, State);
+connection(internal, #key_update{} = KeyUpdate, State0) ->
+ %% TLS 1.3
+ case handle_key_update(KeyUpdate, State0) of
+ {ok, State} ->
+ next_event(?FUNCTION_NAME, no_record, State);
+ {error, State, Alert} ->
+ ssl_connection:handle_own_alert(Alert, {3,4}, connection, State),
+ next_event(?FUNCTION_NAME, no_record, State)
+ end;
+
connection(Type, Event, State) ->
ssl_connection:?FUNCTION_NAME(Type, Event, State, ?MODULE).
@@ -1077,6 +1122,7 @@ initialize_tls_sender(#state{static_env = #static_env{
connection_env = #connection_env{negotiated_version = Version},
socket_options = SockOpts,
ssl_options = #{renegotiate_at := RenegotiateAt,
+ key_update_at := KeyUpdateAt,
log_level := LogLevel},
connection_states = #{current_write := ConnectionWriteState},
protocol_specific = #{sender := Sender}}) ->
@@ -1088,6 +1134,7 @@ initialize_tls_sender(#state{static_env = #static_env{
transport_cb => Transport,
negotiated_version => Version,
renegotiate_at => RenegotiateAt,
+ key_update_at => KeyUpdateAt,
log_level => LogLevel},
tls_sender:initialize(Sender, Init).
@@ -1151,8 +1198,24 @@ handle_info({PassiveTag, Socket}, StateName,
next_event(StateName, no_record,
State#state{protocol_specific = PS#{active_n_toggle => true}});
handle_info({CloseTag, Socket}, StateName,
- #state{static_env = #static_env{socket = Socket, close_tag = CloseTag},
+ #state{static_env = #static_env{
+ role = Role,
+ host = Host,
+ port = Port,
+ socket = Socket,
+ close_tag = CloseTag},
+ handshake_env = #handshake_env{renegotiation = Type},
connection_env = #connection_env{negotiated_version = Version},
+ session = Session} = State) when StateName =/= connection ->
+ ssl_connection:maybe_invalidate_session(Version, Type, Role, Host, Port, Session),
+ Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, transport_closed),
+ ssl_connection:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
+ {stop, {shutdown, transport_closed}, State};
+handle_info({CloseTag, Socket}, StateName,
+ #state{static_env = #static_env{
+ role = Role,
+ socket = Socket,
+ close_tag = CloseTag},
socket_options = #socket_options{active = Active},
protocol_buffers = #protocol_buffers{tls_cipher_texts = CTs},
user_data_buffer = {_,BufferSize,_},
@@ -1165,18 +1228,18 @@ handle_info({CloseTag, Socket}, StateName,
case (Active == false) andalso ((CTs =/= []) or (BufferSize =/= 0)) of
false ->
- case Version of
- {1, N} when N >= 1 ->
- ok;
- _ ->
- %% As invalidate_sessions here causes performance issues,
- %% we will conform to the widespread implementation
- %% practice and go aginst the spec
- %%invalidate_session(Role, Host, Port, Session)
- ok
- end,
-
- ssl_connection:handle_normal_shutdown(?ALERT_REC(?FATAL, ?CLOSE_NOTIFY), StateName, State),
+ %% As invalidate_sessions here causes performance issues,
+ %% we will conform to the widespread implementation
+ %% practice and go aginst the spec
+ %% case Version of
+ %% {3, N} when N >= 1 ->
+ %% ok;
+ %% _ ->
+ %% invalidate_session(Role, Host, Port, Session)
+ %% ok
+ %% end,
+ Alert = ?ALERT_REC(?FATAL, ?CLOSE_NOTIFY, transport_closed),
+ ssl_connection:handle_normal_shutdown(Alert#alert{role = Role}, StateName, State),
{stop, {shutdown, transport_closed}, State};
true ->
%% Fixes non-delivery of final TLS record in {active, once}.
@@ -1405,6 +1468,50 @@ handle_new_session_ticket(#new_session_ticket{ticket_nonce = Nonce} = NewSession
tls_client_ticket_store:store_ticket(NewSessionTicket, HKDF, SNI, PSK).
+handle_key_update(#key_update{request_update = update_not_requested}, State0) ->
+ %% Update read key in connection
+ {ok, update_cipher_key(current_read, State0)};
+handle_key_update(#key_update{request_update = update_requested},
+ #state{protocol_specific = #{sender := Sender}} = State0) ->
+ %% Update read key in connection
+ State1 = update_cipher_key(current_read, State0),
+ %% Send key_update and update sender's write key
+ case send_key_update(Sender, update_not_requested) of
+ ok ->
+ {ok, State1};
+ {error, Reason} ->
+ {error, State1, ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason)}
+ end.
+
+
+update_cipher_key(ConnStateName, #state{connection_states = CS0} = State0) ->
+ CS = update_cipher_key(ConnStateName, CS0),
+ State0#state{connection_states = CS};
+update_cipher_key(ConnStateName, CS0) ->
+ #{security_parameters := SecParams0,
+ cipher_state := CipherState0} = ConnState0 = maps:get(ConnStateName, CS0),
+ HKDF = SecParams0#security_parameters.prf_algorithm,
+ CipherSuite = SecParams0#security_parameters.cipher_suite,
+ ApplicationTrafficSecret0 = SecParams0#security_parameters.application_traffic_secret,
+ ApplicationTrafficSecret = tls_v1:update_traffic_secret(HKDF, ApplicationTrafficSecret0),
+
+ %% Calculate traffic keys
+ #{cipher := Cipher} = ssl_cipher_format:suite_bin_to_map(CipherSuite),
+ {Key, IV} = tls_v1:calculate_traffic_keys(HKDF, Cipher, ApplicationTrafficSecret),
+
+ SecParams = SecParams0#security_parameters{application_traffic_secret = ApplicationTrafficSecret},
+ CipherState = CipherState0#cipher_state{key = Key, iv = IV},
+ ConnState = ConnState0#{security_parameters => SecParams,
+ cipher_state => CipherState,
+ sequence_number => 0},
+ CS0#{ConnStateName => ConnState}.
+
+
+send_key_update(Sender, Type) ->
+ KeyUpdate = tls_handshake_1_3:key_update(Type),
+ tls_sender:send_post_handshake(Sender, KeyUpdate).
+
+
%% Send ticket data to user as opaque binary
send_ticket_data(User, NewSessionTicket, HKDF, SNI, PSK) ->
Timestamp = erlang:system_time(seconds),
diff --git a/lib/ssl/src/tls_connection_1_3.erl b/lib/ssl/src/tls_connection_1_3.erl
index 6fb96b1f5a..b424f8e9e7 100644
--- a/lib/ssl/src/tls_connection_1_3.erl
+++ b/lib/ssl/src/tls_connection_1_3.erl
@@ -191,7 +191,8 @@ wait_finished(internal,
ssl_connection:handle_own_alert(Alert, {3,4}, finished, State0);
State1 ->
{Record, State} = ssl_connection:prepare_connection(State1, Module),
- tls_connection:next_event(connection, Record, State)
+ tls_connection:next_event(connection, Record, State,
+ [{{timeout, handshake}, cancel}])
end;
wait_finished(Type, Msg, State, Connection) ->
ssl_connection:handle_common_event(Type, Msg, ?FUNCTION_NAME, State, Connection).
@@ -217,8 +218,6 @@ wait_ee(internal, #change_cipher_spec{}, State, _Module) ->
tls_connection:next_event(?FUNCTION_NAME, no_record, State);
wait_ee(internal, #encrypted_extensions{} = EE, State0, _Module) ->
case tls_handshake_1_3:do_wait_ee(EE, State0) of
- #alert{} = Alert ->
- ssl_connection:handle_own_alert(Alert, {3,4}, wait_ee, State0);
{State1, NextState} ->
tls_connection:next_event(NextState, no_record, State1)
end;
diff --git a/lib/ssl/src/tls_handshake.erl b/lib/ssl/src/tls_handshake.erl
index 474cbd621b..b6bdba4cb6 100644
--- a/lib/ssl/src/tls_handshake.erl
+++ b/lib/ssl/src/tls_handshake.erl
@@ -411,6 +411,8 @@ get_tls_handshake_aux(Version, <<?BYTE(Type), ?UINT24(Length),
ssl_logger:debug(LogLevel, inbound, 'handshake', Handshake),
get_tls_handshake_aux(Version, Rest, Opts, [{Handshake,Raw} | Acc])
catch
+ throw:#alert{} = Alert ->
+ throw(Alert);
_:_ ->
throw(?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, handshake_decode_error))
end;
diff --git a/lib/ssl/src/tls_handshake_1_3.erl b/lib/ssl/src/tls_handshake_1_3.erl
index dfd82f5b64..8c5d652035 100644
--- a/lib/ssl/src/tls_handshake_1_3.erl
+++ b/lib/ssl/src/tls_handshake_1_3.erl
@@ -39,7 +39,8 @@
%% Create handshake messages
-export([certificate/5,
certificate_verify/4,
- encrypted_extensions/1]).
+ encrypted_extensions/1,
+ key_update/1]).
-export([do_start/2,
do_negotiated/2,
@@ -189,7 +190,7 @@ certificate(OwnCert, CertDbHandle, CertDbRef, _CRContext, Role) ->
certificate_request_context = <<>>,
certificate_list = CertList}};
{error, Error} when Role =:= server ->
- {error, {no_suitable_certificates, Error}};
+ {error, ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {no_suitable_certificates, Error})};
{error, _Error} when Role =:= client ->
%% The client MUST send a Certificate message if and only if the server
%% has requested client authentication via a CertificateRequest message
@@ -229,9 +230,8 @@ certificate_verify(PrivateKey, SignatureScheme,
algorithm = SignatureScheme,
signature = Signature
}};
- {error, badarg} ->
- {error, badarg}
-
+ {error, #alert{} = Alert} ->
+ {error, Alert}
end.
@@ -251,6 +251,10 @@ finished(#state{connection_states = ConnectionStates,
}.
+key_update(Type) ->
+ #key_update{request_update = Type}.
+
+
%%====================================================================
%% Encode handshake
%%====================================================================
@@ -291,7 +295,8 @@ encode_handshake(#new_session_ticket{
encode_handshake(#end_of_early_data{}) ->
{?END_OF_EARLY_DATA, <<>>};
encode_handshake(#key_update{request_update = Update}) ->
- {?KEY_UPDATE, <<?BYTE(Update)>>};
+ EncUpdate = encode_key_update(Update),
+ {?KEY_UPDATE, <<EncUpdate/binary>>};
encode_handshake(HandshakeMsg) ->
ssl_handshake:encode_handshake(HandshakeMsg, {3,4}).
@@ -361,7 +366,7 @@ decode_handshake(?NEW_SESSION_TICKET, <<?UINT32(LifeTime), ?UINT32(Age),
decode_handshake(?END_OF_EARLY_DATA, _) ->
#end_of_early_data{};
decode_handshake(?KEY_UPDATE, <<?BYTE(Update)>>) ->
- #key_update{request_update = Update};
+ #key_update{request_update = decode_key_update(Update)};
decode_handshake(Tag, HandshakeMsg) ->
ssl_handshake:decode_handshake({3,4}, Tag, HandshakeMsg).
@@ -408,6 +413,26 @@ encode_signature(Signature) ->
Size = byte_size(Signature),
<<?UINT16(Size), Signature/binary>>.
+encode_key_update(update_not_requested) ->
+ <<?BYTE(0)>>;
+encode_key_update(update_requested) ->
+ <<?BYTE(1)>>.
+
+%% enum {
+%% update_not_requested(0), update_requested(1), (255)
+%% } KeyUpdateRequest;
+%%
+%% request_update: Indicates whether the recipient of the KeyUpdate
+%% should respond with its own KeyUpdate. If an implementation
+%% receives any other value, it MUST terminate the connection with an
+%% "illegal_parameter" alert.
+decode_key_update(0) ->
+ update_not_requested;
+decode_key_update(1) ->
+ update_requested;
+decode_key_update(N) ->
+ throw(?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER, {request_update,N})).
+
decode_cert_entries(Entries) ->
decode_cert_entries(Entries, []).
@@ -421,6 +446,7 @@ decode_cert_entries(<<?UINT24(DSize), Data:DSize/binary, ?UINT16(Esize), BinExts
encode_extensions(Exts)->
ssl_handshake:encode_extensions(extensions_list(Exts)).
+
decode_extensions(Exts, MessageType) ->
ssl_handshake:decode_extensions(Exts, {3,4}, MessageType).
@@ -467,7 +493,7 @@ sign(THash, Context, HashAlgo, #'ECPrivateKey'{} = PrivateKey) ->
{ok, Signature}
catch
error:badarg ->
- {error, badarg}
+ {error, ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, badarg)}
end;
sign(THash, Context, HashAlgo, PrivateKey) ->
Content = build_content(Context, THash),
@@ -482,7 +508,7 @@ sign(THash, Context, HashAlgo, PrivateKey) ->
{ok, Signature}
catch
error:badarg ->
- {error, badarg}
+ {error, ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, badarg)}
end.
@@ -493,7 +519,7 @@ verify(THash, Context, HashAlgo, Signature, {?'id-ecPublicKey', PublicKey, Publi
{ok, Result}
catch
error:badarg ->
- {error, badarg}
+ {error, ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, badarg)}
end;
verify(THash, Context, HashAlgo, Signature, {?rsaEncryption, PublicKey, _PubKeyParams}) ->
Content = build_content(Context, THash),
@@ -508,7 +534,7 @@ verify(THash, Context, HashAlgo, Signature, {?rsaEncryption, PublicKey, _PubKeyP
{ok, Result}
catch
error:badarg ->
- {error, badarg}
+ {error, ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, badarg)}
end.
@@ -606,18 +632,8 @@ do_start(#client_hello{cipher_suites = ClientCiphers,
Maybe(session_resumption(NextStateTuple, PSK))
end
catch
- {Ref, {insufficient_security, no_suitable_groups}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
- {Ref, illegal_parameter} ->
- ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
- {Ref, no_suitable_cipher} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher);
- {Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
- {Ref, {insufficient_security, no_suitable_public_key}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key);
- {Ref, no_application_protocol} ->
- ?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL)
+ {Ref, #alert{} = Alert} ->
+ Alert
end;
%% TLS Client
do_start(#server_hello{cipher_suite = SelectedCipherSuite,
@@ -696,8 +712,8 @@ do_start(#server_hello{cipher_suite = SelectedCipherSuite,
{State, wait_sh}
catch
- {Ref, {illegal_parameter, Reason}} ->
- ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER, Reason)
+ {Ref, #alert{} = Alert} ->
+ Alert
end.
@@ -757,10 +773,8 @@ do_negotiated({start_handshake, PSK0},
{State9, NextState}
catch
- {Ref, badarg} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg});
- {Ref, {no_suitable_certificates, Reason}} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {no_suitable_certificates, Reason})
+ {Ref, #alert{} = Alert} ->
+ Alert
end.
@@ -769,17 +783,9 @@ do_wait_cert(#certificate_1_3{} = Certificate, State0) ->
try
Maybe(process_certificate(Certificate, State0))
catch
- {Ref, {certificate_required, State}} ->
- {?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required), State};
- {Ref, {{certificate_unknown, Reason}, State}} ->
- {?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, Reason), State};
- {Ref, {{internal_error, Reason}, State}} ->
- {?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason), State};
- {Ref, {{handshake_failure, Reason}, State}} ->
- {?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason), State};
+ {Ref, #alert{} = Alert} ->
+ {Alert, State0};
{Ref, {#alert{} = Alert, State}} ->
- {Alert, State};
- {#alert{} = Alert, State} ->
{Alert, State}
end.
@@ -790,12 +796,8 @@ do_wait_cv(#certificate_verify_1_3{} = CertificateVerify, State0) ->
State1 = Maybe(verify_signature_algorithm(State0, CertificateVerify)),
Maybe(verify_certificate_verify(State1, CertificateVerify))
catch
- {Ref, {{bad_certificate, Reason}, State}} ->
- {?ALERT_REC(?FATAL, ?BAD_CERTIFICATE, {bad_certificate, Reason}), State};
- {Ref, {badarg, State}} ->
- {?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {verify, badarg}), State};
- {Ref, {{handshake_failure, Reason}, State}} ->
- {?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, {handshake_failure, Reason}), State}
+ {Ref, {#alert{} = Alert, State}} ->
+ {Alert, State}
end.
%% TLS Server
@@ -804,29 +806,30 @@ do_wait_finished(#finished{verify_data = VerifyData},
{Ref,Maybe} = maybe(),
try
- Maybe(validate_client_finished(State0, VerifyData)),
+ Maybe(validate_finished(State0, VerifyData)),
State1 = calculate_traffic_secrets(State0),
State2 = maybe_calculate_resumption_master_secret(State1),
+ State3 = forget_master_secret(State2),
%% Configure traffic keys
- State3 = ssl_record:step_encryption_state(State2),
+ State4 = ssl_record:step_encryption_state(State3),
%% Send session ticket
- maybe_send_session_ticket(State3)
+ maybe_send_session_ticket(State4)
catch
- {Ref, decrypt_error} ->
- ?ALERT_REC(?FATAL, ?DECRYPT_ERROR, decrypt_error)
+ {Ref, #alert{} = Alert} ->
+ Alert
end;
%% TLS Client
-do_wait_finished(#finished{verify_data = _VerifyData},
+do_wait_finished(#finished{verify_data = VerifyData},
#state{static_env = #static_env{role = client}} = State0) ->
{Ref,Maybe} = maybe(),
try
- %% Maybe(validate_client_finished(State0, VerifyData)),
+ Maybe(validate_finished(State0, VerifyData)),
%% Maybe send Certificate + CertificateVerify
State1 = Maybe(maybe_queue_cert_cert_cv(State0)),
@@ -841,17 +844,14 @@ do_wait_finished(#finished{verify_data = _VerifyData},
State4 = calculate_traffic_secrets(State3),
State5 = maybe_calculate_resumption_master_secret(State4),
+ State6 = forget_master_secret(State5),
%% Configure traffic keys
- ssl_record:step_encryption_state(State5)
+ ssl_record:step_encryption_state(State6)
catch
- {Ref, decrypt_error} ->
- ?ALERT_REC(?FATAL, ?DECRYPT_ERROR, decrypt_error);
- {Ref, badarg} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {digitally_sign, badarg});
- {Ref, {no_suitable_certificates, Reason}} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {no_suitable_certificates, Reason})
+ {Ref, #alert{} = Alert} ->
+ Alert
end.
@@ -909,16 +909,8 @@ do_wait_sh(#server_hello{cipher_suite = SelectedCipherSuite,
catch
{Ref, {State, StateName, ServerHello}} ->
{State, StateName, ServerHello};
- {Ref, {insufficient_security, no_suitable_groups}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
- {Ref, illegal_parameter} ->
- ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
- {Ref, no_suitable_cipher} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher);
- {Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
- {Ref, {insufficient_security, no_suitable_public_key}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)
+ {Ref, #alert{} = Alert} ->
+ Alert
end.
@@ -939,16 +931,6 @@ do_wait_ee(#encrypted_extensions{extensions = Extensions}, State0) ->
{State1, wait_cert_cr}
catch
- {Ref, {insufficient_security, no_suitable_groups}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups);
- {Ref, illegal_parameter} ->
- ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER);
- {Ref, no_suitable_cipher} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher);
- {Ref, {insufficient_security, no_suitable_signature_algorithm}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, "No suitable signature algorithm");
- {Ref, {insufficient_security, no_suitable_public_key}} ->
- ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key);
{Ref, {State, StateName}} ->
{State, StateName}
end.
@@ -959,14 +941,8 @@ do_wait_cert_cr(#certificate_1_3{} = Certificate, State0) ->
try
Maybe(process_certificate(Certificate, State0))
catch
- {Ref, {certificate_required, _State}} ->
- ?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required);
- {Ref, {{certificate_unknown, Reason}, _State}} ->
- ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, Reason);
- {Ref, {{internal_error, Reason}, _State}} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason);
- {Ref, {{handshake_failure, Reason}, _State}} ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason);
+ {Ref, #alert{} = Alert} ->
+ {Alert, State0};
{Ref, {#alert{} = Alert, State}} ->
{Alert, State}
end;
@@ -975,30 +951,11 @@ do_wait_cert_cr(#certificate_request_1_3{} = CertificateRequest, State0) ->
try
Maybe(process_certificate_request(CertificateRequest, State0))
catch
- {Ref, {certificate_required, _State}} ->
- ?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required);
- {Ref, {{certificate_unknown, Reason}, _State}} ->
- ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, Reason);
- {Ref, {illegal_parameter, Reason}} ->
- ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER, Reason);
- {Ref, {{internal_error, Reason}, _State}} ->
- ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, Reason);
- {Ref, {{handshake_failure, Reason}, _State}} ->
- ?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE, Reason)
+ {Ref, #alert{} = Alert} ->
+ {Alert, State0}
end.
-
-%% TODO: Remove this function!
-%% not_implemented(State, Reason) ->
-%% {error, {not_implemented, State, Reason}}.
-
-%% not_implemented(update_secrets, State0, Reason) ->
-%% State1 = calculate_traffic_secrets(State0),
-%% State = ssl_record:step_encryption_state(State1),
-%% {error, {not_implemented, State, Reason}}.
-
-
%% For reasons of backward compatibility with middleboxes (see
%% Appendix D.4), the HelloRetryRequest message uses the same structure
%% as the ServerHello, but with Random set to the special value of the
@@ -1056,8 +1013,8 @@ maybe_queue_cert_cert_cv(#state{connection_states = _ConnectionStates0,
State = Maybe(maybe_queue_cert_verify(Certificate, State1)),
{ok, State}
catch
- {Ref, badarg} ->
- {error, badarg}
+ {Ref, #alert{} = Alert} ->
+ {error, Alert}
end.
@@ -1076,25 +1033,25 @@ maybe_queue_cert_verify(_Certificate,
CertificateVerify = Maybe(certificate_verify(CertPrivateKey, SignatureScheme, State, client)),
{ok, tls_connection:queue_handshake(CertificateVerify, State)}
catch
- {Ref, badarg} ->
- {error, badarg}
+ {Ref, #alert{} = Alert} ->
+ {error, Alert}
end.
%% Recipients of Finished messages MUST verify that the contents are
%% correct and if incorrect MUST terminate the connection with a
%% "decrypt_error" alert.
-validate_client_finished(#state{connection_states = ConnectionStates,
- handshake_env =
- #handshake_env{
- tls_handshake_history = {Messages0, _}}}, VerifyData) ->
+validate_finished(#state{connection_states = ConnectionStates,
+ handshake_env =
+ #handshake_env{
+ tls_handshake_history = {Messages0, _}}}, VerifyData) ->
#{security_parameters := SecParamsR,
- cipher_state := #cipher_state{finished_key = FinishedKey}} =
+ cipher_state := #cipher_state{finished_key = FinishedKey}} =
ssl_record:current_connection_state(ConnectionStates, read),
#security_parameters{prf_algorithm = HKDFAlgo} = SecParamsR,
- %% Drop the client's finished message, it is not part of the handshake context
- %% when the client calculates its finished message.
+ %% Drop the peer's finished message, it is not part of the handshake context
+ %% when the client/server calculates its finished message.
[_|Messages] = Messages0,
ControlData = tls_v1:finished_verify_data(FinishedKey, HKDFAlgo, Messages),
@@ -1104,7 +1061,7 @@ validate_client_finished(#state{connection_states = ConnectionStates,
compare_verify_data(Data, Data) ->
ok;
compare_verify_data(_, _) ->
- {error, decrypt_error}.
+ {error, ?ALERT_REC(?FATAL, ?DECRYPT_ERROR, decrypt_error)}.
send_hello_retry_request(#state{connection_states = ConnectionStates0} = State0,
@@ -1239,7 +1196,7 @@ process_certificate(#certificate_1_3{
%% secrets.
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
- {error, {certificate_required, State}};
+ {error, {?ALERT_REC(?FATAL, ?CERTIFICATE_REQUIRED, certificate_required), State}};
process_certificate(#certificate_1_3{certificate_list = Certs0},
#state{ssl_options =
#{signature_algs := SignAlgs,
@@ -1271,8 +1228,8 @@ process_certificate(#certificate_1_3{certificate_list = Certs0},
false ->
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
- {error, {{handshake_failure,
- "Client certificate uses unsupported signature algorithm"}, State}}
+ {error, {?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ "Client certificate uses unsupported signature algorithm"), State}}
end.
@@ -1336,9 +1293,9 @@ validate_certificate_chain(Certs, CertDbHandle, CertDbRef,
catch
error:{badmatch,{error, {asn1, Asn1Reason}}} ->
%% ASN-1 decode of certificate somehow failed
- {error, {certificate_unknown, {failed_to_decode_certificate, Asn1Reason}}};
+ {error, ?ALERT_REC(?FATAL, ?CERTIFICATE_UNKNOWN, {failed_to_decode_certificate, Asn1Reason})};
error:OtherReason ->
- {error, {internal_error, {unexpected_error, OtherReason}}}
+ {error, ?ALERT_REC(?FATAL, ?INTERNAL_ERROR, {unexpected_error, OtherReason})}
end.
@@ -1425,6 +1382,7 @@ calculate_handshake_secrets(PublicKey, PrivateKey, SelectedGroup, PSK,
WriteFinishedKey = tls_v1:finished_key(ServerHSTrafficSecret, HKDFAlgo),
update_pending_connection_states(State0, HandshakeSecret, undefined,
+ undefined, undefined,
ReadKey, ReadIV, ReadFinishedKey,
WriteKey, WriteIV, WriteFinishedKey).
@@ -1451,7 +1409,7 @@ get_pre_shared_key(manual = SessionTickets, UseTicket, HKDFAlgo, SelectedIdentit
undefined -> %% full handshake, default PSK
{ok, binary:copy(<<0>>, ssl_cipher:hash_size(HKDFAlgo))};
illegal_parameter ->
- {error, illegal_parameter};
+ {error, ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)};
{_, PSK} ->
{ok, PSK}
end;
@@ -1463,7 +1421,7 @@ get_pre_shared_key(auto = SessionTickets, UseTicket, HKDFAlgo, SelectedIdentity)
{ok, binary:copy(<<0>>, ssl_cipher:hash_size(HKDFAlgo))};
illegal_parameter ->
tls_client_ticket_store:unlock_tickets(self(), UseTicket),
- {error, illegal_parameter};
+ {error, ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)};
{Key, PSK} ->
tls_client_ticket_store:remove_tickets([Key]), %% Remove single-use ticket
tls_client_ticket_store:unlock_tickets(self(), UseTicket -- [Key]),
@@ -1511,6 +1469,7 @@ calculate_traffic_secrets(#state{
{WriteKey, WriteIV} = tls_v1:calculate_traffic_keys(HKDFAlgo, Cipher, ServerAppTrafficSecret0),
update_pending_connection_states(State0, MasterSecret, undefined,
+ ClientAppTrafficSecret0, ServerAppTrafficSecret0,
ReadKey, ReadIV, undefined,
WriteKey, WriteIV, undefined).
@@ -1563,17 +1522,36 @@ maybe_calculate_resumption_master_secret(#state{
update_resumption_master_secret(State, RMS).
+forget_master_secret(#state{connection_states =
+ #{pending_read := PendingRead,
+ pending_write := PendingWrite,
+ current_read := CurrentRead,
+ current_write := CurrentWrite} = CS} = State) ->
+ State#state{connection_states = CS#{pending_read => overwrite_master_secret(PendingRead),
+ pending_write => overwrite_master_secret(PendingWrite),
+ current_read => overwrite_master_secret(CurrentRead),
+ current_write => overwrite_master_secret(CurrentWrite)}}.
+
+
+overwrite_master_secret(ConnectionState = #{security_parameters := SecurityParameters0}) ->
+ SecurityParameters = SecurityParameters0#security_parameters{master_secret = {master_secret, <<0>>}},
+ ConnectionState#{security_parameters => SecurityParameters}.
+
+
update_pending_connection_states(#state{
static_env = #static_env{role = server},
connection_states =
CS = #{pending_read := PendingRead0,
pending_write := PendingWrite0}} = State,
HandshakeSecret, ResumptionMasterSecret,
+ ClientAppTrafficSecret, ServerAppTrafficSecret,
ReadKey, ReadIV, ReadFinishedKey,
WriteKey, WriteIV, WriteFinishedKey) ->
PendingRead = update_connection_state(PendingRead0, HandshakeSecret, ResumptionMasterSecret,
+ ClientAppTrafficSecret,
ReadKey, ReadIV, ReadFinishedKey),
PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret, ResumptionMasterSecret,
+ ServerAppTrafficSecret,
WriteKey, WriteIV, WriteFinishedKey),
State#state{connection_states = CS#{pending_read => PendingRead,
pending_write => PendingWrite}};
@@ -1583,22 +1561,27 @@ update_pending_connection_states(#state{
CS = #{pending_read := PendingRead0,
pending_write := PendingWrite0}} = State,
HandshakeSecret, ResumptionMasterSecret,
+ ClientAppTrafficSecret, ServerAppTrafficSecret,
ReadKey, ReadIV, ReadFinishedKey,
WriteKey, WriteIV, WriteFinishedKey) ->
PendingRead = update_connection_state(PendingRead0, HandshakeSecret, ResumptionMasterSecret,
+ ServerAppTrafficSecret,
WriteKey, WriteIV, WriteFinishedKey),
PendingWrite = update_connection_state(PendingWrite0, HandshakeSecret, ResumptionMasterSecret,
+ ClientAppTrafficSecret,
ReadKey, ReadIV, ReadFinishedKey),
State#state{connection_states = CS#{pending_read => PendingRead,
pending_write => PendingWrite}}.
update_connection_state(ConnectionState = #{security_parameters := SecurityParameters0},
- HandshakeSecret, ResumptionMasterSecret, Key, IV, FinishedKey) ->
+ HandshakeSecret, ResumptionMasterSecret,
+ ApplicationTrafficSecret, Key, IV, FinishedKey) ->
%% Store secret
SecurityParameters = SecurityParameters0#security_parameters{
master_secret = HandshakeSecret,
- resumption_master_secret = ResumptionMasterSecret},
+ resumption_master_secret = ResumptionMasterSecret,
+ application_traffic_secret = ApplicationTrafficSecret},
ConnectionState#{security_parameters => SecurityParameters,
cipher_state => cipher_init(Key, IV, FinishedKey)}.
@@ -1751,8 +1734,8 @@ verify_signature_algorithm(#state{
false ->
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
- {error, {{handshake_failure,
- "CertificateVerify uses unsupported signature algorithm"}, State}}
+ {error, {?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ "CertificateVerify uses unsupported signature algorithm"), State}}
end.
@@ -1796,11 +1779,12 @@ verify_certificate_verify(#state{
{ok, false} ->
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
- {error, {{handshake_failure, "Failed to verify CertificateVerify"}, State}};
- {error, badarg} ->
+ {error, {?ALERT_REC(?FATAL, ?HANDSHAKE_FAILURE,
+ "Failed to verify CertificateVerify"), State}};
+ {error, #alert{} = Alert} ->
State1 = calculate_traffic_secrets(State0),
State = ssl_record:step_encryption_state(State1),
- {error, {badarg, State}}
+ {error, {Alert, State}}
end.
@@ -1822,7 +1806,7 @@ peer_context_string(client) ->
%% server MUST abort the handshake with a "handshake_failure" or an
%% "insufficient_security" alert.
select_common_groups(_, []) ->
- {error, {insufficient_security, no_suitable_groups}};
+ {error, ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_groups)};
select_common_groups(ServerGroups, ClientGroups) ->
Fun = fun(E) -> lists:member(E, ClientGroups) end,
case lists:filter(Fun, ServerGroups) of
@@ -1853,7 +1837,7 @@ select_common_groups(ServerGroups, ClientGroups) ->
validate_client_key_share(_ ,[]) ->
ok;
validate_client_key_share([], _) ->
- {error, illegal_parameter};
+ {error, ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)};
validate_client_key_share([G|ClientGroups], [{_, G, _}|ClientShares]) ->
validate_client_key_share(ClientGroups, ClientShares);
validate_client_key_share([_|ClientGroups], [_|_] = ClientShares) ->
@@ -1861,6 +1845,8 @@ validate_client_key_share([_|ClientGroups], [_|_] = ClientShares) ->
%% Verify that selected group is offered by the client.
+validate_server_key_share([], _) ->
+ {error, ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)};
validate_server_key_share([G|_ClientGroups], {_, G, _}) ->
ok;
validate_server_key_share([_|ClientGroups], {_, _, _} = ServerKeyShare) ->
@@ -1868,17 +1854,17 @@ validate_server_key_share([_|ClientGroups], {_, _, _} = ServerKeyShare) ->
validate_selected_group(SelectedGroup, [SelectedGroup|_]) ->
- {error, {illegal_parameter,
- "Selected group sent by the server shall not correspond to a group"
- " which was provided in the key_share extension"}};
+ {error, ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER,
+ "Selected group sent by the server shall not correspond to a group"
+ " which was provided in the key_share extension")};
validate_selected_group(SelectedGroup, ClientGroups) ->
case lists:member(SelectedGroup, ClientGroups) of
true ->
ok;
false ->
- {error, {illegal_parameter,
- "Selected group sent by the server shall correspond to a group"
- " which was provided in the supported_groups extension"}}
+ {error, ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER,
+ "Selected group sent by the server shall correspond to a group"
+ " which was provided in the supported_groups extension")}
end.
@@ -1930,7 +1916,7 @@ get_server_public_key({key_share_entry, Group, PublicKey}) ->
handle_alpn(undefined, _) ->
{ok, undefined};
handle_alpn([], _) ->
- {error, no_application_protocol};
+ {error, ?ALERT_REC(?FATAL, ?NO_APPLICATION_PROTOCOL)};
handle_alpn([_|_], undefined) ->
{ok, undefined};
handle_alpn([ServerProtocol|T], ClientProtocols) ->
@@ -1943,7 +1929,7 @@ handle_alpn([ServerProtocol|T], ClientProtocols) ->
select_cipher_suite(_, [], _) ->
- {error, no_suitable_cipher};
+ {error, ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_cipher)};
%% If honor_cipher_order is set to true, use the server's preference for
%% cipher suite selection.
select_cipher_suite(true, ClientCiphers, ServerCiphers) ->
@@ -1966,7 +1952,7 @@ validate_cipher_suite(Cipher, ClientCiphers) ->
true ->
ok;
false ->
- {error, illegal_parameter}
+ {error, ?ALERT_REC(?FATAL, ?ILLEGAL_PARAMETER)}
end.
@@ -1992,9 +1978,9 @@ check_cert_sign_algo(SignAlgo, SignHash, _, ClientSignAlgsCert) ->
%% DSA keys are not supported by TLS 1.3
select_sign_algo(dsa, _ClientSignAlgs, _ServerSignAlgs) ->
- {error, {insufficient_security, no_suitable_public_key}};
+ {error, ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_public_key)};
select_sign_algo(_, [], _) ->
- {error, {insufficient_security, no_suitable_signature_algorithm}};
+ {error, ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)};
select_sign_algo(PublicKeyAlgo, [C|ClientSignAlgs], ServerSignAlgs) ->
{_, S, _} = ssl_cipher:scheme_to_components(C),
%% RSASSA-PKCS1-v1_5 and Legacy algorithms are not defined for use in signed
@@ -2017,7 +2003,7 @@ select_sign_algo(PublicKeyAlgo, [C|ClientSignAlgs], ServerSignAlgs) ->
do_check_cert_sign_algo(_, _, []) ->
- {error, {insufficient_security, no_suitable_signature_algorithm}};
+ {error, ?ALERT_REC(?FATAL, ?INSUFFICIENT_SECURITY, no_suitable_signature_algorithm)};
do_check_cert_sign_algo(SignAlgo, SignHash, [Scheme|T]) ->
{Hash, Sign, _Curve} = ssl_cipher:scheme_to_components(Scheme),
case compare_sign_algos(SignAlgo, SignHash, Sign, Hash) of
@@ -2208,32 +2194,32 @@ create_binders(Context, [{_, _, _, PSK, _, HKDF}|T], Acc) ->
%% PskBinderEntry binders<33..2^16-1>;
%% } OfferedPsks;
truncate_client_hello(HelloBin0) ->
- HelloBin1 = remove_binders(HelloBin0),
- {Truncated, _} = split_binary(HelloBin1, size(HelloBin1) - 2),
+ <<?BYTE(Type), ?UINT24(_Length), Body/binary>> = HelloBin0,
+ CH0 = #client_hello{
+ extensions = #{pre_shared_key := PSK0} = Extensions0} =
+ tls_handshake:decode_handshake({3,4}, Type, Body),
+ #pre_shared_key_client_hello{offered_psks = OfferedPsks0} = PSK0,
+ OfferedPsks = OfferedPsks0#offered_psks{binders = []},
+ PSK = PSK0#pre_shared_key_client_hello{offered_psks = OfferedPsks},
+ Extensions = Extensions0#{pre_shared_key => PSK},
+ CH = CH0#client_hello{extensions = Extensions},
+
+ %% Decoding a ClientHello from an another TLS implementation can contain
+ %% unsupported extensions and thus executing decoding and encoding on
+ %% the input can result in a different handshake binary.
+ %% The original length of the binders can still be determined by
+ %% re-encoding the original ClientHello and using its size as reference
+ %% when we substract the size of the truncated binary.
+ TruncatedSize = iolist_size(tls_handshake:encode_handshake(CH, {3,4})),
+ RefSize = iolist_size(tls_handshake:encode_handshake(CH0, {3,4})),
+ BindersSize = RefSize - TruncatedSize,
+
+ %% Return the truncated ClientHello by cutting of the binders from the original
+ %% ClientHello binary.
+ {Truncated, _} = split_binary(HelloBin0, size(HelloBin0) - BindersSize - 2),
Truncated.
-remove_binders(Binary0) ->
- OrigSize = byte_size(Binary0),
- HashSize256 = ssl_cipher:hash_size(sha256),
- HashSize384 = ssl_cipher:hash_size(sha384),
- HashSize512 = ssl_cipher:hash_size(sha512),
-
- NewSize256 = OrigSize - HashSize256 - 1,
- NewSize384 = OrigSize - HashSize384 - 1,
- NewSize512 = OrigSize - HashSize512 - 1,
- case Binary0 of
- <<Binary:NewSize256/binary,?BYTE(HashSize256),_:HashSize256/binary>> ->
- remove_binders(Binary);
- <<Binary:NewSize384/binary,?BYTE(HashSize384),_:HashSize384/binary>> ->
- remove_binders(Binary);
- <<Binary:NewSize512/binary,?BYTE(HashSize512),_:HashSize512/binary>> ->
- remove_binders(Binary);
- Else ->
- Else
- end.
-
-
%% The PskBinderEntry is computed in the same way as the Finished
%% message (Section 4.4.4) but with the BaseKey being the binder_key
%% derived via the key schedule from the corresponding PSK which is
diff --git a/lib/ssl/src/tls_handshake_1_3.hrl b/lib/ssl/src/tls_handshake_1_3.hrl
index cb28ca78f6..94674c3a57 100644
--- a/lib/ssl/src/tls_handshake_1_3.hrl
+++ b/lib/ssl/src/tls_handshake_1_3.hrl
@@ -255,7 +255,8 @@
#certificate_request_1_3{} |
#certificate_1_3{} |
#certificate_verify_1_3{} |
- #new_session_ticket{}.
+ #new_session_ticket{} |
+ #key_update{}.
-export_type([tls_handshake_1_3/0]).
diff --git a/lib/ssl/src/tls_record.erl b/lib/ssl/src/tls_record.erl
index e8040b461d..538c3e44fb 100644
--- a/lib/ssl/src/tls_record.erl
+++ b/lib/ssl/src/tls_record.erl
@@ -38,7 +38,7 @@
%% Encoding TLS records
-export([encode_handshake/3, encode_alert_record/3,
encode_change_cipher_spec/2, encode_data/3]).
--export([encode_plain_text/4]).
+-export([encode_plain_text/4, split_iovec/1]).
%% Decoding
-export([decode_cipher_text/4]).
@@ -395,6 +395,12 @@ hello_version([Highest|_]) when Highest >= {3,3} ->
hello_version(Versions) ->
lowest_protocol_version(Versions).
+split_iovec([]) ->
+ [];
+split_iovec(Data) ->
+ {Part,Rest} = split_iovec(Data, ?MAX_PLAIN_TEXT_LENGTH, []),
+ [Part|split_iovec(Rest)].
+
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
@@ -498,8 +504,9 @@ validate_tls_record_length(_Versions, Q, _SslOpts, Acc, Type, Version, undefined
validate_tls_record_length(Versions, {_,Size0,_} = Q0,
#{log_level := LogLevel} = SslOpts,
Acc, Type, Version, Length) ->
+ Max = max_len(Versions),
if
- Length =< ?MAX_CIPHER_TEXT_LENGTH ->
+ Length =< Max ->
if
Length =< Size0 ->
%% Complete record
@@ -630,12 +637,6 @@ split_iovec(Data, Version, BCA, zero_n)
split_iovec(Data, _Version, _BCA, _BeatMitigation) ->
split_iovec(Data).
-split_iovec([]) ->
- [];
-split_iovec(Data) ->
- {Part,Rest} = split_iovec(Data, ?MAX_PLAIN_TEXT_LENGTH, []),
- [Part|split_iovec(Rest)].
-%%
split_iovec([Bin|Data] = Bin_Data, SplitSize, Acc) ->
BinSize = byte_size(Bin),
if
@@ -671,4 +672,7 @@ sufficient_tlsv1_2_crypto_support() ->
CryptoSupport = crypto:supports(),
proplists:get_bool(sha256, proplists:get_value(hashs, CryptoSupport)).
-
+max_len([{3,4}|_])->
+ ?TLS13_MAX_CIPHER_TEXT_LENGTH;
+max_len(_) ->
+ ?MAX_CIPHER_TEXT_LENGTH.
diff --git a/lib/ssl/src/tls_record_1_3.erl b/lib/ssl/src/tls_record_1_3.erl
index d713062284..52e3c06a3b 100644
--- a/lib/ssl/src/tls_record_1_3.erl
+++ b/lib/ssl/src/tls_record_1_3.erl
@@ -47,7 +47,7 @@ encode_handshake(Frag, ConnectionStates) ->
case iolist_size(Frag) of
N when N > ?MAX_PLAIN_TEXT_LENGTH ->
%% TODO: Consider padding here
- Data = split_bin(iolist_to_binary(Frag), ?MAX_PLAIN_TEXT_LENGTH),
+ Data = tls_record:split_iovec(Frag),
encode_iolist(?HANDSHAKE, Data, ConnectionStates);
_ ->
encode_plain_text(?HANDSHAKE, Frag, ConnectionStates)
@@ -64,13 +64,13 @@ encode_alert_record(#alert{level = Level, description = Description},
encode_plain_text(?ALERT, <<?BYTE(Level), ?BYTE(Description)>>,
ConnectionStates).
%%--------------------------------------------------------------------
--spec encode_data(binary(), ssl_record:connection_states()) ->
+-spec encode_data(iolist(), ssl_record:connection_states()) ->
{iolist(), ssl_record:connection_states()}.
%%
%% Description: Encodes data to send on the ssl-socket.
%%--------------------------------------------------------------------
encode_data(Frag, ConnectionStates) ->
- Data = split_bin(Frag, ?MAX_PLAIN_TEXT_LENGTH, {3,4}),
+ Data = tls_record:split_iovec(Frag),
encode_iolist(?APPLICATION_DATA, Data, ConnectionStates).
encode_plain_text(Type, Data0, #{current_write := Write0} = ConnectionStates) ->
@@ -180,21 +180,6 @@ decode_cipher_text(#ssl_tls{type = Type}, _) ->
%%--------------------------------------------------------------------
%%% Internal functions
%%--------------------------------------------------------------------
-split_bin(Bin, ChunkSize) ->
- split_bin(Bin, ChunkSize, []).
-split_bin(Bin, ChunkSize, _) ->
- do_split_bin(Bin, ChunkSize, []).
-
-do_split_bin(<<>>, _, Acc) ->
- lists:reverse(Acc);
-do_split_bin(Bin, ChunkSize, Acc) ->
- case Bin of
- <<Chunk:ChunkSize/binary, Rest/binary>> ->
- do_split_bin(Rest, ChunkSize, [Chunk | Acc]);
- _ ->
- lists:reverse(Acc, [Bin])
- end.
-
inner_plaintext(Type, Data, Length) ->
#inner_plaintext{
content = Data,
diff --git a/lib/ssl/src/tls_sender.erl b/lib/ssl/src/tls_sender.erl
index 50811ef3dd..790746658e 100644
--- a/lib/ssl/src/tls_sender.erl
+++ b/lib/ssl/src/tls_sender.erl
@@ -26,18 +26,20 @@
-include("ssl_alert.hrl").
-include("ssl_handshake.hrl").
-include("ssl_api.hrl").
+-include("ssl_record.hrl").
+-include("tls_handshake_1_3.hrl").
%% API
--export([start/0, start/1, initialize/2, send_data/2, send_alert/2,
+-export([start/0, start/1, initialize/2, send_data/2,
+ send_post_handshake/2, send_alert/2,
send_and_ack_alert/2, setopts/2, renegotiate/1, peer_renegotiate/1, downgrade/2,
- update_connection_state/3, dist_tls_socket/1, dist_handshake_complete/3]).
+ update_connection_state/3,
+ dist_tls_socket/1, dist_handshake_complete/3]).
%% gen_statem callbacks
-export([callback_mode/0, init/1, terminate/3, code_change/4]).
-export([init/3, connection/3, handshake/3, death_row/3]).
--define(SERVER, ?MODULE).
-
-record(static,
{connection_pid,
role,
@@ -47,6 +49,8 @@
transport_cb,
negotiated_version,
renegotiate_at,
+ key_update_at, %% TLS 1.3
+ bytes_sent, %% TLS 1.3
connection_monitor,
dist_handle,
log_level
@@ -94,6 +98,13 @@ send_data(Pid, AppData) ->
call(Pid, {application_data, AppData}).
%%--------------------------------------------------------------------
+-spec send_post_handshake(pid(), #key_update{}) -> ok | {error, term()}.
+%% Description: Send post handshake data
+%%--------------------------------------------------------------------
+send_post_handshake(Pid, HandshakeData) ->
+ call(Pid, {post_handshake_data, HandshakeData}).
+
+%%--------------------------------------------------------------------
-spec send_alert(pid(), #alert{}) -> _.
%% Description: TLS connection process wants to send an Alert
%% in the connection state.
@@ -204,6 +215,7 @@ init({call, From}, {Pid, #{current_write := WriteState,
transport_cb := Transport,
negotiated_version := Version,
renegotiate_at := RenegotiateAt,
+ key_update_at := KeyUpdateAt,
log_level := LogLevel}},
#data{connection_states = ConnectionStates, static = Static0} = StateData0) ->
Monitor = erlang:monitor(process, Pid),
@@ -218,6 +230,8 @@ init({call, From}, {Pid, #{current_write := WriteState,
transport_cb = Transport,
negotiated_version = Version,
renegotiate_at = RenegotiateAt,
+ key_update_at = KeyUpdateAt,
+ bytes_sent = 0,
log_level = LogLevel}},
{next_state, handshake, StateData, [{reply, From, ok}]};
init(_, _, _) ->
@@ -239,6 +253,8 @@ connection({call, From}, {application_data, AppData},
Data ->
send_application_data(Data, From, ?FUNCTION_NAME, StateData)
end;
+connection({call, From}, {post_handshake_data, HSData}, StateData) ->
+ send_post_handshake_data(HSData, From, ?FUNCTION_NAME, StateData);
connection({call, From}, {ack_alert, #alert{} = Alert}, StateData0) ->
StateData = send_tls_alert(Alert, StateData0),
{next_state, ?FUNCTION_NAME, StateData,
@@ -275,7 +291,8 @@ connection({call, From}, {dist_handshake_complete, _Node, DHandle},
end]};
connection(internal, {application_packets, From, Data}, StateData) ->
send_application_data(Data, From, ?FUNCTION_NAME, StateData);
-%%
+connection(internal, {post_handshake_data, From, HSData}, StateData) ->
+ send_post_handshake_data(HSData, From, ?FUNCTION_NAME, StateData);
connection(cast, #alert{} = Alert, StateData0) ->
StateData = send_tls_alert(Alert, StateData0),
{next_state, ?FUNCTION_NAME, StateData};
@@ -324,11 +341,14 @@ handshake({call, _}, _, _) ->
{keep_state_and_data, [postpone]};
handshake(internal, {application_packets,_,_}, _) ->
{keep_state_and_data, [postpone]};
-handshake(cast, {new_write, WritesState, Version},
- #data{connection_states = ConnectionStates, static = Static} = StateData) ->
+handshake(cast, {new_write, WriteState, Version},
+ #data{connection_states = ConnectionStates,
+ static = #static{key_update_at = KeyUpdateAt0} = Static} = StateData) ->
+ KeyUpdateAt = key_update_at(Version, WriteState, KeyUpdateAt0),
{next_state, connection,
- StateData#data{connection_states = ConnectionStates#{current_write => WritesState},
- static = Static#static{negotiated_version = Version}}};
+ StateData#data{connection_states = ConnectionStates#{current_write => WriteState},
+ static = Static#static{negotiated_version = Version,
+ key_update_at = KeyUpdateAt}}};
handshake(info, dist_data, _) ->
{keep_state_and_data, [postpone]};
handshake(info, tick, _) ->
@@ -422,30 +442,111 @@ send_application_data(Data, From, StateName,
negotiated_version = Version,
transport_cb = Transport,
renegotiate_at = RenegotiateAt,
+ key_update_at = KeyUpdateAt,
+ bytes_sent = BytesSent,
log_level = LogLevel},
connection_states = ConnectionStates0} = StateData0) ->
- case time_to_renegotiate(Data, ConnectionStates0, RenegotiateAt) of
- true ->
+ case time_to_rekey(Version, Data, ConnectionStates0, RenegotiateAt, KeyUpdateAt, BytesSent) of
+ key_update ->
+ KeyUpdate = tls_handshake_1_3:key_update(update_requested),
+ {keep_state_and_data, [{next_event, internal, {post_handshake_data, From, KeyUpdate}},
+ {next_event, internal, {key_update, From}},
+ {next_event, internal, {application_packets, From, Data}}]};
+ renegotiate ->
ssl_connection:internal_renegotiation(Pid, ConnectionStates0),
{next_state, handshake, StateData0,
[{next_event, internal, {application_packets, From, Data}}]};
+ chunk_and_key_update ->
+ KeyUpdate = tls_handshake_1_3:key_update(update_requested),
+ %% Prevent infinite loop of key updates
+ {Chunk, Rest} = chunk_data(Data, KeyUpdateAt),
+ {keep_state_and_data, [{next_event, internal, {post_handshake_data, From, KeyUpdate}},
+ {next_event, internal, {application_packets, From, Chunk}},
+ {next_event, internal, {application_packets, From, Rest}}]};
false ->
{Msgs, ConnectionStates} = tls_record:encode_data(Data, Version, ConnectionStates0),
StateData = StateData0#data{connection_states = ConnectionStates},
case tls_socket:send(Transport, Socket, Msgs) of
ok when DistHandle =/= undefined ->
ssl_logger:debug(LogLevel, outbound, 'record', Msgs),
- {next_state, StateName, StateData, []};
+ StateData1 = update_bytes_sent(Version, StateData, Data),
+ {next_state, StateName, StateData1, []};
Reason when DistHandle =/= undefined ->
{next_state, death_row, StateData, [{state_timeout, 5000, Reason}]};
ok ->
ssl_logger:debug(LogLevel, outbound, 'record', Msgs),
- {next_state, StateName, StateData, [{reply, From, ok}]};
+ StateData1 = update_bytes_sent(Version, StateData, Data),
+ {next_state, StateName, StateData1, [{reply, From, ok}]};
Result ->
{next_state, StateName, StateData, [{reply, From, Result}]}
end
end.
+%% TLS 1.3 Post Handshake Data
+send_post_handshake_data(Handshake, From, StateName,
+ #data{static = #static{socket = Socket,
+ dist_handle = DistHandle,
+ negotiated_version = Version,
+ transport_cb = Transport,
+ log_level = LogLevel},
+ connection_states = ConnectionStates0} = StateData0) ->
+ BinHandshake = tls_handshake:encode_handshake(Handshake, Version),
+ {Encoded, ConnectionStates} =
+ tls_record:encode_handshake(BinHandshake, Version, ConnectionStates0),
+ ssl_logger:debug(LogLevel, outbound, 'handshake', Handshake),
+ StateData1 = StateData0#data{connection_states = ConnectionStates},
+ case tls_socket:send(Transport, Socket, Encoded) of
+ ok when DistHandle =/= undefined ->
+ ssl_logger:debug(LogLevel, outbound, 'record', Encoded),
+ StateData = maybe_update_cipher_key(StateData1, Handshake),
+ {next_state, StateName, StateData, []};
+ Reason when DistHandle =/= undefined ->
+ {next_state, death_row, StateData1, [{state_timeout, 5000, Reason}]};
+ ok ->
+ ssl_logger:debug(LogLevel, outbound, 'record', Encoded),
+ StateData = maybe_update_cipher_key(StateData1, Handshake),
+ {next_state, StateName, StateData, [{reply, From, ok}]};
+ Result ->
+ {next_state, StateName, StateData1, [{reply, From, Result}]}
+ end.
+
+maybe_update_cipher_key(#data{connection_states = ConnectionStates0,
+ static = Static0} = StateData, #key_update{}) ->
+ ConnectionStates = tls_connection:update_cipher_key(current_write, ConnectionStates0),
+ Static = Static0#static{bytes_sent = 0},
+ StateData#data{connection_states = ConnectionStates,
+ static = Static};
+maybe_update_cipher_key(StateData, _) ->
+ StateData.
+
+update_bytes_sent(Version, StateData, _) when Version < {3,4} ->
+ StateData;
+%% Count bytes sent in TLS 1.3 for AES-GCM
+update_bytes_sent(_, #data{static = #static{key_update_at = seq_num_wrap}} = StateData, _) ->
+ StateData; %% Chacha20-Poly1305
+update_bytes_sent(_, #data{static = #static{bytes_sent = Sent} = Static} = StateData, Data) ->
+ StateData#data{static = Static#static{bytes_sent = Sent + iolist_size(Data)}}. %% AES-GCM
+
+%% For AES-GCM, up to 2^24.5 full-size records (about 24 million) may be
+%% encrypted on a given connection while keeping a safety margin of
+%% approximately 2^-57 for Authenticated Encryption (AE) security. For
+%% ChaCha20/Poly1305, the record sequence number would wrap before the
+%% safety limit is reached.
+key_update_at(Version, #{security_parameters :=
+ #security_parameters{
+ bulk_cipher_algorithm = CipherAlgo}}, KeyUpdateAt)
+ when Version >= {3,4} ->
+ case CipherAlgo of
+ ?AES_GCM ->
+ KeyUpdateAt;
+ ?CHACHA20_POLY1305 ->
+ seq_num_wrap;
+ ?AES_CCM ->
+ KeyUpdateAt
+ end;
+key_update_at(_, _, KeyUpdateAt) ->
+ KeyUpdateAt.
+
-compile({inline, encode_packet/2}).
encode_packet(Packet, Data) ->
Len = iolist_size(Data),
@@ -463,9 +564,29 @@ encode_packet(Packet, Data) ->
set_opts(SocketOptions, [{packet, N}]) ->
SocketOptions#socket_options{packet = N}.
-time_to_renegotiate(_Data,
- #{current_write := #{sequence_number := Num}},
- RenegotiateAt) ->
+time_to_rekey(Version, _Data,
+ #{current_write := #{sequence_number := ?MAX_SEQUENCE_NUMBER}},
+ _, _, _) when Version >= {3,4} ->
+ key_update;
+time_to_rekey(Version, _Data, _, _, seq_num_wrap, _) when Version >= {3,4} ->
+ false;
+time_to_rekey(Version, Data, _, _, KeyUpdateAt, BytesSent) when Version >= {3,4} ->
+ DataSize = iolist_size(Data),
+ case (BytesSent + DataSize) > KeyUpdateAt of
+ true ->
+ %% Handle special case that causes an invite loop of key updates.
+ case DataSize > KeyUpdateAt of
+ true ->
+ chunk_and_key_update;
+ false ->
+ key_update
+ end;
+ false ->
+ false
+ end;
+time_to_rekey(_, _Data,
+ #{current_write := #{sequence_number := Num}},
+ RenegotiateAt, _, _) ->
%% We could do test:
%% is_time_to_renegotiate((erlang:byte_size(_Data) div
@@ -473,10 +594,14 @@ time_to_renegotiate(_Data,
%% have a some what lower renegotiateAt and a much cheaper test
is_time_to_renegotiate(Num, RenegotiateAt).
+chunk_data(Data, Size) ->
+ {Chunk, Rest} = split_binary(iolist_to_binary(Data), Size),
+ {[Chunk], [Rest]}.
+
is_time_to_renegotiate(N, M) when N < M->
false;
is_time_to_renegotiate(_,_) ->
- true.
+ renegotiate.
call(FsmPid, Event) ->
try gen_statem:call(FsmPid, Event)
diff --git a/lib/ssl/src/tls_server_session_ticket.erl b/lib/ssl/src/tls_server_session_ticket.erl
index fc3904366e..a1e8ec4331 100644
--- a/lib/ssl/src/tls_server_session_ticket.erl
+++ b/lib/ssl/src/tls_server_session_ticket.erl
@@ -221,7 +221,7 @@ stateful_ticket_store(Ref, NewSessionTicket, Hash, Psk,
max := Max,
ref_index := Index0} = Stateful}
= State0) ->
- Id = erlang:monotonic_time(),
+ Id = {erlang:monotonic_time(), erlang:unique_integer([monotonic])},
StatefulTicket = {NewSessionTicket, Hash, Psk},
case gb_trees:size(Tree0) of
Max ->
@@ -288,7 +288,7 @@ stateful_usable_ticket(Key, Prf, Binder, HandshakeHist, Tree) ->
false
end.
-stateful_living_ticket(TimeStamp,
+stateful_living_ticket({TimeStamp,_},
#new_session_ticket{ticket_lifetime = LifeTime}) ->
Now = erlang:monotonic_time(),
Lived = erlang:convert_time_unit(Now-TimeStamp, native, seconds),
diff --git a/lib/ssl/src/tls_v1.erl b/lib/ssl/src/tls_v1.erl
index 381793c65d..38594151d9 100644
--- a/lib/ssl/src/tls_v1.erl
+++ b/lib/ssl/src/tls_v1.erl
@@ -884,7 +884,9 @@ oid_to_enum(?secp384r1) -> 24;
oid_to_enum(?secp521r1) -> 25;
oid_to_enum(?brainpoolP256r1) -> 26;
oid_to_enum(?brainpoolP384r1) -> 27;
-oid_to_enum(?brainpoolP512r1) -> 28.
+oid_to_enum(?brainpoolP512r1) -> 28;
+oid_to_enum(?'id-X25519') -> 29;
+oid_to_enum(?'id-X448') -> 30.
enum_to_oid(1) -> ?sect163k1;
enum_to_oid(2) -> ?sect163r1;
@@ -914,5 +916,7 @@ enum_to_oid(25) -> ?secp521r1;
enum_to_oid(26) -> ?brainpoolP256r1;
enum_to_oid(27) -> ?brainpoolP384r1;
enum_to_oid(28) -> ?brainpoolP512r1;
+enum_to_oid(29) -> ?'id-X25519';
+enum_to_oid(30) -> ?'id-X448';
enum_to_oid(_) ->
undefined.
diff --git a/lib/ssl/test/Makefile b/lib/ssl/test/Makefile
index cb52a6d3d5..e53f54130f 100644
--- a/lib/ssl/test/Makefile
+++ b/lib/ssl/test/Makefile
@@ -66,6 +66,8 @@ MODULES = \
ssl_dist_bench_SUITE \
ssl_engine_SUITE\
ssl_handshake_SUITE \
+ ssl_key_update_SUITE \
+ openssl_key_update_SUITE \
ssl_npn_hello_SUITE \
ssl_packet_SUITE \
ssl_payload_SUITE \
@@ -73,6 +75,7 @@ MODULES = \
ssl_session_SUITE \
ssl_session_cache_SUITE \
ssl_session_ticket_SUITE \
+ openssl_session_ticket_SUITE \
openssl_session_SUITE \
ssl_ECC_SUITE \
ssl_ECC_openssl_SUITE \
diff --git a/lib/ssl/test/dtls_api_SUITE.erl b/lib/ssl/test/dtls_api_SUITE.erl
index a89e754219..b3bf3b1528 100644
--- a/lib/ssl/test/dtls_api_SUITE.erl
+++ b/lib/ssl/test/dtls_api_SUITE.erl
@@ -39,7 +39,8 @@ groups() ->
api_tests() ->
[
dtls_listen_owner_dies,
- dtls_listen_close
+ dtls_listen_close,
+ dtls_listen_reopen
].
init_per_suite(Config0) ->
@@ -114,7 +115,7 @@ dtls_listen_owner_dies(Config) when is_list(Config) ->
{ok, LSocket} = ssl:listen(Port, [{protocol, dtls} | ServerOpts]),
spawn(fun() ->
{ok, ASocket} = ssl:transport_accept(LSocket),
- _ = ssl:handshake(ASocket),
+ {ok, Socket} = ssl:handshake(ASocket),
receive
{ssl, Socket, "from client"} ->
ssl:send(Socket, "from server"),
@@ -141,6 +142,49 @@ dtls_listen_close(Config) when is_list(Config) ->
{ok, ListenSocket} = ssl:listen(Port, [{protocol, dtls} | ServerOpts]),
ok = ssl:close(ListenSocket).
+
+dtls_listen_reopen() ->
+ [{doc, "Test that you close a DTLS 'listner' socket and open a new one for the same port"}].
+
+dtls_listen_reopen(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Port = ssl_test_lib:inet_port(ServerNode),
+ {ok, LSocket0} = ssl:listen(Port, [{protocol, dtls} | ServerOpts]),
+ spawn(fun() ->
+ {ok, ASocket} = ssl:transport_accept(LSocket0),
+ {ok, Socket} = ssl:handshake(ASocket),
+ receive
+ {ssl, Socket, "from client"} ->
+ ssl:send(Socket, "from server 1"),
+ ssl:close(Socket)
+ end
+ end),
+ {ok, Client1} = ssl:connect(Hostname, Port, ClientOpts),
+ ok = ssl:close(LSocket0),
+ {ok, LSocket1} = ssl:listen(Port, [{protocol, dtls} | ServerOpts]),
+ spawn(fun() ->
+ {ok, ASocket} = ssl:transport_accept(LSocket1),
+ {ok, Socket} = ssl:handshake(ASocket),
+ receive
+ {ssl, Socket, "from client"} ->
+ ssl:send(Socket, "from server 2"),
+ ssl:close(Socket)
+ end
+ end),
+ {ok, Client2} = ssl:connect(Hostname, Port, [{protocol, dtls} | ClientOpts]),
+ ssl:send(Client2, "from client"),
+ ssl:send(Client1, "from client"),
+ receive
+ {ssl, Client1, "from server 1"} ->
+ ssl:close(Client1)
+ end,
+ receive
+ {ssl, Client2, "from server 2"} ->
+ ssl:close(Client2)
+ end.
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/openssl_alpn_SUITE.erl b/lib/ssl/test/openssl_alpn_SUITE.erl
index 3813562cda..0e3e3daee3 100644
--- a/lib/ssl/test/openssl_alpn_SUITE.erl
+++ b/lib/ssl/test/openssl_alpn_SUITE.erl
@@ -46,7 +46,9 @@ all() ->
{group, 'dtlsv1.2'},
{group, 'dtlsv1'}];
false ->
- [{group, 'tlsv1.2'},
+ [
+ {group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'}]
end.
diff --git a/lib/ssl/test/openssl_key_update_SUITE.erl b/lib/ssl/test/openssl_key_update_SUITE.erl
new file mode 100644
index 0000000000..4963f0bb30
--- /dev/null
+++ b/lib/ssl/test/openssl_key_update_SUITE.erl
@@ -0,0 +1,134 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(openssl_key_update_SUITE).
+
+%% Callback functions
+-export([all/0,
+ groups/0,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_group/2,
+ end_per_group/2,
+ init_per_testcase/2,
+ end_per_testcase/2]).
+
+%% Testcases
+-export([openssl_client_explicit_key_update/0,
+ openssl_client_explicit_key_update/1,
+ openssl_server_explicit_key_update/0,
+ openssl_server_explicit_key_update/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+all() ->
+ [{group, 'tlsv1.3'}].
+
+groups() ->
+ [{'tlsv1.3', [], tls_1_3_tests()}].
+
+tls_1_3_tests() ->
+ [openssl_client_explicit_key_update,
+ openssl_server_explicit_key_update].
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ ssl_test_lib:make_ecdsa_cert(Config0);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:init_per_group_openssl(GroupName, Config).
+
+end_per_group(GroupName, Config) ->
+ ssl_test_lib:end_per_group(GroupName, Config).
+
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+openssl_client_explicit_key_update() ->
+ [{doc,"Test ssl:update_key/2 between openssl s_client and erlang server."}].
+
+openssl_client_explicit_key_update(Config) ->
+ Data = "123456789012345", %% 15 bytes
+
+ Server = ssl_test_lib:start_server(erlang, [{log_level, debug}], Config),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client(openssl, [{port, Port}], Config),
+ ssl_test_lib:send_recv_result_active(Client, Server, Data),
+
+ %% TODO s_client can hang after sending special commands e.g "k", "K"
+ %% ssl_test_lib:update_keys(Client, write),
+ %% ssl_test_lib:update_keys(Client, read_write),
+ ssl_test_lib:update_keys(Server, write),
+ ssl_test_lib:update_keys(Server, read_write),
+
+ ssl_test_lib:send_recv_result_active(Client, Server, Data),
+
+ ssl_test_lib:close(Client),
+ ssl_test_lib:close(Server).
+
+openssl_server_explicit_key_update() ->
+ [{doc,"Test ssl:update_key/2 between ssl client and s_server."}].
+
+openssl_server_explicit_key_update(Config) ->
+ Data = "123456789012345", %% 15 bytes
+
+ Server = ssl_test_lib:start_server(openssl, [], Config),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client(erlang, [{port, Port},
+ {log_level, debug},
+ {versions, ['tlsv1.2','tlsv1.3']}],Config),
+ ssl_test_lib:send_recv_result_active(Server, Client, Data),
+
+ ssl_test_lib:update_keys(Client, write),
+ ssl_test_lib:update_keys(Client, read_write),
+ ssl_test_lib:update_keys(Server, write),
+ ssl_test_lib:update_keys(Server, read_write),
+
+ ssl_test_lib:send_recv_result_active(Client, Server, Data),
+
+ ssl_test_lib:close(Client),
+ ssl_test_lib:close(Server).
diff --git a/lib/ssl/test/openssl_session_ticket_SUITE.erl b/lib/ssl/test/openssl_session_ticket_SUITE.erl
new file mode 100644
index 0000000000..775048e355
--- /dev/null
+++ b/lib/ssl/test/openssl_session_ticket_SUITE.erl
@@ -0,0 +1,409 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+
+-module(openssl_session_ticket_SUITE).
+
+%% Callback functions
+-export([all/0,
+ groups/0,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_group/2,
+ end_per_group/2,
+ init_per_testcase/2,
+ end_per_testcase/2]).
+
+%% Testcases
+-export([openssl_server_basic/0,
+ openssl_server_basic/1,
+ openssl_server_hrr/0,
+ openssl_server_hrr/1,
+ openssl_server_hrr_multiple_tickets/0,
+ openssl_server_hrr_multiple_tickets/1,
+ openssl_client_basic/0,
+ openssl_client_basic/1,
+ openssl_client_hrr/0,
+ openssl_client_hrr/1]).
+
+-include("tls_handshake.hrl").
+
+-include_lib("common_test/include/ct.hrl").
+
+-define(SLEEP, 500).
+
+%%--------------------------------------------------------------------
+%% Common Test interface functions -----------------------------------
+%%--------------------------------------------------------------------
+all() ->
+ [
+ {group, 'tlsv1.3'}
+ ].
+
+groups() ->
+ [{'tlsv1.3', [], [{group, stateful},
+ {group, stateless},
+ {group, openssl_server}]},
+ {openssl_server, [], [openssl_server_basic,
+ openssl_server_hrr,
+ openssl_server_hrr_multiple_tickets
+ ]},
+ {stateful, [], session_tests()},
+ {stateless, [], session_tests()}].
+
+session_tests() ->
+ [openssl_client_basic,
+ openssl_client_hrr].
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ ssl_test_lib:make_rsa_cert(Config0)
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:stop(crypto).
+
+init_per_group(stateful, Config) ->
+ [{server_ticket_mode, stateful} | proplists:delete(server_ticket_mode, Config)];
+init_per_group(stateless, Config) ->
+ [{server_ticket_mode, stateless} | proplists:delete(server_ticket_mode, Config)];
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:init_per_group_openssl(GroupName, Config).
+
+end_per_group(GroupName, Config) ->
+ ssl_test_lib:end_per_group(GroupName, Config).
+
+init_per_testcase(_TestCase, Config) ->
+ ssl:stop(),
+ application:load(ssl),
+ ssl:start(),
+ ct:timetrap({seconds, 15}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+openssl_server_basic() ->
+ [{doc,"Test session resumption with session tickets (erlang client - openssl server)"}].
+openssl_server_basic(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Version = 'tlsv1.3',
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CACertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+
+ %% Configure session tickets
+ ClientOpts = [{session_tickets, auto}, {log_level, debug},
+ {versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-cert", CertFile,"-key", KeyFile, "-CAfile", CACertFile, "-msg", "-debug"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ %% Store ticket from first connection
+ Client0 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [false, no_reply]}},
+ {from, self()}, {options, ClientOpts}]),
+ %% Wait for session ticket
+ ct:sleep(100),
+
+ %% Close previous connection as s_server can only handle one at a time
+ ssl_test_lib:close(Client0),
+
+ %% Use ticket
+ Client1 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [true, no_reply]}},
+ {from, self()},
+ {options, ClientOpts}]),
+ process_flag(trap_exit, false),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client1).
+
+openssl_client_basic() ->
+ [{doc,"Test session resumption with session tickets (openssl client - erlang server)"}].
+openssl_client_basic(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TicketFile0 = filename:join([proplists:get_value(priv_dir, Config), "session_ticket0"]),
+ TicketFile1 = filename:join([proplists:get_value(priv_dir, Config), "session_ticket1"]),
+ ServerTicketMode = proplists:get_value(server_ticket_mode, Config),
+
+ Data = "Hello world",
+
+ %% Configure session tickets
+ ServerOpts = [{session_tickets, ServerTicketMode}, {log_level, debug},
+ {versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
+
+ Server0 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [false]}},
+ {options, ServerOpts}]),
+
+ Version = 'tlsv1.3',
+ Port0 = ssl_test_lib:inet_port(Server0),
+
+ Exe = "openssl",
+ Args0 = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
+ ++ ":" ++ integer_to_list(Port0),
+ ssl_test_lib:version_flag(Version),
+ "-sess_out", TicketFile0],
+
+ OpenSslPort0 = ssl_test_lib:portable_open_port(Exe, Args0),
+
+ true = port_command(OpenSslPort0, Data),
+
+ ssl_test_lib:check_result(Server0, ok),
+
+ Server0 ! {listen, {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [true]}}},
+
+ %% Wait for session ticket
+ ct:sleep(100),
+
+ Args1 = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
+ ++ ":" ++ integer_to_list(Port0),
+ ssl_test_lib:version_flag(Version),
+ "-sess_in", TicketFile0,
+ "-sess_out", TicketFile1],
+
+ OpenSslPort1 = ssl_test_lib:portable_open_port(Exe, Args1),
+
+ true = port_command(OpenSslPort1, Data),
+
+ ssl_test_lib:check_result(Server0, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server0),
+ ssl_test_lib:close_port(OpenSslPort0),
+ ssl_test_lib:close_port(OpenSslPort1).
+
+openssl_server_hrr() ->
+ [{doc,"Test session resumption with session tickets and hello_retry_request (erlang client - openssl server)"}].
+openssl_server_hrr(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Version = 'tlsv1.3',
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CACertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+
+ %% Configure session tickets
+ ClientOpts = [{session_tickets, auto}, {log_level, debug},
+ {versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups,[secp256r1, x25519]}|ClientOpts0],
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-cert", CertFile,
+ "-key", KeyFile,
+ "-CAfile", CACertFile,
+ "-groups", "X448:X25519",
+ "-msg", "-debug"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ %% Store ticket from first connection
+ Client0 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [false, no_reply]}},
+ {from, self()}, {options, ClientOpts}]),
+ %% Wait for session ticket
+ ct:sleep(100),
+
+ %% Close previous connection as s_server can only handle one at a time
+ ssl_test_lib:close(Client0),
+
+ %% Use ticket
+ Client1 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [true, no_reply]}},
+ {from, self()},
+ {options, ClientOpts}]),
+ process_flag(trap_exit, false),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client1).
+
+openssl_client_hrr() ->
+ [{doc,"Test session resumption with session tickets and hello_retry_request (openssl client - erlang server)"}].
+openssl_client_hrr(Config) when is_list(Config) ->
+ ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ TicketFile0 = filename:join([proplists:get_value(priv_dir, Config), "session_ticket0"]),
+ TicketFile1 = filename:join([proplists:get_value(priv_dir, Config), "session_ticket1"]),
+ ServerTicketMode = proplists:get_value(server_ticket_mode, Config),
+
+ Data = "Hello world",
+
+ %% Configure session tickets
+ ServerOpts = [{session_tickets, ServerTicketMode}, {log_level, debug},
+ {versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups,[x448, x25519]}|ServerOpts0],
+
+ Server0 =
+ ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [false]}},
+ {options, ServerOpts}]),
+
+ Version = 'tlsv1.3',
+ Port0 = ssl_test_lib:inet_port(Server0),
+
+ Exe = "openssl",
+ Args0 = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
+ ++ ":" ++ integer_to_list(Port0),
+ ssl_test_lib:version_flag(Version),
+ "-groups", "P-256:X25519",
+ "-sess_out", TicketFile0],
+
+ OpenSslPort0 = ssl_test_lib:portable_open_port(Exe, Args0),
+
+ true = port_command(OpenSslPort0, Data),
+
+ ssl_test_lib:check_result(Server0, ok),
+
+ Server0 ! {listen, {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [true]}}},
+
+ %% Wait for session ticket
+ ct:sleep(100),
+
+ Args1 = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
+ ++ ":" ++ integer_to_list(Port0),
+ ssl_test_lib:version_flag(Version),
+ "-groups", "P-256:X25519",
+ "-sess_in", TicketFile0,
+ "-sess_out", TicketFile1],
+
+ OpenSslPort1 = ssl_test_lib:portable_open_port(Exe, Args1),
+
+ true = port_command(OpenSslPort1, Data),
+
+ ssl_test_lib:check_result(Server0, ok),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close(Server0),
+ ssl_test_lib:close_port(OpenSslPort0),
+ ssl_test_lib:close_port(OpenSslPort1).
+
+openssl_server_hrr_multiple_tickets() ->
+ [{doc,"Test session resumption with multiple session tickets and hello_retry_request (erlang client - openssl server)"}].
+openssl_server_hrr_multiple_tickets(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+
+ Version = 'tlsv1.3',
+ Port = ssl_test_lib:inet_port(node()),
+ CertFile = proplists:get_value(certfile, ServerOpts),
+ CACertFile = proplists:get_value(cacertfile, ServerOpts),
+ KeyFile = proplists:get_value(keyfile, ServerOpts),
+
+ %% Configure session tickets
+ ClientOpts = [{session_tickets, manual}, {log_level, debug},
+ {versions, ['tlsv1.2','tlsv1.3']},
+ {supported_groups,[secp256r1, x25519]}|ClientOpts0],
+
+ Exe = "openssl",
+ Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
+ "-cert", CertFile,
+ "-key", KeyFile,
+ "-CAfile", CACertFile,
+ "-groups", "X448:X25519",
+ "-msg", "-debug"],
+
+ OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
+
+ ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
+
+ %% Store ticket from first connection
+ Client0 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [false, no_reply, {tickets, 2}]}},
+ {from, self()}, {options, ClientOpts}]),
+
+ Tickets0 = ssl_test_lib:check_tickets(Client0),
+
+ ct:pal("Received tickets: ~p~n", [Tickets0]),
+
+ %% Close previous connection as s_server can only handle one at a time
+ ssl_test_lib:close(Client0),
+
+ %% Use tickets
+ Client1 = ssl_test_lib:start_client([{node, ClientNode},
+ {port, Port}, {host, Hostname},
+ {mfa, {ssl_test_lib,
+ verify_active_session_resumption,
+ [true, no_reply, no_tickets]}},
+ {from, self()},
+ {options, [{use_ticket, Tickets0}|ClientOpts]}]),
+
+ process_flag(trap_exit, false),
+
+ %% Clean close down! Server needs to be closed first !!
+ ssl_test_lib:close_port(OpensslPort),
+ ssl_test_lib:close(Client1).
diff --git a/lib/ssl/test/openssl_sni_SUITE.erl b/lib/ssl/test/openssl_sni_SUITE.erl
index 26f08e36c0..ebae0e2683 100644
--- a/lib/ssl/test/openssl_sni_SUITE.erl
+++ b/lib/ssl/test/openssl_sni_SUITE.erl
@@ -38,7 +38,8 @@ all() ->
%% Note: SNI not supported in sslv3
case ssl_test_lib:openssl_sane_dtls() of
true ->
- [{group, 'tlsv1.2'},
+ [{group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'}
%% Seems broken in openssl
@@ -46,7 +47,8 @@ all() ->
%%{group, 'dtlsv1'}
];
false ->
- [{group, 'tlsv1.2'},
+ [{group, 'tlsv1.3'},
+ {group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'}]
end.
@@ -54,7 +56,8 @@ all() ->
groups() ->
case ssl_test_lib:openssl_sane_dtls() of
true ->
- [{'tlsv1.2', [], sni_tests()},
+ [{'tlsv1.3', [], sni_tests()},
+ {'tlsv1.2', [], sni_tests()},
{'tlsv1.1', [], sni_tests()},
{'tlsv1', [], sni_tests()}
%% Seems broken in openssl
@@ -62,7 +65,8 @@ groups() ->
%%{'dtlsv1', [], sni_tests()}
];
false ->
- [{'tlsv1.2', [], sni_tests()},
+ [{'tlsv1.3', [], sni_tests()},
+ {'tlsv1.2', [], sni_tests()},
{'tlsv1.1', [], sni_tests()},
{'tlsv1', [], sni_tests()}
]
diff --git a/lib/ssl/test/property_test/ssl_eqc_handshake.erl b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
index 9ae267a2d3..f19a74898d 100644
--- a/lib/ssl/test/property_test/ssl_eqc_handshake.erl
+++ b/lib/ssl/test/property_test/ssl_eqc_handshake.erl
@@ -591,7 +591,7 @@ server_hello_selected_version() ->
#server_hello_selected_version{selected_version = {3,4}}.
request_update() ->
- oneof([?UPDATE_NOT_REQUESTED, ?UPDATE_REQUESTED]).
+ oneof([update_not_requested, update_requested]).
certificate_chain()->
Conf = cert_conf(),
diff --git a/lib/ssl/test/ssl_alert_SUITE.erl b/lib/ssl/test/ssl_alert_SUITE.erl
index a5b9fe9b0e..6b02df759f 100644
--- a/lib/ssl/test/ssl_alert_SUITE.erl
+++ b/lib/ssl/test/ssl_alert_SUITE.erl
@@ -59,7 +59,7 @@ alerts(Config) when is_list(Config) ->
?DECRYPT_ERROR, ?EXPORT_RESTRICTION, ?PROTOCOL_VERSION,
?INSUFFICIENT_SECURITY, ?INTERNAL_ERROR, ?USER_CANCELED,
?NO_RENEGOTIATION, ?UNSUPPORTED_EXTENSION, ?CERTIFICATE_UNOBTAINABLE,
- ?UNRECOGNISED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE,
+ ?UNRECOGNIZED_NAME, ?BAD_CERTIFICATE_STATUS_RESPONSE,
?BAD_CERTIFICATE_HASH_VALUE, ?UNKNOWN_PSK_IDENTITY,
255 %% Unsupported/unknow alert will result in a description too
],
diff --git a/lib/ssl/test/ssl_cipher_suite_SUITE.erl b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
index e598d662e9..855533cc3d 100644
--- a/lib/ssl/test/ssl_cipher_suite_SUITE.erl
+++ b/lib/ssl/test/ssl_cipher_suite_SUITE.erl
@@ -32,6 +32,7 @@
%%--------------------------------------------------------------------
all() ->
[
+ {group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
@@ -42,6 +43,7 @@ all() ->
groups() ->
[
+ {'tlsv1.3', [], tls_1_3_kex()},
{'tlsv1.2', [], kex()},
{'tlsv1.1', [], kex()},
{'tlsv1', [], kex()},
@@ -60,6 +62,7 @@ groups() ->
ecdhe_rsa_aes_256_gcm,
ecdhe_rsa_chacha20_poly1305
]},
+ {ecdhe_1_3_rsa_cert, [], tls_1_3_cipher_suites()},
{ecdhe_ecdsa, [],[ecdhe_ecdsa_rc4_128,
ecdhe_ecdsa_3des_ede_cbc,
ecdhe_ecdsa_aes_128_cbc,
@@ -127,6 +130,17 @@ groups() ->
]}
].
+
+tls_1_3_kex() ->
+ [{group, ecdhe_1_3_rsa_cert}].
+
+tls_1_3_cipher_suites() ->
+ [aes_256_gcm_sha384,
+ aes_128_gcm_sha256,
+ chacha20_poly1305_sha256,
+ aes_128_ccm_sha256
+ ].
+
kex() ->
rsa() ++ ecdsa() ++ dss() ++ anonymous().
@@ -186,7 +200,13 @@ end_per_suite(_Config) ->
ssl:stop(),
application:stop(crypto).
-
+init_per_group(GroupName, Config) when GroupName == ecdhe_1_3_rsa_cert ->
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ init_certs(GroupName, Config);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end;
init_per_group(GroupName, Config) when GroupName == ecdh_anon;
GroupName == ecdhe_rsa;
GroupName == ecdhe_psk ->
@@ -318,6 +338,53 @@ init_per_testcase(TestCase, Config) when TestCase == psk_aes_256_ccm_8;
_ ->
{skip, "Missing AES_256_CCM crypto support"}
end;
+init_per_testcase(aes_256_gcm_sha384, Config) ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ SupHashs = proplists:get_value(hashs, crypto:supports()),
+ case (lists:member(aes_256_gcm, SupCiphers)) andalso
+ (lists:member(sha384, SupHashs))
+ of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_256_GCM_SHA384 crypto support"}
+ end;
+init_per_testcase(aes_128_gcm_sha256, Config) ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ SupHashs = proplists:get_value(hashs, crypto:supports()),
+ case (lists:member(aes_256_gcm, SupCiphers)) andalso
+ (lists:member(sha256, SupHashs))
+ of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_128_GCM_SHA256 crypto support"}
+ end;
+init_per_testcase(chacha20_poly1305_sha256, Config) ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ SupHashs = proplists:get_value(hashs, crypto:supports()),
+ case (lists:member(chacha20_poly1305, SupCiphers)) andalso
+ (lists:member(sha256, SupHashs))
+ of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing chacha20_poly1305_sha256 crypto support"}
+ end;
+init_per_testcase(aes_128_ccm_sha256, Config) ->
+ SupCiphers = proplists:get_value(ciphers, crypto:supports()),
+ SupHashs = proplists:get_value(hashs, crypto:supports()),
+ case (lists:member(aes_128_ccm, SupCiphers)) andalso
+ (lists:member(sha256, SupHashs)) of
+ true ->
+ ct:timetrap({seconds, 5}),
+ Config;
+ _ ->
+ {skip, "Missing AES_128_CCM_SHA256 crypto support"}
+ end;
init_per_testcase(TestCase, Config) ->
Cipher = ssl_test_lib:test_cipher(TestCase, Config),
SupCiphers = proplists:get_value(ciphers, crypto:supports()),
@@ -335,7 +402,6 @@ end_per_testcase(_TestCase, Config) ->
%%--------------------------------------------------------------------
%% Initializtion ------------------------------------------
%%--------------------------------------------------------------------
-
init_certs(srp_rsa, Config) ->
DefConf = ssl_test_lib:default_cert_chain_conf(),
CertChainConf = ssl_test_lib:gen_conf(rsa, rsa, DefConf, DefConf),
@@ -367,6 +433,14 @@ init_certs(rsa, Config) ->
[{tls_config, #{server_config => ServerOpts,
client_config => ClientOpts}} |
proplists:delete(tls_config, Config)];
+init_certs(ecdhe_1_3_rsa_cert, Config) ->
+ ClientExt = x509_test:extensions([{key_usage, [digitalSignature]}]),
+ {ClientOpts, ServerOpts} = ssl_test_lib:make_rsa_cert_chains([{server_chain,
+ [[],[],[{extensions, ClientExt}]]}],
+ Config, "_peer_rsa_digitalsign"),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)];
init_certs(dhe_dss, Config) ->
DefConf = ssl_test_lib:default_cert_chain_conf(),
CertChainConf = ssl_test_lib:gen_conf(dsa, dsa, DefConf, DefConf),
@@ -427,6 +501,22 @@ init_certs(_GroupName, Config) ->
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
+aes_256_gcm_sha384(Config) when is_list(Config)->
+ Version = ssl_test_lib:protocol_version(Config),
+ cipher_suite_test(ssl:str_to_suite("TLS_AES_256_GCM_SHA384"), Version, Config).
+
+aes_128_gcm_sha256(Config) when is_list(Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ cipher_suite_test(ssl:str_to_suite("TLS_AES_128_GCM_SHA256"), Version, Config).
+
+chacha20_poly1305_sha256(Config) when is_list(Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ cipher_suite_test(ssl:str_to_suite("TLS_CHACHA20_POLY1305_SHA256"), Version, Config).
+
+aes_128_ccm_sha256(Config) when is_list(Config) ->
+ Version = ssl_test_lib:protocol_version(Config),
+ cipher_suite_test(ssl:str_to_suite("TLS_AES_128_CCM_SHA256"), Version, Config).
+
%%--------------------------------------------------------------------
%% SRP --------------------------------------------------------
%%--------------------------------------------------------------------
@@ -775,3 +865,4 @@ test_ciphers(Kex, Cipher, Version) ->
(_) -> false
end}]).
+
diff --git a/lib/ssl/test/ssl_key_update_SUITE.erl b/lib/ssl/test/ssl_key_update_SUITE.erl
new file mode 100644
index 0000000000..2816f1a39e
--- /dev/null
+++ b/lib/ssl/test/ssl_key_update_SUITE.erl
@@ -0,0 +1,136 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2020-2020. All Rights Reserved.
+%%
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(ssl_key_update_SUITE).
+
+%% Callback functions
+-export([all/0,
+ groups/0,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_group/2,
+ end_per_group/2,
+ init_per_testcase/2,
+ end_per_testcase/2]).
+
+%% Testcases
+-export([key_update_at/0,
+ key_update_at/1,
+ explicit_key_update/0,
+ explicit_key_update/1]).
+
+-include_lib("common_test/include/ct.hrl").
+
+all() ->
+ [{group, 'tlsv1.3'}].
+
+groups() ->
+ [{'tlsv1.3', [], tls_1_3_tests()}].
+
+tls_1_3_tests() ->
+ [key_update_at,
+ explicit_key_update].
+
+init_per_suite(Config0) ->
+ catch crypto:stop(),
+ try crypto:start() of
+ ok ->
+ ssl_test_lib:clean_start(),
+ case proplists:get_bool(ecdh, proplists:get_value(public_keys, crypto:supports())) of
+ true ->
+ ssl_test_lib:make_ecdsa_cert(Config0);
+ false ->
+ {skip, "Missing EC crypto support"}
+ end
+ catch _:_ ->
+ {skip, "Crypto did not start"}
+ end.
+
+end_per_suite(_Config) ->
+ ssl:stop(),
+ application:unload(ssl),
+ application:stop(crypto).
+
+init_per_group(GroupName, Config) ->
+ ssl_test_lib:init_per_group(GroupName, Config).
+
+end_per_group(GroupName, Config) ->
+ ssl_test_lib:end_per_group(GroupName, Config).
+
+init_per_testcase(_TestCase, Config) ->
+ ssl_test_lib:ct_log_supported_protocol_versions(Config),
+ ct:timetrap({seconds, 10}),
+ Config.
+
+end_per_testcase(_TestCase, Config) ->
+ Config.
+
+
+%%--------------------------------------------------------------------
+%% Test Cases --------------------------------------------------------
+%%--------------------------------------------------------------------
+
+key_update_at() ->
+ [{doc,"Test option 'key_update_at' between erlang client and erlang server."}].
+
+key_update_at(Config) ->
+ %% {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ Data = "123456789012345", %% 15 bytes
+
+ Server = ssl_test_lib:start_server(erlang, [{log_level, debug},
+ {key_update_at, 15}], Config),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client(erlang, [{port, Port},
+ {log_level, debug},
+ {key_update_at, 15}], Config),
+ %% Sending bytes over limit triggers key update
+ ssl_test_lib:send(Client, Data),
+ Data = ssl_test_lib:check_active_receive(Server, Data),
+ %% TODO check if key has been updated (needs debug logging of secrets)
+
+ %% Test mechanism to prevent infinite loop of key updates
+ BigData = binary:copy(<<"1234567890">>, 10), %% 100 bytes
+ ok = ssl_test_lib:send(Client, BigData),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
+
+explicit_key_update() ->
+ [{doc,"Test ssl:update_key/2 between erlang client and erlang server."}].
+
+explicit_key_update(Config) ->
+ Data = "123456789012345", %% 15 bytes
+
+ Server = ssl_test_lib:start_server(erlang, [{log_level, debug}], Config),
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client(erlang, [{port, Port}, {log_level, debug}], Config),
+ ssl_test_lib:send_recv_result_active(Client, Server, Data),
+
+ ssl_test_lib:update_keys(Client, write),
+ ssl_test_lib:update_keys(Client, read_write),
+ ssl_test_lib:send_recv_result_active(Client, Server, Data),
+
+ ssl_test_lib:update_keys(Server, write),
+ ssl_test_lib:update_keys(Server, read_write),
+ ssl_test_lib:send_recv_result_active(Client, Server, Data),
+ %% TODO check if key has been updated (needs debug logging of secrets)
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client).
diff --git a/lib/ssl/test/ssl_packet_SUITE.erl b/lib/ssl/test/ssl_packet_SUITE.erl
index b71be64787..99cf19f3ef 100644
--- a/lib/ssl/test/ssl_packet_SUITE.erl
+++ b/lib/ssl/test/ssl_packet_SUITE.erl
@@ -50,6 +50,7 @@
%%--------------------------------------------------------------------
all() ->
[
+ {group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
@@ -59,7 +60,8 @@ all() ->
].
groups() ->
- [{'tlsv1.2', [], socket_packet_tests() ++ protocol_packet_tests()},
+ [{'tlsv1.3', [], socket_packet_tests() ++ protocol_packet_tests()},
+ {'tlsv1.2', [], socket_packet_tests() ++ protocol_packet_tests()},
{'tlsv1.1', [], socket_packet_tests() ++ protocol_packet_tests()},
{'tlsv1', [], socket_packet_tests() ++ protocol_packet_tests()},
{'sslv3', [], socket_packet_tests() ++ protocol_packet_tests()},
@@ -2009,7 +2011,8 @@ packet(Config, Data, Send, Recv, Quantity, Packet, Active) ->
Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, Send ,[Data, Quantity]}},
- {options, [{packet, Packet}, {nodelay, true}| ServerOpts]}]),
+ {options, [{packet, Packet}, {nodelay, true}| ServerOpts]
+ ++ ssl_test_lib:bigger_buffers()}]),
Port = ssl_test_lib:inet_port(Server),
Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
{host, Hostname},
@@ -2018,7 +2021,7 @@ packet(Config, Data, Send, Recv, Quantity, Packet, Active) ->
{options, [{active, Active},
{nodelay, true},
{packet, Packet} |
- ClientOpts]}]),
+ ClientOpts] ++ ssl_test_lib:bigger_buffers()}]),
ssl_test_lib:check_result(Client, ok),
diff --git a/lib/ssl/test/ssl_payload_SUITE.erl b/lib/ssl/test/ssl_payload_SUITE.erl
index 91043408b7..4374d9ff47 100644
--- a/lib/ssl/test/ssl_payload_SUITE.erl
+++ b/lib/ssl/test/ssl_payload_SUITE.erl
@@ -27,11 +27,13 @@
-define(TIMEOUT, 600000).
+
%%--------------------------------------------------------------------
%% Common Test interface functions -----------------------------------
%%--------------------------------------------------------------------
all() ->
[
+ {group, 'tlsv1.3'},
{group, 'tlsv1.2'},
{group, 'tlsv1.1'},
{group, 'tlsv1'},
@@ -40,6 +42,7 @@ all() ->
groups() ->
[
+ {'tlsv1.3', [], payload_tests()},
{'tlsv1.2', [], payload_tests()},
{'tlsv1.1', [], payload_tests()},
{'tlsv1', [], payload_tests()},
@@ -523,7 +526,7 @@ server_echos_passive(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, echoer, [Length]}},
- {options, [{active, false}, {mode, binary} | ServerOpts]}]),
+ {options, [{active, false}, {mode, binary} | ServerOpts] ++ ssl_test_lib:bigger_buffers()}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client(
@@ -531,7 +534,7 @@ server_echos_passive(
{host, Hostname},
{from, self()},
{mfa, {?MODULE, sender, [Data]}},
- {options, [{active, false}, {mode, binary} | ClientOpts]}]),
+ {options, [{active, false}, {mode, binary} | ClientOpts] ++ ssl_test_lib:bigger_buffers() }]),
%%
ssl_test_lib:check_result(Server, ok, Client, ok),
%%
@@ -569,7 +572,7 @@ server_echos_active_once(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, echoer_active_once, [Length]}},
- {options, [{active, once}, {mode, binary} | ServerOpts]}]),
+ {options, [{active, once}, {mode, binary} | ServerOpts] ++ ssl_test_lib:bigger_buffers()}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client(
@@ -577,7 +580,7 @@ server_echos_active_once(
{host, Hostname},
{from, self()},
{mfa, {?MODULE, sender_active_once, [Data]}},
- {options, [{active, once}, {mode, binary} | ClientOpts]}]),
+ {options, [{active, once}, {mode, binary} | ClientOpts] ++ ssl_test_lib:bigger_buffers() }]),
%%
ssl_test_lib:check_result(Server, ok, Client, ok),
%%
@@ -593,7 +596,7 @@ server_echos_active(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, echoer_active, [Length]}},
- {options, [{active, true}, {mode, binary} | ServerOpts]}]),
+ {options, [{active, true}, {mode, binary} | ServerOpts] ++ ssl_test_lib:bigger_buffers()}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client(
@@ -601,7 +604,7 @@ server_echos_active(
{host, Hostname},
{from, self()},
{mfa, {?MODULE, sender_active, [Data]}},
- {options, [{active, true}, {mode, binary} | ClientOpts]}]),
+ {options, [{active, true}, {mode, binary} | ClientOpts] ++ ssl_test_lib:bigger_buffers()}]),
%%
ssl_test_lib:check_result(Server, ok, Client, ok),
%%
@@ -616,7 +619,7 @@ client_echos_passive(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, sender, [Data]}},
- {options, [{active, false}, {mode, binary} | ServerOpts]}]),
+ {options, [{active, false}, {mode, binary} | ServerOpts] ++ ssl_test_lib:bigger_buffers()}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client(
@@ -624,7 +627,7 @@ client_echos_passive(
{host, Hostname},
{from, self()},
{mfa, {?MODULE, echoer, [Length]}},
- {options, [{active, false}, {mode, binary} | ClientOpts]}]),
+ {options, [{active, false}, {mode, binary} | ClientOpts] ++ ssl_test_lib:bigger_buffers()}]),
%%
ssl_test_lib:check_result(Server, ok, Client, ok),
%%
@@ -640,7 +643,7 @@ client_echos_passive_chunk(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, sender, [Data]}},
- {options, [{active, false}, {mode, binary} | ServerOpts]}]),
+ {options, [{active, false}, {mode, binary} | ServerOpts] ++ ssl_test_lib:bigger_buffers()}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client(
@@ -648,7 +651,7 @@ client_echos_passive_chunk(
{host, Hostname},
{from, self()},
{mfa, {?MODULE, echoer_chunk, [Length]}},
- {options, [{active, false}, {mode, binary} | ClientOpts]}]),
+ {options, [{active, false}, {mode, binary} | ClientOpts] ++ ssl_test_lib:bigger_buffers()}]),
%%
ssl_test_lib:check_result(Server, ok, Client, ok),
%%
@@ -664,7 +667,7 @@ client_echos_active_once(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, sender_active_once, [Data]}},
- {options, [{active, once}, {mode, binary} | ServerOpts]}]),
+ {options, [{active, once}, {mode, binary} | ServerOpts] ++ ssl_test_lib:bigger_buffers()}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client(
@@ -672,7 +675,7 @@ client_echos_active_once(
{host, Hostname},
{from, self()},
{mfa, {?MODULE, echoer_active_once, [Length]}},
- {options,[{active, once}, {mode, binary} | ClientOpts]}]),
+ {options,[{active, once}, {mode, binary} | ClientOpts] ++ ssl_test_lib:bigger_buffers()}]),
%%
ssl_test_lib:check_result(Server, ok, Client, ok),
%%
@@ -687,7 +690,7 @@ client_echos_active(
[{node, ServerNode}, {port, 0},
{from, self()},
{mfa, {?MODULE, sender_active, [Data]}},
- {options, [{active, true}, {mode, binary} | ServerOpts]}]),
+ {options, [{active, true}, {mode, binary} | ServerOpts] ++ ssl_test_lib:bigger_buffers()}]),
Port = ssl_test_lib:inet_port(Server),
Client =
ssl_test_lib:start_client(
@@ -695,7 +698,7 @@ client_echos_active(
{host, Hostname},
{from, self()},
{mfa, {?MODULE, echoer_active, [Length]}},
- {options, [{active, true}, {mode, binary} | ClientOpts]}]),
+ {options, [{active, true}, {mode, binary} | ClientOpts] ++ ssl_test_lib:bigger_buffers()}]),
%
ssl_test_lib:check_result(Server, ok, Client, ok),
%%
@@ -811,3 +814,4 @@ echo_active(Socket, Size) ->
echo_active(Socket, Size - byte_size(Data))
end.
+
diff --git a/lib/ssl/test/ssl_renegotiate_SUITE.erl b/lib/ssl/test/ssl_renegotiate_SUITE.erl
index ef3f9ebb52..921604458a 100644
--- a/lib/ssl/test/ssl_renegotiate_SUITE.erl
+++ b/lib/ssl/test/ssl_renegotiate_SUITE.erl
@@ -115,6 +115,18 @@ end_per_group(GroupName, Config) ->
Config
end.
+init_per_testcase(TestCase, Config) when TestCase == renegotiate_dos_mitigate_active;
+ TestCase == renegotiate_dos_mitigate_passive;
+ TestCase == renegotiate_dos_mitigate_absolute ->
+ ct:timetrap({seconds, 160}),
+ Config;
+init_per_testcase(_, Config) ->
+ ct:timetrap({seconds, 15}),
+ Config.
+
+end_per_testcase(_, Config) ->
+ Config.
+
%%--------------------------------------------------------------------
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
diff --git a/lib/ssl/test/ssl_session_SUITE.erl b/lib/ssl/test/ssl_session_SUITE.erl
index aa79698a72..f8dd633ed4 100644
--- a/lib/ssl/test/ssl_session_SUITE.erl
+++ b/lib/ssl/test/ssl_session_SUITE.erl
@@ -25,6 +25,7 @@
-compile(export_all).
-include("tls_handshake.hrl").
+-include("ssl_record.hrl").
-include_lib("common_test/include/ct.hrl").
-include_lib("public_key/include/public_key.hrl").
@@ -48,11 +49,11 @@ all() ->
groups() ->
[{'dtlsv1.2', [], session_tests()},
{'dtlsv1', [], session_tests()},
- {'tlsv1.3', [], session_tests()},
- {'tlsv1.2', [], session_tests()},
- {'tlsv1.1', [], session_tests()},
- {'tlsv1', [], session_tests()},
- {'sslv3', [], session_tests()}
+ {'tlsv1.3', [], session_tests() ++ tls_session_tests()},
+ {'tlsv1.2', [], session_tests() ++ tls_session_tests()},
+ {'tlsv1.1', [], session_tests() ++ tls_session_tests()},
+ {'tlsv1', [], session_tests() ++ tls_session_tests()},
+ {'sslv3', [], session_tests() ++ tls_session_tests()}
].
session_tests() ->
@@ -62,6 +63,8 @@ session_tests() ->
no_reuses_session_server_restart_new_cert,
no_reuses_session_server_restart_new_cert_file].
+tls_session_tests() ->
+ [session_table_stable_size_on_tcp_close].
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -372,6 +375,177 @@ no_reuses_session_server_restart_new_cert_file(Config) when is_list(Config) ->
ssl_test_lib:close(Server1),
ssl_test_lib:close(Client1).
+session_table_stable_size_on_tcp_close() ->
+ [{doc, "Check that new sessions are cleanup when connection is closed abruptly during first handshake"}].
+
+session_table_stable_size_on_tcp_close(Config) when is_list(Config)->
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ {status, _, _, StatusInfo} = sys:get_status(whereis(ssl_manager)),
+ [_, _,_, _, Prop] = StatusInfo,
+ State = ssl_test_lib:state(Prop),
+ ServerCache = element(3, State),
+
+ N = ets:info(ServerCache, size),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {options, [{reuseaddr, true} | ServerOpts]}]),
+ Port = ssl_test_lib:inet_port(Server),
+ faulty_client(Hostname, Port),
+ check_table_did_not_grow(ServerCache, N).
+
+
%%--------------------------------------------------------------------
%% Internal functions ------------------------------------------------
%%--------------------------------------------------------------------
+check_table_did_not_grow(ServerCache, N) ->
+ ct:sleep(500),
+ check_table_did_not_grow(ServerCache, N, 10).
+
+check_table_did_not_grow(_, _, 0) ->
+ ct:fail(table_grew);
+check_table_did_not_grow(ServerCache, N, Tries) ->
+ case ets:info(ServerCache, size) of
+ N ->
+ ok;
+ _ ->
+ ct:sleep(500),
+ check_table_did_not_grow(ServerCache, N, Tries -1)
+ end.
+
+faulty_client(Host, Port) ->
+ {ok, Sock} = gen_tcp:connect(Host, Port, [], 10000),
+ Random = crypto:strong_rand_bytes(32),
+ CH = client_hello(Random),
+ CHBin = encode_client_hello(CH, Random),
+ gen_tcp:send(Sock, CHBin),
+ ct:sleep(100),
+ gen_tcp:close(Sock).
+
+
+server(LOpts, Port) ->
+ {ok, LSock} = ssl:listen(Port, LOpts),
+ Pid = spawn_link(?MODULE, accept_loop, [LSock]),
+ ssl:controlling_process(LSock, Pid),
+ Pid.
+
+accept_loop(Sock) ->
+ {ok, CSock} = ssl:transport_accept(Sock),
+ _ = ssl:handshake(CSock),
+ accept_loop(Sock).
+
+
+encode_client_hello(CH, Random) ->
+ HSBin = tls_handshake:encode_handshake(CH, {3,3}),
+ CS = connection_states(Random),
+ {Encoded, _} = tls_record:encode_handshake(HSBin, {3,3}, CS),
+ Encoded.
+
+client_hello(Random) ->
+ CipherSuites = [<<0,255>>, <<"À,">>, <<"À0">>, <<"À$">>, <<"À(">>,
+ <<"À.">>, <<"À2">>, <<"À&">>, <<"À*">>, <<0,159>>,
+ <<0,163>>, <<0,107>>, <<0,106>>, <<"À+">>, <<"À/">>,
+ <<"À#">>, <<"À'">>, <<"À-">>, <<"À1">>, <<"À%">>,
+ <<"À)">>, <<0,158>>, <<0,162>>, <<0,103>>, <<0,64>>,
+ <<"À\n">>, <<192,20>>, <<0,57>>, <<0,56>>, <<192,5>>,
+ <<192,15>>, <<"À\t">>, <<192,19>>, <<0,51>>, <<0,50>>,
+ <<192,4>>, <<192,14>>],
+ Extensions = #{alpn => undefined,
+ ec_point_formats =>
+ {ec_point_formats,
+ [0]},
+ elliptic_curves =>
+ {elliptic_curves,
+ [{1,3,132,0,39},
+ {1,3,132,0,38},
+ {1,3,132,0,35},
+ {1,3,36,3,3,2,
+ 8,1,1,13},
+ {1,3,132,0,36},
+ {1,3,132,0,37},
+ {1,3,36,3,3,2,
+ 8,1,1,11},
+ {1,3,132,0,34},
+ {1,3,132,0,16},
+ {1,3,132,0,17},
+ {1,3,36,3,3,2,
+ 8,1,1,7},
+ {1,3,132,0,10},
+ {1,2,840,
+ 10045,3,1,7},
+ {1,3,132,0,3},
+ {1,3,132,0,26},
+ {1,3,132,0,27},
+ {1,3,132,0,32},
+ {1,3,132,0,33},
+ {1,3,132,0,24},
+ {1,3,132,0,25},
+ {1,3,132,0,31},
+ {1,2,840,
+ 10045,3,1,1},
+ {1,3,132,0,1},
+ {1,3,132,0,2},
+ {1,3,132,0,15},
+ {1,3,132,0,9},
+ {1,3,132,0,8},
+ {1,3,132,0,
+ 30}]},
+ next_protocol_negotiation =>
+ undefined,
+ renegotiation_info =>
+ {renegotiation_info,
+ undefined},
+ signature_algs =>
+ {hash_sign_algos,
+ [{sha512,ecdsa},
+ {sha512,rsa},
+ {sha384,ecdsa},
+ {sha384,rsa},
+ {sha256,ecdsa},
+ {sha256,rsa},
+ {sha224,ecdsa},
+ {sha224,rsa},
+ {sha,ecdsa},
+ {sha,rsa},
+ {sha,dsa}]},
+ sni =>
+ {sni,
+ "localhost"},
+ srp =>
+ undefined},
+
+ #client_hello{client_version = {3,3},
+ random = Random,
+ session_id = crypto:strong_rand_bytes(32),
+ cipher_suites = CipherSuites,
+ compression_methods = [0],
+ extensions = Extensions
+ }.
+
+connection_states(Random) ->
+ #{current_write =>
+ #{beast_mitigation => one_n_minus_one,cipher_state => undefined,
+ client_verify_data => undefined,compression_state => undefined,
+ mac_secret => undefined,secure_renegotiation => undefined,
+ security_parameters =>
+ #security_parameters{
+ cipher_suite = <<0,0>>,
+ connection_end = 1,
+ bulk_cipher_algorithm = 0,
+ cipher_type = 0,
+ iv_size = 0,
+ key_size = 0,
+ key_material_length = 0,
+ expanded_key_material_length = 0,
+ mac_algorithm = 0,
+ prf_algorithm = 0,
+ hash_size = 0,
+ compression_algorithm = 0,
+ master_secret = undefined,
+ resumption_master_secret = undefined,
+ client_random = Random,
+ server_random = undefined,
+ exportable = undefined},
+ sequence_number => 0,server_verify_data => undefined}}.
diff --git a/lib/ssl/test/ssl_session_ticket_SUITE.erl b/lib/ssl/test/ssl_session_ticket_SUITE.erl
index 96b0fb5c2a..3d41b59223 100644
--- a/lib/ssl/test/ssl_session_ticket_SUITE.erl
+++ b/lib/ssl/test/ssl_session_ticket_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2007-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2007-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -18,11 +18,27 @@
%% %CopyrightEnd%
%%
-%%
-module(ssl_session_ticket_SUITE).
-%% Note: This directive should only be used in test suites.
--compile(export_all).
+%% Callback functions
+-export([all/0,
+ groups/0,
+ init_per_suite/1,
+ end_per_suite/1,
+ init_per_group/2,
+ end_per_group/2,
+ init_per_testcase/2,
+ end_per_testcase/2]).
+
+%% Testcases
+-export([basic/0,
+ basic/1,
+ hello_retry_request/0,
+ hello_retry_request/1,
+ multiple_tickets/0,
+ multiple_tickets/1,
+ multiple_tickets_2hash/0,
+ multiple_tickets_2hash/1]).
-include("tls_handshake.hrl").
@@ -40,21 +56,15 @@ all() ->
].
groups() ->
- [{'tlsv1.3', [], [{group, stateful}, {group, stateless}, {group, openssl_server}]},
- {openssl_server, [], [erlang_client_openssl_server_basic,
- erlang_client_openssl_server_hrr,
- erlang_client_openssl_server_hrr_multiple_tickets
- ]},
+ [{'tlsv1.3', [], [{group, stateful}, {group, stateless}]},
{stateful, [], session_tests()},
{stateless, [], session_tests()}].
session_tests() ->
- [erlang_client_erlang_server_basic,
- openssl_client_erlang_server_basic,
- erlang_client_erlang_server_hrr,
- openssl_client_erlang_server_hrr,
- erlang_client_erlang_server_multiple_tickets,
- erlang_client_erlang_server_multiple_tickets_2hash].
+ [basic,
+ hello_retry_request,
+ multiple_tickets,
+ multiple_tickets_2hash].
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -75,27 +85,10 @@ init_per_group(stateful, Config) ->
init_per_group(stateless, Config) ->
[{server_ticket_mode, stateless} | proplists:delete(server_ticket_mode, Config)];
init_per_group(GroupName, Config) ->
- ssl_test_lib:clean_tls_version(Config),
- case ssl_test_lib:is_tls_version(GroupName) andalso ssl_test_lib:sufficient_crypto_support(GroupName) of
- true ->
- ssl_test_lib:init_tls_version(GroupName, Config);
- _ ->
- case ssl_test_lib:sufficient_crypto_support(GroupName) of
- true ->
- ssl:start(),
- Config;
- false ->
- {skip, "Missing crypto support"}
- end
- end.
+ ssl_test_lib:init_per_group(GroupName, Config).
end_per_group(GroupName, Config) ->
- case ssl_test_lib:is_tls_version(GroupName) of
- true ->
- ssl_test_lib:clean_tls_version(Config);
- false ->
- Config
- end.
+ ssl_test_lib:end_per_group(GroupName, Config).
init_per_testcase(_, Config) ->
ssl:stop(),
@@ -111,10 +104,9 @@ end_per_testcase(_TestCase, Config) ->
%% Test Cases --------------------------------------------------------
%%--------------------------------------------------------------------
-
-erlang_client_erlang_server_basic() ->
+basic() ->
[{doc,"Test session resumption with session tickets (erlang client - erlang server)"}].
-erlang_client_erlang_server_basic(Config) when is_list(Config) ->
+basic(Config) when is_list(Config) ->
ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -166,127 +158,9 @@ erlang_client_erlang_server_basic(Config) when is_list(Config) ->
ssl_test_lib:close(Server0),
ssl_test_lib:close(Client1).
-
-erlang_client_openssl_server_basic() ->
- [{doc,"Test session resumption with session tickets (erlang client - openssl server)"}].
-erlang_client_openssl_server_basic(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Version = 'tlsv1.3',
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- CACertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
-
- %% Configure session tickets
- ClientOpts = [{session_tickets, auto}, {log_level, debug},
- {versions, ['tlsv1.2','tlsv1.3']}|ClientOpts0],
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile,"-key", KeyFile, "-CAfile", CACertFile, "-msg", "-debug"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- %% Store ticket from first connection
- Client0 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [false, no_reply]}},
- {from, self()}, {options, ClientOpts}]),
- %% Wait for session ticket
- ct:sleep(100),
-
- %% Close previous connection as s_server can only handle one at a time
- ssl_test_lib:close(Client0),
-
- %% Use ticket
- Client1 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [true, no_reply]}},
- {from, self()},
- {options, ClientOpts}]),
- process_flag(trap_exit, false),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client1).
-
-
-openssl_client_erlang_server_basic() ->
- [{doc,"Test session resumption with session tickets (openssl client - erlang server)"}].
-openssl_client_erlang_server_basic(Config) when is_list(Config) ->
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TicketFile0 = filename:join([proplists:get_value(priv_dir, Config), "session_ticket0"]),
- TicketFile1 = filename:join([proplists:get_value(priv_dir, Config), "session_ticket1"]),
- ServerTicketMode = proplists:get_value(server_ticket_mode, Config),
-
- Data = "Hello world",
-
- %% Configure session tickets
- ServerOpts = [{session_tickets, ServerTicketMode}, {log_level, debug},
- {versions, ['tlsv1.2','tlsv1.3']}|ServerOpts0],
-
- Server0 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [false]}},
- {options, ServerOpts}]),
-
- Version = 'tlsv1.3',
- Port0 = ssl_test_lib:inet_port(Server0),
-
- Exe = "openssl",
- Args0 = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
- ++ ":" ++ integer_to_list(Port0),
- ssl_test_lib:version_flag(Version),
- "-sess_out", TicketFile0],
-
- OpenSslPort0 = ssl_test_lib:portable_open_port(Exe, Args0),
-
- true = port_command(OpenSslPort0, Data),
-
- ssl_test_lib:check_result(Server0, ok),
-
- Server0 ! {listen, {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [true]}}},
-
- %% Wait for session ticket
- ct:sleep(100),
-
- Args1 = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
- ++ ":" ++ integer_to_list(Port0),
- ssl_test_lib:version_flag(Version),
- "-sess_in", TicketFile0,
- "-sess_out", TicketFile1],
-
- OpenSslPort1 = ssl_test_lib:portable_open_port(Exe, Args1),
-
- true = port_command(OpenSslPort1, Data),
-
- ssl_test_lib:check_result(Server0, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server0),
- ssl_test_lib:close_port(OpenSslPort0),
- ssl_test_lib:close_port(OpenSslPort1).
-
-
-erlang_client_erlang_server_hrr() ->
+hello_retry_request() ->
[{doc,"Test session resumption with session tickets and hello_retry_request (erlang client - erlang server)"}].
-erlang_client_erlang_server_hrr(Config) when is_list(Config) ->
+hello_retry_request(Config) when is_list(Config) ->
ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -340,135 +214,9 @@ erlang_client_erlang_server_hrr(Config) when is_list(Config) ->
ssl_test_lib:close(Server0),
ssl_test_lib:close(Client1).
-
-erlang_client_openssl_server_hrr() ->
- [{doc,"Test session resumption with session tickets and hello_retry_request (erlang client - openssl server)"}].
-erlang_client_openssl_server_hrr(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Version = 'tlsv1.3',
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- CACertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
-
- %% Configure session tickets
- ClientOpts = [{session_tickets, auto}, {log_level, debug},
- {versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups,[secp256r1, x25519]}|ClientOpts0],
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile,
- "-key", KeyFile,
- "-CAfile", CACertFile,
- "-groups", "X448:X25519",
- "-msg", "-debug"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- %% Store ticket from first connection
- Client0 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [false, no_reply]}},
- {from, self()}, {options, ClientOpts}]),
- %% Wait for session ticket
- ct:sleep(100),
-
- %% Close previous connection as s_server can only handle one at a time
- ssl_test_lib:close(Client0),
-
- %% Use ticket
- Client1 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [true, no_reply]}},
- {from, self()},
- {options, ClientOpts}]),
- process_flag(trap_exit, false),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client1).
-
-
-openssl_client_erlang_server_hrr() ->
- [{doc,"Test session resumption with session tickets and hello_retry_request (openssl client - erlang server)"}].
-openssl_client_erlang_server_hrr(Config) when is_list(Config) ->
- ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
- TicketFile0 = filename:join([proplists:get_value(priv_dir, Config), "session_ticket0"]),
- TicketFile1 = filename:join([proplists:get_value(priv_dir, Config), "session_ticket1"]),
- ServerTicketMode = proplists:get_value(server_ticket_mode, Config),
-
- Data = "Hello world",
-
- %% Configure session tickets
- ServerOpts = [{session_tickets, ServerTicketMode}, {log_level, debug},
- {versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups,[x448, x25519]}|ServerOpts0],
-
- Server0 =
- ssl_test_lib:start_server([{node, ServerNode}, {port, 0},
- {from, self()},
- {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [false]}},
- {options, ServerOpts}]),
-
- Version = 'tlsv1.3',
- Port0 = ssl_test_lib:inet_port(Server0),
-
- Exe = "openssl",
- Args0 = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
- ++ ":" ++ integer_to_list(Port0),
- ssl_test_lib:version_flag(Version),
- "-groups", "P-256:X25519",
- "-sess_out", TicketFile0],
-
- OpenSslPort0 = ssl_test_lib:portable_open_port(Exe, Args0),
-
- true = port_command(OpenSslPort0, Data),
-
- ssl_test_lib:check_result(Server0, ok),
-
- Server0 ! {listen, {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [true]}}},
-
- %% Wait for session ticket
- ct:sleep(100),
-
- Args1 = ["s_client", "-connect", ssl_test_lib:hostname_format(Hostname)
- ++ ":" ++ integer_to_list(Port0),
- ssl_test_lib:version_flag(Version),
- "-groups", "P-256:X25519",
- "-sess_in", TicketFile0,
- "-sess_out", TicketFile1],
-
- OpenSslPort1 = ssl_test_lib:portable_open_port(Exe, Args1),
-
- true = port_command(OpenSslPort1, Data),
-
- ssl_test_lib:check_result(Server0, ok),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close(Server0),
- ssl_test_lib:close_port(OpenSslPort0),
- ssl_test_lib:close_port(OpenSslPort1).
-
-
-erlang_client_erlang_server_multiple_tickets() ->
+multiple_tickets() ->
[{doc,"Test session resumption with multiple session tickets (erlang client - erlang server)"}].
-erlang_client_erlang_server_multiple_tickets(Config) when is_list(Config) ->
+multiple_tickets(Config) when is_list(Config) ->
ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
@@ -524,72 +272,9 @@ erlang_client_erlang_server_multiple_tickets(Config) when is_list(Config) ->
ssl_test_lib:close(Server0),
ssl_test_lib:close(Client1).
-
-erlang_client_openssl_server_hrr_multiple_tickets() ->
- [{doc,"Test session resumption with multiple session tickets and hello_retry_request (erlang client - openssl server)"}].
-erlang_client_openssl_server_hrr_multiple_tickets(Config) when is_list(Config) ->
- process_flag(trap_exit, true),
- ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
- ServerOpts = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
- {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
-
- Version = 'tlsv1.3',
- Port = ssl_test_lib:inet_port(node()),
- CertFile = proplists:get_value(certfile, ServerOpts),
- CACertFile = proplists:get_value(cacertfile, ServerOpts),
- KeyFile = proplists:get_value(keyfile, ServerOpts),
-
- %% Configure session tickets
- ClientOpts = [{session_tickets, manual}, {log_level, debug},
- {versions, ['tlsv1.2','tlsv1.3']},
- {supported_groups,[secp256r1, x25519]}|ClientOpts0],
-
- Exe = "openssl",
- Args = ["s_server", "-accept", integer_to_list(Port), ssl_test_lib:version_flag(Version),
- "-cert", CertFile,
- "-key", KeyFile,
- "-CAfile", CACertFile,
- "-groups", "X448:X25519",
- "-msg", "-debug"],
-
- OpensslPort = ssl_test_lib:portable_open_port(Exe, Args),
-
- ssl_test_lib:wait_for_openssl_server(Port, proplists:get_value(protocol, Config)),
-
- %% Store ticket from first connection
- Client0 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [false, no_reply, {tickets, 2}]}},
- {from, self()}, {options, ClientOpts}]),
-
- Tickets0 = ssl_test_lib:check_tickets(Client0),
-
- ct:pal("Received tickets: ~p~n", [Tickets0]),
-
- %% Close previous connection as s_server can only handle one at a time
- ssl_test_lib:close(Client0),
-
- %% Use tickets
- Client1 = ssl_test_lib:start_client([{node, ClientNode},
- {port, Port}, {host, Hostname},
- {mfa, {ssl_test_lib,
- verify_active_session_resumption,
- [true, no_reply, no_tickets]}},
- {from, self()},
- {options, [{use_ticket, Tickets0}|ClientOpts]}]),
-
- process_flag(trap_exit, false),
-
- %% Clean close down! Server needs to be closed first !!
- ssl_test_lib:close_port(OpensslPort),
- ssl_test_lib:close(Client1).
-
-
-erlang_client_erlang_server_multiple_tickets_2hash() ->
+multiple_tickets_2hash() ->
[{doc,"Test session resumption with multiple session tickets with 2 different hash algorithms (erlang client - erlang server)"}].
-erlang_client_erlang_server_multiple_tickets_2hash(Config) when is_list(Config) ->
+multiple_tickets_2hash(Config) when is_list(Config) ->
ClientOpts0 = ssl_test_lib:ssl_options(client_rsa_verify_opts, Config),
ServerOpts0 = ssl_test_lib:ssl_options(server_rsa_verify_opts, Config),
{ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
diff --git a/lib/ssl/test/ssl_sni_SUITE.erl b/lib/ssl/test/ssl_sni_SUITE.erl
index e68ea2c99d..e58a4642fb 100644
--- a/lib/ssl/test/ssl_sni_SUITE.erl
+++ b/lib/ssl/test/ssl_sni_SUITE.erl
@@ -60,7 +60,9 @@ sni_tests() ->
ip_fallback,
no_ip_fallback,
dns_name_reuse,
- customize_hostname_check].
+ customize_hostname_check,
+ sni_no_trailing_dot,
+ hostname_trailing_dot].
init_per_suite(Config0) ->
catch crypto:stop(),
@@ -288,6 +290,58 @@ customize_hostname_check(Config) when is_list(Config) ->
]),
ssl_test_lib:check_client_alert(Server, Client1, handshake_failure).
+sni_no_trailing_dot() ->
+ [{doc,"Test that sni may not include a triling dot"}].
+sni_no_trailing_dot(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_cert_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_cert_opts, Config),
+
+ {ClientNode, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+
+ Server = ssl_test_lib:start_server_error([{node, ServerNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{log_level, debug} | ServerOpts]}]),
+
+ Port = ssl_test_lib:inet_port(Server),
+
+ Client = ssl_test_lib:start_client_error([{node, ClientNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, no_result, []}},
+ {options, [{log_level, debug},
+ {server_name_indication, Hostname ++ "."} |ClientOpts]}]),
+ ssl_test_lib:check_server_alert(Server, Client, unrecognized_name).
+
+hostname_trailing_dot() ->
+ [{doc,"Test that fallback sni removes trailing dot of hostname"}].
+
+hostname_trailing_dot(Config) when is_list(Config) ->
+ ClientOpts = ssl_test_lib:ssl_options(client_rsa_opts, Config),
+ ServerOpts = ssl_test_lib:ssl_options(server_rsa_opts, Config),
+ {ClientNode, ServerNode, Hostname0} = ssl_test_lib:run_where(Config),
+
+ case trailing_dot_hostname(Hostname0) of
+ {ok, Hostname} ->
+ Server = ssl_test_lib:start_server([{node, ClientNode}, {port, 0},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ServerOpts}]),
+ Port = ssl_test_lib:inet_port(Server),
+ Client = ssl_test_lib:start_client([{node, ServerNode}, {port, Port},
+ {host, Hostname},
+ {from, self()},
+ {mfa, {ssl_test_lib, send_recv_result_active, []}},
+ {options, ClientOpts}]),
+
+ ssl_test_lib:check_result(Server, ok, Client, ok),
+
+ ssl_test_lib:close(Server),
+ ssl_test_lib:close(Client);
+ {skip, _ } = Skip ->
+ Skip
+ end.
+
%%--------------------------------------------------------------------
%% Internal Functions ------------------------------------------------
%%--------------------------------------------------------------------
@@ -426,3 +480,17 @@ host_name(undefined, Hostname) ->
Hostname;
host_name(Hostname, _) ->
Hostname.
+
+trailing_dot_hostname(HostName) ->
+ case lists:member($., HostName) of
+ true ->
+ case lists:last(HostName) =/= $. of
+ true ->
+ {ok, HostName ++ "."};
+ false ->
+ {ok, HostName}
+ end;
+ _ ->
+ {skip, "Trailing dot conf not possible"}
+ end.
+
diff --git a/lib/ssl/test/ssl_test_lib.erl b/lib/ssl/test/ssl_test_lib.erl
index b4b493fbe2..206c4c8b32 100644
--- a/lib/ssl/test/ssl_test_lib.erl
+++ b/lib/ssl/test/ssl_test_lib.erl
@@ -32,6 +32,92 @@
-define(SLEEP, 1000).
-define(DEFAULT_CURVE, secp256r1).
+%%====================================================================
+%% API
+%%====================================================================
+start_client(erlang, Options, Config) ->
+ start_client(Options, Config);
+start_client(openssl, Options, Config) ->
+ start_openssl_client(Options, Config);
+start_client(Type, _Args, _Config) ->
+ {error, unsupported_client_type, Type}.
+
+start_server(erlang, Options, Config) ->
+ start_server(Options, Config);
+start_server(openssl, Options, Config) ->
+ start_openssl_server(Options, Config);
+start_server(Type, _Args, _Config) ->
+ {error, unsupported_server_type, Type}.
+
+%% Test
+send_recv_result_active(Peer1, Peer2, Data) ->
+ ok = ssl_test_lib:send(Peer1, Data),
+ Data = ssl_test_lib:check_active_receive(Peer2, Data),
+ ok = ssl_test_lib:send(Peer2, Data),
+ Data = ssl_test_lib:check_active_receive(Peer1, Data).
+
+%% Certs
+init_ecdsa_certs(Config) ->
+ DefConf = ssl_test_lib:default_cert_chain_conf(),
+ CertChainConf = ssl_test_lib:gen_conf(ecdsa, ecdsa, DefConf, DefConf),
+ #{server_config := ServerOpts,
+ client_config := ClientOpts}
+ = public_key:pkix_test_data(CertChainConf),
+ [{tls_config, #{server_config => ServerOpts,
+ client_config => ClientOpts}} |
+ proplists:delete(tls_config, Config)].
+
+%% Options
+get_server_opts(Config) ->
+ SOpts = proplists:get_value(server_ecdsa_opts, Config),
+ ssl_test_lib:ssl_options(SOpts, Config).
+
+get_client_opts(Config) ->
+ COpts = proplists:get_value(client_ecdsa_opts, Config),
+ ssl_test_lib:ssl_options(COpts, Config).
+
+%% Default callback functions
+init_per_group(GroupName, Config) ->
+ clean_tls_version(Config),
+ case is_tls_version(GroupName) andalso sufficient_crypto_support(GroupName) of
+ true ->
+ init_tls_version(GroupName, Config);
+ _ ->
+ case sufficient_crypto_support(GroupName) of
+ true ->
+ ssl:start(),
+ Config;
+ false ->
+ {skip, "Missing crypto support"}
+ end
+ end.
+
+init_per_group_openssl(GroupName, Config) ->
+ case is_tls_version(GroupName) of
+ true ->
+ case check_sane_openssl_version(GroupName) of
+ true ->
+ [{version, GroupName}|init_tls_version(GroupName, Config)];
+ false ->
+ {skip, "Missing openssl support"}
+ end;
+ _ ->
+ ssl:start(),
+ Config
+ end.
+
+end_per_group(GroupName, Config) ->
+ case is_tls_version(GroupName) of
+ true ->
+ clean_tls_version(Config);
+ false ->
+ Config
+ end.
+
+%%====================================================================
+%% Internal functions
+%%====================================================================
+
%% For now always run locally
run_where(_) ->
ClientNode = node(),
@@ -59,6 +145,18 @@ normalize_loopback({127,_,_,_}, client) ->
normalize_loopback(Address, _) ->
Address.
+
+start_server(Args0, Config) ->
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ ServerOpts = ssl_test_lib:get_server_opts(Config),
+ Node = proplists:get_value(node, Args0, ServerNode),
+ Port = proplists:get_value(port, Args0, 0),
+ Args = [{from, self()},
+ {node, Node},
+ {port, Port},
+ {options, ServerOpts} | Args0],
+ start_server(Args).
+%%
start_server(Args) ->
Node = proplists:get_value(node, Args),
Result = spawn_link(Node, ?MODULE, run_server, [Args]),
@@ -108,17 +206,59 @@ do_run_server(_, ok = Result, Opts) ->
do_run_server(ListenSocket, AcceptSocket, Opts) ->
Pid = proplists:get_value(from, Opts),
Transport = proplists:get_value(transport, Opts, ssl),
- {Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:log("~p:~p~nServer: apply(~p,~p,~p)~n",
- [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
- case apply(Module, Function, [AcceptSocket | Args]) of
+ MFA = proplists:get_value(mfa, Opts),
+ case server_apply_mfa(AcceptSocket, MFA) of
no_result_msg ->
ok;
Msg ->
ct:log("~p:~p~nServer Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg}
end,
+ do_run_server_core(ListenSocket, AcceptSocket, Opts, Transport, Pid).
+
+server_apply_mfa(_, undefined) ->
+ no_result_msg;
+server_apply_mfa(AcceptSocket, {Module, Function, Args}) ->
+ ct:log("~p:~p~nServer: apply(~p,~p,~p)~n",
+ [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
+ apply(Module, Function, [AcceptSocket | Args]).
+
+client_apply_mfa(_, undefined) ->
+ no_result_msg;
+client_apply_mfa(AcceptSocket, {Module, Function, Args}) ->
+ ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
+ [?MODULE,?LINE, Module, Function, [AcceptSocket | Args]]),
+ apply(Module, Function, [AcceptSocket | Args]).
+
+
+do_run_server_core(ListenSocket, AcceptSocket, Opts, Transport, Pid) ->
receive
+ {data, Data} ->
+ ct:log("[server] Send: ~p~n", [Data]),
+ case Transport:send(AcceptSocket, Data) of
+ ok ->
+ Pid ! {self(), ok};
+ {error, Reason} ->
+ Pid ! {self(), Reason}
+ end,
+ do_run_server_core(ListenSocket, AcceptSocket, Opts, Transport, Pid);
+ {active_receive, Data} ->
+ case active_recv(AcceptSocket, length(Data)) of
+ ReceivedData ->
+ ct:log("[server] Received: ~p~n", [Data]),
+ Pid ! {self(), ReceivedData}
+ end,
+ do_run_server_core(ListenSocket, AcceptSocket, Opts, Transport, Pid);
+ {update_keys, Type} ->
+ case ssl:update_keys(AcceptSocket, Type) of
+ ok ->
+ ct:log("[server] Update keys: ~p", [Type]),
+ Pid ! {self(), ok};
+ {error, Reason} ->
+ ct:log("[server] Update keys failed: ~p", [Type]),
+ Pid ! {self(), Reason}
+ end,
+ do_run_server_core(ListenSocket, AcceptSocket, Opts, Transport, Pid);
listen ->
run_server(ListenSocket, Opts);
{listen, MFA} ->
@@ -337,7 +477,233 @@ remove_close_msg(ReconnectTimes) ->
{ssl_closed, _} ->
remove_close_msg(ReconnectTimes -1)
end.
-
+
+
+start_openssl_server(Args0, Config) ->
+ {_, ServerNode, _} = ssl_test_lib:run_where(Config),
+ ServerOpts = ssl_test_lib:get_server_opts(Config),
+ Node = proplists:get_value(node, Args0, ServerNode),
+ Port = proplists:get_value(port, Args0, 0),
+ Args = [{from, self()}, {port, Port}] ++ ServerOpts ++ Args0,
+ Result = spawn_link(Node, ?MODULE, init_openssl_server, [lists:delete(return_socket, Args)]),
+ receive
+ {started, Socket} ->
+ case lists:member(return_socket, Args) of
+ true -> {Result, Socket};
+ false -> Result
+ end;
+ {start_failed, Reason} ->
+ {start_failed, Reason}
+ end.
+
+init_openssl_server(Options) ->
+ {ok, Version} = application:get_env(ssl,protocol_version),
+ %% Port = proplists:get_value(port, Options),
+ Port = inet_port(node()),
+ Pid = proplists:get_value(from, Options),
+
+ Exe = "openssl",
+ Ciphers = proplists:get_value(ciphers, Options, ssl:cipher_suites(default,Version)),
+ Groups0 = proplists:get_value(groups, Options),
+ CertArgs = openssl_cert_options(Options, server),
+ Exe = "openssl",
+
+ Args = case Groups0 of
+ undefined ->
+ ["s_server", "-accept", integer_to_list(Port), cipher_flag(Version),
+ ciphers(Ciphers, Version),
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"];
+ Group ->
+ ["s_server", "-accept", integer_to_list(Port), cipher_flag(Version),
+ ciphers(Ciphers, Version), "-groups", Group,
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"]
+ end,
+ SslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ Pid ! {started, Port},
+ Pid ! {self(), {port, Port}},
+ case openssl_server_started(SslPort) of
+ true ->
+ openssl_server_loop(Pid, SslPort, Args);
+ false ->
+ {error, openssl_server}
+ end.
+
+openssl_server_started(_Port) ->
+ receive
+ {Port, {data, Data}} ->
+ ct:log("~p:~p~n Openssl~n ~s~n",[?MODULE,?LINE, Data]),
+ verify_openssl_server_started(Port, Data)
+ after
+ 5000 ->
+ false
+ end.
+
+openssl_server_loop(Pid, SslPort, Args) ->
+ receive
+ {data, Data} ->
+ case port_command(SslPort, Data, [nosuspend]) of
+ true ->
+ ct:log("[openssl server] Send data: ~p~n", [Data]),
+ Pid ! {self(), ok};
+ _Else ->
+ ct:log("[openssl server] Send failed, data: ~p~n", [Data]),
+ Pid ! {self(), {error, port_command_failed}}
+ end,
+ openssl_server_loop(Pid, SslPort, Args);
+ {active_receive, Data} ->
+ case active_recv(SslPort, length(Data)) of
+ ReceivedData ->
+ ct:log("[openssl server] Received: ~p~n", [Data]),
+ Pid ! {self(), ReceivedData}
+ end,
+ openssl_server_loop(Pid, SslPort, Args);
+ {update_keys, Type} ->
+ case Type of
+ write ->
+ ct:log("[openssl server] Update keys: ~p", [Type]),
+ true = port_command(SslPort, "k", [nosuspend]),
+ Pid ! {self(), ok};
+ read_write ->
+ ct:log("[openssl server] Update keys: ~p", [Type]),
+ true = port_command(SslPort, "K", [nosuspend]),
+ Pid ! {self(), ok}
+ end,
+ openssl_server_loop(Pid, SslPort, Args);
+ close ->
+ ct:log("~p:~p~n[openssl server] Server closing~n", [?MODULE,?LINE]),
+ port_close(SslPort);
+ {ssl_closed, _Socket} ->
+ %% TODO
+ ok
+ end.
+
+start_openssl_client(Args0, Config) ->
+ {ClientNode, _, Hostname} = ssl_test_lib:run_where(Config),
+ ClientOpts = ssl_test_lib:get_client_opts(Config),
+ Node = proplists:get_value(node, Args0, ClientNode),
+ Args = [{from, self()},
+ {host, Hostname},
+ {options, ClientOpts} | Args0],
+
+ Result = spawn_link(Node, ?MODULE, init_openssl_client, [lists:delete(return_socket, Args)]),
+ receive
+ {connected, Socket} ->
+ case lists:member(return_socket, Args) of
+ true -> {Result, Socket};
+ false -> Result
+ end;
+ {connect_failed, Reason} ->
+ {connect_failed, Reason}
+ end.
+
+init_openssl_client(Options) ->
+ {ok, Version} = application:get_env(ssl,protocol_version),
+ Port = proplists:get_value(port, Options),
+ Pid = proplists:get_value(from, Options),
+
+ Exe = "openssl",
+ Ciphers = proplists:get_value(ciphers, Options, ssl:cipher_suites(default,Version)),
+ Groups0 = proplists:get_value(groups, Options),
+ CertArgs = openssl_cert_options(Options, client),
+ Exe = "openssl",
+ Args0 = case Groups0 of
+ undefined ->
+ ["s_client", "-verify", "2", "-port", integer_to_list(Port), cipher_flag(Version),
+ ciphers(Ciphers, Version),
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"];
+ Group ->
+ ["s_client", "-verify", "2", "-port", integer_to_list(Port), cipher_flag(Version),
+ ciphers(Ciphers, Version), "-groups", Group,
+ ssl_test_lib:version_flag(Version)] ++ CertArgs ++ ["-msg", "-debug"]
+ end,
+ Args = maybe_force_ipv4(Args0),
+ SslPort = ssl_test_lib:portable_open_port(Exe, Args),
+ case openssl_client_started(SslPort) of
+ true ->
+ openssl_client_loop(Pid, SslPort, Args);
+ false ->
+ {error, openssl_client}
+ end.
+
+openssl_client_started(Port) ->
+ receive
+ {Port, {data, Data}} ->
+ ct:log("~p:~p~n Openssl~n ~s~n",[?MODULE,?LINE, Data]),
+ verify_openssl_client_started(Port, Data)
+ after
+ 5000 ->
+ false
+ end.
+
+verify_openssl_server_started(Port, Data) ->
+ case re:run(Data, ".*CIPHER is.*") of
+ nomatch ->
+ openssl_server_started(Port);
+ {match, _} ->
+ true
+ end.
+
+verify_openssl_client_started(Port, Data) ->
+ case re:run(Data, ".*New, TLSv\\d[.]\\d, Cipher is.*") of
+ nomatch ->
+ openssl_client_started(Port);
+ {match, _} ->
+ true
+ end.
+
+openssl_client_loop(Pid, SslPort, Args) ->
+ Pid ! {connected, SslPort},
+ openssl_client_loop_core(Pid, SslPort, Args).
+
+openssl_client_loop_core(Pid, SslPort, Args) ->
+ receive
+ {data, Data} ->
+ case port_command(SslPort, Data, [nosuspend]) of
+ true ->
+ ct:log("[openssl client] Send data: ~p~n", [Data]),
+ Pid ! {self(), ok};
+ _Else ->
+ ct:log("[openssl client] Send failed, data: ~p~n", [Data]),
+ Pid ! {self(), {error, port_command_failed}}
+ end,
+ openssl_client_loop_core(Pid, SslPort, Args);
+ {active_receive, Data} ->
+ case active_recv(SslPort, length(Data)) of
+ ReceivedData ->
+ ct:log("[openssl client] Received: ~p~n", [Data]),
+ Pid ! {self(), ReceivedData}
+ end,
+ openssl_client_loop_core(Pid, SslPort, Args);
+ {update_keys, Type} ->
+ case Type of
+ write ->
+ ct:log("[openssl client] Update keys: ~p", [Type]),
+ true = port_command(SslPort, "k", [nosuspend]),
+ Pid ! {self(), ok};
+ read_write ->
+ ct:log("[openssl client] Update keys: ~p", [Type]),
+ true = port_command(SslPort, "K", [nosuspend]),
+ Pid ! {self(), ok}
+ end,
+ openssl_client_loop_core(Pid, SslPort, Args);
+ close ->
+ ct:log("~p:~p~nClient closing~n", [?MODULE,?LINE]),
+ port_close(SslPort);
+ {ssl_closed, _Socket} ->
+ %% TODO
+ ok
+ end.
+
+start_client(Args0, Config) ->
+ {_, ServerNode, Hostname} = ssl_test_lib:run_where(Config),
+ ServerOpts = ssl_test_lib:get_server_opts(Config),
+ Node = proplists:get_value(node, Args0, ServerNode),
+ Args = [{from, self()},
+ {host, Hostname},
+ {node, Node},
+ {options, ServerOpts} | Args0],
+ start_client(Args).
+%%
start_client(Args) ->
Node = proplists:get_value(node, Args),
Result = spawn_link(Node, ?MODULE, run_client_init, [lists:delete(return_socket, Args)]),
@@ -380,25 +746,15 @@ client_loop(_Node, Host, Port, Pid, Transport, Options, Opts) ->
%% In special cases we want to know the client port, it will
%% be indicated by sending {port, 0} in options list!
send_selected_port(Pid, proplists:get_value(port, Options), Socket),
- {Module, Function, Args} = proplists:get_value(mfa, Opts),
- ct:log("~p:~p~nClient: apply(~p,~p,~p)~n",
- [?MODULE,?LINE, Module, Function, [Socket | Args]]),
- case apply(Module, Function, [Socket | Args]) of
+ MFA = proplists:get_value(mfa, Opts),
+ case client_apply_mfa(Socket, MFA) of
no_result_msg ->
ok;
Msg ->
ct:log("~p:~p~nClient Msg: ~p ~n", [?MODULE,?LINE, Msg]),
Pid ! {self(), Msg}
end,
- receive
- close ->
- ct:log("~p:~p~nClient closing~n", [?MODULE,?LINE]),
- Transport:close(Socket);
- {ssl_closed, Socket} ->
- ok;
- {gen_tcp, closed} ->
- ok
- end;
+ client_loop_core(Socket, Pid, Transport);
{error, econnrefused = Reason} ->
case get(retries) of
N when N < 5 ->
@@ -426,6 +782,43 @@ client_loop(_Node, Host, Port, Pid, Transport, Options, Opts) ->
Pid ! {connect_failed, Reason}
end.
+client_loop_core(Socket, Pid, Transport) ->
+ receive
+ {data, Data} ->
+ ct:log("[client] Send: ~p~n", [Data]),
+ case Transport:send(Socket, Data) of
+ ok ->
+ Pid ! {self(), ok};
+ {error, Reason} ->
+ Pid ! {self(), Reason}
+ end,
+ client_loop_core(Socket, Pid, Transport);
+ {active_receive, Data} ->
+ case active_recv(Socket, length(Data)) of
+ ReceivedData ->
+ ct:log("[client] Received: ~p~n", [Data]),
+ Pid ! {self(), ReceivedData}
+ end,
+ client_loop_core(Socket, Pid, Transport);
+ {update_keys, Type} ->
+ case ssl:update_keys(Socket, Type) of
+ ok ->
+ ct:log("[client] Update keys: ~p", [Type]),
+ Pid ! {self(), ok};
+ {error, Reason} ->
+ ct:log("[client] Update keys failed: ~p", [Type]),
+ Pid ! {self(), Reason}
+ end,
+ client_loop_core(Socket, Pid, Transport);
+ close ->
+ ct:log("~p:~p~nClient closing~n", [?MODULE,?LINE]),
+ Transport:close(Socket);
+ {ssl_closed, Socket} ->
+ ok;
+ {gen_tcp, closed} ->
+ ok
+ end.
+
client_cont_loop(_Node, Host, Port, Pid, Transport, Options, cancel, _Opts) ->
case Transport:connect(Host, Port, Options) of
{ok, Socket, _} ->
@@ -1622,7 +2015,7 @@ common_ciphers(crypto) ->
ssl:cipher_suites();
common_ciphers(openssl) ->
OpenSslSuites =
- string:tokens(string:strip(os:cmd("openssl ciphers"), right, $\n), ":"),
+ string:tokens(string:strip(portable_cmd("openssl", ["ciphers"]), right, $\n), ":"),
[ssl_cipher_format:suite_bin_to_map(S)
|| S <- ssl_cipher:suites(tls_record:highest_protocol_version([])),
lists:member(ssl_cipher_format:suite_map_to_openssl_str(ssl_cipher_format:suite_bin_to_map(S)), OpenSslSuites)
@@ -1686,7 +2079,7 @@ openssl_ecdh_rsa_suites() ->
end, Ciphers).
openssl_filter(FilterStr) ->
- Ciphers = string:tokens(os:cmd("openssl ciphers"), ":"),
+ Ciphers = string:tokens(portable_cmd("openssl", ["ciphers"]), ":"),
lists:filter(fun(Str) -> string_regex_filter(Str, FilterStr)
end, Ciphers).
@@ -1952,6 +2345,37 @@ send_recv_result_active(Socket) ->
Data = active_recv(Socket, length(Data)),
ok.
+send_recv_result_active(Socket, Data) ->
+ ssl:send(Socket, Data),
+ Data = active_recv(Socket, length(Data)),
+ ok.
+
+send(Pid, Data) ->
+ Pid ! {data, Data},
+ receive
+ {Pid, ok} ->
+ ok;
+ {Pid, Reason} ->
+ {error, Reason}
+ end.
+
+check_active_receive(Pid, Data) ->
+ Pid ! {active_receive, Data},
+ receive
+ {Pid, Data} ->
+ %% ct:log("Received: ~p~n", [Data]),
+ Data
+ end.
+
+update_keys(Pid, Type) ->
+ Pid ! {update_keys, Type},
+ receive
+ {Pid, ok} ->
+ ok;
+ {Pid, Reason} ->
+ {error, Reason}
+ end.
+
send_recv_result_active_once(Socket) ->
Data = "Hello world",
ssl:send(Socket, Data),
@@ -1973,7 +2397,10 @@ verify_active_session_resumption(Socket, SessionResumption, WaitForReply, Ticket
Expected = boolean_to_log_msg(SessionResumption),
Got = boolean_to_log_msg(Got0),
ct:fail("~p:~p~nFailed to verify session resumption! (expected ~p, got ~p)",
- [?MODULE, ?LINE, Expected, Got])
+ [?MODULE, ?LINE, Expected, Got]);
+ {error, Reason} ->
+ ct:fail("~p:~p~nFailed to verify session resumption! Reason: ~p",
+ [?MODULE, ?LINE, Reason])
end,
Data = "Hello world",
@@ -2025,12 +2452,23 @@ active_recv(Socket, N) ->
active_recv(_Socket, 0, Acc) ->
Acc;
+active_recv(_Socket, N, Acc) when N < 0 ->
+ {_, T} = lists:split(0 - N, Acc),
+ T;
active_recv(Socket, N, Acc) ->
receive
{ssl, Socket, Bytes} ->
+ active_recv(Socket, N-length(Bytes), Acc ++ Bytes);
+ {Socket, {data, Bytes0}} ->
+ Bytes = filter_openssl_debug_data(Bytes0),
active_recv(Socket, N-length(Bytes), Acc ++ Bytes)
end.
+filter_openssl_debug_data(Bytes) ->
+ re:replace(Bytes,
+ "(read.*\n|write to.*\n|[\\dabcdefABCDEF]{4,4} -.*\n|>>> .*\n|<<< .*\n| \\d\\d.*\n|KEYUPDATE\n|.*Read BLOCK\n)*",
+ "", [{return, list}]).
+
active_once_recv(_Socket, 0) ->
ok;
active_once_recv(Socket, N) ->
@@ -2071,7 +2509,7 @@ active_once_disregard(Socket, N) ->
end.
is_ipv6_supported() ->
- case os:cmd("openssl version") of
+ case portable_cmd("openssl", ["version"]) of
"OpenSSL 0.9.8" ++ _ -> % Does not support IPv6
false;
"OpenSSL 1.0" ++ _ -> % Does not support IPv6
@@ -2081,7 +2519,7 @@ is_ipv6_supported() ->
end.
is_sane_ecc(openssl) ->
- case os:cmd("openssl version") of
+ case portable_cmd("openssl", ["version"]) of
"OpenSSL 1.0.0a" ++ _ -> % Known bug in openssl
%% manifests as SSL_CHECK_SERVERHELLO_TLSEXT:tls invalid ecpointformat list
false;
@@ -2121,7 +2559,7 @@ is_sane_oppenssl_client() ->
end.
is_fips(openssl) ->
- VersionStr = os:cmd("openssl version"),
+ VersionStr = portable_cmd("openssl",["version"]),
case re:split(VersionStr, "fips") of
[_] ->
false;
@@ -2155,7 +2593,7 @@ cipher_restriction(Config0) ->
end.
openssl_dsa_support() ->
- case os:cmd("openssl version") of
+ case portable_cmd("openssl", ["version"]) of
"LibreSSL 2.6.1" ++ _ ->
true;
"LibreSSL 2.6.2" ++ _ ->
@@ -2184,7 +2622,7 @@ openssl_dsa_support() ->
%% Acctual support is tested elsewhere, this is to exclude some LibreSSL and OpenSSL versions
openssl_sane_dtls() ->
- case os:cmd("openssl version") of
+ case portable_cmd("openssl", ["version"]) of
"OpenSSL 0." ++ _ ->
false;
"OpenSSL 1.0.1s-freebsd" ++ _ ->
@@ -2203,7 +2641,7 @@ openssl_sane_dtls() ->
false
end.
openssl_sane_client_cert() ->
- case os:cmd("openssl version") of
+ case portable_cmd("openssl", ["version"]) of
"LibreSSL 2.5.2" ++ _ ->
true;
"LibreSSL 2.4" ++ _ ->
@@ -2225,9 +2663,7 @@ openssl_sane_client_cert() ->
check_sane_openssl_version(Version) ->
case supports_ssl_tls_version(Version) of
true ->
- case {Version, os:cmd("openssl version")} of
- {'sslv3', "OpenSSL 1.0.2" ++ _} ->
- false;
+ case {Version, portable_cmd("openssl",["version"])} of
{'dtlsv1', "OpenSSL 0" ++ _} ->
false;
{'dtlsv1.2', "OpenSSL 0" ++ _} ->
@@ -2260,9 +2696,10 @@ check_sane_openssl_version(Version) ->
false ->
false
end.
-check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1';
- Version == 'tlsv1.2' ->
- case os:cmd("openssl version") of
+check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1';
+ Version == 'tlsv1.1';
+ Version == 'tlsv1.2' ->
+ case portable_cmd("openssl", ["version"]) of
"OpenSSL 1.0.1c" ++ _ ->
{skip, "Known renegotiation bug in OpenSSL"};
"OpenSSL 1.0.1b" ++ _ ->
@@ -2271,7 +2708,9 @@ check_sane_openssl_renegotaite(Config, Version) when Version == 'tlsv1.1';
{skip, "Known renegotiation bug in OpenSSL"};
"OpenSSL 1.0.1 " ++ _ ->
{skip, "Known renegotiation bug in OpenSSL"};
- _ ->
+ "LibreSSL 3.0.2" ++ _ ->
+ {skip, "Known renegotiation bug in OpenSSL"};
+ _ ->
check_sane_openssl_renegotaite(Config)
end;
check_sane_openssl_renegotaite(Config, 'sslv3') ->
@@ -2422,26 +2861,45 @@ portable_open_port(Exe, Args) ->
open_port({spawn_executable, AbsPath},
[{args, Args}, stderr_to_stdout]).
-supports_ssl_tls_version(sslv2 = Version) ->
- case os:cmd("openssl version") of
- "OpenSSL 1" ++ _ ->
- false;
- %% Appears to be broken
- "OpenSSL 0.9.8.o" ++ _ ->
- false;
- _ ->
- VersionFlag = version_flag(Version),
- Exe = "openssl",
- Args = ["s_client", VersionFlag],
- [{trap_exit, Trap}] = process_info(self(), [trap_exit]),
- process_flag(trap_exit, true),
- Port = ssl_test_lib:portable_open_port(Exe, Args),
- Bool = do_supports_ssl_tls_version(Port, ""),
- consume_port_exit(Port),
- process_flag(trap_exit, Trap),
- Bool
- end;
+portable_cmd(Exe, Args) ->
+ AbsPath = os:find_executable(Exe),
+ ct:pal("open_port({spawn_executable, ~p}, [{args, ~p}, stderr_to_stdout]).", [AbsPath, Args]),
+ Port = open_port({spawn_executable, AbsPath},
+ [{args, Args}, stderr_to_stdout]),
+ receive
+ {Port, {data, Data}} ->
+ catch erlang:port_close(Port),
+ Data
+ end.
+
+supports_ssl_tls_version(Version) when Version == sslv2;
+ Version == sslv3 ->
+ case ubuntu_legacy_support() of
+ true ->
+ case portable_cmd("openssl", ["version"]) of
+ "OpenSSL 1.1" ++ _ ->
+ false;
+ "OpenSSL 1" ++ _ ->
+ Version =/= sslv2;
+ %% Appears to be broken
+ "OpenSSL 0.9.8.o" ++ _ ->
+ false;
+ _ ->
+ VersionFlag = version_flag(Version),
+ Exe = "openssl",
+ Args = ["s_client", VersionFlag],
+ [{trap_exit, Trap}] = process_info(self(), [trap_exit]),
+ process_flag(trap_exit, true),
+ Port = ssl_test_lib:portable_open_port(Exe, Args),
+ Bool = do_supports_ssl_tls_version(Port, ""),
+ consume_port_exit(Port),
+ process_flag(trap_exit, Trap),
+ Bool
+ end;
+ false ->
+ false
+ end;
supports_ssl_tls_version(Version) ->
VersionFlag = version_flag(Version),
Exe = "openssl",
@@ -2467,6 +2925,20 @@ do_supports_ssl_tls_version(Port, Acc) ->
true
end.
+ubuntu_legacy_support() ->
+ case os:type() of
+ {unix, linux} ->
+ Issue = os:cmd("more /etc/issue"),
+ case re:run(Issue, "Ubuntu 1[6-9]+", [global]) of
+ nomatch ->
+ true;
+ _ ->
+ false
+ end;
+ _ ->
+ true
+ end.
+
ssl_options(Option, Config) when is_atom(Option) ->
ProtocolOpts = proplists:get_value(protocol_opts, Config, []),
Opts = proplists:get_value(Option, Config, []),
@@ -2896,3 +3368,15 @@ openssl_sane_dtls_session_reuse() ->
_->
openssl_sane_dtls()
end.
+
+-define(BIG_BUF, 10000000).
+%% Workaround data delivery issues on solaris | openbsd when kernel buffers are small
+bigger_buffers() ->
+ case os:type() of
+ {unix,sunos} ->
+ [{recbuf, ?BIG_BUF},{sndbuf, ?BIG_BUF}];
+ {unix,openbsd} ->
+ [{recbuf, ?BIG_BUF},{sndbuf, ?BIG_BUF}];
+ _ ->
+ []
+ end.
diff --git a/lib/ssl/test/tls_1_3_record_SUITE.erl b/lib/ssl/test/tls_1_3_record_SUITE.erl
index 26d7694e16..521e9a4fb8 100644
--- a/lib/ssl/test/tls_1_3_record_SUITE.erl
+++ b/lib/ssl/test/tls_1_3_record_SUITE.erl
@@ -81,7 +81,7 @@ encode_decode(_Config) ->
<<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
- 157>>}, undefined,
+ 157>>}, undefined, undefined,
undefined,
<<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
@@ -107,7 +107,7 @@ encode_decode(_Config) ->
<<128,229,186,211,62,127,182,20,62,166,233,23,135,64,121,
3,104,251,214,161,253,31,3,2,232,37,8,221,189,72,64,218,
121,41,112,148,254,34,68,164,228,60,161,201,132,55,56,
- 157>>}, undefined,
+ 157>>}, undefined, undefined,
undefined,
<<92,24,205,75,244,60,136,212,250,32,214,20,37,3,213,87,61,207,
147,61,168,145,177,118,160,153,33,53,48,108,191,174>>,
@@ -744,14 +744,12 @@ encode_decode(_Config) ->
%% PRK (32 octets): 7d f2 35 f2 03 1d 2a 05 12 87 d0 2b 02 41 b0 bf
%% da f8 6c c8 56 23 1f 2d 5a ba 46 c4 34 ec 19 6c
%%
- RMS = hexstr2bin("7d f2 35 f2 03 1d 2a 05 12 87 d0 2b 02 41 b0 bf
+ _RMS = hexstr2bin("7d f2 35 f2 03 1d 2a 05 12 87 d0 2b 02 41 b0 bf
da f8 6c c8 56 23 1f 2d 5a ba 46 c4 34 ec 19 6c"),
%% Verify calculation of resumption master secret that is used to create
%% the pre shared key in '0-RTT'.
- Temp = tls_v1:resumption_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
- erlang:display({rms, RMS}),
- erlang:display({new_rms, Temp}),
+ _Temp = tls_v1:resumption_master_secret(HKDFAlgo, {master_secret, MasterSecret}, CHSF),
%% {server} derive secret "tls13 exp master":
%%
diff --git a/lib/ssl/vsn.mk b/lib/ssl/vsn.mk
index ac79ee5fdc..2b2859b6b6 100644
--- a/lib/ssl/vsn.mk
+++ b/lib/ssl/vsn.mk
@@ -1 +1 @@
-SSL_VSN = 9.5.1
+SSL_VSN = 9.5.3
diff --git a/lib/stdlib/doc/src/gen_statem.xml b/lib/stdlib/doc/src/gen_statem.xml
index dabce02b3d..c12ad2deef 100644
--- a/lib/stdlib/doc/src/gen_statem.xml
+++ b/lib/stdlib/doc/src/gen_statem.xml
@@ -4,7 +4,7 @@
<erlref>
<header>
<copyright>
- <year>2016</year><year>2019</year>
+ <year>2016</year><year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -99,6 +99,14 @@
</seealso>
were added.
</item>
+ <item>
+ In OTP 22.3 the possibility to change the callback module
+ with actions
+ <seealso marker="#type-action"><c>change_callback_module</c></seealso>,
+ <seealso marker="#type-action"><c>push_callback_module</c></seealso> and
+ <seealso marker="#type-action"><c>pop_callback_module</c></seealso>,
+ was added.
+ </item>
</list>
</note>
<p>
@@ -119,6 +127,7 @@
Reply from other state than the request, <c>sys</c> traceable
</item>
<item>Multiple <c>sys</c> traceable replies</item>
+ <item>Changing the callback module</item>
</list>
@@ -129,15 +138,17 @@
</p>
<list type="bulleted">
<item>
- <p>One for finite-state machines
+ <p>
+ One for finite-state machines
(<seealso marker="gen_fsm"><c>gen_fsm</c></seealso> like),
which requires the state to be an atom and uses that state as
- the name of the current callback function
+ the name of the current callback function.
</p>
</item>
<item>
- <p>One without restriction on the state data type
- that uses one callback function for all states
+ <p>
+ One that allows the state to be any term and
+ that uses one callback function for all states.
</p>
</item>
</list>
@@ -150,7 +161,7 @@
</seealso> <c>gen_fsm</c> to <c>gen_statem</c>.
</p>
<p>
- A generic state machine process (<c>gen_statem</c>) implemented
+ A generic state machine server process (<c>gen_statem</c>) implemented
using this module has a standard set of interface functions
and includes functionality for tracing and error reporting.
It also fits into an OTP supervision tree. For more information, see
@@ -626,9 +637,12 @@ handle_event(_, _, State, Data) ->
If the
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
is <c>state_functions</c>,
- the state must be of this type.
+ the state must be an atom.
After a <em>state change</em> (<c>NextState =/= State</c>),
all postponed events are retried.
+ Note that the state <c>terminate</c> is not possible
+ to use since it would collide with the optional callback function
+ <seealso marker="#Module:terminate/3"><c>Module:terminate/3</c></seealso>.
</p>
</desc>
</datatype>
@@ -707,10 +721,9 @@ handle_event(_, _, State, Data) ->
<name name="callback_mode"/>
<desc>
<p>
- The <em>callback mode</em> is selected when starting the
- <c>gen_statem</c> and after code change
- using the return value from
- <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>.
+ The <em>callback mode</em> is selected
+ with the return value from
+ <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>:
</p>
<taglist>
<tag><c>state_functions</c></tag>
@@ -732,6 +745,18 @@ handle_event(_, _, State, Data) ->
</p>
</item>
</taglist>
+ <p>
+ The function
+ <seealso marker="#Module:callback_mode/0"><c>Module:callback_mode/0</c></seealso>
+ is called when starting the <c>gen_statem</c>,
+ after code change
+ and after changing the callback module with any of the actions
+ <seealso marker="#type-action"><c>change_callback_module</c></seealso>,
+ <seealso marker="#type-action"><c>push_callback_module</c></seealso> or
+ <seealso marker="#type-action"><c>pop_callback_module</c></seealso>.
+ The result is cached for subsequent calls to
+ <seealso marker="#state callback">state callbacks</seealso>.
+ </p>
</desc>
</datatype>
<datatype>
@@ -1168,6 +1193,74 @@ handle_event(_, _, State, Data) ->
an event inserted this way from any external event.
</p>
</item>
+ <tag>
+ <c>change_callback_module</c>
+ </tag>
+ <item>
+ <p>
+ Changes the callback module to
+ <c><anno>NewModule</anno></c>
+ which will be used when calling all subsequent
+ <seealso marker="#state callback">state callbacks</seealso>.
+ </p>
+ <p>
+ The <c>gen_statem</c> engine will find out the
+ <seealso marker="#type-callback_mode">
+ <em>callback mode</em>
+ </seealso>
+ of <c><anno>NewModule</anno></c> by calling
+ <seealso marker="#Module:callback_mode/0">
+ <c>NewModule:callback_mode/0</c>
+ </seealso>
+ before the next
+ <seealso marker="#state callback">state callback</seealso>.
+ </p>
+ <p>
+ Changing the callback module does not affect the
+ <em>state transition</em> in any way,
+ it only changes which module that handles the events.
+ Be aware that all relevant callback functions in
+ <c><anno>NewModule</anno></c>
+ such as the
+ <seealso marker="#state callback">state callback</seealso>,
+ <seealso marker="#Module:code_change/4"><c><anno>NewModule</anno>:code_change/4</c></seealso>,
+ <seealso marker="#Module:format_status/2">
+ <c><anno>NewModule</anno>:format_status/2</c>
+ </seealso>
+ and
+ <seealso marker="#Module:terminate/3">
+ <c><anno>NewModule</anno>:terminate/3</c>
+ </seealso>
+ must be able to handle the state and data
+ from the old module.
+ </p>
+ </item>
+ <tag>
+ <c>push_callback_module</c><br />
+ </tag>
+ <item>
+ <p>
+ Pushes the current callback module
+ to the top of an internal stack of callback modules
+ and changes the callback module to
+ <c><anno>NewModule</anno></c>.
+ Otherwise like
+ <c>{change_callback_module, NewModule}</c>
+ above.
+ </p>
+ </item>
+ <tag>
+ <c>pop_callback_module</c>
+ </tag>
+ <item>
+ Pops the top module from the internal stack of
+ callback modules and changes the callback module
+ to be the popped module.
+ If the stack is empty the server fails.
+ Otherwise like
+ <c>{change_callback_module, NewModule}</c>
+ above.
+ </item>
</taglist>
</desc>
</datatype>
@@ -1917,7 +2010,9 @@ handle_event(_, _, State, Data) ->
<funcs>
<func>
<name since="OTP 19.1">Module:callback_mode() -> CallbackMode</name>
- <fsummary>Update the internal state during upgrade/downgrade.</fsummary>
+ <fsummary>
+ Define the callback mode for the callback module.
+ </fsummary>
<type>
<v>
CallbackMode =
@@ -1933,10 +2028,11 @@ handle_event(_, _, State, Data) ->
<seealso marker="#type-callback_mode"><em>callback mode</em></seealso>
of the callback module. The value is cached by <c>gen_statem</c>
for efficiency reasons, so this function is only called
- once after server start and after code change,
+ once after server start, after code change,
+ and after changing the callback module,
but before the first
<seealso marker="#state callback"><em>state callback</em></seealso>
- in the current code version is called.
+ in the current callback module's code version is called.
More occasions may be added in future versions
of <c>gen_statem</c>.
</p>
@@ -1945,9 +2041,16 @@ handle_event(_, _, State, Data) ->
<seealso marker="#Module:init/1"><c>Module:init/1</c></seealso>
returns or when
<seealso marker="#enter_loop/4"><c>enter_loop/4-6</c></seealso>
- is called. Code change happens when
+ is called.
+ Code change happens when
<seealso marker="#Module:code_change/4"><c>Module:code_change/4</c></seealso>
returns.
+ A change of the callback module happens when a
+ <seealso marker="#state callback"><em>state callback</em></seealso>
+ returns any of the actions
+ <seealso marker="#type-action"><c>change_callback_module</c></seealso>,
+ <seealso marker="#type-action"><c>push_callback_module</c></seealso> or
+ <seealso marker="#type-action"><c>pop_callback_module</c></seealso>.
</p>
<p>
The <c>CallbackMode</c> is either just
@@ -1970,7 +2073,9 @@ handle_event(_, _, State, Data) ->
<name since="OTP 19.0">Module:code_change(OldVsn, OldState, OldData, Extra) ->
Result
</name>
- <fsummary>Update the internal state during upgrade/downgrade.</fsummary>
+ <fsummary>
+ Update the internal state during upgrade/downgrade.
+ </fsummary>
<type>
<v>OldVsn = Vsn | {down,Vsn}</v>
<v>&nbsp;&nbsp;Vsn = term()</v>
@@ -2052,13 +2157,44 @@ handle_event(_, _, State, Data) ->
will not be honoured,
most probably causing a server crash.
</p>
+ <p>
+ If the server changes callback module using any of the actions
+ <seealso marker="#type-action"><c>change_callback_module</c></seealso>,
+ <seealso marker="#type-action"><c>push_callback_module</c></seealso> or
+ <seealso marker="#type-action"><c>pop_callback_module</c></seealso>,
+ be aware that it is always the current callback module that
+ will get this callback call. That the current callback module
+ handles the current state and data update should be no surprise,
+ but it must be able to handle even parts of
+ the state and data that it is not familiar with,
+ somehow.
+ </p>
+ <p>
+ In the supervisor
+ <seealso marker="doc/design_principles:sup_princ#child-specification">child specification</seealso>
+ there is a list of modules which is recommended to contain
+ only the callback module.
+ For a <c>gen_statem</c> with multiple callback modules
+ there is no real need to list all of them,
+ it may not even be possible since the list could change
+ after code upgrade.
+ If this list would contain only the start callback module,
+ as recommended, what is important is to upgrade <em>that</em> module
+ whenever a <em>synchronized code replacement</em> is done.
+ Then the release handler concludes that an upgrade
+ that upgrades <em>that</em> module needs to suspend,
+ code change, and resume any server whose child specification
+ declares that it is using <em>that</em> module.
+ And again; the <em>current</em> callback module will get the
+ <c>Module:code_change/4</c> call.
+ </p>
</desc>
</func>
<func>
<name since="OTP 19.0">Module:init(Args) -> Result(StateType)</name>
<fsummary>
- Initializing process and internal state.
+ Initialize process and internal state.
</fsummary>
<type>
<v>Args = term()</v>
@@ -2101,8 +2237,9 @@ init(Args) -> erlang:error(not_implemented, [Args]).</pre>
<name since="OTP 19.0">Module:format_status(Opt, [PDict,State,Data]) ->
Status
</name>
- <fsummary>Optional function for providing a term describing the
- current <c>gen_statem</c> status.</fsummary>
+ <fsummary>
+ Describe the current <c>gen_statem</c> status (optional).
+ </fsummary>
<type>
<v>Opt = normal | terminate</v>
<v>PDict = [{Key, Value}]</v>
diff --git a/lib/stdlib/doc/src/notes.xml b/lib/stdlib/doc/src/notes.xml
index fb24bb63b5..3df13cee27 100644
--- a/lib/stdlib/doc/src/notes.xml
+++ b/lib/stdlib/doc/src/notes.xml
@@ -31,6 +31,43 @@
</header>
<p>This document describes the changes made to the STDLIB application.</p>
+<section><title>STDLIB 3.11.2</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>A directory traversal vulnerability has been
+ eliminated in erl_tar. erl_tar will now refuse to extract
+ symlinks that points outside the targeted extraction
+ directory and will return
+ <c>{error,{Path,unsafe_symlink}}</c>. (Thanks to Eric
+ Meadows-Jönsson for the bug report and for suggesting a
+ fix.)</p>
+ <p>
+ Own Id: OTP-16441</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
+<section><title>STDLIB 3.11.1</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>
+ The <c>ets:update_counter/4</c> core dumped when given an
+ ordered_set with write_concurrency enabled and an invalid
+ position. This bug has been fixed.</p>
+ <p>
+ Own Id: OTP-16378 Aux Id: ERL-1125 </p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.11</title>
<section><title>Fixed Bugs and Malfunctions</title>
@@ -529,6 +566,26 @@
</section>
+<section><title>STDLIB 3.8.2.3</title>
+
+ <section><title>Fixed Bugs and Malfunctions</title>
+ <list>
+ <item>
+ <p>A directory traversal vulnerability has been
+ eliminated in erl_tar. erl_tar will now refuse to extract
+ symlinks that points outside the targeted extraction
+ directory and will return
+ <c>{error,{Path,unsafe_symlink}}</c>. (Thanks to Eric
+ Meadows-Jönsson for the bug report and for suggesting a
+ fix.)</p>
+ <p>
+ Own Id: OTP-16441</p>
+ </item>
+ </list>
+ </section>
+
+</section>
+
<section><title>STDLIB 3.8.2.2</title>
<section><title>Fixed Bugs and Malfunctions</title>
diff --git a/lib/stdlib/doc/src/queue.xml b/lib/stdlib/doc/src/queue.xml
index 89cce6d85b..46a3dc5d19 100644
--- a/lib/stdlib/doc/src/queue.xml
+++ b/lib/stdlib/doc/src/queue.xml
@@ -52,7 +52,7 @@
is to be regarded as opaque by other modules. Any code
assuming knowledge of the format is running on thin ice.</p>
- <p>All operations has an amortized O(1) running time, except
+ <p>All operations have an amortized O(1) running time, except
<seealso marker="#filter/2"><c>filter/2</c></seealso>,
<seealso marker="#join/2"><c>join/2</c></seealso>,
<seealso marker="#len/1"><c>len/1</c></seealso>,
diff --git a/lib/stdlib/src/calendar.erl b/lib/stdlib/src/calendar.erl
index 3a8fe2211b..ef6d1882e6 100644
--- a/lib/stdlib/src/calendar.erl
+++ b/lib/stdlib/src/calendar.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -369,7 +369,7 @@ rfc3339_to_system_time(DateTimeString, Options) ->
IsFractionChar = fun(C) -> C >= $0 andalso C =< $9 orelse C =:= $. end,
{FractionStr, UtcOffset} = lists:splitwith(IsFractionChar, TimeStr),
Time = datetime_to_system_time(DateTime),
- Secs = Time - offset_adjustment(Time, second, UtcOffset),
+ Secs = Time - offset_string_adjustment(Time, second, UtcOffset),
check(DateTimeString, Options, Secs),
ScaledEpoch = erlang:convert_time_unit(Secs, second, Unit),
ScaledEpoch + copy_sign(fraction(Unit, FractionStr), ScaledEpoch).
@@ -689,13 +689,13 @@ offset(OffsetOption, Secs0) when OffsetOption =:= "";
offset(OffsetOption, _Secs) ->
OffsetOption.
+offset_adjustment(Time, Unit, "") ->
+ local_offset(Time, Unit);
offset_adjustment(Time, Unit, OffsetString) when is_list(OffsetString) ->
offset_string_adjustment(Time, Unit, OffsetString);
offset_adjustment(_Time, Unit, Offset) when is_integer(Offset) ->
erlang:convert_time_unit(Offset, Unit, second).
-offset_string_adjustment(Time, Unit, "") ->
- local_offset(Time, Unit);
offset_string_adjustment(_Time, _Unit, "Z") ->
0;
offset_string_adjustment(_Time, _Unit, "z") ->
diff --git a/lib/stdlib/src/erl_parse.yrl b/lib/stdlib/src/erl_parse.yrl
index 4ad94f2507..739f786321 100644
--- a/lib/stdlib/src/erl_parse.yrl
+++ b/lib/stdlib/src/erl_parse.yrl
@@ -2,7 +2,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -27,10 +27,10 @@ attribute attr_val
function function_clauses function_clause
clause_args clause_guard clause_body
expr expr_100 expr_150 expr_160 expr_200 expr_300 expr_400 expr_500
-expr_600 expr_700 expr_800
+expr_600 expr_650 expr_700 expr_800
expr_max
pat_expr pat_expr_200 pat_expr_300 pat_expr_400 pat_expr_500
-pat_expr_600 pat_expr_700 pat_expr_800
+pat_expr_600 pat_expr_650 pat_expr_700 pat_expr_800
pat_expr_max map_pat_expr record_pat_expr
pat_argument_list pat_exprs
list tail
@@ -251,10 +251,12 @@ expr_500 -> expr_500 mult_op expr_600 :
?mkop2('$1', '$2', '$3').
expr_500 -> expr_600 : '$1'.
-expr_600 -> prefix_op expr_700 :
+expr_600 -> prefix_op expr_600 :
?mkop1('$1', '$2').
-expr_600 -> map_expr : '$1'.
-expr_600 -> expr_700 : '$1'.
+expr_600 -> expr_650 : '$1'.
+
+expr_650 -> map_expr : '$1'.
+expr_650 -> expr_700 : '$1'.
expr_700 -> function_call : '$1'.
expr_700 -> record_expr : '$1'.
@@ -298,10 +300,12 @@ pat_expr_500 -> pat_expr_500 mult_op pat_expr_600 :
?mkop2('$1', '$2', '$3').
pat_expr_500 -> pat_expr_600 : '$1'.
-pat_expr_600 -> prefix_op pat_expr_700 :
+pat_expr_600 -> prefix_op pat_expr_600 :
?mkop1('$1', '$2').
-pat_expr_600 -> map_pat_expr : '$1'.
-pat_expr_600 -> pat_expr_700 : '$1'.
+pat_expr_600 -> pat_expr_650 : '$1'.
+
+pat_expr_650 -> map_pat_expr : '$1'.
+pat_expr_650 -> pat_expr_700 : '$1'.
pat_expr_700 -> record_pat_expr : '$1'.
pat_expr_700 -> pat_expr_800 : '$1'.
@@ -732,7 +736,7 @@ Erlang code.
-type af_template() :: abstract_expr().
--type af_qualifier_seq() :: [af_qualifier()].
+-type af_qualifier_seq() :: [af_qualifier(), ...].
-type af_qualifier() :: af_generator() | af_filter().
@@ -749,7 +753,7 @@ Erlang code.
-type af_try() :: {'try',
anno(),
- af_body() | [],
+ af_body(),
af_clause_seq() | [],
af_clause_seq() | [],
af_body() | []}.
@@ -765,7 +769,10 @@ Erlang code.
-type af_remote_fun() ::
{'fun', anno(), {'function', module(), function_name(), arity()}}
- | {'fun', anno(), {'function', af_atom(), af_atom(), af_integer()}}.
+ | {'fun', anno(), {'function',
+ af_atom() | af_variable(),
+ af_atom() | af_variable(),
+ af_integer() | af_variable()}}.
-type af_fun() :: {'fun', anno(), {'clauses', af_clause_seq()}}.
@@ -795,8 +802,8 @@ Erlang code.
| af_record_creation(af_guard_test())
| af_record_index()
| af_record_field_access(af_guard_test())
- | af_map_creation(abstract_expr())
- | af_map_update(abstract_expr())
+ | af_map_creation(af_guard_test())
+ | af_map_update(af_guard_test())
| af_guard_call()
| af_remote_guard_call().
@@ -812,7 +819,7 @@ Erlang code.
-type af_assoc_exact(T) :: {'map_field_exact', anno(), T, T}.
--type af_guard_call() :: {'call', anno(), function_name(), [af_guard_test()]}.
+-type af_guard_call() :: {'call', anno(), af_atom(), [af_guard_test()]}.
-type af_remote_guard_call() ::
{'call', anno(),
@@ -841,7 +848,7 @@ Erlang code.
-type af_record_field(T) :: {'record_field', anno(), af_field_name(), T}.
-type af_map_pattern() ::
- {'map', anno(), [af_assoc_exact(abstract_expr())]}.
+ {'map', anno(), [af_assoc_exact(af_pattern())]}.
-type abstract_type() :: af_annotated_type()
| af_atom()
@@ -903,7 +910,8 @@ Erlang code.
-type af_tuple_type() :: {'type', anno(), 'tuple', 'any'}
| {'type', anno(), 'tuple', [abstract_type()]}.
--type af_type_union() :: {'type', anno(), 'union', [abstract_type()]}.
+-type af_type_union() ::
+ {'type', anno(), 'union', [abstract_type(), ...]}. % at least two
-type af_type_variable() :: {'var', anno(), atom()}. % except '_'
@@ -911,7 +919,7 @@ Erlang code.
{'user_type', anno(), type_name(), [abstract_type()]}.
-type af_function_type_list() :: [af_constrained_function_type() |
- af_function_type()].
+ af_function_type(), ...].
-type af_constrained_function_type() ::
{'type', anno(), 'bounded_fun', [af_function_type() | % [Ft, Fc]
@@ -921,7 +929,7 @@ Erlang code.
{'type', anno(), 'fun',
[{'type', anno(), 'product', [abstract_type()]} | abstract_type()]}.
--type af_function_constraint() :: [af_constraint()].
+-type af_function_constraint() :: [af_constraint(), ...].
-type af_constraint() :: {'type', anno(), 'constraint',
[af_lit_atom('is_subtype') |
@@ -1584,7 +1592,7 @@ max_prec() -> 900.
-spec type_inop_prec(type_inop()) -> {prec(), prec(), prec()}.
type_inop_prec('=') -> {150,100,100};
-type_inop_prec('::') -> {160,150,150};
+type_inop_prec('::') -> {150,150,160};
type_inop_prec('|') -> {180,170,170};
type_inop_prec('..') -> {300,200,300};
type_inop_prec('+') -> {400,400,500};
diff --git a/lib/stdlib/src/erl_pp.erl b/lib/stdlib/src/erl_pp.erl
index 255c0ae81f..daa172af50 100644
--- a/lib/stdlib/src/erl_pp.erl
+++ b/lib/stdlib/src/erl_pp.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1996-2019. All Rights Reserved.
+%% Copyright Ericsson AB 1996-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -322,9 +322,11 @@ ltype(T) ->
ltype(T, 0).
ltype({ann_type,_Line,[V,T]}, Prec) ->
- {_L,P,_R} = type_inop_prec('::'),
- E = typed(lexpr(V, options(none)), T),
- maybe_paren(P, Prec, E);
+ {L,P,R} = type_inop_prec('::'),
+ Vl = ltype(V, L),
+ Tr = ltype(T, R),
+ El = {list,[{cstep,[Vl,' ::'],Tr}]},
+ maybe_paren(P, Prec, El);
ltype({paren_type,_Line,[T]}, P) ->
%% Generated before Erlang/OTP 18.
ltype(T, P);
@@ -410,8 +412,7 @@ field_type({type,_Line,field_type,[Name,Type]}, _Prec) ->
typed(lexpr(Name, options(none)), Type).
typed(B, Type) ->
- {_L,_P,R} = type_inop_prec('::'),
- {list,[{cstep,[B,' ::'],ltype(Type, R)}]}.
+ {list,[{cstep,[B,' ::'],ltype(Type)}]}.
tuple_type([], _) ->
leaf("{}");
@@ -540,11 +541,13 @@ lexpr({nil,_}, _, _) -> '[]';
lexpr({cons,_,H,T}, _, Opts) ->
list(T, [H], Opts);
lexpr({lc,_,E,Qs}, _Prec, Opts) ->
- Lcl = {list,[{step,[lexpr(E, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]},
+ P = max_prec(),
+ Lcl = {list,[{step,[lexpr(E, P, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]},
{list,[{seq,$[,[],[[]],[{force_nl,leaf(" "),[Lcl]}]},$]]};
%% {list,[{step,$[,Lcl},$]]};
lexpr({bc,_,E,Qs}, _Prec, Opts) ->
- Lcl = {list,[{step,[lexpr(E, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]},
+ P = max_prec(),
+ Lcl = {list,[{step,[lexpr(E, P, Opts),leaf(" ||")],lc_quals(Qs, Opts)}]},
{list,[{seq,'<<',[],[[]],[{force_nl,leaf(" "),[Lcl]}]},'>>']};
%% {list,[{step,'<<',Lcl},'>>']};
lexpr({tuple,_,Elts}, _, Opts) ->
@@ -564,14 +567,16 @@ lexpr({record, _, Name, Fs}, Prec, Opts) ->
lexpr({record_field, _, Rec, Name, F}, Prec, Opts) ->
{L,P,R} = inop_prec('#'),
Rl = lexpr(Rec, L, Opts),
- Nl = [$#,{atom,Name},$.],
+ Sep = hash_after_integer(Rec, [$#]),
+ Nl = [Sep,{atom,Name},$.],
El = [Rl,Nl,lexpr(F, R, Opts)],
maybe_paren(P, Prec, El);
lexpr({record, _, Rec, Name, Fs}, Prec, Opts) ->
{L,P,_R} = inop_prec('#'),
Rl = lexpr(Rec, L, Opts),
+ Sep = hash_after_integer(Rec, []),
Nl = record_name(Name),
- El = {first,[Rl,Nl],record_fields(Fs, Opts)},
+ El = {first,[Rl,Sep,Nl],record_fields(Fs, Opts)},
maybe_paren(P, Prec, El);
lexpr({record_field, _, {atom,_,''}, F}, Prec, Opts) ->
{_L,P,R} = inop_prec('.'),
@@ -588,7 +593,8 @@ lexpr({map, _, Fs}, Prec, Opts) ->
lexpr({map, _, Map, Fs}, Prec, Opts) ->
{L,P,_R} = inop_prec('#'),
Rl = lexpr(Map, L, Opts),
- El = {first,[Rl,$#],map_fields(Fs, Opts)},
+ Sep = hash_after_integer(Map, [$#]),
+ El = {first,[Rl|Sep],map_fields(Fs, Opts)},
maybe_paren(P, Prec, El);
lexpr({block,_,Es}, _, Opts) ->
{list,[{step,'begin',body(Es, Opts)},{reserved,'end'}]};
@@ -652,20 +658,20 @@ lexpr({'try',_,Es,Scs,Ccs,As}, _, Opts) ->
true ->
{step,{list,[{step,'try',body(Es, Opts)},{reserved,'of'}]},
cr_clauses(Scs, Opts)}
- end,
+ end] ++
if
Ccs =:= [] ->
[];
true ->
- {step,'catch',try_clauses(Ccs, Opts)}
- end,
+ [{step,'catch',try_clauses(Ccs, Opts)}]
+ end ++
if
As =:= [] ->
[];
true ->
- {step,'after',body(As, Opts)}
- end,
- {reserved,'end'}]};
+ [{step,'after',body(As, Opts)}]
+ end ++
+ [{reserved,'end'}]};
lexpr({'catch',_,Expr}, Prec, Opts) ->
{P,R} = preop_prec('catch'),
El = {list,[{step,'catch',lexpr(Expr, R, Opts)}]},
@@ -718,6 +724,17 @@ lexpr(HookExpr, Precedence, #options{hook = {Mod,Func,Eas}})
lexpr(HookExpr, Precedence, #options{hook = Func, opts = Options}) ->
{hook,HookExpr,Precedence,Func,Options}.
+%% An integer is separated from the following '#' by a space, which
+%% erl_scan can handle.
+hash_after_integer({integer, _, _}, C) ->
+ [$\s|C];
+hash_after_integer({'fun',_,{function, _, _}}, C) ->
+ [$\s|C];
+hash_after_integer({'fun',_,{function, _, _, _}}, C) ->
+ [$\s|C];
+hash_after_integer(_, C) ->
+ C.
+
call(Name, Args, Prec, Opts) ->
{F,P} = func_prec(),
Item = {first,lexpr(Name, F, Opts),args(Args, Opts)},
@@ -839,12 +856,6 @@ cr_clause({clause,_,[T],G,B}, Opts) ->
try_clauses(Cs, Opts) ->
clauses(fun try_clause/2, Opts, Cs).
-try_clause({clause,_,[{tuple,_,[{atom,_,throw},V,S]}],G,B}, Opts) ->
- El = lexpr(V, 0, Opts),
- Sl = stack_backtrace(S, [El], Opts),
- Gl = guard_when(Sl, G, Opts),
- Bl = body(B, Opts),
- {step,Gl,Bl};
try_clause({clause,_,[{tuple,_,[C,V,S]}],G,B}, Opts) ->
Cs = lexpr(C, 0, Opts),
El = lexpr(V, 0, Opts),
@@ -972,7 +983,7 @@ frmt(Item, I, PP) ->
%%% - {prefer_nl,Sep,IPs}: forces linebreak between Is unlesss negative
%%% indentation.
%%% - {atom,A}: an atom
-%%% - {singleton_atom_type,A}: an singleton atom type
+%%% - {singleton_atom_type,A}: a singleton atom type
%%% - {char,C}: a character
%%% - {string,S}: a string.
%%% - {value,T}: a term.
diff --git a/lib/stdlib/src/erl_tar.erl b/lib/stdlib/src/erl_tar.erl
index 591aea2f83..78cdd02307 100644
--- a/lib/stdlib/src/erl_tar.erl
+++ b/lib/stdlib/src/erl_tar.erl
@@ -1616,7 +1616,8 @@ write_extracted_element(#tar_header{name=Name0}=Header, Bin, Opts) ->
create_extracted_dir(Name1, Opts);
symlink ->
read_verbose(Opts, "x ~ts~n", [Name0]),
- create_symlink(Name1, Header#tar_header.linkname, Opts);
+ LinkName = safe_link_name(Header, Opts),
+ create_symlink(Name1, LinkName, Opts);
Device when Device =:= char orelse Device =:= block ->
%% char/block devices will be created as empty files
%% and then have their major/minor device set later
@@ -1644,6 +1645,52 @@ make_safe_path(Path, #read_opts{cwd=Cwd}) ->
filename:absname(SafePath, Cwd)
end.
+safe_link_name(#tar_header{linkname=Path}, #read_opts{cwd=Cwd}) ->
+ case safe_relative_path_links(Path, Cwd) of
+ unsafe ->
+ throw({error,{Path,unsafe_symlink}});
+ SafePath ->
+ SafePath
+ end.
+
+safe_relative_path_links(Path, Cwd) ->
+ case filename:pathtype(Path) of
+ relative -> safe_relative_path_links(filename:split(Path), Cwd, [], "");
+ _ -> unsafe
+ end.
+
+safe_relative_path_links([Segment|Segments], Cwd, PrevSegments, Acc) ->
+ AccSegment = join(Acc, Segment),
+ case lists:member(AccSegment, PrevSegments) of
+ true ->
+ unsafe;
+ false ->
+ case file:read_link(join(Cwd, AccSegment)) of
+ {ok, LinkPath} ->
+ case filename:pathtype(LinkPath) of
+ relative ->
+ safe_relative_path_links(filename:split(LinkPath) ++ Segments,
+ Cwd, [AccSegment|PrevSegments], Acc);
+ _ ->
+ unsafe
+ end;
+
+ {error, _} ->
+ case filename:safe_relative_path(join(Acc, Segment)) of
+ unsafe ->
+ unsafe;
+ NewAcc ->
+ safe_relative_path_links(Segments, Cwd,
+ [AccSegment|PrevSegments], NewAcc)
+ end
+ end
+ end;
+safe_relative_path_links([], _Cwd, _PrevSegments, Acc) ->
+ Acc.
+
+join([], Path) -> Path;
+join(Left, Right) -> filename:join(Left, Right).
+
create_regular(Name, NameInArchive, Bin, Opts) ->
case write_extracted_file(Name, Bin, Opts) of
not_written ->
diff --git a/lib/stdlib/src/gen_statem.erl b/lib/stdlib/src/gen_statem.erl
index 105b2a4577..2cf30e10ec 100644
--- a/lib/stdlib/src/gen_statem.erl
+++ b/lib/stdlib/src/gen_statem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -149,6 +149,9 @@
{'next_event', % Insert event as the next to handle
EventType :: event_type(),
EventContent :: term()} |
+ {'change_callback_module', NewModule :: module()} |
+ {'push_callback_module', NewModule :: module()} |
+ 'pop_callback_module' |
enter_action().
-type enter_action() ::
'hibernate' | % Set the hibernate option
@@ -337,12 +340,13 @@
terminate/3, % Has got a default implementation
code_change/4, % Only needed by advanced soft upgrade
%%
- state_name/3, % Example for callback_mode() =:= state_functions:
+ state_name/3, % Just an example callback;
+ %% for callback_mode() =:= state_functions
%% there has to be a StateName/3 callback function
- %% for every StateName in your state machine but the state name
- %% 'state_name' does of course not have to be used.
+ %% for every StateName in your state machine,
+ %% but not one has to be named 'state_name'
%%
- handle_event/4 % For callback_mode() =:= handle_event_function
+ handle_event/4 % Only for callback_mode() =:= handle_event_function
]).
@@ -421,7 +425,7 @@ timeout_event_type(Type) ->
{callback_mode = undefined :: callback_mode() | undefined,
state_enter = false :: boolean(),
parent :: pid(),
- module :: atom(),
+ modules :: [module()],
name :: atom() | pid(),
hibernate_after = infinity :: timeout()
}).
@@ -689,12 +693,12 @@ enter(
P =
#params{
parent = Parent,
- module = Module,
+ modules = [Module],
name = Name,
hibernate_after = HibernateAfterTimeout},
S = #state{state_data = {State,Data}},
Debug_1 = ?sys_debug(Debug, Name, {enter,State}),
- loop_callback_mode(
+ loop_state_callback(
P, Debug_1, S, Q, {State,Data},
%% Tunneling Actions through CallbackEvent here...
%% Special path to go to action handling, after first
@@ -726,7 +730,7 @@ init_it(Starter, Parent, ServerRef, Module, Args, Opts) ->
proc_lib:init_ack(Starter, {error,Reason}),
error_info(
Class, Reason, Stacktrace, Debug,
- #params{parent = Parent, name = Name, module = Module},
+ #params{parent = Parent, name = Name, modules = [Module]},
#state{}, []),
erlang:raise(Class, Reason, Stacktrace)
end.
@@ -762,7 +766,7 @@ init_result(
proc_lib:init_ack(Starter, {error,Error}),
error_info(
error, Error, ?STACKTRACE(), Debug,
- #params{parent = Parent, name = Name, module = Module},
+ #params{parent = Parent, name = Name, modules = [Module]},
#state{}, []),
exit(Error)
end.
@@ -783,7 +787,7 @@ system_terminate(Reason, Parent, Debug, {P,S}) ->
update_parent(P, Parent), Debug, S, []).
system_code_change(
- {#params{module = Module} = P,
+ {#params{modules = [Module | _]} = P,
#state{state_data = {State,Data}} = S},
_Mod, OldVsn, Extra) ->
case
@@ -814,7 +818,7 @@ system_replace_state(
format_status(
Opt,
[PDict,SysState,Parent,Debug,
- {#params{name = Name} = P,
+ {#params{name = Name, modules = Modules} = P,
#state{postponed = Postponed, timers = Timers} = S}]) ->
Header = gen:format_status_header("Status for state machine", Name),
Log = sys:get_log(Debug),
@@ -822,6 +826,7 @@ format_status(
{data,
[{"Status",SysState},
{"Parent",Parent},
+ {"Modules",Modules},
{"Time-outs",list_timeouts(Timers)},
{"Logged Events",Log},
{"Postponed",Postponed}]} |
@@ -1046,79 +1051,7 @@ loop_event_handler(
%% restored when looping back to loop/3 or loop_event/5.
%%
Q = [Event|Events],
- loop_callback_mode(P, Debug, S, Q, State_Data, Event).
-
-%% Figure out the callback mode
-%%
-loop_callback_mode(
- #params{callback_mode = undefined} = P, Debug, S,
- Q, State_Data, CallbackEvent) ->
- %%
- Module = P#params.module,
- try Module:callback_mode() of
- CallbackMode ->
- loop_callback_mode_result(
- P, Debug, S,
- Q, State_Data, CallbackEvent,
- CallbackMode, listify(CallbackMode), undefined, false)
- catch
- CallbackMode ->
- loop_callback_mode_result(
- P, Debug, S,
- Q, State_Data, CallbackEvent,
- CallbackMode, listify(CallbackMode), undefined, false);
- Class:Reason:Stacktrace ->
- terminate(
- Class, Reason, Stacktrace, P, Debug, S, Q)
- end;
-loop_callback_mode(P, Debug, S, Q, State_Data, CallbackEvent) ->
- loop_state_callback(P, Debug, S, Q, State_Data, CallbackEvent).
-
-%% Check the result of Module:callback_mode()
-%%
-loop_callback_mode_result(
- P, Debug, S, Q, State_Data, CallbackEvent,
- CallbackMode, [H|T], NewCallbackMode, NewStateEnter) ->
- %%
- case callback_mode(H) of
- true ->
- loop_callback_mode_result(
- P, Debug, S, Q, State_Data, CallbackEvent,
- CallbackMode, T, H, NewStateEnter);
- false ->
- case state_enter(H) of
- true ->
- loop_callback_mode_result(
- P, Debug, S, Q, State_Data, CallbackEvent,
- CallbackMode, T, NewCallbackMode, true);
- false ->
- terminate(
- error,
- {bad_return_from_callback_mode,CallbackMode},
- ?STACKTRACE(),
- P, Debug, S, Q)
- end
- end;
-loop_callback_mode_result(
- P, Debug, S, Q, State_Data, CallbackEvent,
- CallbackMode, [], NewCallbackMode, NewStateEnter) ->
- %%
- case NewCallbackMode of
- undefined ->
- terminate(
- error,
- {bad_return_from_callback_mode,CallbackMode},
- ?STACKTRACE(),
- P, Debug, S, Q);
- _ ->
- P_1 =
- P#params{
- callback_mode = NewCallbackMode,
- state_enter = NewStateEnter},
- loop_state_callback(
- P_1, Debug, S, Q, State_Data, CallbackEvent)
- end.
-
+ loop_state_callback(P, Debug, S, Q, State_Data, Event).
%% Make a state enter call to the state function, we loop back here
%% from further down if state enter calls are enabled
@@ -1149,7 +1082,33 @@ loop_state_callback(P, Debug, S, Q, State_Data, CallbackEvent) ->
StateCall, CallbackEvent).
%%
loop_state_callback(
- #params{callback_mode = CallbackMode, module = Module} = P,
+ #params{callback_mode = undefined, modules = [Module | _]} = P,
+ Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent) ->
+ %%
+ %% Figure out the callback mode
+ %%
+ try Module:callback_mode() of
+ CallbackMode ->
+ loop_callback_mode_result(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent,
+ CallbackMode, listify(CallbackMode), undefined, false)
+ catch
+ CallbackMode ->
+ loop_callback_mode_result(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent,
+ CallbackMode, listify(CallbackMode), undefined, false);
+ Class:Reason:Stacktrace ->
+ terminate(
+ Class, Reason, Stacktrace, P, Debug, S, Q)
+ end;
+loop_state_callback(
+ #params{callback_mode = CallbackMode, modules = [Module | _]} = P,
Debug, S, Q, {State,Data} = State_Data,
NextEventsR, Hibernate, TimeoutsR, Postpone,
StateCall, {Type,Content}) ->
@@ -1186,6 +1145,61 @@ loop_state_callback(
NextEventsR, Hibernate, TimeoutsR, Postpone,
CallEnter, StateCall, Actions).
+%% Check the result of Module:callback_mode()
+%%
+loop_callback_mode_result(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent,
+ CallbackMode, [H|T], NewCallbackMode, NewStateEnter) ->
+ %%
+ case callback_mode(H) of
+ true ->
+ loop_callback_mode_result(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent,
+ CallbackMode, T, H, NewStateEnter);
+ false ->
+ case state_enter(H) of
+ true ->
+ loop_callback_mode_result(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent,
+ CallbackMode, T, NewCallbackMode, true);
+ false ->
+ terminate(
+ error,
+ {bad_return_from_callback_mode,CallbackMode},
+ ?STACKTRACE(),
+ P, Debug, S, Q)
+ end
+ end;
+loop_callback_mode_result(
+ P, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent,
+ CallbackMode, [], NewCallbackMode, NewStateEnter) ->
+ %%
+ case NewCallbackMode of
+ undefined ->
+ terminate(
+ error,
+ {bad_return_from_callback_mode,CallbackMode},
+ ?STACKTRACE(),
+ P, Debug, S, Q);
+ _ ->
+ P_1 =
+ P#params{
+ callback_mode = NewCallbackMode,
+ state_enter = NewStateEnter},
+ loop_state_callback(
+ P_1, Debug, S, Q, State_Data,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ StateCall, CallbackEvent)
+ end.
+
%% Process the result from the state function
%%
loop_state_callback_result(
@@ -1434,91 +1448,70 @@ loop_actions_list(
P, Debug, S, Q, NextState_NewData,
NextEventsR, Hibernate, TimeoutsR, Postpone,
CallEnter, StateCall, Actions, Type, Content);
- %%
- Timeout ->
- loop_actions_timeout(
- P, Debug, S, Q, NextState_NewData,
- NextEventsR, Hibernate, TimeoutsR, Postpone,
- CallEnter, StateCall, Actions, Timeout)
- end.
-
-%% Process a reply action
-%%
-loop_actions_reply(
- P, Debug, S, Q, NextState_NewData,
- NextEventsR, Hibernate, TimeoutsR, Postpone,
- CallEnter, StateCall, Actions,
- From, Reply) ->
- %%
- case from(From) of
- true ->
- %% No need for a separate ?not_sys_debug clause here
- %% since the external call to erlang:'!'/2 in reply/2
- %% will cause swap out of all live registers anyway
- reply(From, Reply),
- Debug_1 = ?sys_debug(Debug, P#params.name, {out,Reply,From}),
- loop_actions_list(
- P, Debug_1, S, Q, NextState_NewData,
- NextEventsR, Hibernate, TimeoutsR, Postpone,
- CallEnter, StateCall, Actions);
- false ->
- terminate(
- error,
- {bad_action_from_state_function,{reply,From,Reply}},
- ?STACKTRACE(), P, Debug,
- S#state{
- state_data = NextState_NewData,
- hibernate = Hibernate},
- Q)
- end.
-
-%% Process a next_event action
-%%
-loop_actions_next_event(
- P, Debug, S, Q, NextState_NewData,
- NextEventsR, Hibernate, TimeoutsR, Postpone,
- CallEnter, StateCall, Actions, Type, Content) ->
- case event_type(Type) of
- true when StateCall ->
- NextEvent = {Type,Content},
- case Debug of
- ?not_sys_debug ->
+ %%
+ {Tag, NewModule}
+ when Tag =:= change_callback_module, is_atom(NewModule);
+ Tag =:= push_callback_module, is_atom(NewModule) ->
+ if
+ StateCall ->
+ NewModules =
+ case Tag of
+ change_callback_module ->
+ [NewModule | tl(P#params.modules)];
+ push_callback_module ->
+ [NewModule | P#params.modules]
+ end,
+ P_1 =
+ P#params{
+ callback_mode = undefined, modules = NewModules},
loop_actions_list(
- P, Debug, S, Q, NextState_NewData,
- [NextEvent|NextEventsR],
- Hibernate, TimeoutsR, Postpone,
+ P_1, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
CallEnter, StateCall, Actions);
- _ ->
- Name = P#params.name,
- {State,_Data} = S#state.state_data,
- Debug_1 =
- sys_debug(Debug, Name, {in,{Type,Content},State}),
+ true ->
+ terminate(
+ error,
+ {bad_state_enter_action_from_state_function,Action},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
+ end;
+ pop_callback_module when tl(P#params.modules) =/= [] ->
+ if
+ StateCall ->
+ NewModules = tl(P#params.modules),
+ P_1 =
+ P#params{
+ callback_mode = undefined,
+ modules = NewModules},
loop_actions_list(
- P, Debug_1, S, Q, NextState_NewData,
- [NextEvent|NextEventsR],
- Hibernate, TimeoutsR, Postpone,
- CallEnter, StateCall, Actions)
- end;
+ P_1, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions);
+ true ->
+ terminate(
+ error,
+ {bad_state_enter_action_from_state_function,Action},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
+ end;
+ %%
_ ->
- terminate(
- error,
- {if
- StateCall ->
- bad_action_from_state_function;
- true ->
- bad_state_enter_action_from_state_function
- end,
- {next_event,Type,Content}},
- ?STACKTRACE(), P, Debug,
- S#state{
- state_data = NextState_NewData,
- hibernate = Hibernate},
- Q)
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions, Action)
end.
-%% Process a timeout action, or also any unrecognized action
+%% Process all other actions, i.e timeout actions,
+%% all others are unrecognized
%%
-loop_actions_timeout(
+loop_actions_list(
P, Debug, S, Q, NextState_NewData,
NextEventsR, Hibernate, TimeoutsR, Postpone,
CallEnter, StateCall, Actions,
@@ -1585,7 +1578,7 @@ loop_actions_timeout(
hibernate = Hibernate},
Q)
end;
-loop_actions_timeout(
+loop_actions_list(
P, Debug, S, Q, NextState_NewData,
NextEventsR, Hibernate, TimeoutsR, Postpone,
CallEnter, StateCall, Actions,
@@ -1610,7 +1603,7 @@ loop_actions_timeout(
hibernate = Hibernate},
Q)
end;
-loop_actions_timeout(
+loop_actions_list(
P, Debug, S, Q, NextState_NewData,
NextEventsR, Hibernate, TimeoutsR, Postpone,
CallEnter, StateCall, Actions,
@@ -1634,7 +1627,7 @@ loop_actions_timeout(
hibernate = Hibernate},
Q)
end;
-loop_actions_timeout(
+loop_actions_list(
P, Debug, S, Q, NextState_NewData,
NextEventsR, Hibernate, TimeoutsR, Postpone,
CallEnter, StateCall, Actions,
@@ -1659,6 +1652,80 @@ loop_actions_timeout(
Q)
end.
+%% Process a reply action
+%%
+loop_actions_reply(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions,
+ From, Reply) ->
+ %%
+ case from(From) of
+ true ->
+ %% No need for a separate ?not_sys_debug clause here
+ %% since the external call to erlang:'!'/2 in reply/2
+ %% will cause swap out of all live registers anyway
+ reply(From, Reply),
+ Debug_1 = ?sys_debug(Debug, P#params.name, {out,Reply,From}),
+ loop_actions_list(
+ P, Debug_1, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions);
+ false ->
+ terminate(
+ error,
+ {bad_action_from_state_function,{reply,From,Reply}},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
+ end.
+
+%% Process a next_event action
+%%
+loop_actions_next_event(
+ P, Debug, S, Q, NextState_NewData,
+ NextEventsR, Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions, Type, Content) ->
+ case event_type(Type) of
+ true when StateCall ->
+ NextEvent = {Type,Content},
+ case Debug of
+ ?not_sys_debug ->
+ loop_actions_list(
+ P, Debug, S, Q, NextState_NewData,
+ [NextEvent|NextEventsR],
+ Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions);
+ _ ->
+ Name = P#params.name,
+ {State,_Data} = S#state.state_data,
+ Debug_1 =
+ sys_debug(Debug, Name, {in,{Type,Content},State}),
+ loop_actions_list(
+ P, Debug_1, S, Q, NextState_NewData,
+ [NextEvent|NextEventsR],
+ Hibernate, TimeoutsR, Postpone,
+ CallEnter, StateCall, Actions)
+ end;
+ _ ->
+ terminate(
+ error,
+ {if
+ StateCall ->
+ bad_action_from_state_function;
+ true ->
+ bad_state_enter_action_from_state_function
+ end,
+ {next_event,Type,Content}},
+ ?STACKTRACE(), P, Debug,
+ S#state{
+ state_data = NextState_NewData,
+ hibernate = Hibernate},
+ Q)
+ end.
+
%% Do the state transition
%%
loop_state_transition(
@@ -2236,7 +2303,7 @@ do_reply_then_terminate(
terminate(
Class, Reason, Stacktrace,
- #params{module = Module} = P, Debug,
+ #params{modules = [Module | _]} = P, Debug,
#state{state_data = {State,Data}} = S, Q) ->
case erlang:function_exported(Module, terminate, 3) of
true ->
@@ -2277,6 +2344,7 @@ error_info(
Class, Reason, Stacktrace, Debug,
#params{
name = Name,
+ modules = Modules,
callback_mode = CallbackMode,
state_enter = StateEnter} = P,
#state{
@@ -2288,6 +2356,7 @@ error_info(
name=>Name,
queue=>Q,
postponed=>Postponed,
+ modules=>Modules,
callback_mode=>CallbackMode,
state_enter=>StateEnter,
state=>format_status(terminate, get(), P, S),
@@ -2327,6 +2396,7 @@ format_log(#{label:={gen_statem,terminate},
name:=Name,
queue:=Q,
postponed:=Postponed,
+ modules:=Modules,
callback_mode:=CallbackMode,
state_enter:=StateEnter,
state:=FmtData,
@@ -2373,6 +2443,7 @@ format_log(#{label:={gen_statem,terminate},
end ++
"** When server state = ~tp~n" ++
"** Reason for termination = ~w:~tp~n" ++
+ "** Callback modules = ~p~n" ++
"** Callback mode = ~p~n" ++
case Q of
[_,_|_] -> "** Queued = ~tp~n";
@@ -2401,6 +2472,7 @@ format_log(#{label:={gen_statem,terminate},
end] ++
[error_logger:limit_term(FmtData),
Class,error_logger:limit_term(FixedReason),
+ error_logger:limit_term(Modules),
CBMode] ++
case Q of
[_|[_|_] = Events] -> [error_logger:limit_term(Events)];
@@ -2438,7 +2510,7 @@ format_client_log({_Pid,{Name,Stacktrace}}) ->
%% Call Module:format_status/2 or return a default value
format_status(
Opt, PDict,
- #params{module = Module},
+ #params{modules = [Module | _]},
#state{state_data = {State,Data} = State_Data}) ->
case erlang:function_exported(Module, format_status, 2) of
true ->
diff --git a/lib/stdlib/src/ms_transform.erl b/lib/stdlib/src/ms_transform.erl
index 74efe5c513..2114b17a79 100644
--- a/lib/stdlib/src/ms_transform.erl
+++ b/lib/stdlib/src/ms_transform.erl
@@ -356,11 +356,6 @@ clause({clause,Line,H0,G0,B0},Bound) ->
copy({call,Line,{remote,_Line2,{atom,_Line3,ets},{atom,_Line4,fun2ms}},
As0},Bound) ->
{transform_call(ets,Line,As0,Bound),Bound};
-copy({call,Line,{remote,_Line2,{record_field,_Line3,
- {atom,_Line4,''},{atom,_Line5,ets}},
- {atom,_Line6,fun2ms}}, As0},Bound) ->
- %% Packages...
- {transform_call(ets,Line,As0,Bound),Bound};
copy({call,Line,{remote,_Line2,{atom,_Line3,dbg},{atom,_Line4,fun2ms}},
As0},Bound) ->
{transform_call(dbg,Line,As0,Bound),Bound};
diff --git a/lib/stdlib/src/shell.erl b/lib/stdlib/src/shell.erl
index c73cf22943..9bb48cb157 100644
--- a/lib/stdlib/src/shell.erl
+++ b/lib/stdlib/src/shell.erl
@@ -1496,8 +1496,8 @@ catch_exception(Bool) ->
PromptFunc :: 'default' | {module(),atom()},
PromptFunc2 :: 'default' | {module(),atom()}.
-prompt_func(String) ->
- set_env(stdlib, shell_prompt_func, String, ?DEF_PROMPT_FUNC).
+prompt_func(PromptFunc) ->
+ set_env(stdlib, shell_prompt_func, PromptFunc, ?DEF_PROMPT_FUNC).
-spec strings(Strings) -> Strings2 when
Strings :: boolean(),
diff --git a/lib/stdlib/src/stdlib.app.src b/lib/stdlib/src/stdlib.app.src
index 2bff791c93..6ade386159 100644
--- a/lib/stdlib/src/stdlib.app.src
+++ b/lib/stdlib/src/stdlib.app.src
@@ -108,7 +108,6 @@
dets]},
{applications, [kernel]},
{env, []},
- {runtime_dependencies, ["sasl-3.0","kernel-6.0","erts-10.6","crypto-3.3",
+ {runtime_dependencies, ["sasl-3.0","kernel-6.0","erts-10.6.2","crypto-3.3",
"compiler-5.0"]}
]}.
-
diff --git a/lib/stdlib/src/stdlib.appup.src b/lib/stdlib/src/stdlib.appup.src
index 20d93f1fee..c9c060f575 100644
--- a/lib/stdlib/src/stdlib.appup.src
+++ b/lib/stdlib/src/stdlib.appup.src
@@ -29,6 +29,9 @@
{"%VSN%",
[{<<"^3\\.10$">>,[restart_new_emulator]},
{<<"^3\\.10\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.11$">>,[restart_new_emulator]},
+ {<<"^3\\.11\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.11\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^3\\.5$">>,[restart_new_emulator]},
{<<"^3\\.5\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.5\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
@@ -47,6 +50,9 @@
{<<"^3\\.9\\.2(?:\\.[0-9]+)*$">>,[restart_new_emulator]}],
[{<<"^3\\.10$">>,[restart_new_emulator]},
{<<"^3\\.10\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.11$">>,[restart_new_emulator]},
+ {<<"^3\\.11\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
+ {<<"^3\\.11\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
{<<"^3\\.5$">>,[restart_new_emulator]},
{<<"^3\\.5\\.0(?:\\.[0-9]+)+$">>,[restart_new_emulator]},
{<<"^3\\.5\\.1(?:\\.[0-9]+)*$">>,[restart_new_emulator]},
diff --git a/lib/stdlib/src/uri_string.erl b/lib/stdlib/src/uri_string.erl
index 18ee8375c7..315e5700eb 100644
--- a/lib/stdlib/src/uri_string.erl
+++ b/lib/stdlib/src/uri_string.erl
@@ -297,10 +297,7 @@
NormalizedURI :: uri_string()
| error().
normalize(URIMap) ->
- try normalize(URIMap, [])
- catch
- throw:{error, Atom, RestData} -> {error, Atom, RestData}
- end.
+ normalize(URIMap, []).
-spec normalize(URI, Options) -> NormalizedURI when
@@ -309,20 +306,32 @@ normalize(URIMap) ->
NormalizedURI :: uri_string() | uri_map()
| error().
normalize(URIMap, []) when is_map(URIMap) ->
- recompose(normalize_map(URIMap));
+ try recompose(normalize_map(URIMap))
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end;
normalize(URIMap, [return_map]) when is_map(URIMap) ->
- normalize_map(URIMap);
+ try normalize_map(URIMap)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end;
normalize(URIString, []) ->
case parse(URIString) of
Value when is_map(Value) ->
- recompose(normalize_map(Value));
+ try recompose(normalize_map(Value))
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end;
Error ->
Error
end;
normalize(URIString, [return_map]) ->
case parse(URIString) of
Value when is_map(Value) ->
- normalize_map(Value);
+ try normalize_map(Value)
+ catch
+ throw:{error, Atom, RestData} -> {error, Atom, RestData}
+ end;
Error ->
Error
end.
diff --git a/lib/stdlib/test/calendar_SUITE.erl b/lib/stdlib/test/calendar_SUITE.erl
index 224c0d5625..bea5a217db 100644
--- a/lib/stdlib/test/calendar_SUITE.erl
+++ b/lib/stdlib/test/calendar_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1997-2019. All Rights Reserved.
+%% Copyright Ericsson AB 1997-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -223,6 +223,7 @@ rfc3339(Config) when is_list(Config) ->
{'EXIT', _} = (catch do_format_z(253402300799+1, [])),
{'EXIT', _} = (catch do_parse("9999-12-31T23:59:60Z", [])),
{'EXIT', _} = (catch do_format_z(253402300799*1000000000+999999999+1, Ns)),
+ {'EXIT', _} = (catch do_parse("2010-04-11T22:35:41", [])), % OTP-16514
253402300799 = do_parse("9999-12-31T23:59:59Z", []),
"0000-01-01T00:00:00Z" = test_parse("0000-01-01T00:00:00.0+00:00"),
diff --git a/lib/stdlib/test/erl_eval_SUITE.erl b/lib/stdlib/test/erl_eval_SUITE.erl
index 2436c8091c..c7556f6f7e 100644
--- a/lib/stdlib/test/erl_eval_SUITE.erl
+++ b/lib/stdlib/test/erl_eval_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 1998-2018. All Rights Reserved.
+%% Copyright Ericsson AB 1998-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -48,7 +48,8 @@
zero_width/1,
eep37/1,
eep43/1,
- otp_15035/1]).
+ otp_15035/1,
+ otp_16439/1]).
%%
%% Define to run outside of test server
@@ -88,7 +89,7 @@ all() ->
otp_6539, otp_6543, otp_6787, otp_6977, otp_7550,
otp_8133, otp_10622, otp_13228, otp_14826,
funs, try_catch, eval_expr_5, zero_width,
- eep37, eep43, otp_15035].
+ eep37, eep43, otp_15035, otp_16439].
groups() ->
[].
@@ -1666,6 +1667,17 @@ otp_15035(Config) when is_list(Config) ->
{e, d}),
ok.
+otp_16439(Config) when is_list(Config) ->
+ check(fun() -> + - 5 end, "+ - 5.", -5),
+ check(fun() -> - + - 5 end, "- + - 5.", 5),
+ check(fun() -> case 7 of - - 7 -> seven end end,
+ "case 7 of - - 7 -> seven end.", seven),
+
+ {ok,Ts,_} = erl_scan:string("- #{}. "),
+ {ok,[{op,1,'-',{map,1,[]}}]} = erl_parse:parse_exprs(Ts),
+
+ ok.
+
%% Check the string in different contexts: as is; in fun; from compiled code.
check(F, String, Result) ->
check1(F, String, Result),
diff --git a/lib/stdlib/test/erl_pp_SUITE.erl b/lib/stdlib/test/erl_pp_SUITE.erl
index c0cfd26925..48152243f8 100644
--- a/lib/stdlib/test/erl_pp_SUITE.erl
+++ b/lib/stdlib/test/erl_pp_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2006-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2006-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -52,7 +52,8 @@
otp_6321/1, otp_6911/1, otp_6914/1, otp_8150/1, otp_8238/1,
otp_8473/1, otp_8522/1, otp_8567/1, otp_8664/1, otp_9147/1,
otp_10302/1, otp_10820/1, otp_11100/1, otp_11861/1, pr_1014/1,
- otp_13662/1, otp_14285/1, otp_15592/1, otp_15751/1, otp_15755/1]).
+ otp_13662/1, otp_14285/1, otp_15592/1, otp_15751/1, otp_15755/1,
+ otp_16435/1]).
%% Internal export.
-export([ehook/6]).
@@ -82,7 +83,7 @@ groups() ->
[otp_6321, otp_6911, otp_6914, otp_8150, otp_8238,
otp_8473, otp_8522, otp_8567, otp_8664, otp_9147,
otp_10302, otp_10820, otp_11100, otp_11861, pr_1014, otp_13662,
- otp_14285, otp_15592, otp_15751, otp_15755]}].
+ otp_14285, otp_15592, otp_15751, otp_15755, otp_16435]}].
init_per_suite(Config) ->
Config.
@@ -1189,36 +1190,34 @@ otp_15592(_Config) ->
ok.
otp_15751(_Config) ->
- ok = pp_expr(<<"try foo:bar()
- catch
- Reason : Stacktrace ->
- {Reason, Stacktrace}
- end">>),
- ok = pp_expr(<<"try foo:bar()
- catch
- throw: Reason : Stacktrace ->
- {Reason, Stacktrace}
- end">>),
- ok = pp_expr(<<"try foo:bar()
- catch
- Reason : _ ->
- Reason
- end">>),
- ok = pp_expr(<<"try foo:bar()
- catch
- throw: Reason : _ ->
- Reason
- end">>),
- ok = pp_expr(<<"try foo:bar()
- catch
- Reason ->
- Reason
- end">>),
- ok = pp_expr(<<"try foo:bar()
- catch
- throw: Reason ->
- Reason
- end">>),
+ Check = fun(L) ->
+ ok = pp_expr(L),
+ remove_indentation(flat_parse_and_pp_expr(L, 0, []))
+ end,
+ "try foo:bar() catch Reason:Stacktrace -> {Reason, Stacktrace} end" =
+ Check("try foo:bar()
+ catch Reason:Stacktrace -> {Reason, Stacktrace} end"),
+
+ "try foo:bar() catch throw:Reason:Stacktrace -> {Reason, Stacktrace} end" =
+ Check("try foo:bar()
+ catch throw:Reason:Stacktrace -> {Reason, Stacktrace} end"),
+
+ "try foo:bar() catch Reason:_ -> Reason end" =
+ Check("try foo:bar()
+ catch Reason:_ -> Reason end"),
+
+ "try foo:bar() catch throw:Reason -> Reason end" = % ":_" removed
+ Check("try foo:bar()
+ catch throw:Reason:_-> Reason end"),
+
+ "try foo:bar() catch throw:Reason -> Reason end" = % "throw:" added
+ Check("try foo:bar()
+ catch Reason -> Reason end"),
+
+ "try foo:bar() catch throw:Reason -> Reason end" =
+ Check("try foo:bar()
+ catch throw:Reason -> Reason end"),
+
ok.
otp_15755(_Config) ->
@@ -1261,6 +1260,45 @@ otp_15755(_Config) ->
" 'sf s sdf', [], {}, {[]}}.", [])),
ok.
+otp_16435(_Config) ->
+ CheckF = fun(S) -> S = lists:flatten(parse_and_pp_forms(S, [])) end,
+ CheckF("-type t() :: A :: integer().\n"),
+ CheckF("-type t() :: A :: (B :: integer()).\n"),
+ CheckF("-type t() :: {A :: (B :: integer())}.\n"),
+ CheckF("-record(r,{f :: {A :: (B :: integer())}}).\n"),
+ CheckF("-record(r,{f = 3 :: {A :: (B :: integer())}}).\n"),
+ CheckF("-type t() :: #r{f :: A :: (B :: integer())}.\n"),
+ CheckF("-spec t(X) -> X when X :: Y :: (Z :: #r{}).\n"),
+
+ CheckF("f() ->\n << \n (catch <<1:4>>) ||\n"
+ " A <- []\n >>.\n"),
+ CheckF("f() ->\n [ \n (catch foo) ||\n A <- []\n ].\n"),
+
+
+ Check = fun(S) -> S = flat_parse_and_pp_expr(S, 0, []) end,
+ Check("5 #r4.f1"),
+ Check("17 #{[] => true}"),
+ Check("0 #r1{f2 = foo}"),
+ Check("fun foo:bar/17 #{}"),
+ Check("fun a/2 #{}"),
+
+ Check("try foo:bar() of\n"
+ " a ->\n"
+ " b\n"
+ "after\n"
+ " d\n"
+ "end"),
+
+ Check("try foo:bar() of\n"
+ " a ->\n"
+ " b\n"
+ "catch\n"
+ " _:_ ->\n"
+ " c\n"
+ "end"),
+
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
compile(Config, Tests) ->
diff --git a/lib/stdlib/test/ets_SUITE.erl b/lib/stdlib/test/ets_SUITE.erl
index b7fe664f12..7f349c1bb5 100644
--- a/lib/stdlib/test/ets_SUITE.erl
+++ b/lib/stdlib/test/ets_SUITE.erl
@@ -50,6 +50,7 @@
fixtable_next/1, fixtable_insert/1, rename/1, rename_unnamed/1, evil_rename/1,
update_element/1, update_counter/1, evil_update_counter/1, partly_bound/1, match_heavy/1]).
-export([update_counter_with_default/1]).
+-export([update_counter_with_default_bad_pos/1]).
-export([update_counter_table_growth/1]).
-export([member/1]).
-export([memory/1]).
@@ -131,7 +132,9 @@ all() ->
interface_equality, fixtable_next, fixtable_insert,
rename, rename_unnamed, evil_rename, update_element,
update_counter, evil_update_counter,
- update_counter_with_default, partly_bound,
+ update_counter_with_default,
+ update_counter_with_default_bad_pos,
+ partly_bound,
update_counter_table_growth,
match_heavy, {group, fold}, member, t_delete_object,
select_bound_chunk,
@@ -2376,35 +2379,76 @@ update_counter_with_default_do(Opts) ->
T1 = ets_new(a, [set | Opts]),
%% Insert default object.
3 = ets:update_counter(T1, foo, 2, {beaufort,1}),
+ 1 = ets:info(T1, size),
%% Increment.
5 = ets:update_counter(T1, foo, 2, {cabecou,1}),
+ 1 = ets:info(T1, size),
%% Increment with list.
[9] = ets:update_counter(T1, foo, [{2,4}], {camembert,1}),
+ 1 = ets:info(T1, size),
%% Same with non-immediate key.
3 = ets:update_counter(T1, {foo,bar}, 2, {{chaource,chevrotin},1}),
+ 2 = ets:info(T1, size),
5 = ets:update_counter(T1, {foo,bar}, 2, {{cantal,comté},1}),
+ 2 = ets:info(T1, size),
[9] = ets:update_counter(T1, {foo,bar}, [{2,4}], {{emmental,de,savoie},1}),
+ 2 = ets:info(T1, size),
+ %% default counter is not an integer.
+ {'EXIT',{badarg,_}} = (catch ets:update_counter(T1, qux, 3, {saint,félicien})),
+ 2 = ets:info(T1, size),
+ %% No third element in default value.
+ {'EXIT',{badarg,_}} = (catch ets:update_counter(T1, qux, [{3,1}], {roquefort,1})),
+ 2 = ets:info(T1, size),
+
%% Same with ordered set.
T2 = ets_new(b, [ordered_set | Opts]),
3 = ets:update_counter(T2, foo, 2, {maroilles,1}),
+ 1 = ets:info(T2, size),
5 = ets:update_counter(T2, foo, 2, {mimolette,1}),
+ 1 = ets:info(T2, size),
[9] = ets:update_counter(T2, foo, [{2,4}], {morbier,1}),
+ 1 = ets:info(T2, size),
3 = ets:update_counter(T2, {foo,bar}, 2, {{laguiole},1}),
+ 2 = ets:info(T2, size),
5 = ets:update_counter(T2, {foo,bar}, 2, {{saint,nectaire},1}),
+ 2 = ets:info(T2, size),
[9] = ets:update_counter(T2, {foo,bar}, [{2,4}], {{rocamadour},1}),
+ 2 = ets:info(T2, size),
%% Arithmetically-equal keys.
3 = ets:update_counter(T2, 1.0, 2, {1,1}),
+ 3 = ets:info(T2, size),
5 = ets:update_counter(T2, 1, 2, {1,1}),
+ 3 = ets:info(T2, size),
7 = ets:update_counter(T2, 1, 2, {1.0,1}),
+ 3 = ets:info(T2, size),
%% Same with reversed type difference.
3 = ets:update_counter(T2, 2, 2, {2.0,1}),
+ 4 = ets:info(T2, size),
5 = ets:update_counter(T2, 2.0, 2, {2.0,1}),
+ 4 = ets:info(T2, size),
7 = ets:update_counter(T2, 2.0, 2, {2,1}),
- %% bar is not an integer.
+ 4 = ets:info(T2, size),
+ %% default counter is not an integer.
{'EXIT',{badarg,_}} = (catch ets:update_counter(T1, qux, 3, {saint,félicien})),
+ 4 = ets:info(T2, size),
%% No third element in default value.
{'EXIT',{badarg,_}} = (catch ets:update_counter(T1, qux, [{3,1}], {roquefort,1})),
+ 4 = ets:info(T2, size),
+ ok.
+%% ERL-1125
+update_counter_with_default_bad_pos(Config) when is_list(Config) ->
+ repeat_for_all_ord_set_table_types(fun update_counter_with_default_bad_pos_do/1).
+
+update_counter_with_default_bad_pos_do(Opts) ->
+ T = ets_new(a, Opts),
+ 0 = ets:info(T, size),
+ ok = try ets:update_counter(T, 101065, {1, 1}, {101065, 0})
+ catch
+ error:badarg -> ok;
+ Class:Reason -> {Class, Reason}
+ end,
+ 0 = ets:info(T, size),
ok.
update_counter_table_growth(_Config) ->
diff --git a/lib/stdlib/test/gen_statem_SUITE.erl b/lib/stdlib/test/gen_statem_SUITE.erl
index aa4d258cbf..296973370c 100644
--- a/lib/stdlib/test/gen_statem_SUITE.erl
+++ b/lib/stdlib/test/gen_statem_SUITE.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2016-2019. All Rights Reserved.
+%% Copyright Ericsson AB 2016-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -68,7 +68,8 @@ tcs(sys) ->
error_format_status, terminate_crash_format,
get_state, replace_state];
tcs(undef_callbacks) ->
- [undef_code_change, undef_terminate1, undef_terminate2].
+ [undef_code_change, undef_terminate1, undef_terminate2,
+ pop_too_many].
init_per_suite(Config) ->
Config.
@@ -83,9 +84,7 @@ init_per_group(GroupName, Config)
GroupName =:= sys_handle_event ->
[{callback_mode,handle_event_function}|Config];
init_per_group(undef_callbacks, Config) ->
- DataDir = ?config(data_dir, Config),
- StatemPath = filename:join(DataDir, "oc_statem.erl"),
- {ok, oc_statem} = compile:file(StatemPath),
+ compile_oc_statem(Config),
Config;
init_per_group(_GroupName, Config) ->
Config.
@@ -98,6 +97,9 @@ init_per_testcase(_CaseName, Config) ->
%%% dbg:tracer(),
%%% dbg:p(all, c),
%%% dbg:tpl(gen_statem, cx),
+%%% dbg:tpl(gen_statem, loop_receive, cx),
+%%% dbg:tpl(gen_statem, loop_state_callback, cx),
+%%% dbg:tpl(gen_statem, loop_callback_mode_result, cx),
%%% dbg:tpl(proc_lib, cx),
%%% dbg:tpl(gen, cx),
%%% dbg:tpl(sys, cx),
@@ -107,6 +109,12 @@ end_per_testcase(_CaseName, Config) ->
%%% dbg:stop(),
Config.
+compile_oc_statem(Config) ->
+ DataDir = ?config(data_dir, Config),
+ StatemPath = filename:join(DataDir, "oc_statem.erl"),
+ {ok, oc_statem} = compile:file(StatemPath),
+ ok.
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-define(EXPECT_FAILURE(Code, Reason),
try begin Code end of
@@ -1722,7 +1730,7 @@ enter_loop(Reg1, Reg2, Opts) ->
end.
undef_code_change(_Config) ->
- {ok, Statem} = gen_statem:start(oc_statem, [], []),
+ {ok, Statem} = gen_statem:start(oc_statem, [], [{debug, [trace]}]),
{error, {'EXIT',
{undef, [{oc_statem, code_change, [_, _, _, _], _}|_]}}}
= fake_upgrade(Statem, oc_statem).
@@ -1735,7 +1743,7 @@ fake_upgrade(Pid, Mod) ->
Ret.
undef_terminate1(_Config) ->
- {ok, Statem} = gen_statem:start(oc_statem, [], []),
+ {ok, Statem} = gen_statem:start(oc_statem, [], [{debug,[trace]}]),
MRef = monitor(process, Statem),
ok = gen_statem:stop(Statem),
verify_down(Statem, MRef, normal),
@@ -1743,7 +1751,7 @@ undef_terminate1(_Config) ->
undef_terminate2(_Config) ->
Reason = {error, test},
- {ok, Statem} = oc_statem:start(),
+ {ok, Statem} = oc_statem:start([{debug,[trace]}]),
MRef = monitor(process, Statem),
ok = gen_statem:stop(Statem, Reason, infinity),
verify_down(Statem, MRef, Reason).
@@ -1769,6 +1777,54 @@ verify_down(Statem, MRef, Reason) ->
ct:fail(default_terminate_failed)
end.
+
+pop_too_many(_Config) ->
+ _ = process_flag(trap_exit, true),
+
+ Machine =
+ #{init =>
+ fun () ->
+ {ok,start,undefined}
+ end,
+ start =>
+ fun ({call, From}, {change_callback_module, _Module} = Action,
+ undefined = _Data) ->
+ {keep_state_and_data,
+ [Action,
+ {reply,From,ok}]};
+ ({call, From}, {verify, ?MODULE},
+ undefined = _Data) ->
+ {keep_state_and_data,
+ [{reply,From,ok}]};
+ ({call, From}, pop_callback_module = Action,
+ undefined = _Data) ->
+ {keep_state_and_data,
+ [Action,
+ {reply,From,ok}]}
+ end},
+ {ok, STM} =
+ gen_statem:start_link(
+ ?MODULE,
+ {map_statem, Machine, []},
+ [{debug, [trace]}]),
+
+ ok = gen_statem:call(STM, {change_callback_module, oc_statem}),
+ ok = gen_statem:call(STM, {push_callback_module, ?MODULE}),
+ ok = gen_statem:call(STM, {verify, ?MODULE}),
+ ok = gen_statem:call(STM, pop_callback_module),
+ BadAction = {bad_action_from_state_function, pop_callback_module},
+ {{BadAction, _},
+ {gen_statem,call,[STM,pop_callback_module,infinity]}} =
+ ?EXPECT_FAILURE(gen_statem:call(STM, pop_callback_module), Reason),
+
+ receive
+ {'EXIT', STM, {BadAction, _}} ->
+ ok;
+ Other ->
+ ct:fail({surprise, Other})
+ end.
+
+
%% Test the order for multiple {next_event,T,C}
next_events(Config) ->
{ok,Pid} = gen_statem:start(?MODULE, start_arg(Config, []), []),
diff --git a/lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl b/lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl
index 27c9e0718d..1bcd08867f 100644
--- a/lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl
+++ b/lib/stdlib/test/gen_statem_SUITE_data/oc_statem.erl
@@ -1,7 +1,7 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2017. All Rights Reserved.
+%% Copyright Ericsson AB 2017-2020. All Rights Reserved.
%%
%% Licensed under the Apache License, Version 2.0 (the "License");
%% you may not use this file except in compliance with the License.
@@ -22,16 +22,31 @@
-behaviour(gen_statem).
%% API
--export([start/0]).
+-export([start/1]).
%% gen_statem callbacks
--export([init/1, callback_mode/0]).
+-export([init/1, callback_mode/0, handle_event/4]).
-start() ->
- gen_statem:start({local, ?MODULE}, ?MODULE, [], []).
+start(Opts) ->
+ gen_statem:start({local, ?MODULE}, ?MODULE, [], Opts).
init([]) ->
- {ok, state_name, #{}}.
+ {ok, start, #{}}.
callback_mode() ->
- handle_event_function.
+ [handle_event_function, state_enter].
+
+handle_event(enter, start, start, _Data) ->
+ keep_state_and_data;
+handle_event(
+ {call,From}, {push_callback_module,NewModule} = Action,
+ start, _Data) ->
+ {keep_state_and_data,
+ [Action,
+ {reply,From,ok}]};
+handle_event(
+ {call,From}, pop_callback_module = Action,
+ start, _Data) ->
+ {keep_state_and_data,
+ [Action,
+ {reply,From,ok}]}.
diff --git a/lib/stdlib/test/tar_SUITE.erl b/lib/stdlib/test/tar_SUITE.erl
index 32a33283d1..fb2b7dc45d 100644
--- a/lib/stdlib/test/tar_SUITE.erl
+++ b/lib/stdlib/test/tar_SUITE.erl
@@ -578,19 +578,22 @@ extract_from_open_file(Config) when is_list(Config) ->
symlinks(Config) when is_list(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
Dir = filename:join(PrivDir, "symlinks"),
+ VulnerableDir = filename:join(PrivDir, "vulnerable_symlinks"),
ok = file:make_dir(Dir),
+ ok = file:make_dir(VulnerableDir),
ABadSymlink = filename:join(Dir, "bad_symlink"),
- PointsTo = "/a/definitely/non_existing/path",
- Res = case make_symlink("/a/definitely/non_existing/path", ABadSymlink) of
+ PointsTo = "a/definitely/non_existing/path",
+ Res = case make_symlink("a/definitely/non_existing/path", ABadSymlink) of
{error, enotsup} ->
{skip, "Symbolic links not supported on this platform"};
ok ->
symlinks(Dir, "bad_symlink", PointsTo),
- long_symlink(Dir)
+ long_symlink(Dir),
+ symlink_vulnerability(VulnerableDir)
end,
%% Clean up.
- delete_files([Dir]),
+ delete_files([Dir,VulnerableDir]),
verify_ports(Config),
Res.
@@ -678,7 +681,7 @@ long_symlink(Dir) ->
ok = file:set_cwd(Dir),
AFile = "long_symlink",
- RequiresPAX = "/tmp/aarrghh/this/path/is/far/longer/than/one/hundred/characters/which/is/the/maximum/number/of/characters/allowed",
+ RequiresPAX = "tmp/aarrghh/this/path/is/far/longer/than/one/hundred/characters/which/is/the/maximum/number/of/characters/allowed",
ok = file:make_symlink(RequiresPAX, AFile),
ok = erl_tar:create(Tar, [AFile], [verbose]),
false = is_ustar(Tar),
@@ -690,6 +693,23 @@ long_symlink(Dir) ->
{ok, RequiresPAX} = file:read_link(AFile),
ok.
+symlink_vulnerability(Dir) ->
+ ok = file:set_cwd(Dir),
+ ok = file:make_dir("tar"),
+ ok = file:set_cwd("tar"),
+ ok = file:make_symlink("..", "link"),
+ ok = file:write_file("../file", <<>>),
+ ok = erl_tar:create("../my.tar", ["link","link/file"]),
+ ok = erl_tar:tt("../my.tar"),
+
+ ok = file:set_cwd(Dir),
+ delete_files(["file","tar"]),
+ ok = file:make_dir("tar"),
+ ok = file:set_cwd("tar"),
+ {error,{"..",unsafe_symlink}} = erl_tar:extract("../my.tar"),
+
+ ok.
+
init(Config) when is_list(Config) ->
PrivDir = proplists:get_value(priv_dir, Config),
ok = file:set_cwd(PrivDir),
diff --git a/lib/stdlib/test/uri_string_SUITE.erl b/lib/stdlib/test/uri_string_SUITE.erl
index 55ba75bd5f..0829fcd915 100644
--- a/lib/stdlib/test/uri_string_SUITE.erl
+++ b/lib/stdlib/test/uri_string_SUITE.erl
@@ -29,6 +29,7 @@
normalize_pct_encoded_userinfo/1,
normalize_pct_encoded_query/1,
normalize_pct_encoded_fragment/1,
+ normalize_pct_encoded_negative/1,
parse_binary_fragment/1, parse_binary_host/1, parse_binary_host_ipv4/1,
parse_binary_host_ipv6/1,
parse_binary_path/1, parse_binary_pct_encoded_fragment/1, parse_binary_pct_encoded_query/1,
@@ -86,6 +87,7 @@ all() ->
normalize_pct_encoded_userinfo,
normalize_pct_encoded_query,
normalize_pct_encoded_fragment,
+ normalize_pct_encoded_negative,
parse_binary_scheme,
parse_binary_userinfo,
parse_binary_pct_encoded_userinfo,
@@ -1139,6 +1141,16 @@ normalize_pct_encoded_fragment(_Config) ->
#{host := "example.com", path := "/", fragment := "合気道"} =
uri_string:normalize("//example.com/#%E5%90%88%E6%B0%97%E9%81%93", [return_map]).
+normalize_pct_encoded_negative(_Config) ->
+ {error,invalid_utf8,<<0,0,0,246>>} =
+ uri_string:normalize(#{host => "%00%00%00%F6",path => []}, [return_map]),
+ {error,invalid_utf8,<<0,0,0,246>>} =
+ uri_string:normalize(#{host => "%00%00%00%F6",path => []}, []),
+ {error,invalid_utf8,<<0,0,0,246>>} =
+ uri_string:normalize("//%00%00%00%F6", [return_map]),
+ {error,invalid_utf8,<<0,0,0,246>>} =
+ uri_string:normalize("//%00%00%00%F6", []).
+
interop_query_utf8(_Config) ->
Q = uri_string:compose_query([{"foo bar","1"}, {"合", "2"}]),
Uri = uri_string:recompose(#{path => "/", query => Q}),
diff --git a/lib/stdlib/vsn.mk b/lib/stdlib/vsn.mk
index 6f74c2cd06..dae9e1fd64 100644
--- a/lib/stdlib/vsn.mk
+++ b/lib/stdlib/vsn.mk
@@ -1 +1 @@
-STDLIB_VSN = 3.11
+STDLIB_VSN = 3.11.2
diff --git a/lib/tools/emacs/erlang.el b/lib/tools/emacs/erlang.el
index 838c41a090..dafb9d56ac 100644
--- a/lib/tools/emacs/erlang.el
+++ b/lib/tools/emacs/erlang.el
@@ -4,7 +4,7 @@
;; Author: Anders Lindgren
;; Keywords: erlang, languages, processes
;; Date: 2011-12-11
-;; Version: 2.8.3
+;; Version: 2.8.4
;; Package-Requires: ((emacs "24.3"))
;; %CopyrightBegin%
@@ -87,7 +87,7 @@
"The Erlang programming language."
:group 'languages)
-(defconst erlang-version "2.8.3"
+(defconst erlang-version "2.8.4"
"The version number of Erlang mode.")
(defcustom erlang-root-dir nil
@@ -2890,7 +2890,7 @@ Value is list (stack token-start token-type in-what)."
((looking-at "-type\\s \\|-opaque\\s ")
(if stack
(forward-char 1)
- (erlang-push (list 'icr token (current-column)) stack)
+ (erlang-push (list 'type token (current-column)) stack)
(forward-char 6)))
((looking-at "-spec\\s ")
(if stack
@@ -2933,7 +2933,7 @@ Value is list (stack token-start token-type in-what)."
(erlang-pop stack)
(if (and (eq (car (car stack)) 'fun)
(or (eq (car (car (last stack))) 'spec)
- (eq (car (car (cdr stack))) '::))) ;; -type()
+ (eq (car (car (last stack))) 'type))) ;; -type()
;; Inside fun type def ') closes fun definition
(erlang-pop stack)))
((eq (car (car stack)) 'icr)
@@ -2995,7 +2995,9 @@ Return nil if inside string, t if in a comment."
(- (+ previous erlang-argument-indent) 1))))
(t
(nth 2 stack-top))))
- ((= (following-char) ?,)
+ ((looking-at "||")
+ (erlang-indent-element stack-top indent-point token))
+ ((memq (following-char) '(?, ?|))
;; a comma at the start of the line: line up with opening parenthesis.
(min (nth 2 stack-top)
(erlang-indent-element stack-top indent-point token)))
@@ -3033,9 +3035,9 @@ Return nil if inside string, t if in a comment."
(save-excursion
(goto-char (nth 1 stack-top))
(if (and erlang-icr-indent
- (looking-at "\\(if\\|case\\|receive\\)[^_a-zA-Z0-9]"))
+ (looking-at "\\(if\\|case\\|receive\\|try\\)[^_a-zA-Z0-9]"))
(+ (nth 2 stack-top) erlang-icr-indent)
- (if (looking-at "\\(case\\|receive\\)[^_a-zA-Z0-9]")
+ (if (looking-at "\\(case\\|receive\\|try\\)[^_a-zA-Z0-9]")
(+ (nth 2 stack-top) erlang-indent-level)
(skip-chars-forward "a-z")
(skip-chars-forward " \t")
diff --git a/lib/tools/src/cover.erl b/lib/tools/src/cover.erl
index 2b3af417b6..80af13a4c3 100644
--- a/lib/tools/src/cover.erl
+++ b/lib/tools/src/cover.erl
@@ -1722,7 +1722,10 @@ bool_switch(E, T, F, AllVars, AuxVarN) ->
{'case',Line,E,
[{clause,Line,[{atom,Line,true}],[],[T]},
{clause,Line,[{atom,Line,false}],[],[F]},
- {clause,Line,[AuxVar],[],
+ %% Mark the next clause as compiler-generated to suppress
+ %% a warning if the case expression is an obvious boolean
+ %% value.
+ {clause,erl_anno:set_generated(true, Line),[AuxVar],[],
[{call,Line,
{remote,Line,{atom,Line,erlang},{atom,Line,error}},
[{tuple,Line,[{atom,Line,badarg},AuxVar]}]}]}]}.
diff --git a/lib/tools/src/fprof.erl b/lib/tools/src/fprof.erl
index 36d4828861..369fbb2d42 100644
--- a/lib/tools/src/fprof.erl
+++ b/lib/tools/src/fprof.erl
@@ -2782,6 +2782,8 @@ parsify({A, B, C}) ->
{parsify(A), parsify(B), parsify(C)};
parsify(Tuple) when is_tuple(Tuple) ->
list_to_tuple(parsify(tuple_to_list(Tuple)));
+parsify(Map) when is_map(Map) ->
+ maps:from_list(parsify(maps:to_list(Map)));
parsify(Pid) when is_pid(Pid) ->
erlang:pid_to_list(Pid);
parsify(Port) when is_port(Port) ->
diff --git a/lib/tools/test/cover_SUITE.erl b/lib/tools/test/cover_SUITE.erl
index 462767f430..0de73bc3d7 100644
--- a/lib/tools/test/cover_SUITE.erl
+++ b/lib/tools/test/cover_SUITE.erl
@@ -37,7 +37,7 @@ all() ->
dont_reconnect_after_stop, stop_node_after_disconnect,
export_import, otp_5031, otp_6115,
otp_8270, otp_10979_hanging_node, otp_14817,
- local_only, startup_race],
+ local_only, startup_race, otp_16476],
case whereis(cover_server) of
undefined ->
[coverage,StartStop ++ NoStartStop];
@@ -1803,6 +1803,17 @@ startup_race_1([]) ->
cover:stop(),
ok.
+otp_16476(Config) when is_list(Config) ->
+ Mod = obvious_booleans,
+ Dir = filename:join(proplists:get_value(data_dir, Config),
+ ?FUNCTION_NAME),
+ ok = file:set_cwd(Dir),
+ {ok, Mod} = compile:file(Mod, [debug_info]),
+ {ok, Mod} = cover:compile(Mod),
+ ok = Mod:Mod(),
+ ok = cover:stop(),
+ ok.
+
%%--Auxiliary------------------------------------------------------------
analyse_expr(Expr, Config) ->
diff --git a/lib/tools/test/cover_SUITE_data/otp_16476/obvious_booleans.erl b/lib/tools/test/cover_SUITE_data/otp_16476/obvious_booleans.erl
new file mode 100644
index 0000000000..1f383be0a5
--- /dev/null
+++ b/lib/tools/test/cover_SUITE_data/otp_16476/obvious_booleans.erl
@@ -0,0 +1,17 @@
+-module(obvious_booleans).
+-export([?MODULE/0]).
+-compile([warnings_as_errors]).
+
+?MODULE() ->
+ true = both_ok(ok, ok),
+ false = both_ok(ok, nok),
+ true = one_ok(ok, nok),
+ true = one_ok(nok, ok),
+ false = one_ok(nok, nok),
+ ok.
+
+both_ok(A, B) ->
+ A =:= ok andalso B =:= ok.
+
+one_ok(A, B) ->
+ A =:= ok orelse B =:= ok.
diff --git a/lib/tools/test/emacs_SUITE.erl b/lib/tools/test/emacs_SUITE.erl
index 42a1f395ec..9a0caa0867 100644
--- a/lib/tools/test/emacs_SUITE.erl
+++ b/lib/tools/test/emacs_SUITE.erl
@@ -214,11 +214,12 @@ emacs(EmacsCmds) when is_list(EmacsCmds) ->
"--directory ", dquote(emacs_dir()), " ",
"--eval \"(require 'erlang-start)\" "
| EmacsCmds],
+ io:format("Cmd: ~ts~n", [Cmd]),
Res0 = os:cmd(Cmd ++ " ; echo $?"),
Rows = string:lexemes(Res0, ["\r\n", $\n]),
Res = lists:last(Rows),
Output = string:join(lists:droplast(Rows), "\n"),
- io:format("Cmd ~ts:~n => ~s ~ts~n", [Cmd, Res, Output]),
+ io:format(" => ~s ~ts~n", [Res, Output]),
"0" = Res,
Output.
diff --git a/lib/tools/test/emacs_SUITE_data/type_specs b/lib/tools/test/emacs_SUITE_data/type_specs
index f9b15d7914..a72e90cf57 100644
--- a/lib/tools/test/emacs_SUITE_data/type_specs
+++ b/lib/tools/test/emacs_SUITE_data/type_specs
@@ -66,6 +66,30 @@
, b :: any()
}.
+
+-type combined() :: { atom(),
+ atom()
+ , integer()
+ }
+ | [ atom() |
+ atom()
+ | integer()
+ ].
+
+-type a_list1() :: [ atom() |
+ t()
+ | tuple()
+ ].
+
+
+-type a_list_with_fun() ::
+ %% ERL-1140
+ [ atom() |
+ fun()
+ | tuple()
+ ].
+
+
%% Spec
-spec t1(FooBar :: t99()) -> t99();
diff --git a/lib/tools/test/fprof_SUITE.erl b/lib/tools/test/fprof_SUITE.erl
index ae0e7253ad..cdb207c1e2 100644
--- a/lib/tools/test/fprof_SUITE.erl
+++ b/lib/tools/test/fprof_SUITE.erl
@@ -27,7 +27,7 @@
%% Test suites
-export([stack_seq/1, tail_seq/1, create_file_slow/1, spawn_simple/1,
imm_tail_seq/1, imm_create_file_slow/1, imm_compile/1,
- cpu_create_file_slow/1, unicode/1]).
+ cpu_create_file_slow/1, unicode/1, parsify_maps/1]).
%% Other exports
-export([create_file_slow/2]).
@@ -59,7 +59,7 @@ all() ->
false ->
[stack_seq, tail_seq, create_file_slow, spawn_simple,
imm_tail_seq, imm_create_file_slow, imm_compile,
- cpu_create_file_slow, unicode]
+ cpu_create_file_slow, unicode, parsify_maps]
end.
@@ -544,6 +544,35 @@ unicode(Config) when is_list(Config) ->
ok = fprof:profile(dump, AnalysisFile),
ok = fprof:analyse(dest, AnalysisFile).
+parsify_maps(Config) when is_list(Config) ->
+ Pid = self(),
+ Ref = make_ref(),
+ Port = hd(erlang:ports()),
+ Fun = fun () -> ok end,
+ M = #{pid => Pid, Pid => pid,
+ ref => Ref, Ref => ref,
+ port => Port, Port => port,
+ a_fun => Fun, Fun => a_fun},
+ io:format("M = ~p~n", [M]),
+ L = [{tuple, M}, M, #{my_map => M, M => my_map}],
+ PL = fprof:parsify(L),
+ [{tuple, PM}, PM, PMap] = PL,
+ #{my_map := PM, PM := my_map} = PMap,
+ io:format("PM = ~p~n", [PM]),
+ LPid = pid_to_list(Pid),
+ LRef = ref_to_list(Ref),
+ LPort = port_to_list(Port),
+ LFun = erlang:fun_to_list(Fun),
+ LPid = maps:get(pid, PM),
+ pid = maps:get(LPid, PM),
+ LRef = maps:get(ref, PM),
+ ref = maps:get(LRef, PM),
+ LPort = maps:get(port, PM),
+ port = maps:get(LPort, PM),
+ LFun = maps:get(a_fun, PM),
+ a_fun = maps:get(LFun, PM),
+ ok.
+
%%%---------------------------------------------------------------------
%%% Functions to test
%%%---------------------------------------------------------------------
diff --git a/make/otp_version_tickets_in_merge b/make/otp_version_tickets_in_merge
index f04e1d49f5..e69de29bb2 100644
--- a/make/otp_version_tickets_in_merge
+++ b/make/otp_version_tickets_in_merge
@@ -1,6 +0,0 @@
-OTP-16314
-OTP-16349
-OTP-16357
-OTP-16359
-OTP-16360
-OTP-16361
diff --git a/otp_versions.table b/otp_versions.table
index 47fdc5db8d..e9547c7ead 100644
--- a/otp_versions.table
+++ b/otp_versions.table
@@ -1,5 +1,13 @@
+OTP-22.2.8 : diameter-2.2.2 # asn1-5.0.9 common_test-1.18.1 compiler-7.5.2 crypto-4.6.4 debugger-4.2.8 dialyzer-4.1.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.1 erts-10.6.4 et-1.6.4 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 jinterface-1.10.1 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.1 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.5 ssh-4.8.2 ssl-9.5.3 stdlib-3.11.2 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 :
+OTP-22.2.7 : compiler-7.5.2 # asn1-5.0.9 common_test-1.18.1 crypto-4.6.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.1 erts-10.6.4 et-1.6.4 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 jinterface-1.10.1 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.1 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.5 ssh-4.8.2 ssl-9.5.3 stdlib-3.11.2 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 :
+OTP-22.2.6 : erts-10.6.4 # asn1-5.0.9 common_test-1.18.1 compiler-7.5.1 crypto-4.6.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.1 et-1.6.4 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 jinterface-1.10.1 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.1 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.5 ssh-4.8.2 ssl-9.5.3 stdlib-3.11.2 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 :
+OTP-22.2.5 : erts-10.6.3 stdlib-3.11.2 # asn1-5.0.9 common_test-1.18.1 compiler-7.5.1 crypto-4.6.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.1 et-1.6.4 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 jinterface-1.10.1 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.1 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.5 ssh-4.8.2 ssl-9.5.3 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 :
+OTP-22.2.4 : ssl-9.5.3 # asn1-5.0.9 common_test-1.18.1 compiler-7.5.1 crypto-4.6.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.1 erts-10.6.2 et-1.6.4 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 jinterface-1.10.1 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.1 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.5 ssh-4.8.2 stdlib-3.11.1 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 :
+OTP-22.2.3 : compiler-7.5.1 ssl-9.5.2 # asn1-5.0.9 common_test-1.18.1 crypto-4.6.4 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.1 erts-10.6.2 et-1.6.4 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 jinterface-1.10.1 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.1 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.5 ssh-4.8.2 stdlib-3.11.1 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 :
+OTP-22.2.2 : crypto-4.6.4 erts-10.6.2 ssh-4.8.2 stdlib-3.11.1 # asn1-5.0.9 common_test-1.18.1 compiler-7.5 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.1 et-1.6.4 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 jinterface-1.10.1 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.1 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.5 ssl-9.5.1 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 :
OTP-22.2.1 : erts-10.6.1 snmp-5.4.5 ssl-9.5.1 # asn1-5.0.9 common_test-1.18.1 compiler-7.5 crypto-4.6.3 debugger-4.2.8 dialyzer-4.1.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.11 erl_interface-3.13.1 et-1.6.4 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 jinterface-1.10.1 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7.1 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 ssh-4.8.1 stdlib-3.11 syntax_tools-2.2.1 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 :
OTP-22.2 : common_test-1.18.1 compiler-7.5 crypto-4.6.3 debugger-4.2.8 dialyzer-4.1.1 erl_docgen-0.11 erl_interface-3.13.1 erts-10.6 eunit-2.4 ftp-1.0.4 hipe-3.19.2 inets-7.1.2 kernel-6.5.1 megaco-3.18.7 mnesia-4.16.2 observer-2.9.3 public_key-1.7.1 snmp-5.4.4 ssh-4.8.1 ssl-9.5 stdlib-3.11 tftp-1.0.2 tools-3.3 wx-1.9 xmerl-1.3.23 # asn1-5.0.9 diameter-2.2.1 edoc-0.11 eldap-1.2.8 et-1.6.4 jinterface-1.10.1 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 syntax_tools-2.2.1 :
+OTP-22.1.8.1 : snmp-5.4.3.1 # asn1-5.0.9 common_test-1.18 compiler-7.4.9 crypto-4.6.2 debugger-4.2.7 dialyzer-4.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.10 erl_interface-3.13 erts-10.5.6 et-1.6.4 eunit-2.3.8 ftp-1.0.3 hipe-3.19.1 inets-7.1.1 jinterface-1.10.1 kernel-6.5 megaco-3.18.6 mnesia-4.16.1 observer-2.9.2 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 ssh-4.8 ssl-9.4 stdlib-3.10 syntax_tools-2.2.1 tftp-1.0.1 tools-3.2.1 wx-1.8.9 xmerl-1.3.22 :
OTP-22.1.8 : erts-10.5.6 # asn1-5.0.9 common_test-1.18 compiler-7.4.9 crypto-4.6.2 debugger-4.2.7 dialyzer-4.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.10 erl_interface-3.13 et-1.6.4 eunit-2.3.8 ftp-1.0.3 hipe-3.19.1 inets-7.1.1 jinterface-1.10.1 kernel-6.5 megaco-3.18.6 mnesia-4.16.1 observer-2.9.2 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.3 ssh-4.8 ssl-9.4 stdlib-3.10 syntax_tools-2.2.1 tftp-1.0.1 tools-3.2.1 wx-1.8.9 xmerl-1.3.22 :
OTP-22.1.7 : compiler-7.4.9 erts-10.5.5 # asn1-5.0.9 common_test-1.18 crypto-4.6.2 debugger-4.2.7 dialyzer-4.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.10 erl_interface-3.13 et-1.6.4 eunit-2.3.8 ftp-1.0.3 hipe-3.19.1 inets-7.1.1 jinterface-1.10.1 kernel-6.5 megaco-3.18.6 mnesia-4.16.1 observer-2.9.2 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 snmp-5.4.3 ssh-4.8 ssl-9.4 stdlib-3.10 syntax_tools-2.2.1 tftp-1.0.1 tools-3.2.1 wx-1.8.9 xmerl-1.3.22 :
OTP-22.1.6 : compiler-7.4.8 crypto-4.6.2 erts-10.5.4 snmp-5.4.3 # asn1-5.0.9 common_test-1.18 debugger-4.2.7 dialyzer-4.1 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.10 erl_interface-3.13 et-1.6.4 eunit-2.3.8 ftp-1.0.3 hipe-3.19.1 inets-7.1.1 jinterface-1.10.1 kernel-6.5 megaco-3.18.6 mnesia-4.16.1 observer-2.9.2 odbc-2.12.4 os_mon-2.5.1 parsetools-2.1.8 public_key-1.7 reltool-0.8 runtime_tools-1.14 sasl-3.4.1 ssh-4.8 ssl-9.4 stdlib-3.10 syntax_tools-2.2.1 tftp-1.0.1 tools-3.2.1 wx-1.8.9 xmerl-1.3.22 :
@@ -17,6 +25,9 @@ OTP-22.0.3 : compiler-7.4.2 dialyzer-4.0.1 erts-10.4.2 ssl-9.3.2 stdlib-3.9.2 #
OTP-22.0.2 : compiler-7.4.1 crypto-4.5.1 erts-10.4.1 stdlib-3.9.1 # asn1-5.0.9 common_test-1.17.3 debugger-4.2.7 dialyzer-4.0 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.9.1 erl_interface-3.12 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.19 inets-7.0.8 jinterface-1.10 kernel-6.4 megaco-3.18.5 mnesia-4.16 observer-2.9.1 odbc-2.12.4 os_mon-2.5 parsetools-2.1.8 public_key-1.6.7 reltool-0.8 runtime_tools-1.13.3 sasl-3.4 snmp-5.3 ssh-4.7.7 ssl-9.3.1 syntax_tools-2.2 tftp-1.0.1 tools-3.2 wx-1.8.8 xmerl-1.3.21 :
OTP-22.0.1 : ssl-9.3.1 # asn1-5.0.9 common_test-1.17.3 compiler-7.4 crypto-4.5 debugger-4.2.7 dialyzer-4.0 diameter-2.2.1 edoc-0.11 eldap-1.2.8 erl_docgen-0.9.1 erl_interface-3.12 erts-10.4 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.19 inets-7.0.8 jinterface-1.10 kernel-6.4 megaco-3.18.5 mnesia-4.16 observer-2.9.1 odbc-2.12.4 os_mon-2.5 parsetools-2.1.8 public_key-1.6.7 reltool-0.8 runtime_tools-1.13.3 sasl-3.4 snmp-5.3 ssh-4.7.7 stdlib-3.9 syntax_tools-2.2 tftp-1.0.1 tools-3.2 wx-1.8.8 xmerl-1.3.21 :
OTP-22.0 : asn1-5.0.9 common_test-1.17.3 compiler-7.4 crypto-4.5 debugger-4.2.7 dialyzer-4.0 edoc-0.11 eldap-1.2.8 erl_docgen-0.9.1 erl_interface-3.12 erts-10.4 hipe-3.19 inets-7.0.8 jinterface-1.10 kernel-6.4 megaco-3.18.5 mnesia-4.16 observer-2.9.1 odbc-2.12.4 os_mon-2.5 public_key-1.6.7 reltool-0.8 runtime_tools-1.13.3 sasl-3.4 snmp-5.3 ssh-4.7.7 ssl-9.3 stdlib-3.9 syntax_tools-2.2 tools-3.2 wx-1.8.8 xmerl-1.3.21 # diameter-2.2.1 et-1.6.4 eunit-2.3.7 ftp-1.0.2 parsetools-2.1.8 tftp-1.0.1 :
+OTP-21.3.8.14 : erts-10.3.5.10 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.2 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2.2 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.6.3 ssl-9.2.3.5 stdlib-3.8.2.3 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 :
+OTP-21.3.8.13 : erts-10.3.5.9 stdlib-3.8.2.3 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.2 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2.2 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.6.3 ssl-9.2.3.5 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 :
+OTP-21.3.8.12 : crypto-4.4.2.2 erts-10.3.5.8 ssh-4.7.6.3 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 et-1.6.4 eunit-2.3.7 ftp-1.0.2.2 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssl-9.2.3.5 stdlib-3.8.2.2 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 :
OTP-21.3.8.11 : erts-10.3.5.7 ftp-1.0.2.2 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 et-1.6.4 eunit-2.3.7 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.6.2 ssl-9.2.3.5 stdlib-3.8.2.2 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 :
OTP-21.3.8.10 : ftp-1.0.2.1 ssh-4.7.6.2 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 erts-10.3.5.6 et-1.6.4 eunit-2.3.7 hipe-3.18.3 inets-7.0.7.2 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssl-9.2.3.5 stdlib-3.8.2.2 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 :
OTP-21.3.8.9 : inets-7.0.7.2 # asn1-5.0.8 common_test-1.17.2.1 compiler-7.3.2 crypto-4.4.2.1 debugger-4.2.6 dialyzer-3.3.2 diameter-2.2.1 edoc-0.10 eldap-1.2.7 erl_docgen-0.9 erl_interface-3.11.3 erts-10.3.5.6 et-1.6.4 eunit-2.3.7 ftp-1.0.2 hipe-3.18.3 jinterface-1.9.1 kernel-6.3.1.3 megaco-3.18.4 mnesia-4.15.6 observer-2.9 odbc-2.12.3 os_mon-2.4.7 otp_mibs-1.2.1 parsetools-2.1.8 public_key-1.6.6.1 reltool-0.7.8 runtime_tools-1.13.2 sasl-3.3 snmp-5.2.12 ssh-4.7.6.1 ssl-9.2.3.5 stdlib-3.8.2.2 syntax_tools-2.1.7.1 tftp-1.0.1 tools-3.1.0.1 wx-1.8.7 xmerl-1.3.20.1 :
@@ -61,6 +72,8 @@ OTP-21.0.3 : erts-10.0.3 # asn1-5.0.6 common_test-1.16 compiler-7.2.2 crypto-4.3
OTP-21.0.2 : compiler-7.2.2 erts-10.0.2 public_key-1.6.1 stdlib-3.5.1 # asn1-5.0.6 common_test-1.16 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
OTP-21.0.1 : compiler-7.2.1 erts-10.0.1 # asn1-5.0.6 common_test-1.16 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 megaco-3.18.3 mnesia-4.15.4 observer-2.8 odbc-2.12.1 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 snmp-5.2.11 ssh-4.7 ssl-9.0 stdlib-3.5 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 :
OTP-21.0 : asn1-5.0.6 common_test-1.16 compiler-7.2 crypto-4.3 debugger-4.2.5 dialyzer-3.3 diameter-2.1.5 edoc-0.9.3 eldap-1.2.4 erl_docgen-0.8 erl_interface-3.10.3 erts-10.0 et-1.6.2 eunit-2.3.6 ftp-1.0 hipe-3.18 inets-7.0 jinterface-1.9 kernel-6.0 mnesia-4.15.4 observer-2.8 os_mon-2.4.5 otp_mibs-1.2 parsetools-2.1.7 public_key-1.6 reltool-0.7.6 runtime_tools-1.13 sasl-3.2 ssh-4.7 ssl-9.0 stdlib-3.5 syntax_tools-2.1.5 tftp-1.0 tools-3.0 wx-1.8.4 xmerl-1.3.17 # megaco-3.18.3 odbc-2.12.1 snmp-5.2.11 :
+OTP-20.3.8.26 : erts-9.3.3.15 ssh-4.6.9.7 # asn1-5.0.5.2 common_test-1.15.4.4 compiler-7.1.5.2 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.4 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4.1 edoc-0.9.2 eldap-1.2.3.1 erl_docgen-0.7.3 erl_interface-3.10.2.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.4 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11.2 ssl-8.2.6.4 stdlib-3.4.5.1 syntax_tools-2.1.4.2 tools-2.11.2.2 wx-1.8.3 xmerl-1.3.16.1 :
+OTP-20.3.8.25 : crypto-4.2.2.4 erts-9.3.3.14 ssh-4.6.9.6 # asn1-5.0.5.2 common_test-1.15.4.4 compiler-7.1.5.2 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4.1 edoc-0.9.2 eldap-1.2.3.1 erl_docgen-0.7.3 erl_interface-3.10.2.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.4 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11.2 ssl-8.2.6.4 stdlib-3.4.5.1 syntax_tools-2.1.4.2 tools-2.11.2.2 wx-1.8.3 xmerl-1.3.16.1 :
OTP-20.3.8.24 : common_test-1.15.4.4 erts-9.3.3.13 ssh-4.6.9.5 # asn1-5.0.5.2 compiler-7.1.5.2 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.3 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4.1 edoc-0.9.2 eldap-1.2.3.1 erl_docgen-0.7.3 erl_interface-3.10.2.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.4 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11.2 ssl-8.2.6.4 stdlib-3.4.5.1 syntax_tools-2.1.4.2 tools-2.11.2.2 wx-1.8.3 xmerl-1.3.16.1 :
OTP-20.3.8.23 : crypto-4.2.2.3 erts-9.3.3.12 snmp-5.2.11.2 syntax_tools-2.1.4.2 # asn1-5.0.5.2 common_test-1.15.4.3 compiler-7.1.5.2 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4.1 edoc-0.9.2 eldap-1.2.3.1 erl_docgen-0.7.3 erl_interface-3.10.2.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.4 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 ssh-4.6.9.4 ssl-8.2.6.4 stdlib-3.4.5.1 tools-2.11.2.2 wx-1.8.3 xmerl-1.3.16.1 :
OTP-20.3.8.22 : common_test-1.15.4.3 erts-9.3.3.11 tools-2.11.2.2 # asn1-5.0.5.2 compiler-7.1.5.2 cosEvent-2.2.2 cosEventDomain-1.2.2 cosFileTransfer-1.2.2 cosNotification-1.2.3 cosProperty-1.2.3 cosTime-1.2.3 cosTransactions-1.3.3 crypto-4.2.2.2 debugger-4.2.4 dialyzer-3.2.4 diameter-2.1.4.1 edoc-0.9.2 eldap-1.2.3.1 erl_docgen-0.7.3 erl_interface-3.10.2.2 et-1.6.1 eunit-2.3.5 hipe-3.17.1 ic-4.4.4.2 inets-6.5.2.4 jinterface-1.8.1 kernel-5.4.3.2 megaco-3.18.3 mnesia-4.15.3.2 observer-2.7 odbc-2.12.1 orber-3.8.4 os_mon-2.4.4 otp_mibs-1.1.2 parsetools-2.1.6 public_key-1.5.2 reltool-0.7.5 runtime_tools-1.12.5 sasl-3.1.2 snmp-5.2.11.1 ssh-4.6.9.4 ssl-8.2.6.4 stdlib-3.4.5.1 syntax_tools-2.1.4.1 wx-1.8.3 xmerl-1.3.16.1 :
diff --git a/scripts/bundle-otp b/scripts/bundle-otp
index aa1f166732..df82ff4fc5 100755
--- a/scripts/bundle-otp
+++ b/scripts/bundle-otp
@@ -6,8 +6,8 @@ if [ "$TRAVIS_PULL_REQUEST" = "false" -a "$TRAVIS_REPO_SLUG" != "erlang/otp" ];
exit 0
fi
-OTP_META_FILE=$ERL_TOP/${TRAVIS_TAG}-bundle.txt
-OTP_FILE=$ERL_TOP/${TRAVIS_TAG}-bundle.tar.gz
+OTP_META_FILE=$ERL_TOP/${TRAVIS_TAG}.0-bundle.txt
+OTP_FILE=$ERL_TOP/${TRAVIS_TAG}.0-bundle.tar.gz
REPOSITORIES="otp,$TRAVIS_TAG corba,.*"
diff --git a/system/doc/design_principles/distributed_applications.xml b/system/doc/design_principles/distributed_applications.xml
index a1a0149eb5..62b7882f25 100644
--- a/system/doc/design_principles/distributed_applications.xml
+++ b/system/doc/design_principles/distributed_applications.xml
@@ -61,7 +61,7 @@
<list type="bulleted">
<item>Specifies where the application <c>Application = atom()</c>
can execute.</item>
- <item>><c>NodeDesc = [Node | {Node,...,Node}]</c> is a list of
+ <item><c>NodeDesc = [Node | {Node,...,Node}]</c> is a list of
node names in priority order. The order between nodes in a tuple
is undefined.</item>
<item><c>Timeout = integer()</c> specifies how many milliseconds
diff --git a/system/doc/design_principles/release_handling.xml b/system/doc/design_principles/release_handling.xml
index 027a71c59f..0bcd7dc1b2 100644
--- a/system/doc/design_principles/release_handling.xml
+++ b/system/doc/design_principles/release_handling.xml
@@ -4,7 +4,7 @@
<chapter>
<header>
<copyright>
- <year>2003</year><year>2016</year>
+ <year>2003</year><year>2020</year>
<holder>Ericsson AB. All Rights Reserved.</holder>
</copyright>
<legalnotice>
@@ -59,7 +59,7 @@
<p><em>Step 2</em>) The release is transferred to and installed at
target environment. For information of how to install the first
target system, see
- <seealso marker="system_principles:create_target">System Principles</seealso>.</p>
+ <seealso marker="doc/system_principles:create_target">System Principles</seealso>.</p>
<p><em>Step 3</em>) Modifications, for example, error corrections,
are made to the code in the development environment.</p>
<p><em>Step 4</em>) At some point, it is time to make a new version
diff --git a/system/doc/design_principles/statem.xml b/system/doc/design_principles/statem.xml
index 06bffc72ee..3cfbd3ec22 100644
--- a/system/doc/design_principles/statem.xml
+++ b/system/doc/design_principles/statem.xml
@@ -183,6 +183,23 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
handles the system messages, and calls the <em>callback module</em>
with machine specific events.
</p>
+ <p>
+ The <em>callback module</em> can be changed for a running server
+ using any of the
+ <seealso marker="#Transition Actions">transition actions</seealso>
+ <seealso marker="stdlib:gen_statem#type-action"><c>{change_callback_module, NewModule}</c></seealso>,
+ <seealso marker="stdlib:gen_statem#type-action"><c>{push_callback_module, NewModule}</c></seealso> or
+ <seealso marker="stdlib:gen_statem#type-action"><c>pop_callback_module</c></seealso>.
+ Note that this is a pretty esotheric thing to do...
+ The origin for this feature is a protocol that after
+ version negotiation branches off into quite different
+ state machines depending on the protocol version.
+ There <i>might</i> be other use cases.
+ <i>Beware</i> that the new callback module
+ completely replaces the previous behaviour module,
+ so all relevant callback functions has to handle
+ the state and data from the previous callback module.
+ </p>
</section>
<!-- =================================================================== -->
@@ -216,8 +233,10 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
</item>
</taglist>
<p>
- The <em>callback mode</em> is selected at server start
- and may be changed with a code upgrade/downgrade.
+ The <em>callback mode</em> is a property of
+ the <em>callback module</em> and is set at server start.
+ It may be changed due to a code upgrade/downgrade,
+ or when changing the <em>callback module</em>.
</p>
<p>
See the section
@@ -631,6 +650,57 @@ State(S) x Event(E) -> Actions(A), State(S')</pre>
Generate the next event to handle, see section
<seealso marker="#Inserted Events">Inserted Events</seealso>.
</item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-action">
+ <c>{change_callback_module, NewModule}</c>
+ </seealso>
+ </tag>
+ <item>
+ Change the
+ <seealso marker="#Callback Module">
+ <em>callback module</em>
+ </seealso>
+ for the running server.
+ This can be done during any <em>state transition</em>,
+ whether it is a <em>state change</em> or not,
+ but it can <i>not</i> be done from a
+ <seealso marker="#State Enter Calls"><em>state enter call</em></seealso>.
+ </item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-action">
+ <c>{push_callback_module, NewModule}</c>
+ </seealso>
+ </tag>
+ <item>
+ Push the current <em>callback module</em>
+ to the top of an internal stack of callback modules
+ and set the new
+ <seealso marker="#Callback Module">
+ <em>callback module</em>
+ </seealso>
+ for the running server.
+ Otherwise like
+ <c>{change_callback_module, NewModule}</c>
+ above.
+ </item>
+ <tag>
+ <seealso marker="stdlib:gen_statem#type-action">
+ <c>pop_callback_module</c>
+ </seealso>
+ </tag>
+ <item>
+ Pop the top module from
+ the internal stack of callback modules
+ and set it to be the new
+ <seealso marker="#Callback Module">
+ <em>callback module</em>
+ </seealso>
+ for the running server.
+ If the stack is empty the server fails.
+ Otherwise like
+ <c>{change_callback_module, NewModule}</c>
+ above.
+ </item>
</taglist>
<p>
For details, see the <c>gen_statem(3)</c>
@@ -812,8 +882,10 @@ StateName(EventType, EventContent, Data) ->
<seealso marker="#Transition Actions">State Transition Actions</seealso>.
You may not change the state,
<seealso marker="#Postponing Events">postpone</seealso>
- this non-event, or
- <seealso marker="#Inserted Events">insert any events</seealso>.
+ this non-event,
+ <seealso marker="#Inserted Events">insert any events</seealso>,
+ or change the
+ <seealso marker="#Callback Module"><em>callback module</em></seealso>.
</p>
<p>
The first state that is entered
diff --git a/system/doc/reference_manual/expressions.xml b/system/doc/reference_manual/expressions.xml
index baa1269470..4277c21fdb 100644
--- a/system/doc/reference_manual/expressions.xml
+++ b/system/doc/reference_manual/expressions.xml
@@ -1414,9 +1414,11 @@ end</code>
the patterns <c>Pattern</c> are sequentially matched against
the result in the same way as for a
<seealso marker="#case">case</seealso> expression, except that if
- the matching fails, a <c>try_clause</c> run-time error occurs.</p>
- <p>An exception occurring during the evaluation of <c>Body</c> is
- not caught.</p>
+ the matching fails, a <c>try_clause</c> run-time error occurs instead of a
+ <c>case_clause</c>.</p>
+ <p>Only exceptions occurring during the evaluation of <c>Exprs</c> can be
+ caught by the <c>catch</c> section. Exceptions occurring in a <c>Body</c>
+ or due to a failed match are not caught.</p>
<p>The <c>try</c> expression can also be augmented with an
<c>after</c> section, intended to be used for cleanup with side
effects:</p>