diff options
Diffstat (limited to 'lib/kernel/test/inet_sockopt_SUITE.erl')
-rw-r--r-- | lib/kernel/test/inet_sockopt_SUITE.erl | 681 |
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. |