diff options
Diffstat (limited to 'erts/preloaded')
-rw-r--r-- | erts/preloaded/ebin/erl_prim_loader.beam | bin | 50384 -> 50384 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/erlang.beam | bin | 24316 -> 24320 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/init.beam | bin | 44348 -> 44876 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/otp_ring0.beam | bin | 1428 -> 1432 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_file.beam | bin | 30536 -> 31552 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_inet.beam | bin | 57268 -> 65060 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/prim_zip.beam | bin | 22428 -> 22432 bytes | |||
-rw-r--r-- | erts/preloaded/ebin/zlib.beam | bin | 10612 -> 10616 bytes | |||
-rw-r--r-- | erts/preloaded/src/Makefile | 22 | ||||
-rw-r--r-- | erts/preloaded/src/init.erl | 71 | ||||
-rw-r--r-- | erts/preloaded/src/prim_file.erl | 109 | ||||
-rw-r--r-- | erts/preloaded/src/prim_inet.erl | 250 |
12 files changed, 339 insertions, 113 deletions
diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex 222809e662..87ff5119fd 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 65c7369b76..6b0d96ff8e 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 f1b54b7fcb..8a7a9a1314 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 abf17bcb0e..5d544ff4aa 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 a3f300268f..3ed02ecd44 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 a777971b32..79a8d22366 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 0fe38a1fb2..3cc8c6b8be 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 7108bf44d0..3f9e867542 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/Makefile b/erts/preloaded/src/Makefile index 785ad531f3..145638802f 100644 --- a/erts/preloaded/src/Makefile +++ b/erts/preloaded/src/Makefile @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 2008-2009. All Rights Reserved. +# Copyright Ericsson AB 2008-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 @@ -20,8 +20,7 @@ # be used when the preloaded modules actually are to be updated (i.e. the # beam files are to be recompiled, which is normally not done). # The beam files are placed in the current directory and should be copied -# to the ../ebin directory by using the commit target (only works in -# clearcase). +# to the ../ebin directory by using the copy target. include $(ERL_TOP)/make/target.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk @@ -62,26 +61,9 @@ debug opt: $(TARGET_FILES) clean: rm -f $(TARGET_FILES) -prepare: - cleartool co -nc $(STATIC_EBIN)/* - cleartool co -nc $(STATIC_EBIN) - copy: - for x in *.beam; do\ - if test '!' -f $(STATIC_EBIN)/$$x; then\ - cleartool mkelem -nc $$x;\ - fi;\ - done cp *.beam $(STATIC_EBIN) -commit: - cleartool ci -ident -nc $(STATIC_EBIN)/*.beam - cleartool ci -ident -nc $(STATIC_EBIN) - -cancel: - -cleartool unco -rm $(STATIC_EBIN) - -cleartool unco -rm $(STATIC_EBIN)/*.beam - include $(ERL_TOP)/make/otp_release_targets.mk diff --git a/erts/preloaded/src/init.erl b/erts/preloaded/src/init.erl index 3b98b9cddc..24430a3d40 100644 --- a/erts/preloaded/src/init.erl +++ b/erts/preloaded/src/init.erl @@ -51,6 +51,9 @@ get_status/0,boot/1,get_arguments/0,get_plain_arguments/0, get_argument/1,script_id/0]). +%% for the on_load functionality; not for general use +-export([run_on_load_handlers/0]). + %% internal exports -export([fetch_loaded/0,ensure_loaded/1,make_permanent/2, notify_when_started/1,wait_until_started/0, @@ -69,6 +72,7 @@ script_id = [], loaded = [], subscribed = []}). +-type state() :: #state{}. -define(ON_LOAD_HANDLER, init__boot__on_load_handler). @@ -143,10 +147,10 @@ restart() -> init ! {stop,restart}, ok. -spec reboot() -> 'ok'. reboot() -> init ! {stop,reboot}, ok. --spec stop() -> no_return(). +-spec stop() -> 'ok'. stop() -> init ! {stop,stop}, ok. --spec stop(non_neg_integer() | string()) -> no_return(). +-spec stop(non_neg_integer() | string()) -> 'ok'. stop(Status) -> init ! {stop,{stop,Status}}, ok. -spec boot([binary()]) -> no_return(). @@ -275,7 +279,7 @@ crash(String, List) -> halt(halt_string(String, List)). %% Status is {InternalStatus,ProvidedStatus} --spec boot_loop(pid(), #state{}) -> no_return(). +-spec boot_loop(pid(), state()) -> no_return(). boot_loop(BootPid, State) -> receive {BootPid,loaded,ModLoaded} -> @@ -308,24 +312,6 @@ boot_loop(BootPid, State) -> {stop,Reason} -> stop(Reason,State); {From,fetch_loaded} -> %% Fetch and reset initially loaded modules. - case whereis(?ON_LOAD_HANDLER) of - undefined -> - %% There is no on_load handler process, - %% probably because init:restart/0 has been - %% called and it is not the first time we - %% pass through here. - ok; - Pid when is_pid(Pid) -> - Pid ! run_on_load, - receive - {'EXIT',Pid,on_load_done} -> - ok; - {'EXIT',Pid,Res} -> - %% Failure to run an on_load handler. - %% This is fatal during start-up. - exit(Res) - end - end, From ! {init,State#state.loaded}, garb_boot_loop(BootPid,State#state{loaded = []}); {From,{ensure_loaded,Module}} -> @@ -736,6 +722,7 @@ do_boot(Init,Flags,Start) -> BootList = get_boot(BootFile,Root), LoadMode = b2a(get_flag('-mode',Flags,false)), Deb = b2a(get_flag('-init_debug',Flags,false)), + catch ?ON_LOAD_HANDLER ! {init_debug_flag,Deb}, BootVars = get_flag_args('-boot_var',Flags), ParallelLoad = (Pgm =:= "efile") and (erlang:system_info(thread_pool_size) > 0), @@ -1335,23 +1322,44 @@ archive_extension() -> %%% Support for handling of on_load functions. %%% +run_on_load_handlers() -> + Ref = monitor(process, ?ON_LOAD_HANDLER), + catch ?ON_LOAD_HANDLER ! run_on_load, + receive + {'DOWN',Ref,process,_,noproc} -> + %% There is no on_load handler process, + %% probably because init:restart/0 has been + %% called and it is not the first time we + %% pass through here. + ok; + {'DOWN',Ref,process,_,on_load_done} -> + ok; + {'DOWN',Ref,process,_,Res} -> + %% Failure to run an on_load handler. + %% This is fatal during start-up. + exit(Res) + end. + start_on_load_handler_process() -> register(?ON_LOAD_HANDLER, - spawn_link(fun on_load_handler_init/0)). + spawn(fun on_load_handler_init/0)). on_load_handler_init() -> - on_load_loop([]). + on_load_loop([], false). -on_load_loop(Mods) -> +on_load_loop(Mods, Debug0) -> receive + {init_debug_flag,Debug} -> + on_load_loop(Mods, Debug); {loaded,Mod} -> - on_load_loop([Mod|Mods]); + on_load_loop([Mod|Mods], Debug0); run_on_load -> - run_on_load_handlers(Mods), + run_on_load_handlers(Mods, Debug0), exit(on_load_done) end. -run_on_load_handlers([M|Ms]) -> +run_on_load_handlers([M|Ms], Debug) -> + debug(Debug, {running_on_load_handler,M}), Fun = fun() -> Res = erlang:call_on_load_function(M), exit(Res) @@ -1363,9 +1371,12 @@ run_on_load_handlers([M|Ms]) -> erlang:finish_after_on_load(M, Keep), case Keep of false -> - exit({on_load_function_failed,M}); + Error = {on_load_function_failed,M}, + debug(Debug, Error), + exit(Error); true -> - run_on_load_handlers(Ms) + debug(Debug, {on_load_handler_returned_ok,M}), + run_on_load_handlers(Ms, Debug) end end; -run_on_load_handlers([]) -> ok. +run_on_load_handlers([], _) -> ok. diff --git a/erts/preloaded/src/prim_file.erl b/erts/preloaded/src/prim_file.erl index 7f24889bb2..10be852e92 100644 --- a/erts/preloaded/src/prim_file.erl +++ b/erts/preloaded/src/prim_file.erl @@ -109,6 +109,8 @@ -define(FILE_RESP_LDATA, 6). -define(FILE_RESP_N2DATA, 7). -define(FILE_RESP_EOF, 8). +-define(FILE_RESP_FNAME, 9). +-define(FILE_RESP_ALL_DATA, 10). %% Open modes for the driver's open function. -define(EFILE_MODE_READ, 1). @@ -153,7 +155,7 @@ %% Opens a file using the driver port Port. Returns {error, Reason} %% | {ok, FileDescriptor} open(Port, File, ModeList) when is_port(Port), - is_list(File), + (is_list(File) orelse is_binary(File)), is_list(ModeList) -> case open_mode(ModeList) of {Mode, _Portopts, _Setopts} -> @@ -165,10 +167,11 @@ open(_,_,_) -> {error, badarg}. %% Opens a file. Returns {error, Reason} | {ok, FileDescriptor}. -open(File, ModeList) when is_list(File), is_list(ModeList) -> +open(File, ModeList) when (is_list(File) orelse is_binary(File)), + is_list(ModeList) -> case open_mode(ModeList) of {Mode, Portopts, Setopts} -> - open_int({?FD_DRV, Portopts}, File, Mode, Setopts); + open_int({?FD_DRV, Portopts},File, Mode, Setopts); Reason -> {error, Reason} end; @@ -196,7 +199,7 @@ open_int({Driver, Portopts}, File, Mode, Setopts) -> end; open_int(Port, File, Mode, Setopts) -> M = Mode band ?EFILE_MODE_MASK, - case drv_command(Port, [<<?FILE_OPEN, M:32>>, File, 0]) of + case drv_command(Port, [<<?FILE_OPEN, M:32>>, pathname(File)]) of {ok, Number} -> open_int_setopts(Port, Number, Setopts); Error -> @@ -489,7 +492,7 @@ ipread_s32bu_p32bu(#file_descriptor{module = ?MODULE, data = {_, _}}, %% Returns {ok, Contents} | {error, Reason} -read_file(File) -> +read_file(File) when (is_list(File) orelse is_binary(File)) -> case drv_open(?FD_DRV, [binary]) of {ok, Port} -> Result = read_file(Port, File), @@ -497,11 +500,14 @@ read_file(File) -> Result; {error, _} = Error -> Error - end. + end; +read_file(_) -> + {error, badarg}. %% Takes a Port opened with open/1. -read_file(Port, File) when is_port(Port) -> - Cmd = [?FILE_READ_FILE | File], +read_file(Port, File) when is_port(Port), + (is_list(File) orelse is_binary(File))-> + Cmd = [?FILE_READ_FILE | pathname(File)], case drv_command(Port, Cmd) of {error, enomem} -> %% It could possibly help to do a @@ -512,12 +518,14 @@ read_file(Port, File) when is_port(Port) -> drv_command(Port, Cmd); Result -> Result - end. + end; +read_file(_,_) -> + {error, badarg}. %% Returns {error, Reason} | ok. -write_file(File, Bin) -> +write_file(File, Bin) when (is_list(File) orelse is_binary(File)) -> case open(File, [binary, write]) of {ok, Handle} -> Result = write(Handle, Bin), @@ -525,8 +533,10 @@ write_file(File, Bin) -> Result; Error -> Error - end. - + end; +write_file(_, _) -> + {error, badarg}. + %%%----------------------------------------------------------------- @@ -539,7 +549,7 @@ write_file(File, Bin) -> %% Returns {ok, Port}, the Port should be used as first argument in all %% the following functions. Returns {error, Reason} upon failure. start() -> - try erlang:open_port({spawn, atom_to_list(?DRV)}, []) of + try erlang:open_port({spawn, atom_to_list(?DRV)}, [binary]) of Port -> {ok, Port} catch @@ -596,7 +606,7 @@ get_cwd(_, _) -> {error, badarg}. get_cwd_int(Drive) -> - get_cwd_int({?DRV, []}, Drive). + get_cwd_int({?DRV, [binary]}, Drive). get_cwd_int(Port, Drive) -> drv_command(Port, <<?FILE_PWD, Drive>>). @@ -606,7 +616,7 @@ get_cwd_int(Port, Drive) -> %% set_cwd/{1,2} set_cwd(Dir) -> - set_cwd_int({?DRV, []}, Dir). + set_cwd_int({?DRV, [binary]}, Dir). set_cwd(Port, Dir) when is_port(Port) -> set_cwd_int(Port, Dir). @@ -632,89 +642,88 @@ set_cwd_int(Port, Dir0) -> end), %% Dir is now either a string or an EXIT tuple. %% An EXIT tuple will fail in the following catch. - drv_command(Port, [?FILE_CHDIR, Dir, 0]). + drv_command(Port, [?FILE_CHDIR, pathname(Dir)]). %% delete/{1,2} delete(File) -> - delete_int({?DRV, []}, File). + delete_int({?DRV, [binary]}, File). delete(Port, File) when is_port(Port) -> delete_int(Port, File). delete_int(Port, File) -> - drv_command(Port, [?FILE_DELETE, File, 0]). + drv_command(Port, [?FILE_DELETE, pathname(File)]). %% rename/{2,3} rename(From, To) -> - rename_int({?DRV, []}, From, To). + rename_int({?DRV, [binary]}, From, To). rename(Port, From, To) when is_port(Port) -> rename_int(Port, From, To). rename_int(Port, From, To) -> - drv_command(Port, [?FILE_RENAME, From, 0, To, 0]). + drv_command(Port, [?FILE_RENAME, pathname(From), pathname(To)]). %% make_dir/{1,2} make_dir(Dir) -> - make_dir_int({?DRV, []}, Dir). + make_dir_int({?DRV, [binary]}, Dir). make_dir(Port, Dir) when is_port(Port) -> make_dir_int(Port, Dir). make_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_MKDIR, Dir, 0]). + drv_command(Port, [?FILE_MKDIR, pathname(Dir)]). %% del_dir/{1,2} del_dir(Dir) -> - del_dir_int({?DRV, []}, Dir). + del_dir_int({?DRV, [binary]}, Dir). del_dir(Port, Dir) when is_port(Port) -> del_dir_int(Port, Dir). del_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_RMDIR, Dir, 0]). + drv_command(Port, [?FILE_RMDIR, pathname(Dir)]). %% read_file_info/{1,2} read_file_info(File) -> - read_file_info_int({?DRV, []}, File). + read_file_info_int({?DRV, [binary]}, File). read_file_info(Port, File) when is_port(Port) -> read_file_info_int(Port, File). read_file_info_int(Port, File) -> - drv_command(Port, [?FILE_FSTAT, File, 0]). + drv_command(Port, [?FILE_FSTAT, pathname(File)]). %% altname/{1,2} altname(File) -> - altname_int({?DRV, []}, File). + altname_int({?DRV, [binary]}, File). altname(Port, File) when is_port(Port) -> altname_int(Port, File). altname_int(Port, File) -> - drv_command(Port, [?FILE_ALTNAME, File, 0]). - + drv_command(Port, [?FILE_ALTNAME, pathname(File)]). %% write_file_info/{2,3} write_file_info(File, Info) -> - write_file_info_int({?DRV, []}, File, Info). + write_file_info_int({?DRV, [binary]}, File, Info). write_file_info(Port, File, Info) when is_port(Port) -> write_file_info_int(Port, File, Info). @@ -740,72 +749,72 @@ write_file_info_int(Port, date_to_bytes(Atime), date_to_bytes(Mtime), date_to_bytes(Ctime), - File, 0]). + pathname(File)]). %% make_link/{2,3} make_link(Old, New) -> - make_link_int({?DRV, []}, Old, New). + make_link_int({?DRV, [binary]}, Old, New). make_link(Port, Old, New) when is_port(Port) -> make_link_int(Port, Old, New). make_link_int(Port, Old, New) -> - drv_command(Port, [?FILE_LINK, Old, 0, New, 0]). + drv_command(Port, [?FILE_LINK, pathname(Old), pathname(New)]). %% make_symlink/{2,3} make_symlink(Old, New) -> - make_symlink_int({?DRV, []}, Old, New). + make_symlink_int({?DRV, [binary]}, Old, New). make_symlink(Port, Old, New) when is_port(Port) -> make_symlink_int(Port, Old, New). make_symlink_int(Port, Old, New) -> - drv_command(Port, [?FILE_SYMLINK, Old, 0, New, 0]). + drv_command(Port, [?FILE_SYMLINK, pathname(Old), pathname(New)]). %% read_link/{2,3} read_link(Link) -> - read_link_int({?DRV, []}, Link). + read_link_int({?DRV, [binary]}, Link). read_link(Port, Link) when is_port(Port) -> read_link_int(Port, Link). read_link_int(Port, Link) -> - drv_command(Port, [?FILE_READLINK, Link, 0]). + drv_command(Port, [?FILE_READLINK, pathname(Link)]). %% read_link_info/{2,3} read_link_info(Link) -> - read_link_info_int({?DRV, []}, Link). + read_link_info_int({?DRV, [binary]}, Link). read_link_info(Port, Link) when is_port(Port) -> read_link_info_int(Port, Link). read_link_info_int(Port, Link) -> - drv_command(Port, [?FILE_LSTAT, Link, 0]). + drv_command(Port, [?FILE_LSTAT, pathname(Link)]). %% list_dir/{1,2} list_dir(Dir) -> - list_dir_int({?DRV, []}, Dir). + list_dir_int({?DRV, [binary]}, Dir). list_dir(Port, Dir) when is_port(Port) -> list_dir_int(Port, Dir). list_dir_int(Port, Dir) -> - drv_command(Port, [?FILE_READDIR, Dir, 0], []). + drv_command(Port, [?FILE_READDIR, pathname(Dir)], []). @@ -1026,8 +1035,6 @@ lseek_position(_) -> translate_response(?FILE_RESP_OK, []) -> ok; -translate_response(?FILE_RESP_OK, Data) -> - {ok, Data}; translate_response(?FILE_RESP_ERROR, List) when is_list(List) -> {error, list_to_atom(List)}; translate_response(?FILE_RESP_NUMBER, List) -> @@ -1074,6 +1081,16 @@ translate_response(?FILE_RESP_N2DATA = X, L0) when is_list(L0) -> end; translate_response(?FILE_RESP_EOF, []) -> eof; +translate_response(?FILE_RESP_FNAME, []) -> + ok; +translate_response(?FILE_RESP_FNAME, Data) when is_binary(Data) -> + {ok, prim_file:internal_native2name(Data)}; +translate_response(?FILE_RESP_FNAME, Data) -> + {ok, Data}; + +translate_response(?FILE_RESP_ALL_DATA, Data) -> + {ok, Data}; + translate_response(X, Data) -> {error, {bad_response_from_port, [X | Data]}}. @@ -1209,3 +1226,9 @@ lists_split([Hd | Tl], N, Rev) -> reverse(X) -> lists:reverse(X, []). reverse(L, T) -> lists:reverse(L, T). + +% Will add zero termination too +% The 'EXIT' tuple from a bad argument will eventually generate an error +% in list_to_binary, which is caught and generates the {error,badarg} return +pathname(File) -> + (catch prim_file:internal_name2native(File)). diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 91d39c6a73..446656e45f 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -37,7 +37,7 @@ -export([setopt/3, setopts/2, getopt/2, getopts/2, is_sockopt_val/2]). -export([chgopt/3, chgopts/2]). -export([getstat/2, getfd/1, getindex/1, getstatus/1, gettype/1, - getiflist/1, ifget/3, ifset/3, + getifaddrs/1, getiflist/1, ifget/3, ifset/3, gethostname/1]). -export([getservbyname/3, getservbyport/3]). -export([peername/1, setpeername/2]). @@ -216,9 +216,10 @@ bindx(S, AddFlag, Addrs) -> sctp -> %% Really multi-homed "bindx". Stringified args: %% [AddFlag, (Port, IP)+]: - Args = ?int8(AddFlag) ++ - lists:concat([?int16(Port)++ip_to_bytes(IP) || - {IP, Port} <- Addrs]), + Args = + [?int8(AddFlag)| + [[?int16(Port)|ip_to_bytes(IP)] || + {IP, Port} <- Addrs]], case ctl_cmd(S, ?SCTP_REQ_BINDX, Args) of {ok,_} -> {ok, S}; Error -> Error @@ -623,7 +624,7 @@ chgopt(S, Opt, Value) when is_port(S) -> chgopts(S, [{Opt,Value}]). chgopts(S, Opts) when is_port(S), is_list(Opts) -> - case inet:getopts(S, need_template(Opts)) of + case getopts(S, need_template(Opts)) of {ok,Templates} -> try merge_options(Opts, Templates) of NewOpts -> @@ -636,7 +637,94 @@ chgopts(S, Opts) when is_port(S), is_list(Opts) -> %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% -%% IFLIST(insock()) -> {ok,IfNameList} | {error, Reason} +%% getifaddrs(insock()) -> {ok,IfAddrsList} | {error, Reason} +%% +%% IfAddrsList = [{Name,[Opts]}] +%% Name = string() +%% Opts = {flags,[Flag]} | {addr,Addr} | {netmask,Addr} | {broadaddr,Addr} +%% | {dstaddr,Addr} | {hwaddr,HwAddr} | {mtu,integer()} +%% Flag = up | broadcast | loopback | running | multicast +%% Addr = ipv4addr() | ipv6addr() +%% HwAddr = ethernet_addr() +%% +%% get interface name and addresses list +%% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +getifaddrs(S) when is_port(S) -> + case ctl_cmd(S, ?INET_REQ_GETIFADDRS, []) of + {ok, Data} -> + {ok, comp_ifaddrs(build_ifaddrs(Data), ktree_empty())}; + {error,enotsup} -> + case getiflist(S) of + {ok, IFs} -> + {ok, getifaddrs_ifget(S, IFs)}; + Err1 -> Err1 + end; + Err2 -> Err2 + end. + +%% Restructure interface properties per interface and remove duplicates + +comp_ifaddrs([{If,Opts}|IfOpts], T) -> + case ktree_is_defined(If, T) of + true -> + OptSet = comp_ifaddrs_add(ktree_get(If, T), Opts), + comp_ifaddrs(IfOpts, ktree_update(If, OptSet, T)); + false -> + OptSet = comp_ifaddrs_add(ktree_empty(), Opts), + comp_ifaddrs(IfOpts, ktree_insert(If, OptSet, T)) + end; +comp_ifaddrs([], T) -> + [{If,ktree_keys(ktree_get(If, T))} || If <- ktree_keys(T)]. + +comp_ifaddrs_add(OptSet, [Opt|Opts]) -> + case ktree_is_defined(Opt, OptSet) of + true + when element(1, Opt) =:= flags; + element(1, Opt) =:= hwaddr -> + comp_ifaddrs_add(OptSet, Opts); + _ -> + comp_ifaddrs_add(ktree_insert(Opt, undefined, OptSet), Opts) + end; +comp_ifaddrs_add(OptSet, []) -> OptSet. + +%% Legacy emulation of getifaddrs + +getifaddrs_ifget(_, []) -> []; +getifaddrs_ifget(S, [IF|IFs]) -> + case ifget(S, IF, [flags]) of + {ok,[{flags,Flags}]=FlagsVals} -> + BroadOpts = + case member(broadcast, Flags) of + true -> + [broadaddr,hwaddr]; + false -> + [hwaddr] + end, + P2POpts = + case member(pointtopoint, Flags) of + true -> + [dstaddr|BroadOpts]; + false -> + BroadOpts + end, + getifaddrs_ifget(S, IFs, IF, FlagsVals, [addr,netmask|P2POpts]); + _ -> + getifaddrs_ifget(S, IFs, IF, [], [addr,netmask,hwaddr]) + end. + +getifaddrs_ifget(S, IFs, IF, FlagsVals, Opts) -> + OptVals = + case ifget(S, IF, Opts) of + {ok,OVs} -> OVs; + _ -> [] + end, + [{IF,FlagsVals++OptVals}|getifaddrs_ifget(S, IFs)]. + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%% +%% getiflist(insock()) -> {ok,IfNameList} | {error, Reason} %% %% get interface name list %% @@ -1325,6 +1413,19 @@ type_value_2({enum,List}, Enum) -> {value,_} -> true; false -> false end; +type_value_2(sockaddr, Addr) -> + case Addr of + any -> true; + loopback -> true; + {A,B,C,D} when ?ip(A,B,C,D) -> true; + {A,B,C,D,E,F,G,H} when ?ip6(A,B,C,D,E,F,G,H) -> true; + _ -> false + end; +type_value_2(linkaddr, Addr) when is_list(Addr) -> + case len(Addr, 32768) of + undefined -> false; + _ -> true + end; type_value_2({bitenumlist,List}, EnumList) -> case enum_vals(EnumList, List) of Ls when is_list(Ls) -> true; @@ -1413,14 +1514,21 @@ enc_value_2(addr, {any,Port}) -> [?INET_AF_ANY|?int16(Port)]; enc_value_2(addr, {loopback,Port}) -> [?INET_AF_LOOPBACK|?int16(Port)]; -enc_value_2(addr, {IP,Port}) -> - case tuple_size(IP) of - 4 -> - [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; - 8 -> - [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)] - end; +enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 4 -> + [?INET_AF_INET,?int16(Port)|ip4_to_bytes(IP)]; +enc_value_2(addr, {IP,Port}) when tuple_size(IP) =:= 8 -> + [?INET_AF_INET6,?int16(Port)|ip6_to_bytes(IP)]; enc_value_2(ether, [X1,X2,X3,X4,X5,X6]) -> [X1,X2,X3,X4,X5,X6]; +enc_value_2(sockaddr, any) -> + [?INET_AF_ANY]; +enc_value_2(sockaddr, loopback) -> + [?INET_AF_LOOPBACK]; +enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 4 -> + [?INET_AF_INET|ip4_to_bytes(IP)]; +enc_value_2(sockaddr, IP) when tuple_size(IP) =:= 8 -> + [?INET_AF_INET6|ip6_to_bytes(IP)]; +enc_value_2(linkaddr, Linkaddr) -> + [?int16(length(Linkaddr)),Linkaddr]; enc_value_2(sctp_assoc_id, Val) -> ?int32(Val); %% enc_value_2(sctp_assoc_id, Bin) -> [byte_size(Bin),Bin]; enc_value_2({enum,List}, Enum) -> @@ -1465,6 +1573,10 @@ dec_value(time, [X3,X2,X1,X0|T]) -> end; dec_value(ip, [A,B,C,D|T]) -> {{A,B,C,D}, T}; dec_value(ether,[X1,X2,X3,X4,X5,X6|T]) -> {[X1,X2,X3,X4,X5,X6],T}; +dec_value(sockaddr, [X|T]) -> + get_ip(X, T); +dec_value(linkaddr, [X1,X0|T]) -> + split(?i16(X1,X0), T); dec_value({enum,List}, [X3,X2,X1,X0|T]) -> Val = ?i32(X3,X2,X1,X0), case enum_name(Val, List) of @@ -1480,7 +1592,7 @@ dec_value({bitenumlist,List}, [X3,X2,X1,X0|T]) -> %% {enum_names(Val, List), T}; dec_value(binary,[L0,L1,L2,L3|List]) -> Len = ?i32(L0,L1,L2,L3), - {X,T}=lists:split(Len,List), + {X,T}=split(Len,List), {list_to_binary(X),T}; dec_value(Types, List) when is_tuple(Types) -> {L,T} = dec_value_tuple(Types, List, 1, []), @@ -1495,7 +1607,7 @@ dec_value_tuple(Types, List, N, Acc) {Term,Tail} = dec_value(element(N, Types), List), dec_value_tuple(Types, Tail, N+1, [Term|Acc]); dec_value_tuple(_, List, _, Acc) -> - {lists:reverse(Acc),List}. + {rev(Acc),List}. borlist([V|Vs], Value) -> borlist(Vs, V bor Value); @@ -1702,11 +1814,11 @@ merge_fields(_, _, _) -> []. %% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -type_ifopt(addr) -> ip; -type_ifopt(broadaddr) -> ip; -type_ifopt(dstaddr) -> ip; +type_ifopt(addr) -> sockaddr; +type_ifopt(broadaddr) -> sockaddr; +type_ifopt(dstaddr) -> sockaddr; type_ifopt(mtu) -> int; -type_ifopt(netmask) -> ip; +type_ifopt(netmask) -> sockaddr; type_ifopt(flags) -> {bitenumlist, [{up, ?INET_IFF_UP}, @@ -1718,7 +1830,7 @@ type_ifopt(flags) -> {no_pointtopoint, ?INET_IFF_NPOINTTOPOINT}, {running, ?INET_IFF_RUNNING}, {multicast, ?INET_IFF_MULTICAST}]}; -type_ifopt(hwaddr) -> ether; +type_ifopt(hwaddr) -> linkaddr; type_ifopt(Opt) when is_atom(Opt) -> undefined. enc_ifopt(addr) -> ?INET_IFOPT_ADDR; @@ -1903,6 +2015,30 @@ encode_ifname(Name) -> if N > 255 -> {error, einval}; true -> {ok,[N | Name]} end. + +build_ifaddrs(Cs) -> + build_ifaddrs(Cs, []). +%% +build_ifaddrs([], []) -> + []; +build_ifaddrs([0|Cs], Acc) -> + Name = utf8_to_characters(rev(Acc)), + {Opts,Rest} = build_ifaddrs_opts(Cs, []), + [{Name,Opts}|build_ifaddrs(Rest)]; +build_ifaddrs([C|Cs], Acc) -> + build_ifaddrs(Cs, [C|Acc]). + +build_ifaddrs_opts([0|Cs], Acc) -> + {rev(Acc),Cs}; +build_ifaddrs_opts([C|Cs]=CCs, Acc) -> + case dec_ifopt(C) of + undefined -> + erlang:error(badarg, [CCs,Acc]); + Opt -> + Type = type_ifopt(Opt), + {Val,Rest} = dec_value(Type, Cs), + build_ifaddrs_opts(Rest, [{Opt,Val}|Acc]) + end. build_iflist(Cs) -> build_iflist(Cs, [], []). @@ -1927,6 +2063,80 @@ rev(L) -> rev(L,[]). rev([C|L],Acc) -> rev(L,[C|Acc]); rev([],Acc) -> Acc. +split(N, L) -> split(N, L, []). +split(0, L, R) when is_list(L) -> {rev(R),L}; +split(N, [H|T], R) when is_integer(N), N > 0 -> split(N-1, T, [H|R]). + +len(L, N) -> len(L, N, 0). +len([], N, C) when is_integer(N), N >= 0 -> C; +len(L, 0, _) when is_list(L) -> undefined; +len([_|L], N, C) when is_integer(N), N >= 0 -> len(L, N-1, C+1). + +member(X, [X|_]) -> true; +member(X, [_|Xs]) -> member(X, Xs); +member(_, []) -> false. + + + +%% Lookup tree that keeps key insert order + +ktree_empty() -> {[],tree()}. +ktree_is_defined(Key, {_,T}) -> tree(T, Key, is_defined). +ktree_get(Key, {_,T}) -> tree(T, Key, get). +ktree_insert(Key, V, {Keys,T}) -> {[Key|Keys],tree(T, Key, {insert,V})}. +ktree_update(Key, V, {Keys,T}) -> {Keys,tree(T, Key, {update,V})}. +ktree_keys({Keys,_}) -> rev(Keys). + +%% Simple lookup tree. Hash the key to get statistical balance. +%% Key is matched equal, not compared equal. + +tree() -> nil. +tree(T, Key, Op) -> tree(T, Key, Op, erlang:phash2(Key)). + +tree(nil, _, is_defined, _) -> false; +tree(nil, K, {insert,V}, _) -> {K,V,nil,nil}; +tree({K,_,_,_}, K, is_defined, _) -> true; +tree({K,V,_,_}, K, get, _) -> V; +tree({K,_,L,R}, K, {update,V}, _) -> {K,V,L,R}; +tree({K0,V0,L,R}, K, Op, H) -> + H0 = erlang:phash2(K0), + if H0 < H; H0 =:= H, K0 < K -> + if is_tuple(Op) -> + {K0,V0,tree(L, K, Op, H),R}; + true -> + tree(L, K, Op, H) + end; + true -> + if is_tuple(Op) -> + {K0,V0,L,tree(R, K, Op, H)}; + true -> + tree(R, K, Op, H) + end + end. + + + +utf8_to_characters([]) -> []; +utf8_to_characters([B|Bs]=Arg) when (B band 16#FF) =:= B -> + if 16#F8 =< B -> + erlang:error(badarg, [Arg]); + 16#F0 =< B -> + utf8_to_characters(Bs, B band 16#07, 3); + 16#E0 =< B -> + utf8_to_characters(Bs, B band 16#0F, 2); + 16#C0 =< B -> + utf8_to_characters(Bs, B band 16#1F, 1); + 16#80 =< B -> + erlang:error(badarg, [Arg]); + true -> + [B|utf8_to_characters(Bs)] + end. +%% +utf8_to_characters(Bs, U, 0) -> + [U|utf8_to_characters(Bs)]; +utf8_to_characters([B|Bs], U, N) when ((B band 16#3F) bor 16#80) =:= B -> + utf8_to_characters(Bs, (U bsl 6) bor (B band 16#3F), N-1). + ip_to_bytes(IP) when tuple_size(IP) =:= 4 -> ip4_to_bytes(IP); ip_to_bytes(IP) when tuple_size(IP) =:= 8 -> ip6_to_bytes(IP). |