4
%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
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/.
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
23
%%%-------------------------------------------------------------------
24
%%% File : ssl_dist_SUITE.erl
25
%%% Author : Rickard Green
26
%%% Description : Test that the Erlang distribution works over ssl.
28
%%% Created : 15 Nov 2007 by Rickard Green
29
%%%-------------------------------------------------------------------
30
-module(old_ssl_dist_SUITE).
32
-include("test_server.hrl").
34
-define(DEFAULT_TIMETRAP_SECS, 240).
36
-define(AWAIT_SLL_NODE_UP_TIMEOUT, 30000).
39
-export([init_per_suite/1,
43
-export([cnct2tstsrvr/1]).
47
-record(node_handle, {connection_handler, socket, name, nodename}).
54
init_per_suite(Config) ->
55
add_ssl_opts_config(Config).
57
end_per_suite(Config) ->
60
init_per_testcase(Case, Config) when list(Config) ->
61
Dog = ?t:timetrap(?t:seconds(?DEFAULT_TIMETRAP_SECS)),
62
[{watchdog, Dog},{testcase, Case}|Config].
64
fin_per_testcase(_Case, Config) when list(Config) ->
65
Dog = ?config(watchdog, Config),
66
?t:timetrap_cancel(Dog),
69
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
75
["Test that two nodes can connect via ssl distribution"];
78
basic(Config) when is_list(Config) ->
79
?line NH1 = start_ssl_node(Config),
80
?line Node1 = NH1#node_handle.nodename,
81
?line NH2 = start_ssl_node(Config),
82
?line Node2 = NH2#node_handle.nodename,
84
?line pong = apply_on_ssl_node(NH1, fun () -> net_adm:ping(Node2) end),
86
?line [Node2] = apply_on_ssl_node(NH1, fun () -> nodes() end),
87
?line [Node1] = apply_on_ssl_node(NH2, fun () -> nodes() end),
89
%% The test_server node has the same cookie as the ssl nodes
90
%% but it should not be able to communicate with the ssl nodes
91
%% via the erlang distribution.
92
?line pang = net_adm:ping(Node1),
93
?line pang = net_adm:ping(Node2),
97
%% Check that we are able to communicate over the erlang
98
%% distribution between the ssl nodes.
100
?line Ref = make_ref(),
101
?line spawn(fun () ->
105
tstsrvr_format("Hi from ~p!~n",
107
send_to_tstcntrl({Ref, self()}),
110
From ! {self(), pong}
116
?line ok = apply_on_ssl_node(
119
tstsrvr_format("Hi from ~p!~n",
121
SslPid ! {self(), ping},
129
?line stop_ssl_node(NH1),
130
?line stop_ssl_node(NH2),
131
?line success(Config).
133
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
135
%% Internal functions %%
142
tstsrvr_format(Fmt, ArgList) ->
143
send_to_tstsrvr({format, Fmt, ArgList}).
145
send_to_tstcntrl(Message) ->
146
send_to_tstsrvr({message, Message}).
150
%% test_server side api
153
apply_on_ssl_node(Node, M, F, A) when atom(M), atom(F), list(A) ->
155
send_to_ssl_node(Node, {apply, self(), Ref, M, F, A}),
161
apply_on_ssl_node(Node, Fun) when is_function(Fun, 0) ->
163
send_to_ssl_node(Node, {apply, self(), Ref, Fun}),
169
stop_ssl_node(#node_handle{connection_handler = Handler,
172
?t:format("Trying to stop ssl node ~s.~n", [Name]),
173
Mon = erlang:monitor(process, Handler),
175
case gen_tcp:send(Socket, term_to_binary(stop)) of
178
{'DOWN', Mon, process, Handler, Reason} ->
185
erlang:demonitor(Mon, [flush]),
189
start_ssl_node(Config) ->
190
start_ssl_node(Config, "").
192
start_ssl_node(Config, XArgs) ->
193
Name = mk_node_name(Config),
194
SSL = ?config(ssl_opts, Config),
195
SSLDistOpts = setup_dist_opts(Name, ?config(priv_dir, Config)),
196
start_ssl_node_raw(Name, SSL ++ " " ++ SSLDistOpts ++ XArgs).
198
start_ssl_node_raw(Name, Args) ->
199
{ok, LSock} = gen_tcp:listen(0,
200
[binary, {packet, 4}, {active, false}]),
201
{ok, ListenPort} = inet:port(LSock),
202
CmdLine = mk_node_cmdline(ListenPort, Name, Args),
203
?t:format("Attempting to start ssl node ~s: ~s~n", [Name, CmdLine]),
204
case open_port({spawn, CmdLine}, []) of
205
Port when port(Port) ->
207
erlang:port_close(Port),
208
case await_ssl_node_up(Name, LSock) of
209
#node_handle{} = NodeHandle ->
210
?t:format("Ssl node ~s started.~n", [Name]),
211
NodeName = list_to_atom(Name ++ "@" ++ host_name()),
212
NodeHandle#node_handle{nodename = NodeName};
214
exit({failed_to_start_node, Name, Error})
217
exit({failed_to_start_node, Name, Error})
221
%% command line creation
225
[$@ | Host] = lists:dropwhile(fun ($@) -> false; (_) -> true end,
226
atom_to_list(node())),
229
mk_node_name(Config) ->
230
{A, B, C} = erlang:now(),
231
Case = ?config(testcase, Config),
232
atom_to_list(?MODULE)
234
++ atom_to_list(Case)
236
++ integer_to_list(A)
238
++ integer_to_list(B)
240
++ integer_to_list(C).
242
mk_node_cmdline(ListenPort, Name, Args) ->
243
Static = "-detached -noinput",
244
Pa = filename:dirname(code:which(?MODULE)),
245
Prog = case catch init:get_argument(progname) of
247
_ -> exit(no_progname_argument_found)
249
NameSw = case net_kernel:longnames() of
253
{ok, Pwd} = file:get_cwd(),
256
++ NameSw ++ " " ++ Name ++ " "
257
++ "-pa " ++ Pa ++ " "
258
++ "-run " ++ atom_to_list(?MODULE) ++ " cnct2tstsrvr "
259
++ host_name() ++ " "
260
++ integer_to_list(ListenPort) ++ " "
262
++ "-env ERL_CRASH_DUMP " ++ Pwd ++ "/erl_crash_dump." ++ Name ++ " "
263
++ "-setcookie " ++ atom_to_list(erlang:get_cookie()).
266
%% Connection handler test_server side
269
await_ssl_node_up(Name, LSock) ->
270
case gen_tcp:accept(LSock, ?AWAIT_SLL_NODE_UP_TIMEOUT) of
272
gen_tcp:close(LSock),
273
?t:format("Timeout waiting for ssl node ~s to come up~n",
277
gen_tcp:close(LSock),
278
case gen_tcp:recv(Socket, 0) of
280
check_ssl_node_up(Socket, Name, Bin);
282
gen_tcp:close(Socket),
283
exit({lost_connection_with_ssl_node_before_up, Name})
286
gen_tcp:close(LSock),
287
exit({accept_failed, Error})
290
check_ssl_node_up(Socket, Name, Bin) ->
291
case catch binary_to_term(Bin) of
293
gen_tcp:close(Socket),
294
exit({bad_data_received_from_ssl_node, Name, Bin});
295
{ssl_node_up, NodeName} ->
296
case list_to_atom(Name++"@"++host_name()) of
300
%% Spawn connection handler on test server side
303
receive Go -> ok end,
304
tstsrvr_con_loop(Name, Socket, Parent)
306
ok = gen_tcp:controlling_process(Socket, Pid),
308
#node_handle{connection_handler = Pid,
312
exit({unexpected_ssl_node_connected, NodeName})
315
exit({unexpected_msg_instead_of_ssl_node_up, Name, Msg})
318
send_to_ssl_node(#node_handle{connection_handler = Hndlr}, Term) ->
319
Hndlr ! {relay_to_ssl_node, term_to_binary(Term)},
322
tstsrvr_con_loop(Name, Socket, Parent) ->
323
inet:setopts(Socket,[{active,once}]),
325
{relay_to_ssl_node, Data} when is_binary(Data) ->
326
case gen_tcp:send(Socket, Data) of
330
gen_tcp:close(Socket),
331
exit({failed_to_relay_data_to_ssl_node, Name, Data})
333
{tcp, Socket, Bin} ->
334
case catch binary_to_term(Bin) of
336
gen_tcp:close(Socket),
337
exit({bad_data_received_from_ssl_node, Name, Bin});
338
{format, FmtStr, ArgList} ->
339
?t:format(FmtStr, ArgList);
342
{apply_res, To, Ref, Res} ->
345
?t:format("Ssl node ~s stopped.~n", [Name]),
346
gen_tcp:close(Socket),
349
exit({unexpected_message_from_ssl_node, Name, Unknown})
351
{tcp_closed, Socket} ->
352
gen_tcp:close(Socket),
353
exit({lost_connection_with_ssl_node, Name})
355
tstsrvr_con_loop(Name, Socket, Parent).
358
%% Connection handler ssl_node side
361
% cnct2tstsrvr() is called via command line arg -run ...
362
cnct2tstsrvr([Host, Port]) when list(Host), list(Port) ->
363
%% Spawn connection handler on ssl node side
366
case catch gen_tcp:connect(Host,
367
list_to_integer(Port),
372
notify_ssl_node_up(Socket),
373
ets:new(test_server_info,
378
ets:insert(test_server_info,
379
{test_server_handler, self()}),
380
ssl_node_con_loop(Socket);
382
halt("Failed to connect to test server")
386
Mon = erlang:monitor(process, ConnHandler),
388
{'DOWN', Mon, process, ConnHandler, Reason} ->
389
receive after 1000 -> ok end,
390
halt("test server connection handler terminated: "
392
lists:flatten(io_lib:format("~p", [Reason])))
396
notify_ssl_node_up(Socket) ->
397
case catch gen_tcp:send(Socket,
398
term_to_binary({ssl_node_up, node()})) of
400
_ -> halt("Failed to notify test server that I'm up")
403
send_to_tstsrvr(Term) ->
404
case catch ets:lookup_element(test_server_info, test_server_handler, 2) of
405
Hndlr when pid(Hndlr) ->
406
Hndlr ! {relay_to_test_server, term_to_binary(Term)}, ok;
408
receive after 200 -> ok end,
409
send_to_tstsrvr(Term)
412
ssl_node_con_loop(Socket) ->
413
inet:setopts(Socket,[{active,once}]),
415
{relay_to_test_server, Data} when is_binary(Data) ->
416
case gen_tcp:send(Socket, Data) of
420
gen_tcp:close(Socket),
421
halt("Failed to relay data to test server")
423
{tcp, Socket, Bin} ->
424
case catch binary_to_term(Bin) of
426
gen_tcp:close(Socket),
427
halt("test server sent me bad data");
428
{apply, From, Ref, M, F, A} ->
431
send_to_tstsrvr({apply_res,
434
(catch apply(M, F, A))})
436
{apply, From, Ref, Fun} ->
438
send_to_tstsrvr({apply_res,
444
gen_tcp:send(Socket, term_to_binary(bye)),
445
gen_tcp:close(Socket),
447
receive after infinity -> ok end;
449
halt("test server sent me an unexpected message")
451
{tcp_closed, Socket} ->
452
halt("Lost connection to test server")
454
ssl_node_con_loop(Socket).
457
%% Setup ssl dist info
466
rand_bin(N-1, [random:uniform(256)-1|Acc]).
468
make_randfile(Dir) ->
469
{ok, IoDev} = file:open(filename:join([Dir, "RAND"]), [write]),
470
{A, B, C} = erlang:now(),
471
random:seed(A, B, C),
472
ok = file:write(IoDev, rand_bin(1024)),
475
append_files(FileNames, ResultFileName) ->
476
{ok, ResultFile} = file:open(ResultFileName, [write]),
477
do_append_files(FileNames, ResultFile).
479
do_append_files([], RF) ->
481
do_append_files([F|Fs], RF) ->
482
{ok, Data} = file:read_file(F),
483
ok = file:write(RF, Data),
484
do_append_files(Fs, RF).
486
setup_dist_opts(Name, PrivDir) ->
487
NodeDir = filename:join([PrivDir, Name]),
488
RGenDir = filename:join([NodeDir, "rand_gen"]),
489
ok = file:make_dir(NodeDir),
490
ok = file:make_dir(RGenDir),
491
make_randfile(RGenDir),
492
make_certs:all(RGenDir, NodeDir),
493
SDir = filename:join([NodeDir, "server"]),
494
SC = filename:join([SDir, "cert.pem"]),
495
SK = filename:join([SDir, "key.pem"]),
496
SKC = filename:join([SDir, "keycert.pem"]),
497
append_files([SK, SC], SKC),
498
CDir = filename:join([NodeDir, "client"]),
499
CC = filename:join([CDir, "cert.pem"]),
500
CK = filename:join([CDir, "key.pem"]),
501
CKC = filename:join([CDir, "keycert.pem"]),
502
append_files([CK, CC], CKC),
503
"-proto_dist inet_ssl "
504
++ "-ssl_dist_opt server_certfile " ++ SKC ++ " "
505
++ "-ssl_dist_opt client_certfile " ++ CKC ++ " "
506
.% ++ "-ssl_dist_opt verify 1 depth 1".
509
%% Start scripts etc...
512
add_ssl_opts_config(Config) ->
514
%% Start with boot scripts if on an installed system; otherwise,
515
%% just point out ssl ebin with -pa.
518
Dir = ?config(priv_dir, Config),
519
LibDir = code:lib_dir(),
520
Apps = application:which_applications(),
521
{value, {stdlib, _, STDL_VSN}} = lists:keysearch(stdlib, 1, Apps),
522
{value, {kernel, _, KRNL_VSN}} = lists:keysearch(kernel, 1, Apps),
523
StdlDir = filename:join([LibDir, "stdlib-" ++ STDL_VSN]),
524
KrnlDir = filename:join([LibDir, "kernel-" ++ KRNL_VSN]),
525
{ok, _} = file:read_file_info(StdlDir),
526
{ok, _} = file:read_file_info(KrnlDir),
527
SSL_VSN = case lists:keysearch(ssl, 1, Apps) of
528
{value, {ssl, _, VSN}} ->
531
application:start(ssl),
536
VSN}} = lists:keysearch(ssl,
538
application:which_applications()),
541
application:stop(ssl)
544
SslDir = filename:join([LibDir, "ssl-" ++ SSL_VSN]),
545
{ok, _} = file:read_file_info(SslDir),
546
%% We are using an installed otp system, create the boot script.
547
Script = filename:join(Dir, atom_to_list(?MODULE)),
548
{ok, RelFile} = file:open(Script ++ ".rel", [write]),
551
" {\"SSL distribution test release\", \"~s\"},~n"
553
" [{kernel, \"~s\"},~n"
554
" {stdlib, \"~s\"},~n"
555
" {ssl, \"~s\"}]}.~n",
556
[case catch erlang:system_info(otp_release) of
557
{'EXIT', _} -> "R11B";
560
erlang:system_info(version),
564
ok = file:close(RelFile),
565
ok = systools:make_script(Script, []),
566
[{ssl_opts, "-boot " ++ Script} | Config]
569
[{ssl_opts, "-pa " ++ filename:dirname(code:which(ssl))}
570
| add_comment_config(
571
"Bootscript wasn't used since the test wasn't run on an "
572
"installed OTP system.",
577
%% Add common comments to config
580
add_comment_config(Comment, []) ->
581
[{comment, Comment}];
582
add_comment_config(Comment, [{comment, OldComment} | Cs]) ->
583
[{comment, Comment ++ " " ++ OldComment} | Cs];
584
add_comment_config(Comment, [C|Cs]) ->
585
[C|add_comment_config(Comment, Cs)].
588
%% Call when test case success
592
case lists:keysearch(comment, 1, Config) of
593
{value, {comment, _} = Res} -> Res;