diff options
Diffstat (limited to 'erts/preloaded')
-rw-r--r-- | erts/preloaded/ebin/erl_prim_loader.beam | bin | 52880 -> 53080 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/erlang.beam | bin | 26772 -> 39568 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/init.beam | bin | 45172 -> 45264 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/otp_ring0.beam | bin | 1432 -> 1528 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_file.beam | bin | 32332 -> 32448 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_inet.beam | bin | 64884 -> 69916 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_zip.beam | bin | 22436 -> 22532 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/zlib.beam | bin | 12608 -> 11836 bytes | |||
-rw-r--r-- | erts/preloaded/src/erl_prim_loader.erl | 8 | ||||
-rw-r--r-- | erts/preloaded/src/erlang.erl | 404 | ||||
-rw-r--r-- | erts/preloaded/src/prim_inet.erl | 162 |
11 files changed, 490 insertions, 84 deletions
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex c7daf923c5..fe91a604b5 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex f704135ce8..dda24d4405 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex 4adb3dedf2..37fd8bb832 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex 09216fd9d8..e255cc803f 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 7ac18352c4..6227b562a1 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex 78481e2b00..d44bbbbd27 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex cad777b272..7e1a5d1fdb 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex 44dd264346..ebf9f8e6d6 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/erl_prim_loader.erl b/erts/preloaded/src/erl_prim_loader.erl index 0b4db3d9d0..35defde692 100644 --- a/erts/preloaded/src/erl_prim_loader.erl +++ b/erts/preloaded/src/erl_prim_loader.erl @@ -729,7 +729,7 @@ udp_options() -> %% INET version IPv4 addresses %% ll_tcp_connect(LocalPort, IP, RemotePort) -> - case ll_open_set_bind(tcp, ?INET_FAMILY, tcp_options(), + case ll_open_set_bind(tcp, ?INET_FAMILY, stream, tcp_options(), ?INET_ADDRESS, LocalPort) of {ok,S} -> case prim_inet:connect(S, IP, RemotePort, tcp_timeout()) of @@ -743,11 +743,11 @@ ll_tcp_connect(LocalPort, IP, RemotePort) -> %% Open and initialize an udp port for broadcast %% ll_udp_open(P) -> - ll_open_set_bind(udp, ?INET_FAMILY, udp_options(), ?INET_ADDRESS, P). + ll_open_set_bind(udp, ?INET_FAMILY, dgram, udp_options(), ?INET_ADDRESS, P). -ll_open_set_bind(Protocol, Family, SOpts, IP, Port) -> - case prim_inet:open(Protocol, Family) of +ll_open_set_bind(Protocol, Family, Type, SOpts, IP, Port) -> + case prim_inet:open(Protocol, Family, Type) of {ok, S} -> case prim_inet:setopts(S, SOpts) of ok -> diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index ff3633a3cc..e9a59a7aaf 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -40,6 +40,8 @@ -export([flush_monitor_message/2]). -export([set_cpu_topology/1, format_cpu_topology/1]). -export([await_proc_exit/3]). +-export([memory/0, memory/1]). +-export([alloc_info/1, alloc_sizes/1]). -deprecated([hash/2]). @@ -800,3 +802,405 @@ min(A, _) -> A. Maximum :: term(). max(A, B) when A < B -> B; max(A, _) -> A. + + +%% +%% erlang:memory/[0,1] +%% +%% NOTE! When updating these functions, make sure to also update +%% erts_memory() in $ERL_TOP/erts/emulator/beam/erl_alloc.c +%% + +-type memory_type() :: 'total' | 'processes' | 'processes_used' | 'system' | 'atom' | 'atom_used' | 'binary' | 'code' | 'ets' | 'low' | 'maximum'. + +-define(CARRIER_ALLOCS, [mseg_alloc, sbmbc_alloc, sbmbc_low_alloc]). +-define(LOW_ALLOCS, [sbmbc_low_alloc, ll_low_alloc, std_low_alloc]). +-define(ALL_NEEDED_ALLOCS, (erlang:system_info(alloc_util_allocators) + -- ?CARRIER_ALLOCS)). + +-record(memory, {total = 0, + processes = 0, + processes_used = 0, + system = 0, + atom = 0, + atom_used = 0, + binary = 0, + code = 0, + ets = 0, + low = 0, + maximum = 0}). + +-spec memory() -> [{memory_type(), non_neg_integer()}]. +memory() -> + case aa_mem_data(au_mem_data(?ALL_NEEDED_ALLOCS)) of + notsup -> + erlang:error(notsup); + Mem -> + InstrTail = case Mem#memory.maximum of + 0 -> []; + _ -> [{maximum, Mem#memory.maximum}] + end, + Tail = case Mem#memory.low of + 0 -> InstrTail; + _ -> [{low, Mem#memory.low} | InstrTail] + end, + [{total, Mem#memory.total}, + {processes, Mem#memory.processes}, + {processes_used, Mem#memory.processes_used}, + {system, Mem#memory.system}, + {atom, Mem#memory.atom}, + {atom_used, Mem#memory.atom_used}, + {binary, Mem#memory.binary}, + {code, Mem#memory.code}, + {ets, Mem#memory.ets} | Tail] + end. + +-spec memory(memory_type()|[memory_type()]) -> non_neg_integer() | [{memory_type(), non_neg_integer()}]. +memory(Type) when is_atom(Type) -> + {AA, ALCU, ChkSup, BadArgZero} = need_mem_info(Type), + case get_mem_data(ChkSup, ALCU, AA) of + notsup -> + erlang:error(notsup, [Type]); + Mem -> + Value = get_memval(Type, Mem), + case {BadArgZero, Value} of + {true, 0} -> erlang:error(badarg, [Type]); + _ -> Value + end + end; +memory(Types) when is_list(Types) -> + {AA, ALCU, ChkSup, BadArgZeroList} = need_mem_info_list(Types), + case get_mem_data(ChkSup, ALCU, AA) of + notsup -> + erlang:error(notsup, [Types]); + Mem -> + case memory_result_list(Types, BadArgZeroList, Mem) of + badarg -> erlang:error(badarg, [Types]); + Result -> Result + end + end. + +memory_result_list([], [], _Mem) -> + []; +memory_result_list([T|Ts], [BAZ|BAZs], Mem) -> + case memory_result_list(Ts, BAZs, Mem) of + badarg -> badarg; + TVs -> + V = get_memval(T, Mem), + case {BAZ, V} of + {true, 0} -> badarg; + _ -> [{T, V}| TVs] + end + end. + +get_mem_data(true, AlcUAllocs, NeedAllocatedAreas) -> + case memory_is_supported() of + false -> notsup; + true -> get_mem_data(false, AlcUAllocs, NeedAllocatedAreas) + end; +get_mem_data(false, AlcUAllocs, NeedAllocatedAreas) -> + AlcUMem = case AlcUAllocs of + [] -> #memory{}; + _ -> + au_mem_data(AlcUAllocs) + end, + case NeedAllocatedAreas of + true -> aa_mem_data(AlcUMem); + false -> AlcUMem + end. + +need_mem_info_list([]) -> + {false, [], false, []}; +need_mem_info_list([T|Ts]) -> + {MAA, MALCU, MChkSup, MBadArgZero} = need_mem_info_list(Ts), + {AA, ALCU, ChkSup, BadArgZero} = need_mem_info(T), + {case AA of + true -> true; + _ -> MAA + end, + ALCU ++ (MALCU -- ALCU), + case ChkSup of + true -> true; + _ -> MChkSup + end, + [BadArgZero|MBadArgZero]}. + +need_mem_info(Type) when Type == total; + Type == system -> + {true, ?ALL_NEEDED_ALLOCS, false, false}; +need_mem_info(Type) when Type == processes; + Type == processes_used -> + {true, [eheap_alloc, fix_alloc], true, false}; +need_mem_info(Type) when Type == atom; + Type == atom_used; + Type == code -> + {true, [], true, false}; +need_mem_info(binary) -> + {false, [binary_alloc], true, false}; +need_mem_info(ets) -> + {true, [ets_alloc], true, false}; +need_mem_info(low) -> + LowAllocs = ?LOW_ALLOCS -- ?CARRIER_ALLOCS, + {_, _, FeatureList, _} = erlang:system_info(allocator), + AlcUAllocs = case LowAllocs -- FeatureList of + [] -> LowAllocs; + _ -> [] + end, + {false, AlcUAllocs, true, true}; +need_mem_info(maximum) -> + {true, [], true, true}; +need_mem_info(_) -> + {false, [], false, true}. + +get_memval(total, #memory{total = V}) -> V; +get_memval(processes, #memory{processes = V}) -> V; +get_memval(processes_used, #memory{processes_used = V}) -> V; +get_memval(system, #memory{system = V}) -> V; +get_memval(atom, #memory{atom = V}) -> V; +get_memval(atom_used, #memory{atom_used = V}) -> V; +get_memval(binary, #memory{binary = V}) -> V; +get_memval(code, #memory{code = V}) -> V; +get_memval(ets, #memory{ets = V}) -> V; +get_memval(low, #memory{low = V}) -> V; +get_memval(maximum, #memory{maximum = V}) -> V; +get_memval(_, #memory{}) -> 0. + +memory_is_supported() -> + {_, _, FeatureList, _} = erlang:system_info(allocator), + case ((erlang:system_info(alloc_util_allocators) + -- ?CARRIER_ALLOCS) + -- FeatureList) of + [] -> true; + _ -> false + end. + +get_blocks_size([{blocks_size, Sz, _, _} | Rest], Acc) -> + get_blocks_size(Rest, Acc+Sz); +get_blocks_size([{_, _, _, _} | Rest], Acc) -> + get_blocks_size(Rest, Acc); +get_blocks_size([], Acc) -> + Acc. + +blocks_size([{Carriers, SizeList} | Rest], Acc) when Carriers == mbcs; + Carriers == sbcs; + Carriers == sbmbcs -> + blocks_size(Rest, get_blocks_size(SizeList, Acc)); +blocks_size([_ | Rest], Acc) -> + blocks_size(Rest, Acc); +blocks_size([], Acc) -> + Acc. + +get_fix_proc([{ProcType, A1, U1}| Rest], {A0, U0}) when ProcType == proc; + ProcType == monitor_sh; + ProcType == nlink_sh; + ProcType == msg_ref -> + get_fix_proc(Rest, {A0+A1, U0+U1}); +get_fix_proc([_|Rest], Acc) -> + get_fix_proc(Rest, Acc); +get_fix_proc([], Acc) -> + Acc. + +fix_proc([{fix_types, SizeList} | _Rest], Acc) -> + get_fix_proc(SizeList, Acc); +fix_proc([_ | Rest], Acc) -> + fix_proc(Rest, Acc); +fix_proc([], Acc) -> + Acc. + +is_low_alloc(_A, []) -> + false; +is_low_alloc(A, [A|_As]) -> + true; +is_low_alloc(A, [_A|As]) -> + is_low_alloc(A, As). + +is_low_alloc(A) -> + is_low_alloc(A, ?LOW_ALLOCS). + +au_mem_data(notsup, _) -> + notsup; +au_mem_data(_, [{_, false} | _]) -> + notsup; +au_mem_data(#memory{total = Tot, + processes = Proc, + processes_used = ProcU} = Mem, + [{eheap_alloc, _, Data} | Rest]) -> + Sz = blocks_size(Data, 0), + au_mem_data(Mem#memory{total = Tot+Sz, + processes = Proc+Sz, + processes_used = ProcU+Sz}, + Rest); +au_mem_data(#memory{total = Tot, + system = Sys, + ets = Ets} = Mem, + [{ets_alloc, _, Data} | Rest]) -> + Sz = blocks_size(Data, 0), + au_mem_data(Mem#memory{total = Tot+Sz, + system = Sys+Sz, + ets = Ets+Sz}, + Rest); +au_mem_data(#memory{total = Tot, + system = Sys, + binary = Bin} = Mem, + [{binary_alloc, _, Data} | Rest]) -> + Sz = blocks_size(Data, 0), + au_mem_data(Mem#memory{total = Tot+Sz, + system = Sys+Sz, + binary = Bin+Sz}, + Rest); +au_mem_data(#memory{total = Tot, + processes = Proc, + processes_used = ProcU, + system = Sys} = Mem, + [{fix_alloc, _, Data} | Rest]) -> + {A, U} = fix_proc(Data, {0, 0}), + Sz = blocks_size(Data, 0), + au_mem_data(Mem#memory{total = Tot+Sz, + processes = Proc+A, + processes_used = ProcU+U, + system = Sys+Sz-A}, + Rest); +au_mem_data(#memory{total = Tot, + system = Sys, + low = Low} = Mem, + [{A, _, Data} | Rest]) -> + Sz = blocks_size(Data, 0), + au_mem_data(Mem#memory{total = Tot+Sz, + system = Sys+Sz, + low = case is_low_alloc(A) of + true -> Low+Sz; + false -> Low + end}, + Rest); +au_mem_data(EMD, []) -> + EMD. + +au_mem_data(Allocs) -> + Ref = make_ref(), + erlang:system_info({allocator_sizes, Ref, Allocs}), + receive_emd(Ref). + +receive_emd(_Ref, EMD, 0) -> + EMD; +receive_emd(Ref, EMD, N) -> + receive + {Ref, _, Data} -> + receive_emd(Ref, au_mem_data(EMD, Data), N-1) + end. + +receive_emd(Ref) -> + receive_emd(Ref, #memory{}, erlang:system_info(schedulers)). + +aa_mem_data(notsup, _) -> + notsup; +aa_mem_data(#memory{} = Mem, + [{maximum, Max} | Rest]) -> + aa_mem_data(Mem#memory{maximum = Max}, + Rest); +aa_mem_data(#memory{} = Mem, + [{total, Tot} | Rest]) -> + aa_mem_data(Mem#memory{total = Tot, + system = 0}, % system will be adjusted later + Rest); +aa_mem_data(#memory{atom = Atom, + atom_used = AtomU} = Mem, + [{atom_space, Alloced, Used} | Rest]) -> + aa_mem_data(Mem#memory{atom = Atom+Alloced, + atom_used = AtomU+Used}, + Rest); +aa_mem_data(#memory{atom = Atom, + atom_used = AtomU} = Mem, + [{atom_table, Sz} | Rest]) -> + aa_mem_data(Mem#memory{atom = Atom+Sz, + atom_used = AtomU+Sz}, + Rest); +aa_mem_data(#memory{ets = Ets} = Mem, + [{ets_misc, Sz} | Rest]) -> + aa_mem_data(Mem#memory{ets = Ets+Sz}, + Rest); +aa_mem_data(#memory{processes = Proc, + processes_used = ProcU, + system = Sys} = Mem, + [{ProcData, Sz} | Rest]) when ProcData == bif_timer; + ProcData == link_lh; + ProcData == process_table -> + aa_mem_data(Mem#memory{processes = Proc+Sz, + processes_used = ProcU+Sz, + system = Sys-Sz}, + Rest); +aa_mem_data(#memory{code = Code} = Mem, + [{CodeData, Sz} | Rest]) when CodeData == module_table; + CodeData == export_table; + CodeData == export_list; + CodeData == fun_table; + CodeData == module_refs; + CodeData == loaded_code -> + aa_mem_data(Mem#memory{code = Code+Sz}, + Rest); +aa_mem_data(EMD, [{_, _} | Rest]) -> + aa_mem_data(EMD, Rest); +aa_mem_data(#memory{total = Tot, + processes = Proc, + system = Sys} = Mem, + []) when Sys =< 0 -> + %% Instrumented runtime system -> Sys = Tot - Proc + Mem#memory{system = Tot - Proc}; +aa_mem_data(EMD, []) -> + EMD. + +aa_mem_data(notsup) -> + notsup; +aa_mem_data(EMD) -> + aa_mem_data(EMD, erlang:system_info(allocated_areas)). + +%% +%% alloc_info/1 and alloc_sizes/1 are for internal use only (used by +%% erlang:system_info({allocator|allocator_sizes, _})). +%% + +alloc_info(Allocs) -> + get_alloc_info(allocator, Allocs). + +alloc_sizes(Allocs) -> + get_alloc_info(allocator_sizes, Allocs). + +get_alloc_info(Type, AAtom) when is_atom(AAtom) -> + [{AAtom, Result}] = get_alloc_info(Type, [AAtom]), + Result; +get_alloc_info(Type, AList) when is_list(AList) -> + Ref = make_ref(), + erlang:system_info({Type, Ref, AList}), + receive_allocator(Ref, + erlang:system_info(schedulers), + mk_res_list(AList)). + +mk_res_list([]) -> + []; +mk_res_list([Alloc | Rest]) -> + [{Alloc, []} | mk_res_list(Rest)]. + +insert_instance(I, N, []) -> + [{instance, N, I}]; +insert_instance(I, N, [{instance, M, _}|_] = Rest) when N < M -> + [{instance, N, I} | Rest]; +insert_instance(I, N, [Prev|Rest]) -> + [Prev | insert_instance(I, N, Rest)]. + +insert_info([], Ys) -> + Ys; +insert_info([{A, false}|Xs], [{A, _IList}|Ys]) -> + insert_info(Xs, [{A, false}|Ys]); +insert_info([{A, N, I}|Xs], [{A, IList}|Ys]) -> + insert_info(Xs, [{A, insert_instance(I, N, IList)}|Ys]); +insert_info([{A1, _}|_] = Xs, [{A2, _} = Y | Ys]) when A1 /= A2 -> + [Y | insert_info(Xs, Ys)]; +insert_info([{A1, _, _}|_] = Xs, [{A2, _} = Y | Ys]) when A1 /= A2 -> + [Y | insert_info(Xs, Ys)]. + +receive_allocator(_Ref, 0, Acc) -> + Acc; +receive_allocator(Ref, N, Acc) -> + receive + {Ref, _, InfoList} -> + receive_allocator(Ref, N-1, insert_info(InfoList, Acc)) + end. diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 8f2e845b4f..f144f73d68 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -25,8 +25,8 @@ %% Primitive inet_drv interface --export([open/1, open/2, fdopen/2, fdopen/3, close/1]). --export([bind/3, listen/1, listen/2]). +-export([open/3, fdopen/4, close/1]). +-export([bind/3, listen/1, listen/2, peeloff/2]). -export([connect/3, connect/4, async_connect/4]). -export([accept/1, accept/2, async_accept/2]). -export([shutdown/2]). @@ -56,58 +56,46 @@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% -%% OPEN(tcp | udp | sctp, inet | inet6) -> +%% OPEN(tcp | udp | sctp, inet | inet6, stream | dgram | seqpacket) -> %% {ok, insock()} | %% {error, Reason} %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -open(Protocol) -> open1(Protocol, ?INET_AF_INET). +open(Protocol, Family, Type) -> + open(Protocol, Family, Type, ?INET_REQ_OPEN, []). -open(Protocol, inet) -> open1(Protocol, ?INET_AF_INET); -open(Protocol, inet6) -> open1(Protocol, ?INET_AF_INET6); -open(_, _) -> {error, einval}. +fdopen(Protocol, Family, Type, Fd) when is_integer(Fd) -> + open(Protocol, Family, Type, ?INET_REQ_FDOPEN, ?int32(Fd)). -fdopen(Protocol, Fd) -> fdopen1(Protocol, ?INET_AF_INET, Fd). - -fdopen(Protocol, Fd, inet) -> fdopen1(Protocol, ?INET_AF_INET, Fd); -fdopen(Protocol, Fd, inet6) -> fdopen1(Protocol, ?INET_AF_INET6, Fd); -fdopen(_, _, _) -> {error, einval}. - -open1(Protocol, Family) -> - case open0(Protocol) of - {ok, S} -> - case ctl_cmd(S, ?INET_REQ_OPEN, [Family]) of - {ok, _} -> - {ok,S}; - Error -> - close(S), Error - end; - Error -> Error +open(Protocol, Family, Type, Req, Data) -> + Drv = protocol2drv(Protocol), + AF = enc_family(Family), + T = enc_type(Type), + try erlang:open_port({spawn_driver,Drv}, [binary]) of + S -> + case ctl_cmd(S, Req, [AF,T,Data]) of + {ok,_} -> {ok,S}; + {error,_}=Error -> + close(S), + Error + end + catch + %% The only (?) way to get here is to try to open + %% the sctp driver when it does not exist + error:badarg -> {error,eprotonosupport} end. -fdopen1(Protocol, Family, Fd) when is_integer(Fd) -> - case open0(Protocol) of - {ok, S} -> - case ctl_cmd(S,?INET_REQ_FDOPEN,[Family,?int32(Fd)]) of - {ok, _} -> {ok,S}; - Error -> close(S), Error - end; - Error -> Error - end. +enc_family(inet) -> ?INET_AF_INET; +enc_family(inet6) -> ?INET_AF_INET6. -open0(Protocol) -> - try erlang:open_port({spawn_driver,protocol2drv(Protocol)}, [binary]) of - Port -> {ok,Port} - catch - error:Reason -> {error,Reason} - end. +enc_type(stream) -> ?INET_TYPE_STREAM; +enc_type(dgram) -> ?INET_TYPE_DGRAM; +enc_type(seqpacket) -> ?INET_TYPE_SEQPACKET. protocol2drv(tcp) -> "tcp_inet"; protocol2drv(udp) -> "udp_inet"; -protocol2drv(sctp) -> "sctp_inet"; -protocol2drv(_) -> - erlang:error(eprotonosupport). +protocol2drv(sctp) -> "sctp_inet". drv2protocol("tcp_inet") -> tcp; drv2protocol("udp_inet") -> udp; @@ -139,7 +127,7 @@ shutdown_1(S, How) -> shutdown_2(S, How) -> case ctl_cmd(S, ?TCP_REQ_SHUTDOWN, [How]) of {ok, []} -> ok; - Error -> Error + {error,_}=Error -> Error end. shutdown_pend_loop(S, N0) -> @@ -195,7 +183,7 @@ close_pend_loop(S, N) -> bind(S,IP,Port) when is_port(S), is_integer(Port), Port >= 0, Port =< 65535 -> case ctl_cmd(S,?INET_REQ_BIND,[?int16(Port),ip_to_bytes(IP)]) of {ok, [P1,P0]} -> {ok, ?u16(P1, P0)}; - Error -> Error + {error,_}=Error -> Error end; %% Multi-homed "bind": sctp_bindx(). The Op is 'add' or 'remove'. @@ -222,7 +210,7 @@ bindx(S, AddFlag, Addrs) -> {IP, Port} <- Addrs]], case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of {ok,_} -> {ok, S}; - Error -> Error + {error,_}=Error -> Error end; _ -> {error, einval} end. @@ -265,7 +253,7 @@ async_connect(S, IP, Port, Time) -> case ctl_cmd(S, ?INET_REQ_CONNECT, [enc_time(Time),?int16(Port),ip_to_bytes(IP)]) of {ok, [R1,R0]} -> {ok, S, ?u16(R1,R0)}; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -318,9 +306,9 @@ accept_opts(L, S) -> end. async_accept(L, Time) -> - case ctl_cmd(L,?TCP_REQ_ACCEPT, [enc_time(Time)]) of + case ctl_cmd(L,?INET_REQ_ACCEPT, [enc_time(Time)]) of {ok, [R1,R0]} -> {ok, ?u16(R1,R0)}; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -334,16 +322,30 @@ async_accept(L, Time) -> %% listening) is also accepted: listen(S) -> listen(S, ?LISTEN_BACKLOG). - + +listen(S, true) -> listen(S, ?LISTEN_BACKLOG); +listen(S, false) -> listen(S, 0); listen(S, BackLog) when is_port(S), is_integer(BackLog) -> - case ctl_cmd(S, ?TCP_REQ_LISTEN, [?int16(BackLog)]) of + case ctl_cmd(S, ?INET_REQ_LISTEN, [?int16(BackLog)]) of {ok, _} -> ok; - Error -> Error - end; -listen(S, Flag) when is_port(S), is_boolean(Flag) -> - case ctl_cmd(S, ?SCTP_REQ_LISTEN, enc_value(set, bool8, Flag)) of - {ok,_} -> ok; - Error -> Error + {error,_}=Error -> Error + end. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% PEELOFF(insock(), AssocId) -> {ok,outsock()} | {error, Reason} +%% +%% SCTP: Peel off one association into a type stream socket +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +peeloff(S, AssocId) -> + case ctl_cmd(S, ?SCTP_REQ_PEELOFF, [?int32(AssocId)]) of + inet_reply -> + receive + {inet_reply,S,Res} -> Res + end; + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -395,12 +397,12 @@ sendto(S, IP, Port, Data) when is_port(S), Port >= 0, Port =< 65535 -> true -> receive {inet_reply,S,Reply} -> - ?DBG_FORMAT("prim_inet:send() -> ~p~n", [Reply]), + ?DBG_FORMAT("prim_inet:sendto() -> ~p~n", [Reply]), Reply end catch error:_ -> - ?DBG_FORMAT("prim_inet:send() -> {error,einval}~n", []), + ?DBG_FORMAT("prim_inet:sendto() -> {error,einval}~n", []), {error,einval} end. @@ -455,7 +457,7 @@ recv0(S, Length, Time) when is_port(S), is_integer(Length), Length >= 0 -> async_recv(S, Length, Time) -> case ctl_cmd(S, ?TCP_REQ_RECV, [enc_time(Time), ?int32(Length)]) of {ok,[R1,R0]} -> {ok, ?u16(R1,R0)}; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -501,7 +503,7 @@ recvfrom0(S, Length, Time) {inet_async, S, Ref, Error={error, _}} -> Error end; - Error -> + {error,_}=Error -> Error % Front-end error end; recvfrom0(_, _, _) -> {error,einval}. @@ -517,18 +519,18 @@ peername(S) when is_port(S) -> {ok, [F, P1,P0 | Addr]} -> {IP, _} = get_ip(F, Addr), {ok, { IP, ?u16(P1, P0) }}; - Error -> Error + {error,_}=Error -> Error end. setpeername(S, {IP,Port}) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_SETPEER, [?int16(Port),ip_to_bytes(IP)]) of {ok,[]} -> ok; - Error -> Error + {error,_}=Error -> Error end; setpeername(S, undefined) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_SETPEER, []) of {ok,[]} -> ok; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -542,18 +544,18 @@ sockname(S) when is_port(S) -> {ok, [F, P1, P0 | Addr]} -> {IP, _} = get_ip(F, Addr), {ok, { IP, ?u16(P1, P0) }}; - Error -> Error + {error,_}=Error -> Error end. setsockname(S, {IP,Port}) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_SETNAME, [?int16(Port),ip_to_bytes(IP)]) of {ok,[]} -> ok; - Error -> Error + {error,_}=Error -> Error end; setsockname(S, undefined) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_SETNAME, []) of {ok,[]} -> ok; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -573,7 +575,7 @@ setopts(S, Opts) when is_port(S) -> {ok, Buf} -> case ctl_cmd(S, ?INET_REQ_SETOPTS, Buf) of {ok, _} -> ok; - Error -> Error + {error,_}=Error -> Error end; Error -> Error end. @@ -599,12 +601,12 @@ getopts(S, Opts) when is_port(S), is_list(Opts) -> {ok,Rep} -> %% Non-SCTP: "Rep" contains the encoded option vals: decode_opt_val(Rep); - {error,sctp_reply} -> + inet_reply -> %% SCTP: Need to receive the full value: receive {inet_reply,S,Res} -> Res end; - Error -> Error + {error,_}=Error -> Error end; Error -> Error end. @@ -733,7 +735,7 @@ getifaddrs_ifget(S, IFs, IF, FlagsVals, Opts) -> getiflist(S) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_GETIFLIST, []) of {ok, Data} -> {ok, build_iflist(Data)}; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -751,7 +753,7 @@ ifget(S, Name, Opts) -> {ok, Buf2} -> case ctl_cmd(S, ?INET_REQ_IFGET, [Buf1,Buf2]) of {ok, Data} -> decode_ifopts(Data,[]); - Error -> Error + {error,_}=Error -> Error end; Error -> Error end; @@ -773,7 +775,7 @@ ifset(S, Name, Opts) -> {ok, Buf2} -> case ctl_cmd(S, ?INET_REQ_IFSET, [Buf1,Buf2]) of {ok, _} -> ok; - Error -> Error + {error,_}=Error -> Error end; Error -> Error end; @@ -801,7 +803,7 @@ subscribe(S, Sub) when is_port(S), is_list(Sub) -> {ok, Bytes} -> case ctl_cmd(S, ?INET_REQ_SUBSCRIBE, Bytes) of {ok, Data} -> decode_subs(Data); - Error -> Error + {error,_}=Error -> Error end; Error -> Error end. @@ -819,7 +821,7 @@ getstat(S, Stats) when is_port(S), is_list(Stats) -> {ok, Bytes} -> case ctl_cmd(S, ?INET_REQ_GETSTAT, Bytes) of {ok, Data} -> decode_stats(Data); - Error -> Error + {error,_}=Error -> Error end; Error -> Error end. @@ -835,7 +837,7 @@ getstat(S, Stats) when is_port(S), is_list(Stats) -> getfd(S) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_GETFD, []) of {ok, [S3,S2,S1,S0]} -> {ok, ?u32(S3,S2,S1,S0)}; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -873,7 +875,7 @@ gettype(S) when is_port(S) -> _ -> undefined end, {ok, {Family, Type}}; - Error -> Error + {error,_}=Error -> Error end. getprotocol(S) when is_port(S) -> @@ -901,7 +903,7 @@ getstatus(S) when is_port(S) -> case ctl_cmd(S, ?INET_REQ_GETSTATUS, []) of {ok, [S3,S2,S1,S0]} -> {ok, dec_status(?u32(S3,S2,S1,S0))}; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -943,7 +945,7 @@ getservbyname1(S,Name,Proto) -> case ctl_cmd(S, ?INET_REQ_GETSERVBYNAME, [L1,Name,L2,Proto]) of {ok, [P1,P0]} -> {ok, ?u16(P1,P0)}; - Error -> + {error,_}=Error -> Error end end. @@ -971,7 +973,7 @@ getservbyport1(S,Port,Proto) -> true -> case ctl_cmd(S, ?INET_REQ_GETSERVBYPORT, [?int16(Port),L,Proto]) of {ok, Name} -> {ok, Name}; - Error -> Error + {error,_}=Error -> Error end end. @@ -985,7 +987,7 @@ getservbyport1(S,Port,Proto) -> unrecv(S, Data) -> case ctl_cmd(S, ?TCP_REQ_UNRECV, Data) of {ok, _} -> ok; - Error -> Error + {error,_}=Error -> Error end. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -2163,7 +2165,7 @@ ctl_cmd(Port, Cmd, Args) -> Result = try erlang:port_control(Port, Cmd, Args) of [?INET_REP_OK|Reply] -> {ok,Reply}; - [?INET_REP_SCTP] -> {error,sctp_reply}; + [?INET_REP] -> inet_reply; [?INET_REP_ERROR|Err] -> {error,list_to_atom(Err)} catch error:_ -> {error,einval} |