%%
%% %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.