1: %% 2: %% %CopyrightBegin% 3: %% 4: %% Copyright Ericsson AB 1997-2013. All Rights Reserved. 5: %% 6: %% The contents of this file are subject to the Erlang Public License, 7: %% Version 1.1, (the "License"); you may not use this file except in 8: %% compliance with the License. You should have received a copy of the 9: %% Erlang Public License along with this software. If not, it can be 10: %% retrieved online at http://www.erlang.org/. 11: %% 12: %% Software distributed under the License is distributed on an "AS IS" 13: %% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 14: %% the License for the specific language governing rights and limitations 15: %% under the License. 16: %% 17: %% %CopyrightEnd% 18: %% 19: 20: -module(distribution_SUITE). 21: -compile(r15). 22: 23: -define(VERSION_MAGIC, 131). 24: 25: -define(ATOM_EXT, 100). 26: -define(REFERENCE_EXT, 101). 27: -define(PORT_EXT, 102). 28: -define(PID_EXT, 103). 29: -define(NEW_REFERENCE_EXT, 114). 30: -define(ATOM_UTF8_EXT, 118). 31: -define(SMALL_ATOM_UTF8_EXT, 119). 32: 33: %% Tests distribution and the tcp driver. 34: 35: -include_lib("test_server/include/test_server.hrl"). 36: 37: -export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, 38: init_per_group/2,end_per_group/2, 39: ping/1, bulk_send_small/1, 40: bulk_send_big/1, bulk_send_bigbig/1, 41: local_send_small/1, local_send_big/1, 42: local_send_legal/1, link_to_busy/1, exit_to_busy/1, 43: lost_exit/1, link_to_dead/1, link_to_dead_new_node/1, 44: applied_monitor_node/1, ref_port_roundtrip/1, nil_roundtrip/1, 45: trap_bif_1/1, trap_bif_2/1, trap_bif_3/1, 46: stop_dist/1, 47: dist_auto_connect_never/1, dist_auto_connect_once/1, 48: dist_parallel_send/1, 49: atom_roundtrip/1, 50: unicode_atom_roundtrip/1, 51: atom_roundtrip_r15b/1, 52: contended_atom_cache_entry/1, 53: contended_unicode_atom_cache_entry/1, 54: bad_dist_structure/1, 55: bad_dist_ext_receive/1, 56: bad_dist_ext_process_info/1, 57: bad_dist_ext_control/1, 58: bad_dist_ext_connection_id/1]). 59: 60: -export([init_per_testcase/2, end_per_testcase/2]). 61: 62: %% Internal exports. 63: -export([sender/3, receiver2/2, dummy_waiter/0, dead_process/0, 64: roundtrip/1, bounce/1, do_dist_auto_connect/1, inet_rpc_server/1, 65: dist_parallel_sender/3, dist_parallel_receiver/0, 66: dist_evil_parallel_receiver/0, 67: sendersender/4, sendersender2/4]). 68: 69: suite() -> [{ct_hooks,[ts_install_cth]}]. 70: 71: all() -> 72: [ping, {group, bulk_send}, {group, local_send}, 73: link_to_busy, exit_to_busy, lost_exit, link_to_dead, 74: link_to_dead_new_node, applied_monitor_node, 75: ref_port_roundtrip, nil_roundtrip, stop_dist, 76: {group, trap_bif}, {group, dist_auto_connect}, 77: dist_parallel_send, atom_roundtrip, unicode_atom_roundtrip, atom_roundtrip_r15b, 78: contended_atom_cache_entry, contended_unicode_atom_cache_entry, 79: bad_dist_structure, {group, bad_dist_ext}]. 80: 81: groups() -> 82: [{bulk_send, [], [bulk_send_small, bulk_send_big, bulk_send_bigbig]}, 83: {local_send, [], 84: [local_send_small, local_send_big, local_send_legal]}, 85: {trap_bif, [], [trap_bif_1, trap_bif_2, trap_bif_3]}, 86: {dist_auto_connect, [], 87: [dist_auto_connect_never, dist_auto_connect_once]}, 88: {bad_dist_ext, [], 89: [bad_dist_ext_receive, bad_dist_ext_process_info, 90: bad_dist_ext_control, bad_dist_ext_connection_id]}]. 91: 92: init_per_suite(Config) -> 93: Config. 94: 95: end_per_suite(_Config) -> 96: ok. 97: 98: init_per_group(_GroupName, Config) -> 99: Config. 100: 101: end_per_group(_GroupName, Config) -> 102: Config. 103: 104: -define(DEFAULT_TIMETRAP, 4*60*1000). 105: 106: init_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 107: Dog=?t:timetrap(?DEFAULT_TIMETRAP), 108: [{watchdog, Dog},{testcase, Func}|Config]. 109: 110: end_per_testcase(Func, Config) when is_atom(Func), is_list(Config) -> 111: Dog=?config(watchdog, Config), 112: ?t:timetrap_cancel(Dog). 113: 114: ping(doc) -> 115: ["Tests pinging a node in different ways."]; 116: ping(Config) when is_list(Config) -> 117: Times = 1024, 118: 119: %% Ping a non-existing node many times. This used to crash the emulator 120: %% on Windows. 121: 122: ?line Host = hostname(), 123: ?line BadName = list_to_atom("__pucko__@" ++ Host), 124: ?line io:format("Pinging ~s (assumed to not exist)", [BadName]), 125: ?line test_server:do_times(Times, fun() -> pang = net_adm:ping(BadName) 126: end), 127: 128: %% Pings another node. 129: 130: ?line {ok, OtherNode} = start_node(distribution_SUITE_other), 131: ?line io:format("Pinging ~s (assumed to exist)", [OtherNode]), 132: ?line test_server:do_times(Times, fun() -> pong = net_adm:ping(OtherNode) end), 133: ?line stop_node(OtherNode), 134: 135: %% Pings our own node many times. 136: 137: ?line Node = node(), 138: ?line io:format("Pinging ~s (the same node)", [Node]), 139: ?line test_server:do_times(Times, fun() -> pong = net_adm:ping(Node) end), 140: 141: ok. 142: 143: bulk_send_small(Config) when is_list(Config) -> 144: ?line bulk_send(64, 32). 145: 146: bulk_send_big(Config) when is_list(Config) -> 147: ?line bulk_send(32, 64). 148: 149: bulk_send_bigbig(Config) when is_list(Config) -> 150: ?line bulk_sendsend(32*5, 4). 151: 152: bulk_send(Terms, BinSize) -> 153: ?line Dog = test_server:timetrap(test_server:seconds(30)), 154: 155: ?line io:format("Sending ~w binaries, each of size ~w K", 156: [Terms, BinSize]), 157: ?line {ok, Node} = start_node(bulk_receiver), 158: ?line Recv = spawn(Node, erlang, apply, [fun receiver/2, [0, 0]]), 159: ?line Bin = list_to_binary(lists:duplicate(BinSize*1024, 253)), 160: ?line Size = Terms*size(Bin), 161: ?line {Elapsed, {Terms, Size}} = test_server:timecall(?MODULE, sender, 162: [Recv, Bin, Terms]), 163: ?line stop_node(Node), 164: 165: ?line test_server:timetrap_cancel(Dog), 166: {comment, integer_to_list(trunc(Size/1024/Elapsed+0.5)) ++ " K/s"}. 167: 168: bulk_sendsend(Terms, BinSize) -> 169: {Rate1, MonitorCount1} = bulk_sendsend2(Terms, BinSize, 5), 170: {Rate2, MonitorCount2} = bulk_sendsend2(Terms, BinSize, 995), 171: Ratio = if MonitorCount2 == 0 -> MonitorCount1 / 1.0; 172: true -> MonitorCount1 / MonitorCount2 173: end, 174: Comment = integer_to_list(Rate1) ++ " K/s, " ++ 175: integer_to_list(Rate2) ++ " K/s, " ++ 176: integer_to_list(MonitorCount1) ++ " monitor msgs, " ++ 177: integer_to_list(MonitorCount2) ++ " monitor msgs, " ++ 178: float_to_list(Ratio) ++ " monitor ratio", 179: if 180: %% A somewhat arbitrary ratio, but hopefully one that will 181: %% accommodate a wide range of CPU speeds. 182: Ratio > 8.0 -> 183: {comment,Comment}; 184: true -> 185: io:put_chars(Comment), 186: ?line ?t:fail(ratio_too_low) 187: end. 188: 189: bulk_sendsend2(Terms, BinSize, BusyBufSize) -> 190: ?line Dog = test_server:timetrap(test_server:seconds(30)), 191: 192: ?line io:format("Sending ~w binaries, each of size ~w K", 193: [Terms, BinSize]), 194: ?line {ok, NodeRecv} = start_node(bulk_receiver), 195: ?line Recv = spawn(NodeRecv, erlang, apply, [fun receiver/2, [0, 0]]), 196: ?line Bin = list_to_binary(lists:duplicate(BinSize*1024, 253)), 197: %%?line Size = Terms*size(Bin), 198: 199: %% SLF LEFT OFF HERE. 200: %% When the caller uses small hunks, like 4k via 201: %% bulk_sendsend(32*5, 4), then (on my laptop at least), we get 202: %% zero monitor messages. But if we use "+zdbbl 5", then we 203: %% get a lot of monitor messages. So, if we can count up the 204: %% total number of monitor messages that we get when running both 205: %% default busy size and "+zdbbl 5", and if the 5 case gets 206: %% "many many more" monitor messages, then we know we're working. 207: 208: ?line {ok, NodeSend} = start_node(bulk_sender, "+zdbbl " ++ integer_to_list(BusyBufSize)), 209: ?line _Send = spawn(NodeSend, erlang, apply, [fun sendersender/4, [self(), Recv, Bin, Terms]]), 210: ?line {Elapsed, {_TermsN, SizeN}, MonitorCount} = 211: receive {sendersender, BigRes} -> 212: BigRes 213: end, 214: ?line stop_node(NodeRecv), 215: ?line stop_node(NodeSend), 216: 217: ?line test_server:timetrap_cancel(Dog), 218: {trunc(SizeN/1024/Elapsed+0.5), MonitorCount}. 219: 220: sender(To, _Bin, 0) -> 221: To ! {done, self()}, 222: receive 223: Any -> 224: Any 225: end; 226: sender(To, Bin, Left) -> 227: To ! {term, Bin}, 228: sender(To, Bin, Left-1). 229: 230: %% Sender process to be run on a slave node 231: 232: sendersender(Parent, To, Bin, Left) -> 233: erlang:system_monitor(self(), [busy_dist_port]), 234: [spawn(fun() -> sendersender2(To, Bin, Left, false) end) || 235: _ <- lists:seq(1,1)], 236: {USec, {Res, MonitorCount}} = 237: timer:tc(?MODULE, sendersender2, [To, Bin, Left, true]), 238: Parent ! {sendersender, {USec/1000000, Res, MonitorCount}}. 239: 240: sendersender2(To, Bin, Left, SendDone) -> 241: sendersender3(To, Bin, Left, SendDone, 0). 242: 243: sendersender3(To, _Bin, 0, SendDone, MonitorCount) -> 244: if SendDone -> 245: To ! {done, self()}; 246: true -> 247: ok 248: end, 249: receive 250: {monitor, _Pid, _Type, _Info} -> 251: sendersender3(To, _Bin, 0, SendDone, MonitorCount + 1) 252: after 0 -> 253: if SendDone -> 254: receive 255: Any when is_tuple(Any), size(Any) == 2 -> 256: {Any, MonitorCount} 257: end; 258: true -> 259: exit(normal) 260: end 261: end; 262: sendersender3(To, Bin, Left, SendDone, MonitorCount) -> 263: To ! {term, Bin}, 264: %%timer:sleep(50), 265: sendersender3(To, Bin, Left-1, SendDone, MonitorCount). 266: 267: %% Receiver process to be run on a slave node. 268: 269: receiver(Terms, Size) -> 270: receive 271: {term, Bin} -> 272: receiver(Terms+1, Size+size(Bin)); 273: {done, ReplyTo} -> 274: ReplyTo ! {Terms, Size} 275: end. 276: 277: 278: 279: local_send_big(doc) -> 280: ["Sends several big message to an non-registered process on ", 281: "the local node."]; 282: local_send_big(Config) when is_list(Config) -> 283: Data0=local_send_big(doc)++ 284: ["Tests sending small and big messages to a non-existing ", 285: "local registered process."], 286: Data1=[Data0,[Data0, Data0, [Data0], Data0],Data0], 287: Data2=Data0++lists:flatten(Data1)++ 288: list_to_binary(lists:flatten(Data1)), 289: Func=fun() -> Data2= {arbitrary_name, node()} ! Data2 end, 290: ?line test_server:do_times(4096, Func), 291: ok. 292: 293: local_send_small(doc) -> 294: ["Sends a small message to an non-registered process on the ", 295: "local node."]; 296: local_send_small(Config) when is_list(Config) -> 297: Data={some_stupid, "arbitrary", 'Data'}, 298: Func=fun() -> Data= {unregistered_name, node()} ! Data end, 299: ?line test_server:do_times(4096, Func), 300: ok. 301: 302: local_send_legal(doc) -> 303: ["Sends data to a registered process on the local node, ", 304: "as if it was on another node."]; 305: local_send_legal(Config) when is_list(Config) -> 306: Times=16384, 307: Data={local_send_legal(doc), local_send_legal(doc)}, 308: Pid=spawn(?MODULE,receiver2, [0, 0]) , 309: ?line true=register(registered_process, Pid), 310: 311: Func=fun() -> Data={registered_process, node()} ! Data end, 312: TotalSize=size(Data)*Times, 313: ?line test_server:do_times(Times, Func), 314: 315: % Check that all msgs really came through. 316: Me=self(), 317: ?line {done, Me}= 318: {registered_process, node()} ! {done, Me}, 319: receive 320: {Times, TotalSize} -> 321: ok; 322: _ -> 323: test_server:fail("Wrong number of msgs received.") 324: end, 325: ok. 326: 327: receiver2(Num, TotSize) -> 328: receive 329: {done, ReplyTo} -> 330: ReplyTo ! {Num, TotSize}; 331: Stuff -> 332: receiver2(Num+1, TotSize+size(Stuff)) 333: end. 334: 335: link_to_busy(doc) -> "Test that link/1 to a busy distribution port works."; 336: link_to_busy(Config) when is_list(Config) -> 337: ?line Dog = test_server:timetrap(test_server:seconds(60)), 338: ?line {ok, Node} = start_node(link_to_busy), 339: ?line Recv = spawn(Node, erlang, apply, [fun sink/1, [link_to_busy_sink]]), 340: 341: Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of 342: "true" -> start_busy_dist_port_tracer(); 343: _ -> false 344: end, 345: 346: %% We will spawn off a process which will try to link to the other 347: %% node. The linker process will not actually run until this 348: %% process is suspended due to the busy distribution port (because 349: %% of the big send). When the link/1 is run, the linker 350: %% process will block, too, because of the because busy port, 351: %% and will later be restarted. 352: 353: ?line do_busy_test(Node, fun () -> linker(Recv) end), 354: 355: %% Same thing, but we apply link/1 instead of calling it directly. 356: 357: ?line do_busy_test(Node, fun () -> applied_linker(Recv) end), 358: 359: %% Same thing again, but we apply link/1 in the tail of a function. 360: 361: ?line do_busy_test(Node, fun () -> tail_applied_linker(Recv) end), 362: 363: %% Done. 364: ?line stop_node(Node), 365: ?line stop_busy_dist_port_tracer(Tracer), 366: ?line test_server:timetrap_cancel(Dog), 367: ok. 368: 369: linker(Pid) -> 370: true = link(Pid), 371: {links, Links} = process_info(self(), links), 372: true = lists:member(Pid, Links). 373: 374: applied_linker(Pid) -> 375: true = apply(erlang, link, [Pid]), 376: {links, Links} = process_info(self(), links), 377: true = lists:member(Pid, Links). 378: 379: tail_applied_linker(Pid) -> 380: apply(erlang, link, [Pid]). 381: 382: exit_to_busy(doc) -> "Test that exit/2 to a busy distribution port works."; 383: exit_to_busy(Config) when is_list(Config) -> 384: ?line Dog = test_server:timetrap(test_server:seconds(60)), 385: ?line {ok, Node} = start_node(exit_to_busy), 386: 387: Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of 388: "true" -> start_busy_dist_port_tracer(); 389: _ -> false 390: end, 391: 392: %% We will spawn off a process which will try to exit a process on 393: %% the other node. That process will not actually run until this 394: %% process is suspended due to the busy distribution port 395: %% The process executing exit/2 will block, 396: %% too, because of the busy distribution port, and will be allowed 397: %% to continue when the port becomes non-busy. 398: 399: ?line Recv1 = spawn(Node, fun () -> sink(exit_to_busy_sink) end), 400: ?line M1 = erlang:monitor(process, Recv1), 401: ?line do_busy_test(Node, fun () -> joey_killer(Recv1) end), 402: ?line receive 403: {'DOWN', M1, process, Recv1, R1} -> 404: ?line joey_said_die = R1 405: end, 406: 407: %% Same thing, but tail call to exit/2. 408: ?line Recv2 = spawn(Node, fun () -> sink(exit_to_busy_sink) end), 409: ?line M2 = erlang:monitor(process, Recv2), 410: ?line do_busy_test(Node, fun () -> tail_joey_killer(Recv2) end), 411: ?line receive 412: {'DOWN', M2, process, Recv2, R2} -> 413: ?line joey_said_die = R2 414: end, 415: 416: %% Same thing, but we apply exit/2 instead of calling it directly. 417: ?line Recv3 = spawn(Node, fun () -> sink(exit_to_busy_sink) end), 418: ?line M3 = erlang:monitor(process, Recv3), 419: ?line do_busy_test(Node, fun () -> applied_joey_killer(Recv3) end), 420: ?line receive 421: {'DOWN', M3, process, Recv3, R3} -> 422: ?line joey_said_die = R3 423: end, 424: 425: %% Same thing again, but we apply exit/2 in the tail of a function. 426: ?line Recv4 = spawn(Node, fun () -> sink(exit_to_busy_sink) end), 427: ?line M4 = erlang:monitor(process, Recv4), 428: ?line do_busy_test(Node, fun () -> tail_applied_joey_killer(Recv4) end), 429: ?line receive 430: {'DOWN', M4, process, Recv4, R4} -> 431: ?line joey_said_die = R4 432: end, 433: 434: %% Done. 435: ?line stop_node(Node), 436: ?line stop_busy_dist_port_tracer(Tracer), 437: ?line test_server:timetrap_cancel(Dog), 438: ok. 439: 440: make_busy_data() -> 441: Size = 1024*1024, 442: Key = '__busy__port__data__', 443: case get(Key) of 444: undefined -> 445: Data = list_to_binary(lists:duplicate(Size, 253)), 446: put(Key, Data), 447: Data; 448: Data -> 449: true = is_binary(Data), 450: true = size(Data) == Size, 451: Data 452: end. 453: 454: make_busy(Node, Time) when is_integer(Time) -> 455: Own = 500, 456: freeze_node(Node, Time+Own), 457: Data = make_busy_data(), 458: %% first make port busy 459: Pid = spawn_link(fun () -> 460: forever(fun () -> 461: dport_reg_send(Node, 462: '__noone__', 463: Data) 464: end) 465: end), 466: receive after Own -> ok end, 467: until(fun () -> 468: case process_info(Pid, status) of 469: {status, suspended} -> true; 470: _ -> false 471: end 472: end), 473: %% then dist entry 474: make_busy(Node, [nosuspend], Data), 475: Pid. 476: 477: make_busy(Node, Opts, Data) -> 478: case erlang:send({'__noone__', Node}, Data, Opts) of 479: nosuspend -> nosuspend; 480: _ -> make_busy(Node, Opts, Data) 481: end. 482: 483: unmake_busy(Pid) -> 484: unlink(Pid), 485: exit(Pid, bang). 486: 487: do_busy_test(Node, Fun) -> 488: Busy = make_busy(Node, 1000), 489: {P, M} = spawn_monitor(Fun), 490: receive after 100 -> ok end, 491: Pinfo = process_info(P, [status, current_function]), 492: unmake_busy(Busy), 493: ?t:format("~p : ~p~n", [P, Pinfo]), 494: case Pinfo of 495: undefined -> 496: receive 497: {'DOWN', M, process, P, Reason} -> 498: ?t:format("~p died with exit reason ~p~n", [P, Reason]) 499: end, 500: ?t:fail(premature_death); 501: _ -> 502: %% Don't match arity; it is different in debug and 503: %% optimized emulator 504: [{status, suspended}, 505: {current_function, {erlang, bif_return_trap, _}}] = Pinfo, 506: receive 507: {'DOWN', M, process, P, Reason} -> 508: ?t:format("~p died with exit reason ~p~n", [P, Reason]), 509: normal = Reason 510: end 511: end. 512: 513: remote_is_process_alive(Pid) -> 514: rpc:call(node(Pid), erlang, is_process_alive, 515: [Pid]). 516: 517: joey_killer(Pid) -> 518: exit(Pid, joey_said_die), 519: until(fun () -> false == remote_is_process_alive(Pid) end). 520: 521: tail_joey_killer(Pid) -> 522: exit(Pid, joey_said_die). 523: 524: applied_joey_killer(Pid) -> 525: apply(erlang, exit, [Pid, joey_said_die]), 526: until(fun () -> false == remote_is_process_alive(Pid) end). 527: 528: tail_applied_joey_killer(Pid) -> 529: apply(erlang, exit, [Pid, joey_said_die]). 530: 531: sink(Name) -> 532: register(Name, self()), 533: sink1(). 534: 535: sink1() -> 536: receive 537: _Any -> sink1() 538: end. 539: 540: lost_exit(doc) -> 541: "Test that EXIT and DOWN messages send to another node are not lost if " 542: "the distribution port is busy."; 543: lost_exit(Config) when is_list(Config) -> 544: ?line {ok, Node} = start_node(lost_exit), 545: 546: Tracer = case os:getenv("TRACE_BUSY_DIST_PORT") of 547: "true" -> start_busy_dist_port_tracer(); 548: _ -> false 549: end, 550: 551: Self = self(), 552: Die = make_ref(), 553: ?line R1 = spawn(fun () -> receive after infinity -> ok end end), 554: ?line MR1 = erlang:monitor(process, R1), 555: 556: ?line {L1, ML1} = spawn_monitor(fun() -> 557: link(R1), 558: Self ! {self(), linked}, 559: receive 560: Die -> 561: exit(controlled_suicide) 562: end 563: end), 564: 565: ?line R2 = spawn(fun () -> 566: M = erlang:monitor(process, L1), 567: receive 568: {'DOWN', M, process, L1, R} -> 569: Self ! {self(), got_down_message, L1, R} 570: end 571: end), 572: 573: ?line receive {L1, linked} -> ok end, 574: 575: Busy = make_busy(Node, 2000), 576: receive after 100 -> ok end, 577: L1 ! Die, 578: ?line receive 579: {'DOWN', ML1, process, L1, RL1} -> 580: ?line controlled_suicide = RL1 581: end, 582: receive after 500 -> ok end, 583: unmake_busy(Busy), 584: 585: ?line receive 586: {'DOWN', MR1, process, R1, RR1} -> 587: ?line controlled_suicide = RR1 588: end, 589: 590: ?line receive 591: {R2, got_down_message, L1, RR2} -> 592: ?line controlled_suicide = RR2 593: end, 594: 595: %% Done. 596: ?line stop_busy_dist_port_tracer(Tracer), 597: ?line stop_node(Node), 598: ok. 599: 600: dummy_waiter() -> 601: receive 602: after infinity -> 603: ok 604: end. 605: 606: link_to_dead(doc) -> 607: ["Test that linking to a dead remote process gives an EXIT message ", 608: "AND that the link is teared down."]; 609: link_to_dead(Config) when is_list(Config) -> 610: ?line process_flag(trap_exit, true), 611: ?line {ok, Node} = start_node(link_to_dead), 612: % ?line monitor_node(Node, true), 613: ?line net_adm:ping(Node), %% Ts_cross_server workaround. 614: ?line Pid = spawn(Node, ?MODULE, dead_process, []), 615: receive 616: after 5000 -> ok 617: end, 618: ?line link(Pid), 619: ?line receive 620: {'EXIT', Pid, noproc} -> 621: ok; 622: Other -> 623: ?line test_server:fail({unexpected_message, Other}) 624: after 5000 -> 625: ?line test_server:fail(nothing_received) 626: end, 627: ?line {links, Links} = process_info(self(), links), 628: ?line io:format("Pid=~p, links=~p", [Pid, Links]), 629: ?line false = lists:member(Pid, Links), 630: ?line stop_node(Node), 631: ?line receive 632: Message -> 633: ?line test_server:fail({unexpected_message, Message}) 634: after 3000 -> 635: ok 636: end, 637: ok. 638: 639: dead_process() -> 640: erlang:error(die). 641: 642: link_to_dead_new_node(doc) -> 643: ["Test that linking to a pid on node that has gone and restarted gives ", 644: "the correct EXIT message (OTP-2304)."]; 645: link_to_dead_new_node(Config) when is_list(Config) -> 646: ?line process_flag(trap_exit, true), 647: 648: %% Start the node, get a Pid and stop the node again. 649: ?line {ok, Node} = start_node(link_to_dead_new_node), 650: ?line Pid = spawn(Node, ?MODULE, dead_process, []), 651: ?line stop_node(Node), 652: 653: %% Start a new node with the same name. 654: ?line {ok, Node} = start_node(link_to_dead_new_node), 655: ?line link(Pid), 656: ?line receive 657: {'EXIT', Pid, noproc} -> 658: ok; 659: Other -> 660: ?line test_server:fail({unexpected_message, Other}) 661: after 5000 -> 662: ?line test_server:fail(nothing_received) 663: end, 664: 665: %% Make sure that the link wasn't created. 666: ?line {links, Links} = process_info(self(), links), 667: ?line io:format("Pid=~p, links=~p", [Pid, Links]), 668: ?line false = lists:member(Pid, Links), 669: ?line stop_node(Node), 670: ?line receive 671: Message -> 672: ?line test_server:fail({unexpected_message, Message}) 673: after 3000 -> 674: ok 675: end, 676: ok. 677: 678: applied_monitor_node(doc) -> 679: "Test that monitor_node/2 works when applied."; 680: applied_monitor_node(Config) when is_list(Config) -> 681: ?line NonExisting = list_to_atom("__non_existing__@" ++ hostname()), 682: 683: %% Tail-recursive call to apply (since the node is non-existing, 684: %% there will be a trap). 685: 686: ?line true = tail_apply(erlang, monitor_node, [NonExisting, true]), 687: ?line [{nodedown, NonExisting}] = test_server:messages_get(), 688: 689: %% Ordinary call (with trap). 690: 691: ?line true = apply(erlang, monitor_node, [NonExisting, true]), 692: ?line [{nodedown, NonExisting}] = test_server:messages_get(), 693: 694: ok. 695: 696: tail_apply(M, F, A) -> 697: apply(M, F, A). 698: 699: ref_port_roundtrip(doc) -> 700: "Test that sending a port or reference to another node and back again " 701: "doesn't correct them in any way."; 702: ref_port_roundtrip(Config) when is_list(Config) -> 703: ?line process_flag(trap_exit, true), 704: ?line Port = open_port({spawn, efile}, []), 705: ?line Ref = make_ref(), 706: ?line {ok, Node} = start_node(ref_port_roundtrip), 707: ?line net_adm:ping(Node), 708: ?line Term = {Port, Ref}, 709: ?line io:format("Term before: ~p", [show_term(Term)]), 710: ?line Pid = spawn_link(Node, ?MODULE, roundtrip, [Term]), 711: ?line receive after 5000 -> ok end, 712: ?line stop_node(Node), 713: ?line receive 714: {'EXIT', Pid, {Port, Ref}} -> 715: ?line io:format("Term after: ~p", [show_term(Term)]), 716: ok; 717: Other -> 718: ?line io:format("Term after: ~p", [show_term(Term)]), 719: ?line test_server:fail({unexpected, Other}) 720: after 10000 -> 721: ?line test_server:fail(timeout) 722: end, 723: ok. 724: 725: roundtrip(Term) -> 726: exit(Term). 727: 728: nil_roundtrip(doc) -> 729: "Test that the smallest external term [] aka NIL can be sent to " 730: "another node node and back again."; 731: nil_roundtrip(Config) when is_list(Config) -> 732: ?line process_flag(trap_exit, true), 733: ?line {ok, Node} = start_node(nil_roundtrip), 734: ?line net_adm:ping(Node), 735: ?line Pid = spawn_link(Node, ?MODULE, bounce, [self()]), 736: ?line Pid ! [], 737: ?line receive 738: [] -> 739: ?line receive 740: {'EXIT', Pid, []} -> 741: ?line stop_node(Node), 742: ok 743: end 744: end. 745: 746: bounce(Dest) -> 747: receive Msg -> 748: Dest ! Msg, 749: exit(Msg) 750: end. 751: 752: show_term(Term) -> 753: binary_to_list(term_to_binary(Term)). 754: 755: stop_dist(doc) -> 756: ["Tests behaviour after net_kernel:stop (OTP-2586)."]; 757: stop_dist(Config) when is_list(Config) -> 758: ?line Str = os:cmd(atom_to_list(lib:progname()) 759: ++ " -noshell -pa " 760: ++ ?config(data_dir, Config) 761: ++ " -s run"), 762: %% The "true" may be followed by an error report, so ignore anything that 763: %% follows it. 764: ?line "true\n"++_ = Str, 765: 766: %% "May fail on FreeBSD due to differently configured name lookup - ask Arndt", 767: %% if you can find him. 768: 769: ok. 770: 771: 772: trap_bif_1(doc) -> 773: [""]; 774: trap_bif_1(Config) when is_list(Config) -> 775: ?line {true} = tr1(), 776: ok. 777: 778: trap_bif_2(doc) -> 779: [""]; 780: trap_bif_2(Config) when is_list(Config) -> 781: ?line {true} = tr2(), 782: ok. 783: 784: trap_bif_3(doc) -> 785: [""]; 786: trap_bif_3(Config) when is_list(Config) -> 787: ?line {hoo} = tr3(), 788: ok. 789: 790: tr1() -> 791: ?line NonExisting = 'abc@boromir', 792: ?line X = erlang:monitor_node(NonExisting, true), 793: {X}. 794: 795: tr2() -> 796: ?line NonExisting = 'abc@boromir', 797: ?line X = apply(erlang, monitor_node, [NonExisting, true]), 798: {X}. 799: 800: tr3() -> 801: ?line NonExisting = 'abc@boromir', 802: ?line X = {NonExisting, glirp} ! hoo, 803: {X}. 804: 805: 806: 807: 808: % This has to be done by nodes with differrent cookies, otherwise global 809: % will connect nodes, which is correct, but makes it hard to test. 810: % * Start two nodes, n1 and n2. n2 with the dist_auto_connect once parameter 811: % * n2 pings n1 -> connection 812: % * check that they now know each other 813: % * Kill n1 814: % * Make sure n2 gets pang when pinging n1 815: % * restart n1 816: % * Make sure n2 *still gets pang*! 817: % * Ping n2 from n1 -> pong 818: % * n2 now also gets pong when pinging n1 819: % * disconnect n2 from n1 820: % * n2 gets pang when pinging n1 821: % * n2 forces connection by using net_kernel:connect_node (ovverrides) 822: % * n2 gets pong when pinging n1. 823: dist_auto_connect_once(doc) -> "Test the dist_auto_connect once kernel parameter"; 824: dist_auto_connect_once(Config) when is_list(Config) -> 825: ?line Sock = start_relay_node(dist_auto_connect_relay_node,[]), 826: ?line NN = inet_rpc_nodename(Sock), 827: ?line Sock2 = start_relay_node(dist_auto_connect_once_node, 828: "-kernel dist_auto_connect once"), 829: ?line NN2 = inet_rpc_nodename(Sock2), 830: ?line {ok,[]} = do_inet_rpc(Sock,erlang,nodes,[]), 831: ?line {ok, pong} = do_inet_rpc(Sock2,net_adm,ping,[NN]), 832: ?line {ok,[NN2]} = do_inet_rpc(Sock,erlang,nodes,[]), 833: ?line {ok,[NN]} = do_inet_rpc(Sock2,erlang,nodes,[]), 834: ?line [_,HostPartPeer] = string:tokens(atom_to_list(NN),"@"), 835: ?line [_,MyHostPart] = string:tokens(atom_to_list(node()),"@"), 836: % Give net_kernel a chance to change the state of the node to up to. 837: ?line receive after 1000 -> ok end, 838: case HostPartPeer of 839: MyHostPart -> 840: ?line ok = stop_relay_node(Sock), 841: ?line {ok,pang} = do_inet_rpc(Sock2,net_adm,ping,[NN]); 842: _ -> 843: ?line {ok, true} = do_inet_rpc(Sock,net_kernel,disconnect,[NN2]), 844: receive 845: after 500 -> ok 846: end 847: end, 848: ?line {ok, []} = do_inet_rpc(Sock2,erlang,nodes,[]), 849: Sock3 = case HostPartPeer of 850: MyHostPart -> 851: ?line start_relay_node(dist_auto_connect_relay_node,[]); 852: _ -> 853: Sock 854: end, 855: ?line TS1 = timestamp(), 856: ?line {ok, pang} = do_inet_rpc(Sock2,net_adm,ping,[NN]), 857: ?line TS2 = timestamp(), 858: RefT = net_kernel:connecttime() - 1000, 859: ?line true = ((TS2 - TS1) < RefT), 860: ?line TS3 = timestamp(), 861: ?line {ok, true} = do_inet_rpc(Sock2,erlang,monitor_node, 862: [NN,true,[allow_passive_connect]]), 863: ?line TS4 = timestamp(), 864: ?line true = ((TS4 - TS3) > RefT), 865: ?line {ok, pong} = do_inet_rpc(Sock3,net_adm,ping,[NN2]), 866: ?line {ok, pong} = do_inet_rpc(Sock2,net_adm,ping,[NN]), 867: ?line {ok, true} = do_inet_rpc(Sock3,net_kernel,disconnect,[NN2]), 868: receive 869: after 500 -> ok 870: end, 871: ?line {ok, pang} = do_inet_rpc(Sock2,net_adm,ping,[NN]), 872: ?line {ok, true} = do_inet_rpc(Sock2,net_kernel,connect_node,[NN]), 873: ?line {ok, pong} = do_inet_rpc(Sock2,net_adm,ping,[NN]), 874: ?line stop_relay_node(Sock3), 875: ?line stop_relay_node(Sock2). 876: 877: 878: 879: %% Start a relay node and a lonely (dist_auto_connect never) node. 880: %% Lonely node pings relay node. That should fail. 881: %% Lonely node connects to relay node with net_kernel:connect_node/1. 882: %% Result is sent here through relay node. 883: dist_auto_connect_never(Config) when is_list(Config) -> 884: Self = self(), 885: ?line {ok, RelayNode} = 886: start_node(dist_auto_connect_relay), 887: ?line spawn(RelayNode, 888: fun() -> 889: register(dist_auto_connect_relay, self()), 890: dist_auto_connect_relay(Self) 891: end), 892: ?line {ok, Handle} = dist_auto_connect_start(dist_auto_connect, never), 893: ?line Result = 894: receive 895: {do_dist_auto_connect, ok} -> 896: ok; 897: {do_dist_auto_connect, Error} -> 898: {error, Error}; 899: Other -> 900: {error, Other} 901: after 32000 -> 902: timeout 903: end, 904: ?line stop_node(RelayNode), 905: ?line Stopped = dist_auto_connect_stop(Handle), 906: ?line Junk = 907: receive 908: {do_dist_auto_connect, _} = J -> 909: J 910: after 0 -> 911: ok 912: end, 913: ?line {ok, ok, ok} = {Result, Stopped, Junk}, 914: ok. 915: 916: 917: do_dist_auto_connect([never]) -> 918: Node = list_to_atom("dist_auto_connect_relay@" ++ hostname()), 919: io:format("~p:do_dist_auto_connect([false]) Node=~p~n", 920: [?MODULE, Node]), 921: Ping = net_adm:ping(Node), 922: io:format("~p:do_dist_auto_connect([false]) Ping=~p~n", 923: [?MODULE, Ping]), 924: Result = case Ping of 925: pang -> ok; 926: _ -> {error, Ping} 927: end, 928: io:format("~p:do_dist_auto_connect([false]) Result=~p~n", 929: [?MODULE, Result]), 930: net_kernel:connect_node(Node), 931: catch {dist_auto_connect_relay, Node} ! {do_dist_auto_connect, Result}; 932: % receive after 1000 -> ok end, 933: % halt(); 934: 935: do_dist_auto_connect(Arg) -> 936: io:format("~p:do_dist_auto_connect(~p)~n", 937: [?MODULE, Arg]), 938: receive after 10000 -> ok end, 939: halt(). 940: 941: 942: dist_auto_connect_start(Name, Value) when is_atom(Name) -> 943: dist_auto_connect_start(atom_to_list(Name), Value); 944: dist_auto_connect_start(Name, Value) when is_list(Name), is_atom(Value) -> 945: Node = list_to_atom(lists:append([Name, "@", hostname()])), 946: ModuleDir = filename:dirname(code:which(?MODULE)), 947: ValueStr = atom_to_list(Value), 948: Cookie = atom_to_list(erlang:get_cookie()), 949: Cmd = lists:concat( 950: [%"xterm -e ", 951: atom_to_list(lib:progname()), 952: % " -noinput ", 953: " -detached ", 954: long_or_short(), " ", Name, 955: " -setcookie ", Cookie, 956: " -pa ", ModuleDir, 957: " -s ", atom_to_list(?MODULE), 958: " do_dist_auto_connect ", ValueStr, 959: " -kernel dist_auto_connect ", ValueStr]), 960: io:format("~p:dist_auto_connect_start() cmd: ~p~n", [?MODULE, Cmd]), 961: Port = open_port({spawn, Cmd}, [stream]), 962: {ok, {Port, Node}}. 963: 964: 965: dist_auto_connect_stop({Port, Node}) -> 966: Pid = spawn_link(fun() -> rpc:call(Node, erlang, halt, []) end), 967: dist_auto_connect_stop(Port, Node, Pid, 5000). 968: 969: dist_auto_connect_stop(Port, _Node, Pid, N) when is_integer(N), N =< 0 -> 970: exit(Pid, normal), 971: catch erlang:port_close(Port), 972: Result = {error, node_not_down}, 973: io:format("~p:dist_auto_connect_stop() ~p~n", [?MODULE, Result]), 974: Result; 975: dist_auto_connect_stop(Port, Node, Pid, N) when is_integer(N) -> 976: case net_adm:ping(Node) of 977: pong -> 978: receive after 100 -> ok end, 979: dist_auto_connect_stop(Port, Node, Pid, N-100); 980: pang -> 981: exit(Pid, normal), 982: catch erlang:port_close(Port), 983: io:format("~p:dist_auto_connect_stop() ok~n", [?MODULE]), 984: ok 985: end. 986: 987: 988: dist_auto_connect_relay(Parent) -> 989: receive X -> 990: catch Parent ! X 991: end, 992: dist_auto_connect_relay(Parent). 993: 994: 995: dist_parallel_send(doc) -> 996: []; 997: dist_parallel_send(suite) -> 998: []; 999: dist_parallel_send(Config) when is_list(Config) -> 1000: ?line {ok, RNode} = start_node(dist_parallel_receiver), 1001: ?line {ok, SNode} = start_node(dist_parallel_sender), 1002: ?line WatchDog = spawn_link( 1003: fun () -> 1004: TRef = erlang:start_timer((?DEFAULT_TIMETRAP 1005: div 2), 1006: self(), 1007: oops), 1008: receive 1009: {timeout, TRef, _ } -> 1010: spawn(SNode, 1011: fun () -> 1012: abort(timeout) 1013: end), 1014: spawn(RNode, 1015: fun () -> 1016: abort(timeout) 1017: end) 1018: %% rpc:cast(SNode, erlang, halt, 1019: %% ["Timetrap (sender)"]), 1020: %% rpc:cast(RNode, erlang, halt, 1021: %% ["Timetrap (receiver)"]) 1022: end 1023: end), 1024: ?line MkSndrs = fun (Receiver) -> 1025: lists:map(fun (_) -> 1026: spawn_link(SNode, 1027: ?MODULE, 1028: dist_parallel_sender, 1029: [self(), 1030: Receiver, 1031: 1000]) 1032: end, 1033: lists:seq(1, 64)) 1034: end, 1035: ?line SndrsStart = fun (Sndrs) -> 1036: Parent = self(), 1037: spawn_link( 1038: SNode, 1039: fun () -> 1040: lists:foreach(fun (P) -> 1041: P ! {go, Parent} 1042: end, 1043: Sndrs) 1044: end) 1045: end, 1046: ?line SndrsWait = fun (Sndrs) -> 1047: lists:foreach(fun (P) -> 1048: receive {P, done} -> ok end 1049: end, 1050: Sndrs) 1051: end, 1052: ?line DPR = spawn_link(RNode, ?MODULE, dist_parallel_receiver, []), 1053: ?line Sndrs1 = MkSndrs(DPR), 1054: ?line SndrsStart(Sndrs1), 1055: ?line SndrsWait(Sndrs1), 1056: ?line unlink(DPR), 1057: ?line exit(DPR, bang), 1058: 1059: ?line DEPR = spawn_link(RNode, ?MODULE, dist_evil_parallel_receiver, []), 1060: ?line Sndrs2 = MkSndrs(DEPR), 1061: ?line SndrsStart(Sndrs2), 1062: ?line SndrsWait(Sndrs2), 1063: ?line unlink(DEPR), 1064: ?line exit(DEPR, bang), 1065: 1066: ?line unlink(WatchDog), 1067: ?line exit(WatchDog, bang), 1068: 1069: ?line stop_node(RNode), 1070: ?line stop_node(SNode), 1071: 1072: ?line ok. 1073: 1074: do_dist_parallel_sender(Parent, _Receiver, 0) -> 1075: Parent ! {self(), done}; 1076: do_dist_parallel_sender(Parent, Receiver, N) -> 1077: Receiver ! {self(), "Some data"}, 1078: do_dist_parallel_sender(Parent, Receiver, N-1). 1079: 1080: dist_parallel_sender(Parent, Receiver, N) -> 1081: receive {go, Parent} -> ok end, 1082: do_dist_parallel_sender(Parent, Receiver, N). 1083: 1084: dist_parallel_receiver() -> 1085: receive {_Sender, _Data} -> ok end, 1086: dist_parallel_receiver(). 1087: 1088: dist_evil_parallel_receiver() -> 1089: receive {Sender, _Data} -> ok end, 1090: net_kernel:disconnect(node(Sender)), 1091: dist_evil_parallel_receiver(). 1092: 1093: atom_roundtrip(Config) when is_list(Config) -> 1094: ?line AtomData = atom_data(), 1095: ?line verify_atom_data(AtomData), 1096: ?line {ok, Node} = start_node(Config), 1097: ?line do_atom_roundtrip(Node, AtomData), 1098: ?line stop_node(Node), 1099: ?line ok. 1100: 1101: atom_roundtrip_r15b(Config) when is_list(Config) -> 1102: case ?t:is_release_available("r15b") of 1103: true -> 1104: ?line AtomData = atom_data(), 1105: ?line verify_atom_data(AtomData), 1106: ?line {ok, Node} = start_node(Config, [], "r15b"), 1107: ?line do_atom_roundtrip(Node, AtomData), 1108: ?line stop_node(Node), 1109: ?line ok; 1110: false -> 1111: ?line {skip,"No OTP R15B available"} 1112: end. 1113: 1114: unicode_atom_roundtrip(Config) when is_list(Config) -> 1115: ?line AtomData = unicode_atom_data(), 1116: ?line verify_atom_data(AtomData), 1117: ?line {ok, Node} = start_node(Config), 1118: ?line do_atom_roundtrip(Node, AtomData), 1119: ?line stop_node(Node), 1120: ?line ok. 1121: 1122: do_atom_roundtrip(Node, AtomData) -> 1123: ?line Parent = self(), 1124: ?line Proc = spawn_link(Node, fun () -> verify_atom_data_loop(Parent) end), 1125: ?line Proc ! {self(), AtomData}, 1126: ?line receive {Proc, AD1} -> AtomData = AD1 end, 1127: ?line Proc ! {self(), AtomData}, 1128: ?line receive {Proc, AD2} -> AtomData = AD2 end, 1129: ?line RevAtomData = lists:reverse(AtomData), 1130: ?line Proc ! {self(), RevAtomData}, 1131: ?line receive {Proc, RAD1} -> RevAtomData = RAD1 end, 1132: ?line unlink(Proc), 1133: ?line exit(Proc, bang), 1134: ?line ok. 1135: 1136: verify_atom_data_loop(From) -> 1137: receive 1138: {From, AtomData} -> 1139: verify_atom_data(AtomData), 1140: From ! {self(), AtomData}, 1141: verify_atom_data_loop(From) 1142: end. 1143: 1144: atom_data() -> 1145: lists:map(fun (N) -> 1146: ATxt = "a"++integer_to_list(N), 1147: {list_to_atom(ATxt), ATxt} 1148: end, 1149: lists:seq(1, 2000)). 1150: 1151: verify_atom_data(AtomData) -> 1152: lists:foreach(fun ({Atom, AtomTxt}) when is_atom(Atom) -> 1153: AtomTxt = atom_to_list(Atom); 1154: ({PPR, AtomTxt}) -> 1155: % Pid, Port, or Ref 1156: AtomTxt = atom_to_list(node(PPR)) 1157: end, 1158: AtomData). 1159: 1160: uc_atom_tup(ATxt) -> 1161: Atom = string_to_atom(ATxt), 1162: ATxt = atom_to_list(Atom), 1163: {Atom, ATxt}. 1164: 1165: uc_pid_tup(ATxt) -> 1166: ATxtExt = string_to_atom_ext(ATxt), 1167: Pid = mk_pid({ATxtExt, 1}, 4711,17), 1168: true = is_pid(Pid), 1169: Atom = node(Pid), 1170: true = is_atom(Atom), 1171: ATxt = atom_to_list(Atom), 1172: {Pid, ATxt}. 1173: 1174: uc_port_tup(ATxt) -> 1175: ATxtExt = string_to_atom_ext(ATxt), 1176: Port = mk_port({ATxtExt, 2}, 4711), 1177: true = is_port(Port), 1178: Atom = node(Port), 1179: true = is_atom(Atom), 1180: ATxt = atom_to_list(Atom), 1181: {Port, ATxt}. 1182: 1183: uc_ref_tup(ATxt) -> 1184: ATxtExt = string_to_atom_ext(ATxt), 1185: Ref = mk_ref({ATxtExt, 3}, [4711,17, 4711]), 1186: true = is_reference(Ref), 1187: Atom = node(Ref), 1188: true = is_atom(Atom), 1189: ATxt = atom_to_list(Atom), 1190: {Ref, ATxt}. 1191: 1192: 1193: unicode_atom_data() -> 1194: [uc_pid_tup(lists:seq(16#1f600, 16#1f600+249) ++ "@host"), 1195: uc_pid_tup(lists:seq(16#1f600, 16#1f600+30) ++ "@host"), 1196: uc_port_tup(lists:seq(16#1f600, 16#1f600+249) ++ "@host"), 1197: uc_port_tup(lists:seq(16#1f600, 16#1f600+30) ++ "@host"), 1198: uc_ref_tup(lists:seq(16#1f600, 16#1f600+249) ++ "@host"), 1199: uc_ref_tup(lists:seq(16#1f600, 16#1f600+30) ++ "@host"), 1200: uc_atom_tup(lists:seq(16#1f600, 16#1f600+254)), 1201: uc_atom_tup(lists:seq(16#1f600, 16#1f600+63)), 1202: uc_atom_tup(lists:seq(0, 254)), 1203: uc_atom_tup(lists:seq(100, 163)), 1204: uc_atom_tup(lists:seq(200, 354)), 1205: uc_atom_tup(lists:seq(200, 263)), 1206: uc_atom_tup(lists:seq(2000, 2254)), 1207: uc_atom_tup(lists:seq(2000, 2063)), 1208: uc_atom_tup(lists:seq(65500, 65754)), 1209: uc_atom_tup(lists:seq(65500, 65563)) 1210: | lists:map(fun (N) -> 1211: uc_atom_tup(lists:seq(64000+N, 64254+N)) 1212: end, 1213: lists:seq(1, 2000))]. 1214: 1215: contended_atom_cache_entry(Config) when is_list(Config) -> 1216: contended_atom_cache_entry_test(Config, latin1). 1217: 1218: contended_unicode_atom_cache_entry(Config) when is_list(Config) -> 1219: contended_atom_cache_entry_test(Config, unicode). 1220: 1221: contended_atom_cache_entry_test(Config, Type) -> 1222: ?line TestServer = self(), 1223: ?line ProcessPairs = 10, 1224: ?line Msgs = 100000, 1225: ?line {ok, SNode} = start_node(Config), 1226: ?line {ok, RNode} = start_node(Config), 1227: ?line Success = make_ref(), 1228: ?line spawn_link( 1229: SNode, 1230: fun () -> 1231: erts_debug:set_internal_state(available_internal_state, 1232: true), 1233: Master = self(), 1234: CIX = get_cix(), 1235: TestAtoms = case Type of 1236: latin1 -> 1237: get_conflicting_atoms(CIX, 1238: ProcessPairs); 1239: unicode -> 1240: get_conflicting_unicode_atoms(CIX, 1241: ProcessPairs) 1242: end, 1243: io:format("Testing with the following atoms all using " 1244: "cache index ~p:~n ~w~n", 1245: [CIX, TestAtoms]), 1246: Ps = lists:map( 1247: fun (A) -> 1248: Ref = make_ref(), 1249: R = spawn_link( 1250: RNode, 1251: fun () -> 1252: Atom = receive 1253: {Ref, txt, ATxt} -> 1254: case Type of 1255: latin1 -> 1256: list_to_atom(ATxt); 1257: unicode -> 1258: string_to_atom(ATxt) 1259: end 1260: end, 1261: receive_ref_atom(Ref, 1262: Atom, 1263: Msgs), 1264: Master ! {self(), success} 1265: end), 1266: S = spawn_link( 1267: SNode, 1268: fun () -> 1269: receive go -> ok end, 1270: R ! {Ref, 1271: txt, 1272: atom_to_list(A)}, 1273: send_ref_atom(R, Ref, A, Msgs) 1274: end), 1275: {S, R} 1276: end, 1277: TestAtoms), 1278: lists:foreach(fun ({S, _}) -> 1279: S ! go 1280: end, 1281: Ps), 1282: lists:foreach(fun ({_, R}) -> 1283: receive {R, success} -> ok end 1284: end, 1285: Ps), 1286: TestServer ! Success 1287: end), 1288: ?line receive 1289: Success -> 1290: ok 1291: end, 1292: ?line stop_node(SNode), 1293: ?line stop_node(RNode), 1294: ?line ok. 1295: 1296: send_ref_atom(_To, _Ref, _Atom, 0) -> 1297: ok; 1298: send_ref_atom(To, Ref, Atom, N) -> 1299: To ! {Ref, Atom}, 1300: send_ref_atom(To, Ref, Atom, N-1). 1301: 1302: receive_ref_atom(_Ref, _Atom, 0) -> 1303: ok; 1304: receive_ref_atom(Ref, Atom, N) -> 1305: receive 1306: {Ref, Value} -> 1307: Atom = Value 1308: end, 1309: receive_ref_atom(Ref, Atom, N-1). 1310: 1311: get_cix() -> 1312: get_cix(1000). 1313: 1314: get_cix(CIX) when is_integer(CIX), CIX < 0 -> 1315: get_cix(0); 1316: get_cix(CIX) when is_integer(CIX) -> 1317: get_cix(CIX, 1318: unwanted_cixs(), 1319: erts_debug:get_internal_state(max_atom_out_cache_index)). 1320: 1321: get_cix(CIX, Unwanted, MaxCIX) when CIX > MaxCIX -> 1322: get_cix(0, Unwanted, MaxCIX); 1323: get_cix(CIX, Unwanted, MaxCIX) -> 1324: case lists:member(CIX, Unwanted) of 1325: true -> get_cix(CIX+1, Unwanted, MaxCIX); 1326: false -> CIX 1327: end. 1328: 1329: unwanted_cixs() -> 1330: lists:map(fun (Node) -> 1331: erts_debug:get_internal_state({atom_out_cache_index, 1332: Node}) 1333: end, 1334: nodes()). 1335: 1336: 1337: get_conflicting_atoms(_CIX, 0) -> 1338: []; 1339: get_conflicting_atoms(CIX, N) -> 1340: {A, B, C} = now(), 1341: Atom = list_to_atom("atom" ++ integer_to_list(A*1000000000000 1342: + B*1000000 1343: + C)), 1344: case erts_debug:get_internal_state({atom_out_cache_index, Atom}) of 1345: CIX -> 1346: [Atom|get_conflicting_atoms(CIX, N-1)]; 1347: _ -> 1348: get_conflicting_atoms(CIX, N) 1349: end. 1350: 1351: get_conflicting_unicode_atoms(_CIX, 0) -> 1352: []; 1353: get_conflicting_unicode_atoms(CIX, N) -> 1354: {A, B, C} = now(), 1355: Atom = string_to_atom([16#1f608] ++ "atom" ++ integer_to_list(A*1000000000000 1356: + B*1000000 1357: + C)), 1358: case erts_debug:get_internal_state({atom_out_cache_index, Atom}) of 1359: CIX -> 1360: [Atom|get_conflicting_unicode_atoms(CIX, N-1)]; 1361: _ -> 1362: get_conflicting_unicode_atoms(CIX, N) 1363: end. 1364: 1365: -define(COOKIE, ''). 1366: -define(DOP_LINK, 1). 1367: -define(DOP_SEND, 2). 1368: -define(DOP_EXIT, 3). 1369: -define(DOP_UNLINK, 4). 1370: -define(DOP_REG_SEND, 6). 1371: -define(DOP_GROUP_LEADER, 7). 1372: -define(DOP_EXIT2, 8). 1373: 1374: -define(DOP_SEND_TT, 12). 1375: -define(DOP_EXIT_TT, 13). 1376: -define(DOP_REG_SEND_TT, 16). 1377: -define(DOP_EXIT2_TT, 18). 1378: 1379: -define(DOP_MONITOR_P, 19). 1380: -define(DOP_DEMONITOR_P, 20). 1381: -define(DOP_MONITOR_P_EXIT, 21). 1382: 1383: start_monitor(Offender,P) -> 1384: ?line Parent = self(), 1385: ?line Q = spawn(Offender, 1386: fun () -> 1387: Ref = erlang:monitor(process,P), 1388: Parent ! {self(),ref,Ref}, 1389: receive 1390: just_stay_alive -> ok 1391: end 1392: end), 1393: ?line Ref = receive 1394: {Q,ref,R} -> 1395: R 1396: after 5000 -> 1397: error 1398: end, 1399: io:format("Ref is ~p~n",[Ref]), 1400: ok. 1401: start_link(Offender,P) -> 1402: ?line Parent = self(), 1403: ?line Q = spawn(Offender, 1404: fun () -> 1405: process_flag(trap_exit,true), 1406: link(P), 1407: Parent ! {self(),ref,P}, 1408: receive 1409: just_stay_alive -> ok 1410: end 1411: end), 1412: ?line Ref = receive 1413: {Q,ref,R} -> 1414: R 1415: after 5000 -> 1416: error 1417: end, 1418: io:format("Ref is ~p~n",[Ref]), 1419: ok. 1420: 1421: bad_dist_structure(suite) -> 1422: []; 1423: bad_dist_structure(doc) -> 1424: ["Test dist messages with valid structure (binary to term ok) but malformed" 1425: "control content"]; 1426: bad_dist_structure(Config) when is_list(Config) -> 1427: %process_flag(trap_exit,true), 1428: ODog = ?config(watchdog, Config), 1429: ?t:timetrap_cancel(ODog), 1430: Dog = ?t:timetrap(?t:seconds(15)), 1431: 1432: ?line {ok, Offender} = start_node(bad_dist_structure_offender), 1433: ?line {ok, Victim} = start_node(bad_dist_structure_victim), 1434: ?line start_node_monitors([Offender,Victim]), 1435: ?line Parent = self(), 1436: ?line P = spawn(Victim, 1437: fun () -> 1438: process_flag(trap_exit,true), 1439: Parent ! {self(), started}, 1440: receive check_msgs -> ok end, 1441: bad_dist_struct_check_msgs([one, 1442: two]), 1443: Parent ! {self(), messages_checked}, 1444: receive done -> ok end 1445: end), 1446: ?line receive {P, started} -> ok end, 1447: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1448: ?line verify_up(Offender, Victim), 1449: ?line true = lists:member(Offender, rpc:call(Victim, erlang, nodes, [])), 1450: ?line start_monitor(Offender,P), 1451: ?line P ! one, 1452: ?line send_bad_structure(Offender, P,{?DOP_MONITOR_P_EXIT,'replace',P,normal},2), 1453: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1454: ?line start_monitor(Offender,P), 1455: ?line send_bad_structure(Offender, P,{?DOP_MONITOR_P_EXIT,'replace',P,normal,normal},2), 1456: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1457: ?line start_link(Offender,P), 1458: ?line send_bad_structure(Offender, P,{?DOP_LINK},0), 1459: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1460: ?line start_link(Offender,P), 1461: ?line send_bad_structure(Offender, P,{?DOP_UNLINK,'replace'},2), 1462: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1463: ?line start_link(Offender,P), 1464: ?line send_bad_structure(Offender, P,{?DOP_UNLINK,'replace',make_ref()},2), 1465: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1466: ?line start_link(Offender,P), 1467: ?line send_bad_structure(Offender, P,{?DOP_UNLINK,make_ref(),P},0), 1468: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1469: ?line start_link(Offender,P), 1470: ?line send_bad_structure(Offender, P,{?DOP_UNLINK,normal,normal},0), 1471: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1472: ?line start_monitor(Offender,P), 1473: ?line send_bad_structure(Offender, P,{?DOP_MONITOR_P,'replace',P},2), 1474: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1475: ?line start_monitor(Offender,P), 1476: ?line send_bad_structure(Offender, P,{?DOP_MONITOR_P,'replace',P,normal},2), 1477: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1478: ?line start_monitor(Offender,P), 1479: ?line send_bad_structure(Offender, P,{?DOP_DEMONITOR_P,'replace',P},2), 1480: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1481: ?line start_monitor(Offender,P), 1482: ?line send_bad_structure(Offender, P,{?DOP_DEMONITOR_P,'replace',P,normal},2), 1483: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1484: ?line send_bad_structure(Offender, P,{?DOP_EXIT,'replace',P},2), 1485: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1486: ?line send_bad_structure(Offender, P,{?DOP_EXIT,make_ref(),normal,normal},0), 1487: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1488: ?line send_bad_structure(Offender, P,{?DOP_EXIT_TT,'replace',token,P},2), 1489: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1490: ?line send_bad_structure(Offender, P,{?DOP_EXIT_TT,make_ref(),token,normal,normal},0), 1491: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1492: ?line send_bad_structure(Offender, P,{?DOP_EXIT2,'replace',P},2), 1493: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1494: ?line send_bad_structure(Offender, P,{?DOP_EXIT2,make_ref(),normal,normal},0), 1495: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1496: ?line send_bad_structure(Offender, P,{?DOP_EXIT2_TT,'replace',token,P},2), 1497: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1498: ?line send_bad_structure(Offender, P,{?DOP_EXIT2_TT,make_ref(),token,normal,normal},0), 1499: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1500: ?line send_bad_structure(Offender, P,{?DOP_GROUP_LEADER,'replace'},2), 1501: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1502: ?line send_bad_structure(Offender, P,{?DOP_GROUP_LEADER,'replace','atomic'},2), 1503: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1504: ?line send_bad_structure(Offender, P,{?DOP_GROUP_LEADER,'replace',P},0), 1505: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1506: ?line send_bad_structure(Offender, P,{?DOP_REG_SEND_TT,'replace','',name},2,{message}), 1507: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1508: ?line send_bad_structure(Offender, P,{?DOP_REG_SEND_TT,'replace','',name,token},0,{message}), 1509: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1510: ?line send_bad_structure(Offender, P,{?DOP_REG_SEND,'replace',''},2,{message}), 1511: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1512: ?line send_bad_structure(Offender, P,{?DOP_REG_SEND,'replace','',P},0,{message}), 1513: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1514: ?line send_bad_structure(Offender, P,{?DOP_REG_SEND,'replace','',name},0,{message}), 1515: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1516: ?line send_bad_structure(Offender, P,{?DOP_REG_SEND,'replace','',name,{token}},2,{message}), 1517: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1518: ?line send_bad_structure(Offender, P,{?DOP_SEND_TT,'',P},0,{message}), 1519: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1520: ?line send_bad_structure(Offender, P,{?DOP_SEND_TT,'',name,token},0,{message}), 1521: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1522: ?line send_bad_structure(Offender, P,{?DOP_SEND,''},0,{message}), 1523: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1524: ?line send_bad_structure(Offender, P,{?DOP_SEND,'',name},0,{message}), 1525: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1526: ?line send_bad_structure(Offender, P,{?DOP_SEND,'',P,{token}},0,{message}), 1527: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1528: ?line P ! two, 1529: ?line P ! check_msgs, 1530: ?line receive 1531: {P, messages_checked} -> ok 1532: after 5000 -> 1533: exit(victim_is_dead) 1534: end, 1535: 1536: ?line {message_queue_len, 0} 1537: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1538: 1539: ?line unlink(P), 1540: ?line P ! done, 1541: ?line stop_node(Offender), 1542: ?line stop_node(Victim), 1543: ?t:timetrap_cancel(Dog), 1544: ok. 1545: 1546: 1547: 1548: bad_dist_ext_receive(Config) when is_list(Config) -> 1549: ?line {ok, Offender} = start_node(bad_dist_ext_receive_offender), 1550: ?line {ok, Victim} = start_node(bad_dist_ext_receive_victim), 1551: ?line start_node_monitors([Offender,Victim]), 1552: 1553: ?line Parent = self(), 1554: 1555: ?line P = spawn_link(Victim, 1556: fun () -> 1557: Parent ! {self(), started}, 1558: receive check_msgs -> ok end, 1559: bad_dist_ext_check_msgs([one, 1560: two, 1561: three]), 1562: Parent ! {self(), messages_checked}, 1563: receive done -> ok end 1564: end), 1565: 1566: ?line receive {P, started} -> ok end, 1567: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1568: ?line verify_up(Offender, Victim), 1569: ?line true = lists:member(Offender, rpc:call(Victim, erlang, nodes, [])), 1570: ?line P ! one, 1571: ?line send_bad_msg(Offender, P), 1572: ?line P ! two, 1573: ?line verify_down(Offender, connection_closed, Victim, killed), 1574: ?line {message_queue_len, 2} 1575: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1576: 1577: ?line Suspended = make_ref(), 1578: ?line S = spawn(Victim, 1579: fun () -> 1580: erlang:suspend_process(P), 1581: Parent ! Suspended, 1582: receive after infinity -> ok end 1583: end), 1584: ?line MS = erlang:monitor(process, S), 1585: ?line receive Suspended -> ok end, 1586: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1587: ?line verify_up(Offender, Victim), 1588: ?line true = lists:member(Offender, rpc:call(Victim, erlang, nodes, [])), 1589: ?line send_bad_msgs(Offender, P, 5), 1590: ?line true = lists:member(Offender, rpc:call(Victim, erlang, nodes, [])), 1591: ?line P ! three, 1592: ?line send_bad_msgs(Offender, P, 5), 1593: 1594: %% Make sure bad msgs has reached Victim 1595: ?line rpc:call(Offender, rpc, call, [Victim, erlang, node, []]), 1596: 1597: ?line verify_still_up(Offender, Victim), 1598: ?line {message_queue_len, 13} 1599: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1600: 1601: ?line exit(S, bang), 1602: ?line receive {'DOWN', MS, process, S, bang} -> ok end, 1603: ?line verify_down(Offender, connection_closed, Victim, killed), 1604: ?line {message_queue_len, 3} 1605: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1606: 1607: ?line P ! check_msgs, 1608: ?line receive {P, messages_checked} -> ok end, 1609: 1610: ?line {message_queue_len, 0} 1611: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1612: 1613: ?line P ! done, 1614: ?line unlink(P), 1615: ?line verify_no_down(Offender, Victim), 1616: ?line stop_node(Offender), 1617: ?line stop_node(Victim). 1618: 1619: 1620: bad_dist_ext_process_info(Config) when is_list(Config) -> 1621: ?line {ok, Offender} = start_node(bad_dist_ext_process_info_offender), 1622: ?line {ok, Victim} = start_node(bad_dist_ext_process_info_victim), 1623: ?line start_node_monitors([Offender,Victim]), 1624: 1625: ?line Parent = self(), 1626: ?line P = spawn_link(Victim, 1627: fun () -> 1628: Parent ! {self(), started}, 1629: receive check_msgs -> ok end, 1630: bad_dist_ext_check_msgs([one, two]), 1631: Parent ! {self(), messages_checked}, 1632: receive done -> ok end 1633: end), 1634: 1635: ?line receive {P, started} -> ok end, 1636: ?line P ! one, 1637: 1638: ?line Suspended = make_ref(), 1639: ?line S = spawn(Victim, 1640: fun () -> 1641: erlang:suspend_process(P), 1642: Parent ! Suspended, 1643: receive after infinity -> ok end 1644: end), 1645: 1646: ?line receive Suspended -> ok end, 1647: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1648: ?line verify_up(Offender, Victim), 1649: ?line send_bad_msgs(Offender, P, 5), 1650: 1651: ?line P ! two, 1652: ?line send_bad_msgs(Offender, P, 5), 1653: 1654: %% Make sure bad msgs has reached Victim 1655: ?line rpc:call(Offender, rpc, call, [Victim, erlang, node, []]), 1656: 1657: ?line verify_still_up(Offender, Victim), 1658: ?line {message_queue_len, 12} 1659: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1660: ?line verify_still_up(Offender, Victim), 1661: ?line [{message_queue_len, 2}, 1662: {messages, [one, two]}] 1663: = rpc:call(Victim, erlang, process_info, [P, [message_queue_len, 1664: messages]]), 1665: ?line verify_down(Offender, connection_closed, Victim, killed), 1666: 1667: ?line P ! check_msgs, 1668: ?line exit(S, bang), 1669: ?line receive {P, messages_checked} -> ok end, 1670: 1671: ?line {message_queue_len, 0} 1672: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1673: 1674: ?line P ! done, 1675: ?line unlink(P), 1676: ?line verify_no_down(Offender, Victim), 1677: ?line stop_node(Offender), 1678: ?line stop_node(Victim). 1679: 1680: bad_dist_ext_control(Config) when is_list(Config) -> 1681: ?line {ok, Offender} = start_node(bad_dist_ext_control_offender), 1682: ?line {ok, Victim} = start_node(bad_dist_ext_control_victim), 1683: ?line start_node_monitors([Offender,Victim]), 1684: 1685: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1686: ?line verify_up(Offender, Victim), 1687: ?line send_bad_dhdr(Offender, Victim), 1688: ?line verify_down(Offender, connection_closed, Victim, killed), 1689: 1690: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1691: ?line verify_up(Offender, Victim), 1692: ?line send_bad_ctl(Offender, Victim), 1693: ?line verify_down(Offender, connection_closed, Victim, killed), 1694: 1695: ?line verify_no_down(Offender, Victim), 1696: ?line stop_node(Offender), 1697: ?line stop_node(Victim). 1698: 1699: bad_dist_ext_connection_id(Config) when is_list(Config) -> 1700: ?line {ok, Offender} = start_node(bad_dist_ext_connection_id_offender), 1701: ?line {ok, Victim} = start_node(bad_dist_ext_connection_id_victim), 1702: ?line start_node_monitors([Offender,Victim]), 1703: 1704: ?line Parent = self(), 1705: ?line P = spawn_link(Victim, 1706: fun () -> 1707: Parent ! {self(), started}, 1708: receive check_msgs -> ok end, 1709: bad_dist_ext_check_msgs([]), 1710: Parent ! {self(), messages_checked}, 1711: receive done -> ok end 1712: end), 1713: 1714: ?line receive {P, started} -> ok end, 1715: ?line Suspended = make_ref(), 1716: ?line S = spawn(Victim, 1717: fun () -> 1718: erlang:suspend_process(P), 1719: Parent ! Suspended, 1720: receive after infinity -> ok end 1721: end), 1722: ?line MS = erlang:monitor(process, S), 1723: ?line receive Suspended -> ok end, 1724: ?line pong = rpc:call(Victim, net_adm, ping, [Offender]), 1725: ?line verify_up(Offender, Victim), 1726: ?line send_bad_msg(Offender, P), 1727: 1728: %% Make sure bad msg has reached Victim 1729: ?line rpc:call(Offender, rpc, call, [Victim, erlang, node, []]), 1730: 1731: ?line {message_queue_len, 1} 1732: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1733: 1734: ?line true = rpc:call(Offender, net_kernel, disconnect, [Victim]), 1735: ?line verify_down(Offender, disconnect, Victim, connection_closed), 1736: ?line pong = rpc:call(Offender, net_adm, ping, [Victim]), 1737: 1738: ?line verify_up(Offender, Victim), 1739: %% We have a new connection between Offender and Victim, bad message 1740: %% should not bring it down. 1741: 1742: ?line {message_queue_len, 1} 1743: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1744: 1745: ?line exit(S, bang), 1746: ?line receive {'DOWN', MS, process, S, bang} -> ok end, 1747: %% Wait for a while (if the connection is taken down it might take a 1748: %% while). 1749: ?line receive after 2000 -> ok end, 1750: ?line verify_still_up(Offender, Victim), 1751: 1752: ?line P ! check_msgs, 1753: ?line receive {P, messages_checked} -> ok end, 1754: 1755: ?line {message_queue_len, 0} 1756: = rpc:call(Victim, erlang, process_info, [P, message_queue_len]), 1757: 1758: ?line verify_still_up(Offender, Victim), 1759: ?line P ! done, 1760: ?line unlink(P), 1761: ?line verify_no_down(Offender, Victim), 1762: ?line stop_node(Offender), 1763: ?line stop_node(Victim). 1764: 1765: 1766: bad_dist_struct_check_msgs([]) -> 1767: receive 1768: Msg -> 1769: exit({unexpected_message, Msg}) 1770: after 0 -> 1771: ok 1772: end; 1773: bad_dist_struct_check_msgs([M|Ms]) -> 1774: receive 1775: {'EXIT',_,_} = EM -> 1776: io:format("Ignoring exit message: ~p~n",[EM]), 1777: bad_dist_struct_check_msgs([M|Ms]); 1778: Msg -> 1779: M = Msg, 1780: bad_dist_struct_check_msgs(Ms) 1781: end. 1782: bad_dist_ext_check_msgs([]) -> 1783: receive 1784: Msg -> 1785: exit({unexpected_message, Msg}) 1786: after 0 -> 1787: ok 1788: end; 1789: bad_dist_ext_check_msgs([M|Ms]) -> 1790: receive 1791: Msg -> 1792: M = Msg, 1793: bad_dist_ext_check_msgs(Ms) 1794: end. 1795: 1796: 1797: dport_reg_send(Node, Name, Msg) -> 1798: DPrt = case dport(Node) of 1799: undefined -> 1800: pong = net_adm:ping(Node), 1801: dport(Node); 1802: Prt -> 1803: Prt 1804: end, 1805: port_command(DPrt, [dmsg_hdr(), 1806: dmsg_ext({?DOP_REG_SEND, 1807: self(), 1808: ?COOKIE, 1809: Name}), 1810: dmsg_ext(Msg)]). 1811: 1812: 1813: dport_send(To, Msg) -> 1814: Node = node(To), 1815: DPrt = case dport(Node) of 1816: undefined -> 1817: pong = net_adm:ping(Node), 1818: dport(Node); 1819: Prt -> 1820: Prt 1821: end, 1822: port_command(DPrt, [dmsg_hdr(), 1823: dmsg_ext({?DOP_SEND, 1824: ?COOKIE, 1825: To}), 1826: dmsg_ext(Msg)]). 1827: send_bad_structure(Offender,Victim,Bad,WhereToPutSelf) -> 1828: send_bad_structure(Offender,Victim,Bad,WhereToPutSelf,[]). 1829: send_bad_structure(Offender,Victim,Bad,WhereToPutSelf,PayLoad) -> 1830: Parent = self(), 1831: Done = make_ref(), 1832: spawn(Offender, 1833: fun () -> 1834: Node = node(Victim), 1835: pong = net_adm:ping(Node), 1836: DPrt = dport(Node), 1837: Bad1 = case WhereToPutSelf of 1838: 0 -> 1839: Bad; 1840: N when N > 0 -> 1841: setelement(N,Bad,self()) 1842: end, 1843: DData = [dmsg_hdr(), 1844: dmsg_ext(Bad1)] ++ 1845: case PayLoad of 1846: [] -> []; 1847: _Other -> [dmsg_ext(PayLoad)] 1848: end, 1849: port_command(DPrt, DData), 1850: Parent ! {DData,Done} 1851: end), 1852: receive 1853: {WhatSent,Done} -> 1854: io:format("Offender sent ~p~n",[WhatSent]), 1855: ok 1856: after 5000 -> 1857: exit(unable_to_send) 1858: end. 1859: 1860: 1861: %% send_bad_msgs(): 1862: %% Send a valid distribution header and control message 1863: %% but an invalid message. This invalid message will be 1864: %% enqueued in the receivers message queue. 1865: send_bad_msg(BadNode, To) -> 1866: send_bad_msgs(BadNode, To, 1). 1867: 1868: send_bad_msgs(BadNode, To, Repeat) when is_atom(BadNode), 1869: is_pid(To), 1870: is_integer(Repeat) -> 1871: Parent = self(), 1872: Done = make_ref(), 1873: spawn_link(BadNode, 1874: fun () -> 1875: Node = node(To), 1876: pong = net_adm:ping(Node), 1877: DPrt = dport(Node), 1878: DData = [dmsg_hdr(), 1879: dmsg_ext({?DOP_SEND, ?COOKIE, To}), 1880: dmsg_bad_atom_cache_ref()], 1881: repeat(fun () -> port_command(DPrt, DData) end, Repeat), 1882: Parent ! Done 1883: end), 1884: receive Done -> ok end. 1885: 1886: %% send_bad_ctl(): 1887: %% Send a valid distribution header but an invalid control message. 1888: send_bad_ctl(BadNode, ToNode) when is_atom(BadNode), is_atom(ToNode) -> 1889: Parent = self(), 1890: Done = make_ref(), 1891: spawn_link(BadNode, 1892: fun () -> 1893: pong = net_adm:ping(ToNode), 1894: %% We creat a valid ctl msg and replace an 1895: %% atom with an invalid atom cache reference 1896: <<131,Replace/binary>> = term_to_binary(replace), 1897: Ctl = dmsg_ext({?DOP_REG_SEND, 1898: self(), 1899: ?COOKIE, 1900: replace}), 1901: CtlBeginSize = size(Ctl) - size(Replace), 1902: <<CtlBegin:CtlBeginSize/binary, Replace/binary>> = Ctl, 1903: port_command(dport(ToNode), 1904: [dmsg_fake_hdr2(), 1905: CtlBegin, 1906: dmsg_bad_atom_cache_ref(), 1907: dmsg_ext({a, message})]), 1908: Parent ! Done 1909: end), 1910: receive Done -> ok end. 1911: 1912: %% send_bad_dhr(): 1913: %% Send an invalid distribution header 1914: send_bad_dhdr(BadNode, ToNode) when is_atom(BadNode), is_atom(ToNode) -> 1915: Parent = self(), 1916: Done = make_ref(), 1917: spawn_link(BadNode, 1918: fun () -> 1919: pong = net_adm:ping(ToNode), 1920: port_command(dport(ToNode), dmsg_bad_hdr()), 1921: Parent ! Done 1922: end), 1923: receive Done -> ok end. 1924: 1925: dport(Node) when is_atom(Node) -> 1926: case catch erts_debug:get_internal_state(available_internal_state) of 1927: true -> true; 1928: _ -> erts_debug:set_internal_state(available_internal_state, true) 1929: end, 1930: erts_debug:get_internal_state({dist_port, Node}). 1931: 1932: dmsg_hdr() -> 1933: [131, % Version Magic 1934: $D, % Dist header 1935: 0]. % No atom cache referenses 1936: 1937: dmsg_bad_hdr() -> 1938: [131, % Version Magic 1939: $D, % Dist header 1940: 255]. % 255 atom references 1941: 1942: 1943: %% dmsg_fake_hdr1() -> 1944: %% A = <<"fake header atom 1">>, 1945: %% [131, % Version Magic 1946: %% $D, 1, 16#8, 0, size(A), A]. % Fake header 1947: 1948: dmsg_fake_hdr2() -> 1949: A1 = <<"fake header atom 1">>, 1950: A2 = <<"atom 2">>, 1951: A3 = <<"atom 3">>, 1952: [131, % Version Magic 1953: $D, 1954: 3, 1955: 16#88, 16#08, % Flags 1956: 0, size(A1), A1, 1957: 1, size(A2), A2, 1958: 2, size(A3), A3]. 1959: 1960: dmsg_ext(Term) -> 1961: <<131, Res/binary>> = term_to_binary(Term), 1962: Res. 1963: 1964: dmsg_bad_atom_cache_ref() -> 1965: [$R, 137]. 1966: 1967: %%% Utilities 1968: 1969: timestamp() -> 1970: {A,B,C} = erlang:now(), 1971: (C div 1000) + (B * 1000) + (A * 1000000000). 1972: 1973: start_node(X) -> 1974: start_node(X, [], []). 1975: 1976: start_node(X, Y) -> 1977: start_node(X, Y, []). 1978: 1979: start_node(Name, Args, Rel) when is_atom(Name), is_list(Rel) -> 1980: Pa = filename:dirname(code:which(?MODULE)), 1981: Cookie = atom_to_list(erlang:get_cookie()), 1982: RelArg = case Rel of 1983: [] -> []; 1984: _ -> [{erl,[{release,Rel}]}] 1985: end, 1986: test_server:start_node(Name, slave, 1987: [{args, 1988: Args++" -setcookie "++Cookie++" -pa \""++Pa++"\""} 1989: | RelArg]); 1990: start_node(Config, Args, Rel) when is_list(Config), is_list(Rel) -> 1991: Name = list_to_atom((atom_to_list(?MODULE) 1992: ++ "-" 1993: ++ atom_to_list(?config(testcase, Config)) 1994: ++ "-" 1995: ++ integer_to_list(timestamp()))), 1996: start_node(Name, Args, Rel). 1997: 1998: stop_node(Node) -> 1999: test_server:stop_node(Node). 2000: 2001: freeze_node(Node, MS) -> 2002: Own = 300, 2003: DoingIt = make_ref(), 2004: Freezer = self(), 2005: spawn_link(Node, 2006: fun () -> 2007: erts_debug:set_internal_state(available_internal_state, 2008: true), 2009: dport_send(Freezer, DoingIt), 2010: receive after Own -> ok end, 2011: erts_debug:set_internal_state(block, MS+Own) 2012: end), 2013: receive DoingIt -> ok end, 2014: receive after Own -> ok end. 2015: 2016: inet_rpc_nodename({N,H,_Sock}) -> 2017: list_to_atom(N++"@"++H). 2018: 2019: do_inet_rpc({_,_,Sock},M,F,A) -> 2020: Bin = term_to_binary({M,F,A}), 2021: gen_tcp:send(Sock,Bin), 2022: case gen_tcp:recv(Sock,0) of 2023: {ok, Bin2} -> 2024: T = binary_to_term(Bin2), 2025: {ok,T}; 2026: Else -> 2027: {error, Else} 2028: end. 2029: 2030: inet_rpc_server([Host, PortList]) -> 2031: Port = list_to_integer(PortList), 2032: {ok, Sock} = gen_tcp:connect(Host, Port,[binary, {packet, 4}, 2033: {active, false}]), 2034: inet_rpc_server_loop(Sock). 2035: 2036: inet_rpc_server_loop(Sock) -> 2037: case gen_tcp:recv(Sock,0) of 2038: {ok, Bin} -> 2039: {M,F,A} = binary_to_term(Bin), 2040: Res = (catch apply(M,F,A)), 2041: RB = term_to_binary(Res), 2042: gen_tcp:send(Sock,RB), 2043: inet_rpc_server_loop(Sock); 2044: _ -> 2045: erlang:halt() 2046: end. 2047: 2048: 2049: start_relay_node(Node, Args) -> 2050: Pa = filename:dirname(code:which(?MODULE)), 2051: Cookie = "NOT"++atom_to_list(erlang:get_cookie()), 2052: {ok, LSock} = gen_tcp:listen(0, [binary, {packet, 4}, 2053: {active, false}]), 2054: {ok, Port} = inet:port(LSock), 2055: {ok, Host} = inet:gethostname(), 2056: RunArg = "-run " ++ atom_to_list(?MODULE) ++ " inet_rpc_server " ++ 2057: Host ++ " " ++ integer_to_list(Port), 2058: {ok, NN} = 2059: test_server:start_node(Node, peer, 2060: [{args, Args ++ 2061: " -setcookie "++Cookie++" -pa "++Pa++" "++ 2062: RunArg}]), 2063: [N,H] = string:tokens(atom_to_list(NN),"@"), 2064: {ok, Sock} = gen_tcp:accept(LSock), 2065: pang = net_adm:ping(NN), 2066: {N,H,Sock}. 2067: 2068: stop_relay_node({N,H,Sock}) -> 2069: catch do_inet_rpc(Sock,erlang,halt,[]), 2070: catch gen_tcp:close(Sock), 2071: wait_dead(N,H,10). 2072: 2073: wait_dead(N,H,0) -> 2074: {error,{not_dead,N,H}}; 2075: wait_dead(N,H,X) -> 2076: case erl_epmd:port_please(N,H) of 2077: {port,_,_} -> 2078: receive 2079: after 1000 -> 2080: ok 2081: end, 2082: wait_dead(N,H,X-1); 2083: noport -> 2084: ok; 2085: Else -> 2086: {error, {unexpected, Else}} 2087: end. 2088: 2089: 2090: start_node_monitors(Nodes) -> 2091: Master = self(), 2092: lists:foreach(fun (Node) -> 2093: spawn(Node, 2094: fun () -> 2095: node_monitor(Master) 2096: end) 2097: end, 2098: Nodes), 2099: ok. 2100: 2101: node_monitor(Master) -> 2102: Opts = [nodedown_reason,{node_type,all}], 2103: Nodes0 = nodes(connected), 2104: net_kernel:monitor_nodes(true, Opts), 2105: Nodes1 = nodes(connected), 2106: case lists:sort(Nodes0) == lists:sort(Nodes1) of 2107: true -> 2108: lists:foreach(fun (Node) -> 2109: Master ! {nodeup, node(), Node} 2110: end, 2111: Nodes0), 2112: ?t:format("~p ~p: ~p~n", [node(), erlang:now(), Nodes0]), 2113: node_monitor_loop(Master); 2114: false -> 2115: net_kernel:monitor_nodes(false, Opts), 2116: flush_node_changes(), 2117: node_monitor(Master) 2118: end. 2119: 2120: flush_node_changes() -> 2121: receive 2122: {NodeChange, _Node, _InfoList} when NodeChange == nodeup; 2123: NodeChange == nodedown -> 2124: flush_node_changes() 2125: after 0 -> 2126: ok 2127: end. 2128: 2129: node_monitor_loop(Master) -> 2130: receive 2131: {nodeup, Node, _InfoList} = Msg -> 2132: Master ! {nodeup, node(), Node}, 2133: ?t:format("~p ~p: ~p~n", [node(), erlang:now(), Msg]), 2134: node_monitor_loop(Master); 2135: {nodedown, Node, InfoList} = Msg -> 2136: Reason = case lists:keysearch(nodedown_reason, 1, InfoList) of 2137: {value, {nodedown_reason, R}} -> R; 2138: _ -> undefined 2139: end, 2140: Master ! {nodedown, node(), Node, Reason}, 2141: ?t:format("~p ~p: ~p~n", [node(), erlang:now(), Msg]), 2142: node_monitor_loop(Master) 2143: end. 2144: 2145: verify_up(A, B) -> 2146: receive {nodeup, A, B} -> ok end, 2147: receive {nodeup, B, A} -> ok end. 2148: 2149: verify_still_up(A, B) -> 2150: true = lists:member(B, rpc:call(A, erlang, nodes, [connected])), 2151: true = lists:member(A, rpc:call(B, erlang, nodes, [connected])), 2152: verify_no_down(A, B). 2153: 2154: verify_no_down(A, B) -> 2155: receive 2156: {nodedown, A, B, _} = Msg0 -> 2157: ?t:fail(Msg0) 2158: after 0 -> 2159: ok 2160: end, 2161: receive 2162: {nodedown, B, A, _} = Msg1 -> 2163: ?t:fail(Msg1) 2164: after 0 -> 2165: ok 2166: end. 2167: 2168: %% verify_down(A, B) -> 2169: %% receive {nodedown, A, B, _} -> ok end, 2170: %% receive {nodedown, B, A, _} -> ok end. 2171: 2172: verify_down(A, ReasonA, B, ReasonB) -> 2173: receive 2174: {nodedown, A, B, _} = Msg0 -> 2175: {nodedown, A, B, ReasonA} = Msg0 2176: end, 2177: receive 2178: {nodedown, B, A, _} = Msg1 -> 2179: {nodedown, B, A, ReasonB} = Msg1 2180: end, 2181: ok. 2182: 2183: hostname() -> 2184: from($@, atom_to_list(node())). 2185: 2186: from(H, [H | T]) -> T; 2187: from(H, [_ | T]) -> from(H, T); 2188: from(_, []) -> []. 2189: 2190: %% fun_spawn(Fun) -> 2191: %% fun_spawn(Fun, []). 2192: 2193: %% fun_spawn(Fun, Args) -> 2194: %% spawn_link(erlang, apply, [Fun, Args]). 2195: 2196: 2197: long_or_short() -> 2198: case net_kernel:longnames() of 2199: true -> " -name "; 2200: false -> " -sname " 2201: end. 2202: 2203: until(Fun) -> 2204: case Fun() of 2205: true -> 2206: ok; 2207: false -> 2208: receive after 10 -> ok end, 2209: until(Fun) 2210: end. 2211: 2212: forever(Fun) -> 2213: Fun(), 2214: forever(Fun). 2215: 2216: abort(Why) -> 2217: erts_debug:set_internal_state(available_internal_state, true), 2218: erts_debug:set_internal_state(abort, Why). 2219: 2220: 2221: start_busy_dist_port_tracer() -> 2222: Tracer = spawn_link(fun () -> busy_dist_port_tracer() end), 2223: erlang:system_monitor(Tracer, [busy_dist_port]), 2224: Tracer. 2225: 2226: stop_busy_dist_port_tracer(Tracer) when is_pid(Tracer) -> 2227: unlink(Tracer), 2228: exit(Tracer, bye); 2229: stop_busy_dist_port_tracer(_) -> 2230: true. 2231: 2232: busy_dist_port_tracer() -> 2233: receive 2234: {monitor, _SuspendedProcess, busy_dist_port, _Port} = M -> 2235: erlang:display(M), 2236: busy_dist_port_tracer() 2237: end. 2238: 2239: repeat(_Fun, 0) -> 2240: ok; 2241: repeat(Fun, N) -> 2242: Fun(), 2243: repeat(Fun, N-1). 2244: 2245: string_to_atom_ext(String) -> 2246: Utf8List = string_to_utf8_list(String), 2247: Len = length(Utf8List), 2248: case Len < 256 of 2249: true -> 2250: [?SMALL_ATOM_UTF8_EXT, Len | Utf8List]; 2251: false -> 2252: [?ATOM_UTF8_EXT, Len bsr 8, Len band 16#ff | Utf8List] 2253: end. 2254: 2255: string_to_atom(String) -> 2256: binary_to_term(list_to_binary([?VERSION_MAGIC 2257: | string_to_atom_ext(String)])). 2258: 2259: string_to_utf8_list([]) -> 2260: []; 2261: string_to_utf8_list([CP|CPs]) when is_integer(CP), 2262: 0 =< CP, 2263: CP =< 16#7F -> 2264: [CP | string_to_utf8_list(CPs)]; 2265: string_to_utf8_list([CP|CPs]) when is_integer(CP), 2266: 16#80 =< CP, 2267: CP =< 16#7FF -> 2268: [16#C0 bor (CP bsr 6), 2269: 16#80 bor (16#3F band CP) 2270: | string_to_utf8_list(CPs)]; 2271: string_to_utf8_list([CP|CPs]) when is_integer(CP), 2272: 16#800 =< CP, 2273: CP =< 16#FFFF -> 2274: [16#E0 bor (CP bsr 12), 2275: 16#80 bor (16#3F band (CP bsr 6)), 2276: 16#80 bor (16#3F band CP) 2277: | string_to_utf8_list(CPs)]; 2278: string_to_utf8_list([CP|CPs]) when is_integer(CP), 2279: 16#10000 =< CP, 2280: CP =< 16#10FFFF -> 2281: [16#F0 bor (CP bsr 18), 2282: 16#80 bor (16#3F band (CP bsr 12)), 2283: 16#80 bor (16#3F band (CP bsr 6)), 2284: 16#80 bor (16#3F band CP) 2285: | string_to_utf8_list(CPs)]. 2286: 2287: utf8_list_to_string([]) -> 2288: []; 2289: utf8_list_to_string([B|Bs]) when is_integer(B), 2290: 0 =< B, 2291: B =< 16#7F -> 2292: [B | utf8_list_to_string(Bs)]; 2293: utf8_list_to_string([B0, B1 | Bs]) when is_integer(B0), 2294: 16#C0 =< B0, 2295: B0 =< 16#DF, 2296: is_integer(B1), 2297: 16#80 =< B1, 2298: B1 =< 16#BF -> 2299: [(((B0 band 16#1F) bsl 6) 2300: bor (B1 band 16#3F)) 2301: | utf8_list_to_string(Bs)]; 2302: utf8_list_to_string([B0, B1, B2 | Bs]) when is_integer(B0), 2303: 16#E0 =< B0, 2304: B0 =< 16#EF, 2305: is_integer(B1), 2306: 16#80 =< B1, 2307: B1 =< 16#BF, 2308: is_integer(B2), 2309: 16#80 =< B2, 2310: B2 =< 16#BF -> 2311: [(((B0 band 16#F) bsl 12) 2312: bor ((B1 band 16#3F) bsl 6) 2313: bor (B2 band 16#3F)) 2314: | utf8_list_to_string(Bs)]; 2315: utf8_list_to_string([B0, B1, B2, B3 | Bs]) when is_integer(B0), 2316: 16#F0 =< B0, 2317: B0 =< 16#F7, 2318: is_integer(B1), 2319: 16#80 =< B1, 2320: B1 =< 16#BF, 2321: is_integer(B2), 2322: 16#80 =< B2, 2323: B2 =< 16#BF, 2324: is_integer(B3), 2325: 16#80 =< B3, 2326: B3 =< 16#BF -> 2327: [(((B0 band 16#7) bsl 18) 2328: bor ((B1 band 16#3F) bsl 12) 2329: bor ((B2 band 16#3F) bsl 6) 2330: bor (B3 band 16#3F)) 2331: | utf8_list_to_string(Bs)]. 2332: 2333: mk_pid({NodeName, Creation}, Number, Serial) when is_atom(NodeName) -> 2334: <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 2335: mk_pid({NodeNameExt, Creation}, Number, Serial); 2336: mk_pid({NodeNameExt, Creation}, Number, Serial) -> 2337: case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 2338: ?PID_EXT, 2339: NodeNameExt, 2340: uint32_be(Number), 2341: uint32_be(Serial), 2342: uint8(Creation)])) of 2343: Pid when is_pid(Pid) -> 2344: Pid; 2345: {'EXIT', {badarg, _}} -> 2346: exit({badarg, mk_pid, [{NodeNameExt, Creation}, Number, Serial]}); 2347: Other -> 2348: exit({unexpected_binary_to_term_result, Other}) 2349: end. 2350: 2351: mk_port({NodeName, Creation}, Number) when is_atom(NodeName) -> 2352: <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 2353: mk_port({NodeNameExt, Creation}, Number); 2354: mk_port({NodeNameExt, Creation}, Number) -> 2355: case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 2356: ?PORT_EXT, 2357: NodeNameExt, 2358: uint32_be(Number), 2359: uint8(Creation)])) of 2360: Port when is_port(Port) -> 2361: Port; 2362: {'EXIT', {badarg, _}} -> 2363: exit({badarg, mk_port, [{NodeNameExt, Creation}, Number]}); 2364: Other -> 2365: exit({unexpected_binary_to_term_result, Other}) 2366: end. 2367: 2368: mk_ref({NodeName, Creation}, [Number] = NL) when is_atom(NodeName), 2369: is_integer(Creation), 2370: is_integer(Number) -> 2371: <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 2372: mk_ref({NodeNameExt, Creation}, NL); 2373: mk_ref({NodeNameExt, Creation}, [Number]) when is_integer(Creation), 2374: is_integer(Number) -> 2375: case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 2376: ?REFERENCE_EXT, 2377: NodeNameExt, 2378: uint32_be(Number), 2379: uint8(Creation)])) of 2380: Ref when is_reference(Ref) -> 2381: Ref; 2382: {'EXIT', {badarg, _}} -> 2383: exit({badarg, mk_ref, [{NodeNameExt, Creation}, [Number]]}); 2384: Other -> 2385: exit({unexpected_binary_to_term_result, Other}) 2386: end; 2387: mk_ref({NodeName, Creation}, Numbers) when is_atom(NodeName), 2388: is_integer(Creation), 2389: is_list(Numbers) -> 2390: <<?VERSION_MAGIC, NodeNameExt/binary>> = term_to_binary(NodeName), 2391: mk_ref({NodeNameExt, Creation}, Numbers); 2392: mk_ref({NodeNameExt, Creation}, Numbers) when is_integer(Creation), 2393: is_list(Numbers) -> 2394: case catch binary_to_term(list_to_binary([?VERSION_MAGIC, 2395: ?NEW_REFERENCE_EXT, 2396: uint16_be(length(Numbers)), 2397: NodeNameExt, 2398: uint8(Creation), 2399: lists:map(fun (N) -> 2400: uint32_be(N) 2401: end, 2402: Numbers)])) of 2403: Ref when is_reference(Ref) -> 2404: Ref; 2405: {'EXIT', {badarg, _}} -> 2406: exit({badarg, mk_ref, [{NodeNameExt, Creation}, Numbers]}); 2407: Other -> 2408: exit({unexpected_binary_to_term_result, Other}) 2409: end. 2410: 2411: 2412: uint32_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 32 -> 2413: [(Uint bsr 24) band 16#ff, 2414: (Uint bsr 16) band 16#ff, 2415: (Uint bsr 8) band 16#ff, 2416: Uint band 16#ff]; 2417: uint32_be(Uint) -> 2418: exit({badarg, uint32_be, [Uint]}). 2419: 2420: 2421: uint16_be(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 16 -> 2422: [(Uint bsr 8) band 16#ff, 2423: Uint band 16#ff]; 2424: uint16_be(Uint) -> 2425: exit({badarg, uint16_be, [Uint]}). 2426: 2427: uint8(Uint) when is_integer(Uint), 0 =< Uint, Uint < 1 bsl 8 -> 2428: Uint band 16#ff; 2429: uint8(Uint) -> 2430: exit({badarg, uint8, [Uint]}).