%% %% %CopyrightBegin% %% %% Copyright Ericsson AB 2007-2010. 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_lib("test_server/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/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, init_per_group/2,end_per_group/2, 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]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> [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]. groups() -> []. init_per_suite(Config) -> Config. end_per_suite(_Config) -> ok. init_per_group(_GroupName, Config) -> Config. end_per_group(_GroupName, Config) -> Config. 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.