diff options
-rw-r--r-- | erts/emulator/beam/erl_nif.c | 1 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 3 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 13 | ||||
-rw-r--r-- | lib/common_test/src/ct_telnet.erl | 136 | ||||
-rw-r--r-- | lib/common_test/src/ct_telnet_client.erl | 10 | ||||
-rw-r--r-- | lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl | 12 | ||||
-rw-r--r-- | lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl | 41 | ||||
-rw-r--r-- | lib/common_test/test/telnet_server.erl | 36 | ||||
-rw-r--r-- | lib/kernel/doc/src/inet.xml | 61 |
9 files changed, 243 insertions, 70 deletions
diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index ede5f335dc..adc3520ebb 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1646,6 +1646,7 @@ init_nif_sched_data(ErlNifEnv* env, NativeFunPtr direct_fp, NativeFunPtr indirec ep->m = env->mod_nif; ep->fp = indirect_fp; proc->freason = TRAP; + proc->arity = argc; return THE_NON_VALUE; } diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 14e6585220..4560077a51 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -1564,6 +1564,8 @@ dirty_nif(Config) when is_list(Config) -> Val2 = "Erlang", Val3 = list_to_binary([Val2, 0]), {Val1, Val2, Val3} = call_dirty_nif(Val1, Val2, Val3), + LargeArray = lists:duplicate(1000, ok), + LargeArray = call_dirty_nif_zero_args(), ok catch error:badarg -> @@ -1740,6 +1742,7 @@ call_nif_schedule(_,_) -> ?nif_stub. call_dirty_nif(_,_,_) -> ?nif_stub. send_from_dirty_nif(_) -> ?nif_stub. call_dirty_nif_exception() -> ?nif_stub. +call_dirty_nif_zero_args() -> ?nif_stub. %% maps is_map_nif(_) -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 291c903947..85544db2ab 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -1623,6 +1623,18 @@ static ERL_NIF_TERM call_dirty_nif_exception(ErlNifEnv* env, int argc, const ERL call_dirty_nif_exception, argc-1, argv); } } + +static ERL_NIF_TERM call_dirty_nif_zero_args(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + int i; + ERL_NIF_TERM result[1000]; + ERL_NIF_TERM ok = enif_make_atom(env, "ok"); + assert(argc == 0); + for (i = 0; i < sizeof(result)/sizeof(*result); i++) { + result[i] = ok; + } + return enif_make_list_from_array(env, result, i); +} #endif static ERL_NIF_TERM is_map_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) @@ -1807,6 +1819,7 @@ static ErlNifFunc nif_funcs[] = {"call_dirty_nif", 3, call_dirty_nif}, {"send_from_dirty_nif", 1, send_from_dirty_nif, ERL_NIF_DIRTY_JOB_CPU_BOUND}, {"call_dirty_nif_exception", 0, call_dirty_nif_exception, ERL_NIF_DIRTY_JOB_IO_BOUND}, + {"call_dirty_nif_zero_args", 0, call_dirty_nif_zero_args, ERL_NIF_DIRTY_JOB_CPU_BOUND}, #endif {"is_map_nif", 1, is_map_nif}, {"get_map_size_nif", 1, get_map_size_nif}, diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index 3b2652d06c..babe73e575 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2013. All Rights Reserved. +%% Copyright Ericsson AB 2003-2014. 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 @@ -141,7 +141,8 @@ -export([open/1, open/2, open/3, open/4, close/1]). -export([cmd/2, cmd/3, cmdf/3, cmdf/4, get_data/1, - send/2, sendf/3, expect/2, expect/3]). + send/2, send/3, sendf/3, sendf/4, + expect/2, expect/3]). %% Callbacks -export([init/3,handle_msg/2,reconnect/2,terminate/2]). @@ -304,42 +305,74 @@ close(Connection) -> %%% Test suite interface %%%----------------------------------------------------------------- %%% @spec cmd(Connection,Cmd) -> {ok,Data} | {error,Reason} -%%% @equiv cmd(Connection,Cmd,DefaultTimeout) +%%% @equiv cmd(Connection,Cmd,[]) cmd(Connection,Cmd) -> - cmd(Connection,Cmd,default). + cmd(Connection,Cmd,[]). %%%----------------------------------------------------------------- -%%% @spec cmd(Connection,Cmd,Timeout) -> {ok,Data} | {error,Reason} +%%% @spec cmd(Connection,Cmd,Opts) -> {ok,Data} | {error,Reason} %%% Connection = ct_telnet:connection() %%% Cmd = string() -%%% Timeout = integer() +%%% Opts = [Opt] +%%% Opt = {timeout,timeout()} | {newline,boolean()} %%% Data = [string()] %%% Reason = term() %%% @doc Send a command via telnet and wait for prompt. -cmd(Connection,Cmd,Timeout) -> - case get_handle(Connection) of - {ok,Pid} -> - call(Pid,{cmd,Cmd,Timeout}); +%%% +%%% This function will by default add a newline to the end of the +%%% given command. If this is not desired, the option +%%% `{newline,false}' can be used. This is necessary, for example, +%%% when sending telnet command sequences (prefixed with the +%%% Interprete As Command, IAC, character). +%%% +%%% The option `timeout' specifies how long the client shall wait for +%%% prompt. If the time expires, the function returns +%%% `{error,timeout}'. See the module description for information +%%% about the default value for the command timeout. +cmd(Connection,Cmd,Opts) when is_list(Opts) -> + case check_cmd_opts(Opts) of + ok -> + case get_handle(Connection) of + {ok,Pid} -> + call(Pid,{cmd,Cmd,Opts}); + Error -> + Error + end; Error -> Error - end. + end; +cmd(Connection,Cmd,Timeout) when is_integer(Timeout); Timeout==default -> + %% This clause is kept for backwards compatibility only + cmd(Connection,Cmd,[{timeout,Timeout}]). + +check_cmd_opts([{timeout,Timeout}|Opts]) when is_integer(Timeout); + Timeout==default -> + check_cmd_opts(Opts); +check_cmd_opts([]) -> + ok; +check_cmd_opts(Opts) -> + check_send_opts(Opts). + %%%----------------------------------------------------------------- %%% @spec cmdf(Connection,CmdFormat,Args) -> {ok,Data} | {error,Reason} -%%% @equiv cmdf(Connection,CmdFormat,Args,DefaultTimeout) +%%% @equiv cmdf(Connection,CmdFormat,Args,[]) cmdf(Connection,CmdFormat,Args) -> - cmdf(Connection,CmdFormat,Args,default). + cmdf(Connection,CmdFormat,Args,[]). %%%----------------------------------------------------------------- -%%% @spec cmdf(Connection,CmdFormat,Args,Timeout) -> {ok,Data} | {error,Reason} +%%% @spec cmdf(Connection,CmdFormat,Args,Opts) -> {ok,Data} | {error,Reason} %%% Connection = ct_telnet:connection() %%% CmdFormat = string() %%% Args = list() -%%% Timeout = integer() +%%% Opts = [Opt] +%%% Opt = {timeout,timeout()} | {newline,boolean()} %%% Data = [string()] %%% Reason = term() %%% @doc Send a telnet command and wait for prompt %%% (uses a format string and list of arguments to build the command). -cmdf(Connection,CmdFormat,Args,Timeout) when is_list(Args) -> +%%% +%%% See {@link cmd/3} further description. +cmdf(Connection,CmdFormat,Args,Opts) when is_list(Args) -> Cmd = lists:flatten(io_lib:format(CmdFormat,Args)), - cmd(Connection,Cmd,Timeout). + cmd(Connection,Cmd,Opts). %%%----------------------------------------------------------------- %%% @spec get_data(Connection) -> {ok,Data} | {error,Reason} @@ -358,32 +391,67 @@ get_data(Connection) -> %%%----------------------------------------------------------------- %%% @spec send(Connection,Cmd) -> ok | {error,Reason} +%%% @equiv send(Connection,Cmd,[]) +send(Connection,Cmd) -> + send(Connection,Cmd,[]). + +%%%----------------------------------------------------------------- +%%% @spec send(Connection,Cmd,Opts) -> ok | {error,Reason} %%% Connection = ct_telnet:connection() %%% Cmd = string() +%%% Opts = [Opt] +%%% Opt = {newline,boolean()} %%% Reason = term() %%% @doc Send a telnet command and return immediately. %%% +%%% This function will by default add a newline to the end of the +%%% given command. If this is not desired, the option +%%% `{newline,false}' can be used. This is necessary, for example, +%%% when sending telnet command sequences (prefixed with the +%%% Interprete As Command, IAC, character). +%%% %%% <p>The resulting output from the command can be read with %%% <code>get_data/1</code> or <code>expect/2/3</code>.</p> -send(Connection,Cmd) -> - case get_handle(Connection) of - {ok,Pid} -> - call(Pid,{send,Cmd}); +send(Connection,Cmd,Opts) -> + case check_send_opts(Opts) of + ok -> + case get_handle(Connection) of + {ok,Pid} -> + call(Pid,{send,Cmd,Opts}); + Error -> + Error + end; Error -> Error end. +check_send_opts([{newline,Bool}|Opts]) when is_boolean(Bool) -> + check_send_opts(Opts); +check_send_opts([Invalid|_]) -> + {error,{invalid_option,Invalid}}; +check_send_opts([]) -> + ok. + + %%%----------------------------------------------------------------- %%% @spec sendf(Connection,CmdFormat,Args) -> ok | {error,Reason} +%%% @equiv sendf(Connection,CmdFormat,Args,[]) +sendf(Connection,CmdFormat,Args) when is_list(Args) -> + sendf(Connection,CmdFormat,Args,[]). + +%%%----------------------------------------------------------------- +%%% @spec sendf(Connection,CmdFormat,Args,Opts) -> ok | {error,Reason} %%% Connection = ct_telnet:connection() %%% CmdFormat = string() %%% Args = list() +%%% Opts = [Opt] +%%% Opt = {newline,boolean()} %%% Reason = term() %%% @doc Send a telnet command and return immediately (uses a format %%% string and a list of arguments to build the command). -sendf(Connection,CmdFormat,Args) when is_list(Args) -> +sendf(Connection,CmdFormat,Args,Opts) when is_list(Args) -> Cmd = lists:flatten(io_lib:format(CmdFormat,Args)), - send(Connection,Cmd). + send(Connection,Cmd,Opts). %%%----------------------------------------------------------------- %%% @spec expect(Connection,Patterns) -> term() @@ -559,7 +627,7 @@ set_telnet_defaults([],S) -> S. %% @hidden -handle_msg({cmd,Cmd,Timeout},State) -> +handle_msg({cmd,Cmd,Opts},State) -> start_gen_log(heading(cmd,State#state.name)), log(State,cmd,"Cmd: ~p",[Cmd]), @@ -584,11 +652,14 @@ handle_msg({cmd,Cmd,Timeout},State) -> {ip,true} -> ok end, - TO = if Timeout == default -> State#state.com_to; - true -> Timeout + TO = case proplists:get_value(timeout,Opts,default) of + default -> State#state.com_to; + Timeout -> Timeout end, + Newline = proplists:get_value(newline,Opts,true), {Return,NewBuffer,Prompt} = - case teln_cmd(State#state.teln_pid, Cmd, State#state.prx, TO) of + case teln_cmd(State#state.teln_pid, Cmd, State#state.prx, + Newline, TO) of {ok,Data,_PromptType,Rest} -> log(State,recv,"Return: ~p",[{ok,Data}]), {{ok,Data},Rest,true}; @@ -597,13 +668,13 @@ handle_msg({cmd,Cmd,Timeout},State) -> {State#state.name, State#state.type}, State#state.teln_pid, - {cmd,Cmd,TO}}}, + {cmd,Cmd,Opts}}}, log(State,recv,"Return: ~p",[Error]), {Retry,[],false} end, end_gen_log(), {Return,State#state{buffer=NewBuffer,prompt=Prompt}}; -handle_msg({send,Cmd},State) -> +handle_msg({send,Cmd,Opts},State) -> start_gen_log(heading(send,State#state.name)), log(State,send,"Sending: ~p",[Cmd]), @@ -628,7 +699,8 @@ handle_msg({send,Cmd},State) -> {ip,true} -> ok end, - ct_telnet_client:send_data(State#state.teln_pid,Cmd), + Newline = proplists:get_value(newline,Opts,true), + ct_telnet_client:send_data(State#state.teln_pid,Cmd,Newline), end_gen_log(), {ok,State#state{buffer=[],prompt=false}}; handle_msg(get_data,State) -> @@ -868,8 +940,8 @@ format_data(_How,{String,Args}) -> %%%================================================================= %%% Abstraction layer on top of ct_telnet_client.erl -teln_cmd(Pid,Cmd,Prx,Timeout) -> - ct_telnet_client:send_data(Pid,Cmd), +teln_cmd(Pid,Cmd,Prx,Newline,Timeout) -> + ct_telnet_client:send_data(Pid,Cmd,Newline), teln_receive_until_prompt(Pid,Prx,Timeout). teln_get_all_data(Pid,Prx,Data,Acc,LastLine) -> diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl index ce30dcb74b..3ae373e433 100644 --- a/lib/common_test/src/ct_telnet_client.erl +++ b/lib/common_test/src/ct_telnet_client.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2003-2013. All Rights Reserved. +%% Copyright Ericsson AB 2003-2014. 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 @@ -35,7 +35,7 @@ %% -define(debug, true). -export([open/2, open/3, open/4, open/5, close/1]). --export([send_data/2, get_data/1]). +-export([send_data/2, send_data/3, get_data/1]). -define(TELNET_PORT, 23). -define(OPEN_TIMEOUT,10000). @@ -97,7 +97,11 @@ close(Pid) -> end. send_data(Pid, Data) -> - Pid ! {send_data, Data++"\n"}, + send_data(Pid, Data, true). +send_data(Pid, Data, true) -> + send_data(Pid, Data++"\n", false); +send_data(Pid, Data, false) -> + Pid ! {send_data, Data}, ok. get_data(Pid) -> diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl index 80616af064..3885c1991d 100644 --- a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_basic_SUITE.erl @@ -20,7 +20,7 @@ suite() -> [ operations() -> [start_stop, send_and_get, expect, already_closed, - cmd, sendf, close_wrong_type]. + cmd, sendf, no_newline, close_wrong_type]. mult_case(_Case, 0) -> []; @@ -129,6 +129,16 @@ sendf(Config) -> ok = ct_telnet:close(Handle), ok. +no_newline(Config) -> + {ok, Handle} = ct_telnet:open(?conn_name(?get_n(Config))), + IAC = 255, % interprete as command + AYT = 246, % are you there + ok = ct_telnet:send(Handle, [IAC,AYT], [{newline,false}]), + {ok,_} = ct_telnet:expect(Handle,"yes",[no_prompt_check]), + {ok,_} = ct_telnet:cmd(Handle, ""), % send newline only to get back prompt + ok = ct_telnet:close(Handle), + ok. + close_wrong_type(_) -> {error, _} = ct_telnet:close(whatever), ok. diff --git a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl index c0f79d0f10..9afe545b26 100644 --- a/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE_data/ct_telnet_own_server_SUITE.erl @@ -4,6 +4,24 @@ -include_lib("common_test/include/ct.hrl"). +%% telnet control characters +-define(SE, 240). +-define(NOP, 241). +-define(DM, 242). +-define(BRK, 243). +-define(IP, 244). +-define(AO, 245). +-define(AYT, 246). +-define(EC, 247). +-define(EL, 248). +-define(GA, 249). +-define(SB, 250). +-define(WILL, 251). +-define(WONT, 252). +-define(DO, 253). +-define(DONT, 254). +-define(IAC, 255). + %%-------------------------------------------------------------------- %% TEST SERVER CALLBACK FUNCTIONS %%-------------------------------------------------------------------- @@ -34,7 +52,9 @@ all() -> ignore_prompt_timeout, large_string, server_speaks, - server_disconnects + server_disconnects, + newline_ayt, + newline_break ]. groups() -> @@ -285,3 +305,22 @@ server_disconnects(_) -> timer:sleep(3000), _ = ct_telnet:close(Handle), ok. + +%% Test option {newline,false} to send telnet command sequence. +newline_ayt(_) -> + {ok, Handle} = ct_telnet:open(telnet_server_conn1), + ok = ct_telnet:send(Handle, [?IAC,?AYT], [{newline,false}]), + {ok,["yes"]} = ct_telnet:expect(Handle, ["yes"]), + ok = ct_telnet:close(Handle), + ok. + +%% Test option {newline,false} to send telnet command sequence. +newline_break(_) -> + {ok, Handle} = ct_telnet:open(telnet_server_conn1), + ok = ct_telnet:send(Handle, [?IAC,?BRK], [{newline,false}]), + %% '#' is the prompt in break mode + {ok,["# "]} = ct_telnet:expect(Handle, ["# "], [no_prompt_check]), + {ok,R} = ct_telnet:cmd(Handle, "q", [{newline,false}]), + "> " = lists:flatten(R), + ok = ct_telnet:close(Handle), + ok. diff --git a/lib/common_test/test/telnet_server.erl b/lib/common_test/test/telnet_server.erl index 1d341d6106..0a23a66324 100644 --- a/lib/common_test/test/telnet_server.erl +++ b/lib/common_test/test/telnet_server.erl @@ -31,7 +31,8 @@ users, authorized=false, suppress_go_ahead=false, - buffer=[]}). + buffer=[], + break=false}). -type options() :: [{port,pos_integer()} | {users,users()}]. -type users() :: [{user(),password()}]. @@ -148,6 +149,9 @@ loop(State, N) -> stopped end. +handle_data(Cmd,#state{break=true}=State) -> + dbg("Server got data when in break mode: ~p~n",[Cmd]), + handle_break_cmd(Cmd,State); handle_data([?IAC|Cmd],State) -> dbg("Server got cmd: ~p~n",[Cmd]), handle_cmd(Cmd,State); @@ -171,24 +175,38 @@ handle_data(Data,State) -> {ok,State#state{buffer=[Data|State#state.buffer]}} end. -%% Add function clause below to handle new telnet commands (sent with -%% ?IAC from client - this is not possible to do from ct_telnet API, -%% but ct_telnet sends DONT SUPPRESS_GO_AHEAD) +%% Add function clause below to handle new telnet commands sent with +%% ?IAC from client. This can be done from ct_telnet:send or +%% ct_telnet:cmd if using the option {newline,false}. Also, ct_telnet +%% sends DONT SUPPRESS_GO_AHEAD. handle_cmd([?DO,?SUPPRESS_GO_AHEAD|T],State) -> send([?IAC,?WILL,?SUPPRESS_GO_AHEAD],State), - handle_cmd(T,State#state{suppress_go_ahead=true}); + handle_data(T,State#state{suppress_go_ahead=true}); handle_cmd([?DONT,?SUPPRESS_GO_AHEAD|T],State) -> send([?IAC,?WONT,?SUPPRESS_GO_AHEAD],State), - handle_cmd(T,State#state{suppress_go_ahead=false}); -handle_cmd([?IAC|T],State) -> - %% Multiple commands in one packet - handle_cmd(T,State); + handle_data(T,State#state{suppress_go_ahead=false}); +handle_cmd([?BRK|T],State) -> + %% Used when testing 'newline' option in ct_telnet:send and ct_telnet:cmd. + send("# ",State), + handle_data(T,State#state{break=true}); +handle_cmd([?AYT|T],State) -> + %% Used when testing 'newline' option in ct_telnet:send and ct_telnet:cmd. + send("yes\r\n> ",State), + handle_data(T,State); handle_cmd([_H|T],State) -> %% Not responding to this command handle_cmd(T,State); handle_cmd([],State) -> {ok,State}. +handle_break_cmd([$q|T],State) -> + %% Dummy cmd allowed in break mode - quit break mode + send("\r\n> ",State), + handle_data(T,State#state{break=false}); +handle_break_cmd([],State) -> + {ok,State}. + + %% Add function clause below to handle new text command (text entered %% from the telnet prompt) do_handle_data(Data,#state{authorized=false}=State) -> diff --git a/lib/kernel/doc/src/inet.xml b/lib/kernel/doc/src/inet.xml index 50e1cc290c..8dd311e5cd 100644 --- a/lib/kernel/doc/src/inet.xml +++ b/lib/kernel/doc/src/inet.xml @@ -138,7 +138,7 @@ fe80::204:acff:fe17:bf38 <name name="get_rc" arity="0"/> <fsummary>Return a list of IP configuration parameters</fsummary> <desc> - <p>Returns the state of the Inet configuration database in + <p>Returns the state of the Inet configuration database in form of a list of recorded configuration parameters. (See the ERTS User's Guide, Inet configuration, for more information). Only parameters with other than default values are returned.</p> @@ -258,8 +258,8 @@ fe80::204:acff:fe17:bf38 <type name="socket_getopt"/> <type name="socket_setopt"/> <desc> - <p>Gets one or more options for a socket. - See <seealso marker="#setopts/2">setopts/2</seealso> + <p>Gets one or more options for a socket. + See <seealso marker="#setopts/2">setopts/2</seealso> for a list of available options.</p> <p>The number of elements in the returned <c><anno>OptionValues</anno></c> list does not necessarily correspond to the number of options @@ -278,14 +278,14 @@ fe80::204:acff:fe17:bf38 by the protocol level, the option number and either a binary or the size, in bytes, of the buffer in which the option value is to be stored. A binary - should be used when the underlying <c>getsockopt</c> requires + should be used when the underlying <c>getsockopt</c> requires <em>input</em> in the argument field, in which case the size of the binary should correspond to the required buffer size of the return value. The supplied values in a <c>RawOptReq</c> correspond to the second, third and fourth/fifth parameters to the <c>getsockopt</c> call in the C socket API. The value stored - in the buffer is returned as a binary <c>ValueBin</c> + in the buffer is returned as a binary <c>ValueBin</c> where all values are coded in the native endianess.</p> <p>Asking for and inspecting raw socket options require low level information about the current operating system and TCP @@ -306,7 +306,7 @@ fe80::204:acff:fe17:bf38 value to be a 32 bit integer. We could use the following code to retrieve the value:</p> <code type="none"><![CDATA[ - get_tcpi_sacked(Sock) -> + get_tcpi_sacked(Sock) -> {ok,[{raw,_,_,Info}]} = inet:getopts(Sock,[{raw,6,11,92}]), <<_:28/binary,TcpiSacked:32/native,_/binary>> = Info, TcpiSacked.]]></code> @@ -408,7 +408,7 @@ fe80::204:acff:fe17:bf38 <name name="parse_ipv6strict_address" arity="1" /> <fsummary>Parse an IPv6 address strict.</fsummary> <desc> - <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>. + <p>Parses an IPv6 address string and returns an <a href="#type-ip6_address">ip6_address()</a>. Does <b>not</b> accept IPv4 adresses.</p> </desc> </func> @@ -613,15 +613,20 @@ fe80::204:acff:fe17:bf38 <marker id="option-buffer"></marker> </item> - <tag><c>{buffer, Size}</c></tag> + <tag><c>{buffer, Size}</c></tag> <item> - <p>Determines the size of the user-level software buffer used by - the driver. Not to be confused with <c>sndbuf</c> - and <c>recbuf</c> options which correspond to - the kernel socket buffers. It is recommended - to have <c>val(buffer) >= max(val(sndbuf),val(recbuf))</c>. - In fact, the <c>val(buffer)</c> is automatically set to - the above maximum when <c>sndbuf</c> or <c>recbuf</c> values are set.</p> + <p>The size of the user-level software buffer used by + the driver. Not to be confused with <c>sndbuf</c> + and <c>recbuf</c> options which correspond to + the kernel socket buffers. It is recommended + to have <c>val(buffer) >= max(val(sndbuf),val(recbuf))</c> to + avoid performance issues due to unnecessary copying. + In fact, the <c>val(buffer)</c> is automatically set to + the above maximum when <c>sndbuf</c> or <c>recbuf</c> values are set. + However, since the actual sizes set for <c>sndbuf</c> and <c>recbuf</c> + usually becomes larger, you are encouraged to use + <seealso marker="inet#getopts/2"><c>inet:getopts/2</c></seealso> + to analyze the behavior of your operating system.</p> </item> <tag><c>{delay_send, Boolean}</c></tag> @@ -998,8 +1003,12 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp </item> <tag><c>{recbuf, Size}</c></tag> <item> - <p>Gives the size of the receive buffer to use for - the socket.</p> + <p>The minimum size of the receive buffer to use for + the socket. You are encouraged to use + <seealso marker="inet#getopts/2"><c>inet:getopts/2</c></seealso>, + to retrieve the actual size set by your operating system. + + </p> </item> <tag><c>{reuseaddr, Boolean}</c></tag> <item> @@ -1030,20 +1039,24 @@ setcap cap_sys_admin,cap_sys_ptrace,cap_dac_read_search+epi beam.smp <tag><c>{sndbuf, Size}</c></tag> <item> - <p>Gives the size of the send buffer to use for the socket.</p> + <p>The minimum size of the send buffer to use for the socket. + You are encouraged to use + <seealso marker="inet#getopts/2"><c>inet:getopts/2</c></seealso>, + to retrieve the actual size set by your operating system. + </p> </item> <tag><c>{priority, Integer}</c></tag> <item> - <p>Sets the SO_PRIORITY socket level option on platforms where - this is implemented. The behaviour and allowed range varies on - different systems. The option is ignored on platforms where the + <p>Sets the SO_PRIORITY socket level option on platforms where + this is implemented. The behaviour and allowed range varies on + different systems. The option is ignored on platforms where the option is not implemented. Use with caution.</p> </item> <tag><c>{tos, Integer}</c></tag> <item> - <p>Sets IP_TOS IP level options on platforms where this is - implemented. The behaviour and allowed range varies on different - systems. The option is ignored on platforms where the option is + <p>Sets IP_TOS IP level options on platforms where this is + implemented. The behaviour and allowed range varies on different + systems. The option is ignored on platforms where the option is not implemented. Use with caution.</p> </item> </taglist> |