aboutsummaryrefslogtreecommitdiffstats
path: root/lib/kernel/test/inet_sockopt_SUITE.erl
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kernel/test/inet_sockopt_SUITE.erl')
-rw-r--r--lib/kernel/test/inet_sockopt_SUITE.erl681
1 files changed, 681 insertions, 0 deletions
diff --git a/lib/kernel/test/inet_sockopt_SUITE.erl b/lib/kernel/test/inet_sockopt_SUITE.erl
new file mode 100644
index 0000000000..0fa0226ccf
--- /dev/null
+++ b/lib/kernel/test/inet_sockopt_SUITE.erl
@@ -0,0 +1,681 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-2009. All Rights Reserved.
+%%
+%% The contents of this file are subject to the Erlang Public License,
+%% Version 1.1, (the "License"); you may not use this file except in
+%% compliance with the License. You should have received a copy of the
+%% Erlang Public License along with this software. If not, it can be
+%% retrieved online at http://www.erlang.org/.
+%%
+%% Software distributed under the License is distributed on an "AS IS"
+%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+%% the License for the specific language governing rights and limitations
+%% under the License.
+%%
+%% %CopyrightEnd%
+%%
+-module(inet_sockopt_SUITE).
+
+-include("test_server.hrl").
+
+
+-define(C_GET_IPPROTO_TCP,1).
+-define(C_GET_IPPROTO_IP,2).
+-define(C_GET_SOL_SOCKET,3).
+-define(C_GET_SOL_IP,4).
+
+-define(C_GET_TCP_KEEPIDLE,11).
+-define(C_GET_TCP_LINGER2,12).
+-define(C_GET_TCP_INFO,13).
+-define(C_GET_SO_REUSEADDR,14).
+-define(C_GET_SO_KEEPALIVE,15).
+-define(C_GET_SO_LINGER,16).
+
+-define(C_GET_LINGER_SIZE,21).
+-define(C_GET_TCP_INFO_SIZE,22).
+
+-define(C_GET_OFF_LINGER_L_ONOFF,31).
+-define(C_GET_OFF_LINGER_L_LINGER,32).
+-define(C_GET_OFF_TCPI_SACKED,33).
+-define(C_GET_OFF_TCPI_OPTIONS,34).
+
+-define(C_GET_SIZ_LINGER_L_ONOFF,41).
+-define(C_GET_SIZ_LINGER_L_LINGER,42).
+-define(C_GET_SIZ_TCPI_SACKED,43).
+-define(C_GET_SIZ_TCPI_OPTIONS,44).
+
+-define(C_QUIT,99).
+
+-export([all/1, simple/1, loop_all/1, simple_raw/1, simple_raw_getbin/1,
+ doc_examples_raw/1,doc_examples_raw_getbin/1,
+ large_raw/1,large_raw_getbin/1,combined/1,combined_getbin/1,
+ type_errors/1]).
+
+-export([init_per_testcase/2, end_per_testcase/2]).
+
+
+all(suite) ->
+ [simple,loop_all,simple_raw,simple_raw_getbin,
+ doc_examples_raw, doc_examples_raw_getbin,
+ large_raw,large_raw_getbin,combined,combined_getbin,type_errors].
+
+init_per_testcase(_Func, Config) ->
+ Dog = test_server:timetrap(test_server:seconds(60)),
+ [{watchdog,Dog}|Config].
+
+end_per_testcase(_Func, Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog).
+
+simple(suite) -> [];
+simple(doc) -> "Test inet:setopt/getopt simple functionality.";
+simple(Config) when is_list(Config) ->
+ ?line XOpt = case os:type() of
+ {unix,_} -> [{reuseaddr,true}];
+ _ -> []
+ end,
+ ?line Opt = [{nodelay,true},
+ {keepalive,true},{packet,4},
+ {active,false}|XOpt],
+ ?line OptTags = [X || {X,_} <- Opt],
+ ?line {S1,S2} = create_socketpair(Opt, Opt),
+ ?line {ok,Opt} = inet:getopts(S1,OptTags),
+ ?line {ok,Opt} = inet:getopts(S2,OptTags),
+ ?line COpt = [{X,case X of nodelay -> false;_ -> Y end} || {X,Y} <- Opt],
+ ?line inet:setopts(S1,COpt),
+ ?line {ok,COpt} = inet:getopts(S1,OptTags),
+ ?line {ok,Opt} = inet:getopts(S2,OptTags),
+ ?line gen_tcp:close(S1),
+ ?line gen_tcp:close(S2),
+ ok.
+
+loop_all(suite) -> [];
+loop_all(doc) -> "Loop through all socket options and check that they work";
+loop_all(Config) when is_list(Config) ->
+ ?line ListenFailures =
+ lists:foldr(make_check_fun(listen,1),[],all_listen_options()),
+ ?line ConnectFailures =
+ lists:foldr(make_check_fun(connect,2),[],all_connect_options()),
+ ?line case ListenFailures++ConnectFailures of
+ [] ->
+ ?line ok;
+ Failed ->
+ ?line {comment,lists:flatten(
+ io_lib:format("Non mandatory failed:~w",
+ [Failed]))}
+ end.
+
+
+
+simple_raw(suite) -> [];
+simple_raw(doc) -> "Test simple setopt/getopt of raw options.";
+simple_raw(Config) when is_list(Config) ->
+ do_simple_raw(Config,false).
+simple_raw_getbin(suite) -> [];
+simple_raw_getbin(doc) -> "Test simple setopt/getopt of raw options, "
+ "with binaries in getopt.";
+simple_raw_getbin(Config) when is_list(Config) ->
+ do_simple_raw(Config,true).
+
+do_simple_raw(Config,Binary) when is_list(Config) ->
+ ?line Port = start_helper(Config),
+ ?line SolSocket = ask_helper(Port,?C_GET_SOL_SOCKET),
+ ?line SoKeepAlive = ask_helper(Port,?C_GET_SO_KEEPALIVE),
+ ?line OptionTrue = {raw,SolSocket,SoKeepAlive,<<1:32/native>>},
+ ?line OptionFalse = {raw,SolSocket,SoKeepAlive,<<0:32/native>>},
+ ?line {S1,S2} = create_socketpair([OptionTrue],[{keepalive,true}]),
+ ?line {ok,[{keepalive,true}]} = inet:getopts(S1,[keepalive]),
+ ?line {ok,[{keepalive,true}]} = inet:getopts(S2,[keepalive]),
+ ?line {ok,[{raw,SolSocket,SoKeepAlive,X1B}]} =
+ inet:getopts(S1,[{raw,SolSocket,SoKeepAlive,binarify(4,Binary)}]),
+ ?line X1 = nintbin2int(X1B),
+ ?line {ok,[{raw,SolSocket,SoKeepAlive,X2B}]} =
+ inet:getopts(S2,[{raw,SolSocket,SoKeepAlive,binarify(4,Binary)}]),
+ ?line X2 = nintbin2int(X2B),
+ ?line true = X1 > 0,
+ ?line true = X2 > 0,
+ ?line inet:setopts(S1,[{keepalive,false}]),
+ ?line inet:setopts(S2,[OptionFalse]),
+ ?line {ok,[{keepalive,false}]} = inet:getopts(S1,[keepalive]),
+ ?line {ok,[{keepalive,false}]} = inet:getopts(S2,[keepalive]),
+ ?line {ok,[{raw,SolSocket,SoKeepAlive,Y1B}]} =
+ inet:getopts(S1,[{raw,SolSocket,SoKeepAlive,binarify(4,Binary)}]),
+ ?line Y1 = nintbin2int(Y1B),
+ ?line {ok,[{raw,SolSocket,SoKeepAlive,Y2B}]} =
+ inet:getopts(S2,[{raw,SolSocket,SoKeepAlive,binarify(4,Binary)}]),
+ ?line Y2 = nintbin2int(Y2B),
+ ?line true = Y1 == 0,
+ ?line true = Y2 == 0,
+ ?line gen_tcp:close(S1),
+ ?line gen_tcp:close(S2),
+ ?line stop_helper(Port),
+ ok.
+
+nintbin2int(<<Int:32/native>>) -> Int;
+nintbin2int(<<Int:24/native>>) -> Int;
+nintbin2int(<<Int:16/native>>) -> Int;
+nintbin2int(<<Int:8/native>>) -> Int;
+nintbin2int(<<>>) -> 0.
+
+doc_examples_raw(suite) -> [];
+doc_examples_raw(doc) -> "Test that the example code from the documentation "
+ "works";
+doc_examples_raw(Config) when is_list(Config) ->
+ do_doc_examples_raw(Config,false).
+doc_examples_raw_getbin(suite) -> [];
+doc_examples_raw_getbin(doc) -> "Test that the example code from the "
+ "documentation works when getopt uses "
+ "binaries";
+doc_examples_raw_getbin(Config) when is_list(Config) ->
+ do_doc_examples_raw(Config,true).
+do_doc_examples_raw(Config,Binary) when is_list(Config) ->
+ ?line Port = start_helper(Config),
+ ?line Proto = ask_helper(Port,?C_GET_IPPROTO_TCP),
+ ?line TcpInfo = ask_helper(Port,?C_GET_TCP_INFO),
+ ?line TcpInfoSize = ask_helper(Port,?C_GET_TCP_INFO_SIZE),
+ ?line TcpiSackedOffset = ask_helper(Port,?C_GET_OFF_TCPI_SACKED),
+ ?line TcpiOptionsOffset = ask_helper(Port,?C_GET_OFF_TCPI_OPTIONS),
+ ?line TcpiSackedSize = ask_helper(Port,?C_GET_SIZ_TCPI_SACKED),
+ ?line TcpiOptionsSize = ask_helper(Port,?C_GET_SIZ_TCPI_OPTIONS),
+ ?line TcpLinger2 = ask_helper(Port,?C_GET_TCP_LINGER2),
+ ?line stop_helper(Port),
+ case all_ok([Proto,TcpInfo,TcpInfoSize,TcpiSackedOffset,
+ TcpiOptionsOffset,TcpiSackedSize,TcpiOptionsSize,
+ TcpLinger2]) of
+ false ->
+ {skipped,"Does not run on this OS."};
+ true ->
+ ?line {Sock,I} = create_socketpair([],[]),
+ ?line {ok,[{raw,Proto,TcpLinger2,<<OrigLinger:32/native>>}]} =
+ inet:getopts(Sock,[{raw,Proto,TcpLinger2,binarify(4,Binary)}]),
+ ?line NewLinger = OrigLinger div 2,
+ ?line ok = inet:setopts(Sock,[{raw,Proto,TcpLinger2,
+ <<NewLinger:32/native>>}]),
+ ?line {ok,[{raw,Proto,TcpLinger2,<<NewLinger:32/native>>}]} =
+ inet:getopts(Sock,[{raw,Proto,TcpLinger2,binarify(4,Binary)}]),
+ ?line ok = inet:setopts(Sock,[{raw,Proto,TcpLinger2,
+ <<OrigLinger:32/native>>}]),
+ ?line {ok,[{raw,Proto,TcpLinger2,<<OrigLinger:32/native>>}]} =
+ inet:getopts(Sock,[{raw,Proto,TcpLinger2,binarify(4,Binary)}]),
+ ?line {ok,[{raw,_,_,Info}]} =
+ inet:getopts(Sock,[{raw,Proto,TcpInfo,
+ binarify(TcpInfoSize,Binary)}]),
+ ?line Bit1 = TcpiSackedSize * 8,
+ ?line <<_:TcpiSackedOffset/binary,
+ TcpiSacked:Bit1/native,_/binary>> =
+ Info,
+ ?line 0 = TcpiSacked,
+ ?line Bit2 = TcpiOptionsSize * 8,
+ ?line <<_:TcpiOptionsOffset/binary,
+ TcpiOptions:Bit2/native,_/binary>> =
+ Info,
+ ?line true = TcpiOptions =/= 0,
+ ?line gen_tcp:close(Sock),
+ ?line gen_tcp:close(I),
+ ok
+ end.
+
+large_raw(suite) -> [];
+large_raw(doc) -> "Test structs and large/too large buffers when raw";
+large_raw(Config) when is_list(Config) ->
+ do_large_raw(Config,false).
+large_raw_getbin(suite) -> [];
+large_raw_getbin(doc) -> "Test structs and large/too large buffers when raw"
+ "using binaries to getopts";
+large_raw_getbin(Config) when is_list(Config) ->
+ do_large_raw(Config,true).
+do_large_raw(Config,Binary) when is_list(Config) ->
+ ?line Port = start_helper(Config),
+ ?line Proto = ask_helper(Port,?C_GET_SOL_SOCKET),
+ ?line Linger = ask_helper(Port,?C_GET_SO_LINGER),
+ ?line LingerSize = ask_helper(Port,?C_GET_LINGER_SIZE),
+ ?line LingerOnOffOffset = ask_helper(Port,?C_GET_OFF_LINGER_L_ONOFF),
+ ?line LingerLingerOffset = ask_helper(Port,?C_GET_OFF_LINGER_L_LINGER),
+ ?line LingerOnOffSize = ask_helper(Port,?C_GET_SIZ_LINGER_L_ONOFF),
+ ?line LingerLingerSize = ask_helper(Port,?C_GET_SIZ_LINGER_L_LINGER),
+ ?line stop_helper(Port),
+ case all_ok([Proto,Linger,LingerSize,LingerOnOffOffset,
+ LingerLingerOffset,LingerOnOffSize,LingerLingerSize]) of
+ false ->
+ {skipped,"Does not run on this OS."};
+ true ->
+ ?line {Sock1,Sock2} = create_socketpair([{linger,{true,10}}],
+ [{linger,{false,0}}]),
+ ?line LargeSize = 1024, % Solaris can take up to 1024*9,
+ % linux 1024*63...
+ ?line TooLargeSize = 1024*64,
+ ?line {ok,[{raw,Proto,Linger,Linger1}]} =
+ inet:getopts(Sock1,[{raw,Proto,Linger,
+ binarify(LargeSize,Binary)}]),
+ ?line {ok,[{raw,Proto,Linger,Linger2}]} =
+ inet:getopts(Sock2,[{raw,Proto,Linger,
+ binarify(LingerSize,Binary)}]),
+ ?line true = byte_size(Linger1) =:= LingerSize,
+ ?line LingerLingerBits = LingerLingerSize * 8,
+ ?line LingerOnOffBits = LingerOnOffSize * 8,
+ ?line <<_:LingerLingerOffset/binary,
+ Ling1:LingerLingerBits/native,_/binary>> = Linger1,
+ ?line <<_:LingerOnOffOffset/binary,
+ Off1:LingerOnOffBits/native,_/binary>> = Linger1,
+ ?line <<_:LingerOnOffOffset/binary,
+ Off2:LingerOnOffBits/native,_/binary>> = Linger2,
+ ?line true = Off1 =/= 0,
+ ?line true = Off2 == 0,
+ ?line true = Ling1 == 10,
+ ?line {error,einval} =
+ inet:getopts(Sock1,[{raw,Proto,Linger,TooLargeSize}]),
+ ?line gen_tcp:close(Sock1),
+ ?line gen_tcp:close(Sock2),
+ ok
+ end.
+
+combined(suite) -> [];
+combined(doc) -> "Test raw structs combined w/ other options ";
+combined(Config) when is_list(Config) ->
+ do_combined(Config,false).
+combined_getbin(suite) -> [];
+combined_getbin(doc) -> "Test raw structs combined w/ other options and "
+ "binarise in getopts";
+combined_getbin(Config) when is_list(Config) ->
+ do_combined(Config,true).
+do_combined(Config,Binary) when is_list(Config) ->
+ ?line Port = start_helper(Config),
+ ?line Proto = ask_helper(Port,?C_GET_SOL_SOCKET),
+ ?line Linger = ask_helper(Port,?C_GET_SO_LINGER),
+ ?line LingerSize = ask_helper(Port,?C_GET_LINGER_SIZE),
+ ?line LingerOnOffOffset = ask_helper(Port,?C_GET_OFF_LINGER_L_ONOFF),
+ ?line LingerLingerOffset = ask_helper(Port,?C_GET_OFF_LINGER_L_LINGER),
+ ?line LingerOnOffSize = ask_helper(Port,?C_GET_SIZ_LINGER_L_ONOFF),
+ ?line LingerLingerSize = ask_helper(Port,?C_GET_SIZ_LINGER_L_LINGER),
+ ?line stop_helper(Port),
+ case all_ok([Proto,Linger,LingerSize,LingerOnOffOffset,
+ LingerLingerOffset,LingerOnOffSize,LingerLingerSize]) of
+ false ->
+ {skipped,"Does not run on this OS."};
+ true ->
+ ?line LingerLingerBits = LingerLingerSize * 8,
+ ?line LingerOnOffBits = LingerOnOffSize * 8,
+ ?line {LingerOn,LingerOff} =
+ case LingerOnOffOffset < LingerLingerOffset of
+ true ->
+ Pad1 =
+ list_to_binary(
+ lists:duplicate(LingerOnOffOffset,
+ 0)),
+ Pad2Siz =
+ LingerLingerOffset - LingerOnOffSize -
+ LingerOnOffOffset,
+ Pad2 =
+ list_to_binary(
+ lists:duplicate(Pad2Siz,
+ 0)),
+ Pad3Siz = LingerSize - LingerLingerSize -
+ LingerLingerOffset,
+ Pad3 = list_to_binary(
+ lists:duplicate(Pad3Siz,
+ 0)),
+ {<<Pad1/binary,1:LingerOnOffBits/native,
+ Pad2/binary,10:LingerLingerBits/native,
+ Pad3/binary>>,
+ <<Pad1/binary,0:LingerOnOffBits/native,
+ Pad2/binary,0:LingerLingerBits/native,
+ Pad3/binary>>};
+ false ->
+ Pad1 =
+ list_to_binary(
+ lists:duplicate(LingerLingerOffset,
+ 0)),
+ Pad2Siz =
+ LingerOnOffOffset - LingerLingerSize -
+ LingerLingerOffset,
+ Pad2 =
+ list_to_binary(
+ lists:duplicate(Pad2Siz,
+ 0)),
+ Pad3Siz = LingerSize - LingerOnOffSize -
+ LingerOnOffOffset,
+ Pad3 = list_to_binary(
+ lists:duplicate(Pad3Siz,
+ 0)),
+ {<<Pad1/binary,1:LingerLingerBits/native,
+ Pad2/binary,10:LingerOnOffBits/native,
+ Pad3/binary>>,
+ <<Pad1/binary,0:LingerLingerBits/native,
+ Pad2/binary,0:LingerOnOffBits/native,
+ Pad3/binary>>}
+ end,
+ ?line RawLingerOn = {raw,Proto,Linger,LingerOn},
+ ?line RawLingerOff = {raw,Proto,Linger,LingerOff},
+ ?line {Sock1,Sock2} =
+ create_socketpair([{keepalive,true},
+ RawLingerOn],
+ [{keepalive,false},
+ RawLingerOff]),
+ ?line {ok,[{raw,Proto,Linger,Linger1},{keepalive,Keep1}]} =
+ inet:getopts(Sock1,[{raw,Proto,Linger,
+ binarify(LingerSize,Binary)},keepalive]),
+ ?line {ok,[{raw,Proto,Linger,Linger2},{keepalive,Keep2}]} =
+ inet:getopts(Sock2,[{raw,Proto,Linger,
+ binarify(LingerSize,Binary)},keepalive]),
+ ?line true = byte_size(Linger1) =:= LingerSize,
+ ?line <<_:LingerLingerOffset/binary,
+ Ling1:LingerLingerBits/native,_/binary>> = Linger1,
+ ?line <<_:LingerOnOffOffset/binary,
+ Off1:LingerOnOffBits/native,_/binary>> = Linger1,
+ ?line <<_:LingerOnOffOffset/binary,
+ Off2:LingerOnOffBits/native,_/binary>> = Linger2,
+ ?line true = Off1 =/= 0,
+ ?line true = Off2 == 0,
+ ?line true = Ling1 == 10,
+ ?line true = Keep1 =:= true,
+ ?line true = Keep2 =:= false,
+ ?line {Sock3,Sock4} =
+ create_socketpair([RawLingerOn,{keepalive,true}],
+ [RawLingerOff,{keepalive,false}]),
+ ?line {ok,[{raw,Proto,Linger,Linger3},{keepalive,Keep3}]} =
+ inet:getopts(Sock3,[{raw,Proto,Linger,
+ binarify(LingerSize,Binary)},keepalive]),
+ ?line {ok,[{raw,Proto,Linger,Linger4},{keepalive,Keep4}]} =
+ inet:getopts(Sock4,[{raw,Proto,Linger,
+ binarify(LingerSize,Binary)},keepalive]),
+ ?line true = byte_size(Linger3) =:= LingerSize,
+ ?line <<_:LingerLingerOffset/binary,
+ Ling3:LingerLingerBits/native,_/binary>> = Linger3,
+ ?line <<_:LingerOnOffOffset/binary,
+ Off3:LingerOnOffBits/native,_/binary>> = Linger3,
+ ?line <<_:LingerOnOffOffset/binary,
+ Off4:LingerOnOffBits/native,_/binary>> = Linger4,
+ ?line true = Off3 =/= 0,
+ ?line true = Off4 == 0,
+ ?line true = Ling3 == 10,
+ ?line true = Keep3 =:= true,
+ ?line true = Keep4 =:= false,
+ ?line {Sock5,Sock6} =
+ create_socketpair([{packet,4},RawLingerOn,{keepalive,true}],
+ [{packet,2},RawLingerOff,{keepalive,false}]),
+ ?line {ok,[{packet,Pack5},{raw,Proto,Linger,Linger5},
+ {keepalive,Keep5}]} =
+ inet:getopts(Sock5,[packet,{raw,Proto,Linger,
+ binarify(LingerSize,Binary)},
+ keepalive]),
+ ?line {ok,[{packet,Pack6},{raw,Proto,Linger,Linger6},
+ {keepalive,Keep6}]} =
+ inet:getopts(Sock6,[packet,{raw,Proto,Linger,
+ binarify(LingerSize,Binary)},
+ keepalive]),
+ ?line true = byte_size(Linger5) =:= LingerSize,
+ ?line <<_:LingerLingerOffset/binary,
+ Ling5:LingerLingerBits/native,_/binary>> = Linger5,
+ ?line <<_:LingerOnOffOffset/binary,
+ Off5:LingerOnOffBits/native,_/binary>> = Linger5,
+ ?line <<_:LingerOnOffOffset/binary,
+ Off6:LingerOnOffBits/native,_/binary>> = Linger6,
+ ?line true = Off5 =/= 0,
+ ?line true = Off6 == 0,
+ ?line true = Ling5 == 10,
+ ?line true = Keep5 =:= true,
+ ?line true = Keep6 =:= false,
+ ?line true = Pack5 =:= 4,
+ ?line true = Pack6 =:= 2,
+ ?line inet:setopts(Sock6,[{packet,4},RawLingerOn,
+ {keepalive,true}]),
+ ?line {ok,[{packet,Pack7},{raw,Proto,Linger,Linger7},
+ {keepalive,Keep7}]} =
+ inet:getopts(Sock6,[packet,{raw,Proto,Linger,
+ binarify(LingerSize,Binary)},
+ keepalive]),
+ ?line <<_:LingerOnOffOffset/binary,
+ Off7:LingerOnOffBits/native,_/binary>> = Linger7,
+ ?line true = Off7 =/= 0,
+ ?line true = Keep7 =:= true,
+ ?line true = Pack7 =:= 4,
+ ?line gen_tcp:close(Sock1),
+ ?line gen_tcp:close(Sock2),
+ ?line gen_tcp:close(Sock3),
+ ?line gen_tcp:close(Sock4),
+ ?line gen_tcp:close(Sock5),
+ ?line gen_tcp:close(Sock6),
+ ok
+ end.
+
+type_errors(suite) ->
+ [];
+type_errors(doc) ->
+ "Test that raw data requests are not executed for bad types";
+type_errors(Config) when is_list(Config) ->
+ ?line BadSetOptions =
+ [
+ {raw,x,3,<<1:32>>},
+ {raw,1,tre,<<1:32>>},
+ {raw,1,3,ko},
+ {raw,1,3,5},
+ {raw,1,3},
+ {raw,1},
+ {raw},
+ {raw,ett},
+ {raw,ett,tre},
+ {raw,{true,10}},
+ {raw,{ett,tre,<<1:32>>}},
+ {rav,1,3,<<1:32>>},
+ raw,
+ rav,
+ {linger,banan}
+ ],
+ ?line BadGetOptions =
+ [
+ {raw,x,3,<<1:32>>},
+ {raw,1,tre,<<1:32>>},
+ {raw,1,3,ko},
+ {raw,1,3,5.1},
+ {raw,1,3,-3},
+ {raw,1,3},
+ {raw,1},
+ {raw},
+ {raw,ett},
+ {raw,ett,tre},
+ {raw,{true,10}},
+ {raw,{ett,tre,<<1:32>>}},
+ {rav,1,3,<<1:32>>},
+ raw,
+ rav,
+ {linger,banan}
+ ],
+ ?line lists:foreach(fun(Option) ->
+ ?line case
+ catch create_socketpair([Option],[]) of
+ {'EXIT',badarg} ->
+ ?line ok;
+ Unexpected1 ->
+ ?line exit({unexpected,
+ Unexpected1})
+ end,
+ ?line case
+ catch create_socketpair([],[Option]) of
+ {'EXIT',badarg} ->
+ ?line ok;
+ Unexpected2 ->
+ ?line exit({unexpected,
+ Unexpected2})
+ end,
+ ?line {Sock1,Sock2} = create_socketpair([],[]),
+ ?line case inet:setopts(Sock1, [Option]) of
+ {error,einval} ->
+ ?line ok;
+ Unexpected3 ->
+ ?line exit({unexpected,
+ Unexpected3})
+ end,
+ ?line gen_tcp:close(Sock1),
+ ?line gen_tcp:close(Sock2)
+ end,BadSetOptions),
+ ?line {Sock1,Sock2} = create_socketpair([],[]),
+ ?line lists:foreach(fun(Option) ->
+ ?line case inet:getopts(Sock1, [Option]) of
+ {error,einval} ->
+ ?line ok;
+ Unexpected ->
+ ?line exit({unexpected,
+ Unexpected})
+ end
+ end,BadGetOptions),
+ ?line gen_tcp:close(Sock1),
+ ?line gen_tcp:close(Sock2),
+ ok.
+
+all_ok([]) ->
+ true;
+all_ok([H|T]) when H >= 0 ->
+ all_ok(T);
+all_ok(_) ->
+ false.
+
+
+make_check_fun(Type,Element) ->
+ fun({Name,V1,V2,Mand,Chang},Acc) ->
+ ?line {LO1,CO1} = setelement(Element,{[],[]}, [{Name,V1}]),
+ ?line {LO2,CO2} = setelement(Element,{[],[]}, [{Name,V2}]),
+ ?line {X1,Y1} = create_socketpair(LO1,CO1),
+ ?line {X2,Y2} = create_socketpair(LO2,CO2),
+ ?line S1 = element(Element,{X1,Y1}),
+ ?line S2 = element(Element,{X2,Y2}),
+ ?line {ok,[{Name,R1}]} = inet:getopts(S1,[Name]),
+ ?line {ok,[{Name,R2}]} = inet:getopts(S2,[Name]),
+ NewAcc =
+ case R1 =/= R2 of
+ true ->
+ case Chang of
+ true ->
+ ?line inet:setopts(S1,[{Name,V2}]),
+ ?line {ok,[{Name,R3}]} =
+ inet:getopts(S1,[Name]),
+ case {R3 =/= R1, R3 =:= R2} of
+ {true,true} ->
+ ?line Acc;
+ _ ->
+ case Mand of
+ true ->
+ ?line exit
+ ({failed_sockopt,
+ {change,
+ Name}});
+ false ->
+ ?line [{change,Name}|Acc]
+ end
+ end;
+ false ->
+ ?line Acc
+ end;
+ false ->
+ case Mand of
+ true ->
+ ?line exit({failed_sockopt,
+ {Type,Name}});
+ false ->
+ ?line [{Type,Name}|Acc]
+ end
+ end,
+ ?line gen_tcp:close(X1),
+ ?line gen_tcp:close(Y1),
+ ?line gen_tcp:close(X2),
+ ?line gen_tcp:close(Y2),
+ NewAcc
+ end.
+
+% {OptionName,Value1,Value2,Mandatory,Changeable}
+all_listen_options() ->
+ [{tos,0,1,false,true},
+ {priority,0,1,false,true},
+ {reuseaddr,false,true,false,true},
+ {keepalive,false,true,true,true},
+ {linger, {false,10}, {true,10},true,true},
+ {sndbuf,2048,4096,false,true},
+ {recbuf,2048,4096,false,true},
+ {nodelay,false,true,true,true},
+ {header,2,4,true,true},
+ {active,false,true,true,false},
+ {packet,2,4,true,true},
+ {buffer,1000,2000,true,true},
+ {mode,list,binary,true,true},
+ {deliver,term,port,true,true},
+ {exit_on_close, true, false, true, true},
+ %{high_watermark,4096,8192,true,true},
+ %{low_watermark,2048,4096,true,true},
+ {bit8,on,off,true,true},
+ {send_timeout,infinity,1000,true,true},
+ {send_timeout_close,false,true,true,true},
+ {delay_send,false,true,true,true},
+ {packet_size,0,4,true,true}
+ ].
+all_connect_options() ->
+ [{tos,0,1,false,true},
+ {priority,0,1,false,true},
+ {reuseaddr,false,true,false,true},
+ {keepalive,false,true,true,true},
+ {linger, {false,10}, {true,10},true,true},
+ {sndbuf,2048,4096,false,true},
+ {recbuf,2048,4096,false,true},
+ {nodelay,false,true,true,true},
+ {header,2,4,true,true},
+ {active,false,true,true,false},
+ {packet,2,4,true,true},
+ {buffer,1000,2000,true,true},
+ {mode,list,binary,true,true},
+ {deliver,term,port,true,true},
+ {exit_on_close, true, false, true, true},
+ {high_watermark,4096,8192,false,true},
+ {low_watermark,2048,4096,false,true},
+ {bit8,on,off,true,true},
+ {send_timeout,infinity,1000,true,true},
+ {send_timeout_close,false,true,true,true},
+ {delay_send,false,true,true,true},
+ {packet_size,0,4,true,true}
+ ].
+
+
+create_socketpair(ListenOptions,ConnectOptions) ->
+ ?line {ok,LS}=gen_tcp:listen(0,ListenOptions),
+ ?line {ok,Port}=inet:port(LS),
+ ?line {ok,CS}=gen_tcp:connect(localhost,Port,ConnectOptions),
+ ?line {ok,AS}=gen_tcp:accept(LS),
+ ?line gen_tcp:close(LS),
+ {AS,CS}.
+
+
+start_helper(Config) ->
+ Progname = filename:join(?config(data_dir, Config), "sockopt_helper"),
+ Port = open_port({spawn,Progname},[eof,line]),
+ Port.
+
+ask_helper(Port,Code) ->
+ Com = integer_to_list(Code)++"\n",
+ Port ! {self(),{command,Com}},
+ receive
+ {Port,{data,{eol,Text}}} ->
+ list_to_integer(Text);
+ Other ->
+ exit({error,{unexpected_data_from_helper,Other}})
+ after 3000 ->
+ exit({error,helper_timeout})
+ end.
+
+stop_helper(Port) ->
+ catch ask_helper(Port,?C_QUIT),
+ receive
+ {Port,eof} ->
+ Port ! {self(), close},
+ receive
+ {Port,closed} ->
+ ok
+ after 1000 ->
+ timeout
+ end
+ after 1000 ->
+ timeout
+ end.
+
+binarify(Size,Binary) when Binary =:= true ->
+ <<0:Size/unit:8>>;
+binarify(Size,Binary) when Binary =:= false ->
+ Size.