From 84adefa331c4159d432d22840663c38f155cd4c1 Mon Sep 17 00:00:00 2001 From: Erlang/OTP Date: Fri, 20 Nov 2009 14:54:40 +0000 Subject: The R13B03 release. --- lib/inets/src/inets_app/Makefile | 121 +++++ lib/inets/src/inets_app/inets.app.src | 110 +++++ lib/inets/src/inets_app/inets.appup.src | 50 ++ lib/inets/src/inets_app/inets.config | 2 + lib/inets/src/inets_app/inets.erl | 740 +++++++++++++++++++++++++++++ lib/inets/src/inets_app/inets_app.erl | 30 ++ lib/inets/src/inets_app/inets_internal.hrl | 49 ++ lib/inets/src/inets_app/inets_regexp.erl | 413 ++++++++++++++++ lib/inets/src/inets_app/inets_service.erl | 65 +++ lib/inets/src/inets_app/inets_sup.erl | 117 +++++ 10 files changed, 1697 insertions(+) create mode 100644 lib/inets/src/inets_app/Makefile create mode 100644 lib/inets/src/inets_app/inets.app.src create mode 100644 lib/inets/src/inets_app/inets.appup.src create mode 100644 lib/inets/src/inets_app/inets.config create mode 100644 lib/inets/src/inets_app/inets.erl create mode 100644 lib/inets/src/inets_app/inets_app.erl create mode 100644 lib/inets/src/inets_app/inets_internal.hrl create mode 100644 lib/inets/src/inets_app/inets_regexp.erl create mode 100644 lib/inets/src/inets_app/inets_service.erl create mode 100644 lib/inets/src/inets_app/inets_sup.erl (limited to 'lib/inets/src/inets_app') diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile new file mode 100644 index 0000000000..2dab99386a --- /dev/null +++ b/lib/inets/src/inets_app/Makefile @@ -0,0 +1,121 @@ +# +# %CopyrightBegin% +# +# Copyright Ericsson AB 2005-2009. All Rights Reserved. +# +# The contents of this file are subject to the Erlang Public License, +# Version 1.1, (the "License"); you may not use this file except in +# compliance with the License. You should have received a copy of the +# Erlang Public License along with this software. If not, it can be +# retrieved online at http://www.erlang.org/. +# +# Software distributed under the License is distributed on an "AS IS" +# basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +# the License for the specific language governing rights and limitations +# under the License. +# +# %CopyrightEnd% +# +# + +include $(ERL_TOP)/make/target.mk +EBIN = ../../ebin +include $(ERL_TOP)/make/$(TARGET)/otp.mk + +# ---------------------------------------------------- +# Application version +# ---------------------------------------------------- +include ../../vsn.mk + +VSN = $(INETS_VSN) + +# ---------------------------------------------------- +# Release directory specification +# ---------------------------------------------------- +RELSYSDIR = $(RELEASE_PATH)/lib/inets-$(VSN) + + +# ---------------------------------------------------- +# Target Specs +# ---------------------------------------------------- +MODULES = \ + inets_service \ + inets \ + inets_app \ + inets_sup \ + inets_regexp + +HRL_FILES = inets_internal.hrl + +ERL_FILES = $(MODULES:%=%.erl) + +TARGET_FILES= $(MODULES:%=$(EBIN)/%.$(EMULATOR)) \ + $(APP_TARGET) \ + $(APPUP_TARGET) + +APP_FILE = inets.app +APPUP_FILE = inets.appup + +APP_SRC = $(APP_FILE).src +APP_TARGET = $(EBIN)/$(APP_FILE) + +APPUP_SRC = $(APPUP_FILE).src +APPUP_TARGET = $(EBIN)/$(APPUP_FILE) + + +# ---------------------------------------------------- +# INETS FLAGS +# ---------------------------------------------------- +INETS_FLAGS = -D'SERVER_SOFTWARE="inets/$(VSN)"' \ + + +# ---------------------------------------------------- +# FLAGS +# ---------------------------------------------------- + +ERL_COMPILE_FLAGS += $(INETS_FLAGS) \ + +'{parse_transform,sys_pre_attributes}' \ + +'{attribute,insert,app_vsn,$(APP_VSN)}' + + +# ---------------------------------------------------- +# Targets +# ---------------------------------------------------- + +debug opt: $(TARGET_FILES) + +clean: + rm -f $(TARGET_FILES) + rm -f core + +docs: + + +# ---------------------------------------------------- +# Special Build Targets +# ---------------------------------------------------- + +$(APP_TARGET): $(APP_SRC) ../../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + +$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk + sed -e 's;%VSN%;$(VSN);' $< > $@ + + +# ---------------------------------------------------- +# Release Target +# ---------------------------------------------------- +include $(ERL_TOP)/make/otp_release_targets.mk + +release_spec: opt + $(INSTALL_DIR) $(RELSYSDIR)/src + $(INSTALL_DATA) $(HRL_FILES) $(ERL_FILES) $(RELSYSDIR)/src + $(INSTALL_DIR) $(RELSYSDIR)/ebin + $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin + +release_docs_spec: + +info: + @echo "INETS_DEBUG = $(INETS_DEBUG)" + @echo "INETS_FLAGS = $(INETS_FLAGS)" + @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)" diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src new file mode 100644 index 0000000000..6524c3b19b --- /dev/null +++ b/lib/inets/src/inets_app/inets.app.src @@ -0,0 +1,110 @@ +%% This is an -*- erlang -*- file. +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +{application,inets, + [{description,"INETS CXC 138 49"}, + {vsn,"%VSN%"}, + {modules,[ + inets, + inets_sup, + inets_app, + inets_service, + inets_regexp, + + %% FTP + ftp, + ftp_progress, + ftp_response, + ftp_sup, + + %% HTTP client: + http, + httpc_handler, + httpc_handler_sup, + httpc_manager, + httpc_profile_sup, + httpc_request, + httpc_response, + httpc_sup, + http_cookie, + + http_uri, %% Proably will by used by server also in the future + + %% HTTP used by both client and server + http_chunk, + http_request, + http_response, + http_transport, + http_util, + + %% HTTP server: + httpd, + httpd_acceptor, + httpd_acceptor_sup, + httpd_cgi, + httpd_conf, + httpd_esi, + httpd_example, + httpd_file, + httpd_instance_sup, + httpd_log, + httpd_manager, + httpd_misc_sup, + httpd_request, + httpd_request_handler, + httpd_response, + httpd_script_env, + httpd_socket, + httpd_sup, + httpd_util, + mod_actions, + mod_alias, + mod_auth, + mod_auth_dets, + mod_auth_mnesia, + mod_auth_plain, + mod_auth_server, + mod_browser, + mod_cgi, + mod_dir, + mod_disk_log, + mod_esi, + mod_get, + mod_head, + mod_htaccess, + mod_include, + mod_log, + mod_range, + mod_responsecontrol, + mod_security, + mod_security_server, + mod_trace, + + %% TFTP + tftp, + tftp_binary, + tftp_engine, + tftp_file, + tftp_lib, + tftp_logger, + tftp_sup + ]}, + {registered,[inets_sup, httpc_manager]}, + {applications,[kernel,stdlib]}, + {mod,{inets_app,[]}}]}. diff --git a/lib/inets/src/inets_app/inets.appup.src b/lib/inets/src/inets_app/inets.appup.src new file mode 100644 index 0000000000..59ee1ba03d --- /dev/null +++ b/lib/inets/src/inets_app/inets.appup.src @@ -0,0 +1,50 @@ +%% This is an -*- erlang -*- file. +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1999-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% + +{"%VSN%", + [ + {"5.1.3", + [ + {load_module, httpd_response, soft_purge, soft_purge, []}, + {update, ftp, {advanced, upgrade_from_pre_5_12}, + soft_purge, soft_purge, []}, + {update, httpc_handler, soft, soft_purge, soft_purge, []} + ] + }, + {"5.1.2", + [ + {restart_application, inets} + ] + } + ], + [ + {"5.1.3", + [ + {load_module, httpd_response, soft_purge, soft_purge, []}, + {update, ftp, {advanced, downgrade_to_pre_5_12}, + soft_purge, soft_purge, []}, + {update, httpc_handler, soft, soft_purge, soft_purge, []} + ] + }, + {"5.1.2", + [ + {restart_application, inets} + ] + } + ] +}. diff --git a/lib/inets/src/inets_app/inets.config b/lib/inets/src/inets_app/inets.config new file mode 100644 index 0000000000..adf0e3ecf1 --- /dev/null +++ b/lib/inets/src/inets_app/inets.config @@ -0,0 +1,2 @@ +[{inets,[{services,[{httpd,"/var/tmp/server_root/conf/8888.conf"}, + {httpd,"/var/tmp/server_root/conf/8080.conf"}]}]}]. diff --git a/lib/inets/src/inets_app/inets.erl b/lib/inets/src/inets_app/inets.erl new file mode 100644 index 0000000000..7977a3dc2a --- /dev/null +++ b/lib/inets/src/inets_app/inets.erl @@ -0,0 +1,740 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2006-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: The main interface module of the inets application +%%---------------------------------------------------------------------- + +-module(inets). + +%% API +-export([start/0, start/1, start/2, start/3, + stop/0, stop/2, + services/0, services_info/0, + service_names/0]). +-export([enable_trace/2, enable_trace/3, disable_trace/0, set_trace/1, + report_event/4]). +-export([versions/0, + print_version_info/0, print_version_info/1]). + + +%%==================================================================== +%% API +%%==================================================================== + +%%-------------------------------------------------------------------- +%% Function: start([, Type]) -> ok +%% +%% Type = permanent | transient | temporary +%% +%% Description: Starts the inets application. Default type +%% is temporary. see application(3) +%%-------------------------------------------------------------------- +start() -> + application:start(inets). + +start(Type) -> + application:start(inets, Type). + + +%%-------------------------------------------------------------------- +%% Function: start(Service, ServiceConfig [, How]) -> {ok, Pid} | +%% {error, Reason} +%% +%% Service = - ftpc | tftpd | httpc | httpd +%% ServiceConfig = ConfPropList | ConfFile +%% ConfPropList = [{Property, Value}] according to service +%% ConfFile = Path - when service is httpd +%% How = inets | stand_alone +%% +%% Description: Dynamically starts an inets service after the inets +%% application has been started. +%% +%% Note: Dynamically started services will not be handled by +%% application takeover and failover behavior when inets is run as a +%% distributed application. Nor will they be automaticly restarted +%% when the inets application is restarted, but as long as the inets +%% application is up and running they will be supervised and may be +%% soft code upgraded. Services started with the option stand alone, +%% e.i. the service is not started as part of the inets application, +%% will lose all OTP application benefits such as soft upgrade. The +%% stand alone service will be linked to the process that started it. +%% In most cases some of the supervison functionallity will still be +%% in place and in some sense the calling process has now become the +%% top supervisor. +%% -------------------------------------------------------------------- +start(Service, ServiceConfig) -> + Module = service_module(Service), + start_service(Module, ServiceConfig, inets). + +start(Service, ServiceConfig, How) -> + Module = service_module(Service), + start_service(Module, ServiceConfig, How). + +%%-------------------------------------------------------------------- +%% Function: stop() -> ok +%% +%% Description: Stops the inets application. +%%-------------------------------------------------------------------- +stop() -> + application:stop(inets). + + +%%-------------------------------------------------------------------- +%% Function: stop(Service, Pid) -> ok +%% +%% Service - ftp | tftpd | http | httpd | stand_alone +%% +%% Description: Stops a started service of the inets application or takes +%% down a stand alone "service" gracefully. +%%-------------------------------------------------------------------- +stop(stand_alone, Pid) -> + true = exit(Pid, shutdown), + ok; + +stop(Service, Pid) -> + Module = service_module(Service), + call_service(Module, stop_service, Pid). + + +%%-------------------------------------------------------------------- +%% Function: services() -> [{Service, Pid}] +%% +%% Description: Returns a list of currently running services. +%% Note: Services started with the stand alone option will not be listed +%%-------------------------------------------------------------------- +services() -> + Modules = [service_module(Service) || Service <- + service_names()], + try lists:flatten(lists:map(fun(Module) -> + Module:services() + end, Modules)) of + Result -> + Result + catch + exit:{noproc, _} -> + {error, inets_not_started} + end. + + +%%-------------------------------------------------------------------- +%% Function: services_info() -> [{Service, Pid, Info}] +%% +%% Description: Returns a list of currently running services where +%% each service is described by a [{Property, Value}] list. +%%-------------------------------------------------------------------- +services_info() -> + case services() of + {error, inets_not_started} -> + {error, inets_not_started}; + Services -> + Fun = fun({Service, Pid}) -> + Module = service_module(Service), + Info = + case Module:service_info(Pid) of + {ok, PropList} -> + PropList; + {error, Reason} -> + Reason + end, + {Service, Pid, Info} + end, + lists:flatten(lists:map(Fun, Services)) + end. + + + +%%-------------------------------------------------------------------- +%% Function: print_version_info() +%% +%% Description: Simple utility function to print information +%% about versions (system, OS and modules). +%%-------------------------------------------------------------------- + +print_version_info() -> + {ok, Versions} = inets:versions(), + print_version_info(Versions). + +print_version_info(Versions) when is_list(Versions) -> + print_sys_info(Versions), + print_os_info(Versions), + print_mods_info(Versions). + +print_sys_info(Versions) -> + case key1search(sys_info, Versions) of + {value, SysInfo} when is_list(SysInfo) -> + {value, Arch} = key1search(arch, SysInfo, "Not found"), + {value, Ver} = key1search(ver, SysInfo, "Not found"), + io:format("System info: " + "~n Arch: ~s" + "~n Ver: ~s" + "~n", [Arch, Ver]), + ok; + _ -> + io:format("System info: Not found~n", []), + not_found + end. + +print_os_info(Versions) -> + case key1search(os_info, Versions) of + {value, OsInfo} when is_list(OsInfo) -> + Fam = + case key1search(fam, OsInfo, "Not found") of + {value, F} when is_atom(F) -> + atom_to_list(F); + {value, LF} when is_list(LF) -> + LF; + {value, XF} -> + lists:flatten(io_lib:format("~p", [XF])) + end, + Name = + case key1search(name, OsInfo) of + {value, N} when is_atom(N) -> + "[" ++ atom_to_list(N) ++ "]"; + {value, LN} when is_list(LN) -> + "[" ++ LN ++ "]"; + not_found -> + "" + end, + Ver = + case key1search(ver, OsInfo, "Not found") of + {value, T} when is_tuple(T) -> + tversion(T); + {value, LV} when is_list(LV) -> + LV; + {value, XV} -> + lists:flatten(io_lib:format("~p", [XV])) + end, + io:format("OS info: " + "~n Family: ~s ~s" + "~n Ver: ~s" + "~n", [Fam, Name, Ver]), + ok; + _ -> + io:format("OS info: Not found~n", []), + not_found + end. + +versions() -> + App = inets, + LibDir = code:lib_dir(App), + File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]), + case file:consult(File) of + {ok, [{application, App, AppFile}]} -> + case lists:keysearch(modules, 1, AppFile) of + {value, {modules, Mods}} -> + {ok, version_info(Mods)}; + _ -> + {error, {invalid_format, modules}} + end; + Error -> + {error, {invalid_format, Error}} + end. + +version_info(Mods) -> + SysInfo = sys_info(), + OsInfo = os_info(), + ModInfo = [mod_version_info(Mod) || Mod <- Mods], + [{sys_info, SysInfo}, {os_info, OsInfo}, {mod_info, ModInfo}]. + +mod_version_info(Mod) -> + Info = Mod:module_info(), + {value, {attributes, Attr}} = lists:keysearch(attributes, 1, Info), + {value, {vsn, [Vsn]}} = lists:keysearch(vsn, 1, Attr), + {value, {app_vsn, AppVsn}} = lists:keysearch(app_vsn, 1, Attr), + {value, {compile, Comp}} = lists:keysearch(compile, 1, Info), + {value, {version, Ver}} = lists:keysearch(version, 1, Comp), + {value, {time, Time}} = lists:keysearch(time, 1, Comp), + {Mod, [{vsn, Vsn}, + {app_vsn, AppVsn}, + {compiler_version, Ver}, + {compile_time, Time}]}. + +sys_info() -> + SysArch = string:strip(erlang:system_info(system_architecture),right,$\n), + SysVer = string:strip(erlang:system_info(system_version),right,$\n), + [{arch, SysArch}, {ver, SysVer}]. + +os_info() -> + V = os:version(), + case os:type() of + {OsFam, OsName} -> + [{fam, OsFam}, {name, OsName}, {ver, V}]; + OsFam -> + [{fam, OsFam}, {ver, V}] + end. + + +print_mods_info(Versions) -> + case key1search(mod_info, Versions) of + {value, ModsInfo} when is_list(ModsInfo) -> + io:format("Module info: ~n", []), + lists:foreach(fun print_mod_info/1, ModsInfo); + _ -> + io:format("Module info: Not found~n", []), + not_found + end. + +tversion(T) -> + L = tuple_to_list(T), + lversion(L). + +lversion([]) -> + ""; +lversion([A]) -> + integer_to_list(A); +lversion([A|R]) -> + integer_to_list(A) ++ "." ++ lversion(R). + +print_mod_info({Module, Info}) -> + % Maybe a asn1 generated module + Asn1Vsn = + case (catch Module:info()) of + AI when is_list(AI) -> + case (catch key1search(vsn, AI)) of + {value, V} when is_atom(V) -> + atom_to_list(V); + _ -> + "-" + end; + _ -> + "-" + end, + Vsn = + case key1search(vsn, Info) of + {value, I} when is_integer(I) -> + integer_to_list(I); + _ -> + "Not found" + end, + AppVsn = + case key1search(app_vsn, Info) of + {value, S1} when is_list(S1) -> + S1; + _ -> + "Not found" + end, + CompVer = + case key1search(compiler_version, Info) of + {value, S2} when is_list(S2) -> + S2; + _ -> + "Not found" + end, + CompDate = + case key1search(compile_time, Info) of + {value, {Year, Month, Day, Hour, Min, Sec}} -> + lists:flatten( + io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w", + [Year, Month, Day, Hour, Min, Sec])); + _ -> + "Not found" + end, + io:format(" ~w:~n" + " Vsn: ~s~n" + " App vsn: ~s~n" + " ASN.1 vsn: ~s~n" + " Compiler ver: ~s~n" + " Compile time: ~s~n", + [Module, Vsn, AppVsn, Asn1Vsn, CompVer, CompDate]), + ok. + + +key1search(Key, Vals) -> + case lists:keysearch(Key, 1, Vals) of + {value, {Key, Val}} -> + {value, Val}; + false -> + not_found + end. + +key1search(Key, Vals, Def) -> + case key1search(Key, Vals) of + not_found -> + {value, Def}; + Value -> + Value + end. + + +%%-------------------------------------------------------------------- +%% Function: service_names() -> [ServiceName] +%% +%% ServiceName = atom() +%% +%% Description: Returns a list of supported services +%%------------------------------------------------------------------- +service_names() -> + [ftpc, tftpd, httpc, httpd]. + + +%%----------------------------------------------------------------- +%% enable_trace(Level, Destination) -> void() +%% enable_trace(Level, Destination, Service) -> void() +%% +%% Parameters: +%% Level -> max | min | integer() +%% Destination -> File | Port | io | HandlerSpec +%% Service -> httpc | httpd | ftpc | tftp | all +%% File -> string() +%% Port -> integer() +%% Verbosity -> true | false +%% HandlerSpec = {function(), Data} +%% Data = term() +%% +%% Description: +%% This function is used to start tracing at level Level and send +%% the result either to the file File, the port Port or to a +%% trace handler. +%% Note that it starts a tracer server. +%% When Destination is the atom io (or the tuple {io, Verbosity}), +%% all (printable) inets trace events (trace_ts events which has +%% Severity withing Limit) will be written to stdout using io:format. +%% +%%----------------------------------------------------------------- +enable_trace(Level, Dest) -> + enable_trace(Level, Dest, all). + +enable_trace(Level, Dest, Service) -> + case valid_trace_service(Service) of + true -> + enable_trace2(Level, Dest, Service); + false -> + {error, {invalid_service, Service}} + end. + +enable_trace2(Level, File, Service) + when is_list(File) -> + case file:open(File, [write]) of + {ok, Fd} -> + HandleSpec = {fun handle_trace/2, {Service, Fd}}, + do_enable_trace(Level, process, HandleSpec); + Err -> + Err + end; +enable_trace2(Level, Port, _) when is_integer(Port) -> + do_enable_trace(Level, port, dbg:trace_port(ip, Port)); +enable_trace2(Level, io, Service) -> + HandleSpec = {fun handle_trace/2, {Service, standard_io}}, + do_enable_trace(Level, process, HandleSpec); +enable_trace2(Level, {Fun, _Data} = HandleSpec, _) when is_function(Fun) -> + do_enable_trace(Level, process, HandleSpec). + +do_enable_trace(Level, Type, HandleSpec) -> + case dbg:tracer(Type, HandleSpec) of + {ok, _} -> + set_trace(Level), + ok; + Error -> + Error + end. + +valid_trace_service(all) -> + true; +valid_trace_service(Service) -> + lists:member(Service, [httpc, httpd, ftpc, tftp]). + + +%%----------------------------------------------------------------- +%% disable_trace() -> void() +%% +%% Description: +%% This function is used to stop tracing. +%%----------------------------------------------------------------- +disable_trace() -> + %% This is to make handle_trace/2 close the output file (if the + %% event gets there before dbg closes) + inets:report_event(100, "stop trace", stop_trace, [stop_trace]), + dbg:stop(). + + + +%%----------------------------------------------------------------- +%% set_trace(Level) -> void() +%% +%% Parameters: +%% Level -> max | min | integer() +%% +%% Description: +%% This function is used to change the trace level when tracing has +%% already been started. +%%----------------------------------------------------------------- +set_trace(Level) -> + set_trace(Level, all). + +set_trace(Level, Service) -> + Pat = make_pattern(?MODULE, Service, Level), + change_pattern(Pat). + +make_pattern(Mod, Service, Level) + when is_atom(Mod) andalso is_atom(Service) -> + case Level of + min -> + {Mod, Service, []}; + max -> + Head = ['$1', '_', '_', '_'], + Body = [], + Cond = [], + {Mod, Service, [{Head, Cond, Body}]}; + DetailLevel when is_integer(DetailLevel) -> + Head = ['$1', '_', '_', '_'], + Body = [], + Cond = [{ '=<', '$1', DetailLevel}], + {Mod, Service, [{Head, Cond, Body}]}; + _ -> + exit({bad_level, Level}) + end. + +change_pattern({Mod, Service, Pattern}) + when is_atom(Mod) andalso is_atom(Service) -> + MFA = {Mod, report_event, 4}, + case Pattern of + [] -> + try + error_to_exit(ctp, dbg:ctp(MFA)), + error_to_exit(p, dbg:p(all, clear)) + catch + exit:{Where, Reason} -> + {error, {Where, Reason}} + end; + List when is_list(List) -> + try + error_to_exit(ctp, dbg:ctp(MFA)), + error_to_exit(tp, dbg:tp(MFA, Pattern)), + error_to_exit(p, dbg:p(all, [call, timestamp])) + catch + exit:{Where, Reason} -> + {error, {Where, Reason}} + end; + _ -> + exit({bad_pattern, Pattern}) + end, + ok. + +error_to_exit(_Where, {ok, _} = OK) -> + OK; +error_to_exit(Where, {error, Reason}) -> + exit({Where, Reason}). + + +%%----------------------------------------------------------------- +%% report_event(Serverity, Label, Service, Content) +%% +%% Parameters: +%% Severity -> 0 =< integer() =< 100 +%% Label -> string() +%% Service -> httpd | httpc | ftp | tftp +%% Content -> [{tag, term()}] +%% +%% Description: +%% This function is used to generate trace events, that is, +%% put trace on this function. +%%----------------------------------------------------------------- + +report_event(Severity, Label, Service, Content) + when (is_integer(Severity) andalso + (Severity >= 0) andalso (100 >= Severity)) andalso + is_list(Label) andalso + is_atom(Service) andalso + is_list(Content) -> + hopefully_traced. + + +%% ---------------------------------------------------------------------- +%% handle_trace(Event, Fd) -> Verbosity +%% +%% Parameters: +%% Event -> The trace event (only megaco 'trace_ts' events are printed) +%% Fd -> standard_io | file_descriptor() | trace_port() +%% +%% Description: +%% This function is used to "receive" and print the trace events. +%% Events are printed if: +%% - Verbosity is max +%% - Severity is =< Verbosity (e.g. Severity = 30, and Verbosity = 40) +%% Events are not printed if: +%% - Verbosity is min +%% - Severity is > Verbosity +%%----------------------------------------------------------------- + +handle_trace(_, closed_file = Fd) -> + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + {standard_io, _} = Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + standard_io = Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + Fd; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + {_Service, Fd}) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + (catch file:close(Fd)), + closed_file; +handle_trace({trace_ts, _Who, call, + {?MODULE, report_event, + [_Sev, "stop trace", stop_trace, [stop_trace]]}, + Timestamp}, + Fd) -> + (catch io:format(Fd, "stop trace at ~s~n", [format_timestamp(Timestamp)])), + (catch file:close(Fd)), + closed_file; +handle_trace({trace_ts, Who, call, + {?MODULE, report_event, + [Sev, Label, Service, Content]}, Timestamp}, + Fd) -> + (catch print_inets_trace(Fd, Sev, Timestamp, Who, + Label, Service, Content)), + Fd; +handle_trace(Event, Fd) -> + (catch print_trace(Fd, Event)), + Fd. + + +print_inets_trace({Service, Fd}, + Sev, Timestamp, Who, Label, Service, Content) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content); +print_inets_trace({ServiceA, Fd}, + Sev, Timestamp, Who, Label, ServiceB, Content) + when (ServiceA =:= all) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, ServiceB, Content); +print_inets_trace({ServiceA, _Fd}, + _Sev, _Timestamp, _Who, _Label, ServiceB, _Content) + when ServiceA =/= ServiceB -> + ok; +print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> + do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content). + +do_print_inets_trace(Fd, Sev, Timestamp, Who, Label, Service, Content) -> + Ts = format_timestamp(Timestamp), + io:format(Fd, "[inets ~w trace ~w ~w ~s] ~s " + "~n Content: ~p" + "~n", + [Service, Sev, Who, Ts, Label, Content]). + +print_trace({_, Fd}, Event) -> + do_print_trace(Fd, Event); +print_trace(Fd, Event) -> + do_print_trace(Fd, Event). + +do_print_trace(Fd, {trace, Who, What, Where}) -> + io:format(Fd, "[trace]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n", [Who, What, Where]); + +do_print_trace(Fd, {trace, Who, What, Where, Extra}) -> + io:format(Fd, "[trace]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n Extra: ~p" + "~n", [Who, What, Where, Extra]); + +do_print_trace(Fd, {trace_ts, Who, What, Where, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[trace ~s]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n", [Ts, Who, What, Where]); + +do_print_trace(Fd, {trace_ts, Who, What, Where, Extra, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[trace ~s]" + "~n Who: ~p" + "~n What: ~p" + "~n Where: ~p" + "~n Extra: ~p" + "~n", [Ts, Who, What, Where, Extra]); + +do_print_trace(Fd, {seq_trace, What, Where}) -> + io:format(Fd, "[seq trace]" + "~n What: ~p" + "~n Where: ~p" + "~n", [What, Where]); + +do_print_trace(Fd, {seq_trace, What, Where, When}) -> + Ts = format_timestamp(When), + io:format(Fd, "[seq trace ~s]" + "~n What: ~p" + "~n Where: ~p" + "~n", [Ts, What, Where]); + +do_print_trace(Fd, {drop, Num}) -> + io:format(Fd, "[drop trace] ~p~n", [Num]); + +do_print_trace(Fd, Trace) -> + io:format(Fd, "[trace] " + "~n ~p" + "~n", [Trace]). + + +format_timestamp({_N1, _N2, N3} = Now) -> + {Date, Time} = calendar:now_to_datetime(Now), + {YYYY,MM,DD} = Date, + {Hour,Min,Sec} = Time, + FormatDate = + io_lib:format("~.4w:~.2.0w:~.2.0w ~.2.0w:~.2.0w:~.2.0w 4~w", + [YYYY,MM,DD,Hour,Min,Sec,round(N3/1000)]), + lists:flatten(FormatDate). + + +%%-------------------------------------------------------------------- +%%% Internal functions +%%-------------------------------------------------------------------- +start_service(Service, Args, stand_alone) -> + Service:start_standalone(Args); +start_service(Service, Args, inets) -> + call_service(Service, start_service, Args). + +call_service(Service, Call, Args) -> + try Service:Call(Args) of + Result -> + Result + catch + exit:{noproc, _} -> + {error, inets_not_started} + end. + +service_module(tftpd) -> + tftp; +service_module(httpc) -> + http; +service_module(ftpc) -> + ftp; +service_module(Service) -> + Service. + + + + + + diff --git a/lib/inets/src/inets_app/inets_app.erl b/lib/inets/src/inets_app/inets_app.erl new file mode 100644 index 0000000000..cae79a6767 --- /dev/null +++ b/lib/inets/src/inets_app/inets_app.erl @@ -0,0 +1,30 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2004-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +-module(inets_app). + +-behaviour(application). + +-export([start/2, stop/1]). + +start(_Type, _State) -> + supervisor:start_link({local, inets_sup}, inets_sup, []). + +stop(_State) -> + ok. diff --git a/lib/inets/src/inets_app/inets_internal.hrl b/lib/inets/src/inets_app/inets_internal.hrl new file mode 100644 index 0000000000..55c3669e4a --- /dev/null +++ b/lib/inets/src/inets_app/inets_internal.hrl @@ -0,0 +1,49 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2005-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-ifndef(inets_internal_hrl). +-define(inets_internal_hrl, true). + +%% Various trace macros + +-define(report(Severity, Label, Service, Content), + inets:report_event(Severity, Label, Service, + [{module, ?MODULE}, {line, ?LINE} | Content])). +-define(report_important(Label, Service, Content), + ?report(20, Label, Service, Content)). +-define(report_verbose(Label, Service, Content), + ?report(40, Label, Service, Content)). +-define(report_debug(Label, Service, Content), + ?report(60, Label, Service, Content)). +-define(report_trace(Label, Service, Content), + ?report(80, Label, Service, Content)). + + +-define(CR, $\r). +-define(LF, $\n). +-define(CRLF, [$\r,$\n]). +-define(SP, $\s). +-define(TAB, $\t). +-define(LEFT_PAREN, $(). +-define(RIGHT_PAREN, $)). +-define(WHITE_SPACE, $ ). +-define(DOUBLE_QUOTE, $"). + +-endif. % -ifdef(inets_internal_hrl). diff --git a/lib/inets/src/inets_app/inets_regexp.erl b/lib/inets/src/inets_app/inets_regexp.erl new file mode 100644 index 0000000000..a065533236 --- /dev/null +++ b/lib/inets/src/inets_app/inets_regexp.erl @@ -0,0 +1,413 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +-module(inets_regexp). + +-export([parse/1, match/2, first_match/2, split/2, sub/3, gsub/3]). + + +%%%========================================================================= +%%% API +%%%========================================================================= + +%% parse(RegExp) -> {ok, RE} | {error, E}. +%% Parse the regexp described in the string RegExp. + +parse(S) -> + case (catch reg(S)) of + {R, []} -> + {ok, R}; + {_R, [C|_]} -> + {error, {illegal, [C]}}; + {error, E} -> + {error, E} + end. + + +%% Find the longest match of RegExp in String. + +match(S, RegExp) when is_list(RegExp) -> + case parse(RegExp) of + {ok,RE} -> match(S, RE); + {error,E} -> {error,E} + end; +match(S, RE) -> + case match(RE, S, 1, 0, -1) of + {Start,Len} when Len >= 0 -> + {match, Start, Len}; + {_Start,_Len} -> + nomatch + end. + +%% Find the first match of RegExp in String. + +first_match(S, RegExp) when is_list(RegExp) -> + case parse(RegExp) of + {ok, RE} -> + first_match(S, RE); + {error, E} -> + {error, E} + end; +first_match(S, RE) -> + case first_match(RE, S, 1) of + {Start,Len} when Len >= 0 -> + {match, Start,Len}; + nomatch -> + nomatch + end. + +first_match(RE, S, St) when S =/= [] -> + case re_apply(S, St, RE) of + {match, P, _Rest} -> + {St, P-St}; + nomatch -> + first_match(RE, tl(S), St+1) + end; +first_match(_RE, [], _St) -> + nomatch. + + +match(RE, S, St, Pos, L) -> + case first_match(RE, S, St) of + {St1, L1} -> + Nst = St1 + 1, + if L1 > L -> + match(RE, lists:nthtail(Nst-St, S), Nst, St1, L1); + true -> + match(RE, lists:nthtail(Nst-St, S), Nst, Pos, L) + end; + nomatch -> + {Pos, L} + end. + + +%% Split a string into substrings where the RegExp describes the +%% field seperator. The RegExp " " is specially treated. + +split(String, " ") -> %This is really special + {ok, RE} = parse("[ \t]+"), + case split_apply(String, RE, true) of + [[]|Ss] -> + {ok,Ss}; + Ss -> + {ok,Ss} + end; +split(String, RegExp) when is_list(RegExp) -> + case parse(RegExp) of + {ok, RE} -> + {ok, split_apply(String, RE, false)}; + {error, E} -> + {error,E} + end; +split(String, RE) -> + {ok, split_apply(String, RE, false)}. + + +%% Substitute the first match of the regular expression RegExp +%% with the string Replace in String. Accept pre-parsed regular +%% expressions. + +sub(String, RegExp, Rep) when is_list(RegExp) -> + case parse(RegExp) of + {ok, RE} -> + sub(String, RE, Rep); + {error, E} -> + {error, E} + end; +sub(String, RE, Rep) -> + Ss = sub_match(String, RE, 1), + {ok, sub_repl(Ss, Rep, String, 1), length(Ss)}. + + +%% Substitute every match of the regular expression RegExp with +%% the string New in String. Accept pre-parsed regular expressions. + +gsub(String, RegExp, Rep) when is_list(RegExp) -> + case parse(RegExp) of + {ok, RE} -> + gsub(String, RE, Rep); + {error, E} -> + {error, E} + end; +gsub(String, RE, Rep) -> + Ss = matches(String, RE, 1), + {ok, sub_repl(Ss, Rep, String, 1), length(Ss)}. + + +%%%======================================================================== +%%% Internal functions +%%%======================================================================== + +%% This is the regular expression grammar used. It is equivalent to the +%% one used in AWK, except that we allow ^ $ to be used anywhere and fail +%% in the matching. +%% +%% reg -> reg1 : '$1'. +%% reg1 -> reg1 "|" reg2 : {'or','$1','$2'}. +%% reg1 -> reg2 : '$1'. +%% reg2 -> reg2 reg3 : {concat,'$1','$2'}. +%% reg2 -> reg3 : '$1'. +%% reg3 -> reg3 "*" : {kclosure,'$1'}. +%% reg3 -> reg3 "+" : {pclosure,'$1'}. +%% reg3 -> reg3 "?" : {optional,'$1'}. +%% reg3 -> reg4 : '$1'. +%% reg4 -> "(" reg ")" : '$2'. +%% reg4 -> "\\" char : '$2'. +%% reg4 -> "^" : bos. +%% reg4 -> "$" : eos. +%% reg4 -> "." : char. +%% reg4 -> "[" class "]" : {char_class,char_class('$2')} +%% reg4 -> "[" "^" class "]" : {comp_class,char_class('$3')} +%% reg4 -> "\"" chars "\"" : char_string('$2') +%% reg4 -> char : '$1'. +%% reg4 -> empty : epsilon. +%% The grammar of the current regular expressions. The actual parser +%% is a recursive descent implementation of the grammar. + +reg(S) -> reg1(S). + +%% reg1 -> reg2 reg1' +%% reg1' -> "|" reg2 +%% reg1' -> empty + +reg1(S0) -> + {L,S1} = reg2(S0), + reg1p(S1, L). + +reg1p([$||S0], L) -> + {R,S1} = reg2(S0), + reg1p(S1, {'or',L,R}); +reg1p(S, L) -> {L,S}. + +%% reg2 -> reg3 reg2' +%% reg2' -> reg3 +%% reg2' -> empty + +reg2(S0) -> + {L,S1} = reg3(S0), + reg2p(S1, L). + +reg2p([C|S0], L) when (C =/= $|) andalso (C =/= $)) -> + {R,S1} = reg3([C|S0]), + reg2p(S1, {concat,L,R}); +reg2p(S, L) -> {L,S}. + +%% reg3 -> reg4 reg3' +%% reg3' -> "*" reg3' +%% reg3' -> "+" reg3' +%% reg3' -> "?" reg3' +%% reg3' -> empty + +reg3(S0) -> + {L,S1} = reg4(S0), + reg3p(S1, L). + +reg3p([$*|S], L) -> reg3p(S, {kclosure,L}); +reg3p([$+|S], L) -> reg3p(S, {pclosure,L}); +reg3p([$?|S], L) -> reg3p(S, {optional,L}); +reg3p(S, L) -> {L,S}. + +reg4([$(|S0]) -> + case reg(S0) of + {R,[$)|S1]} -> {R,S1}; + {_R,_S} -> throw({error,{unterminated,"("}}) + end; +reg4([$\\,O1,O2,O3|S]) + when ((O1 >= $0) andalso + (O1 =< $7) andalso + (O2 >= $0) andalso + (O2 =< $7) andalso + (O3 >= $0) andalso + (O3 =< $7)) -> + {(O1*8 + O2)*8 + O3 - 73*$0,S}; +reg4([$\\,C|S]) -> + {escape_char(C),S}; +reg4([$\\]) -> + throw({error, {unterminated,"\\"}}); +reg4([$^|S]) -> + {bos,S}; +reg4([$$|S]) -> + {eos,S}; +reg4([$.|S]) -> + {{comp_class,"\n"},S}; +reg4("[^" ++ S0) -> + case char_class(S0) of + {Cc,[$]|S1]} -> {{comp_class,Cc},S1}; + {_Cc,_S} -> throw({error,{unterminated,"["}}) + end; +reg4([$[|S0]) -> + case char_class(S0) of + {Cc,[$]|S1]} -> {{char_class,Cc},S1}; + {_Cc,_S1} -> throw({error,{unterminated,"["}}) + end; +reg4([C|S]) + when (C =/= $*) andalso (C =/= $+) andalso (C =/= $?) andalso (C =/= $]) -> + {C, S}; +reg4([C|_S]) -> + throw({error,{illegal,[C]}}); +reg4([]) -> + {epsilon,[]}. + +escape_char($n) -> $\n; %\n = LF +escape_char($r) -> $\r; %\r = CR +escape_char($t) -> $\t; %\t = TAB +escape_char($v) -> $\v; %\v = VT +escape_char($b) -> $\b; %\b = BS +escape_char($f) -> $\f; %\f = FF +escape_char($e) -> $\e; %\e = ESC +escape_char($s) -> $\s; %\s = SPACE +escape_char($d) -> $\d; %\d = DEL +escape_char(C) -> C. + +char_class([$]|S]) -> char_class(S, [$]]); +char_class(S) -> char_class(S, []). + +char($\\, [O1,O2,O3|S]) when + O1 >= $0, O1 =< $7, O2 >= $0, O2 =< $7, O3 >= $0, O3 =< $7 -> + {(O1*8 + O2)*8 + O3 - 73*$0,S}; +char($\\, [C|S]) -> {escape_char(C),S}; +char(C, S) -> {C,S}. + +char_class([C1|S0], Cc) when C1 =/= $] -> + case char(C1, S0) of + {Cf,[$-,C2|S1]} when C2 =/= $] -> + case char(C2, S1) of + {Cl,S2} when Cf < Cl -> char_class(S2, [{Cf,Cl}|Cc]); + {Cl,_S2} -> throw({error,{char_class,[Cf,$-,Cl]}}) + end; + {C,S1} -> char_class(S1, [C|Cc]) + end; +char_class(S, Cc) -> {Cc,S}. + + +%% re_apply(String, StartPos, RegExp) -> re_app_res(). +%% +%% Apply the (parse of the) regular expression RegExp to String. If +%% there is a match return the position of the remaining string and +%% the string if else return 'nomatch'. BestMatch specifies if we want +%% the longest match, or just a match. +%% +%% StartPos should be the real start position as it is used to decide +%% if we ae at the beginning of the string. +%% +%% Pass two functions to re_apply_or so it can decide, on the basis +%% of BestMatch, whether to just any take any match or try both to +%% find the longest. This is slower but saves duplicatng code. + +re_apply(S, St, RE) -> re_apply(RE, [], S, St). + +re_apply(epsilon, More, S, P) -> %This always matches + re_apply_more(More, S, P); +re_apply({'or',RE1,RE2}, More, S, P) -> + re_apply_or(re_apply(RE1, More, S, P), + re_apply(RE2, More, S, P)); +re_apply({concat,RE1,RE2}, More, S0, P) -> + re_apply(RE1, [RE2|More], S0, P); +re_apply({kclosure,CE}, More, S, P) -> + %% Be careful with the recursion, explicitly do one call before + %% looping. + re_apply_or(re_apply_more(More, S, P), + re_apply(CE, [{kclosure,CE}|More], S, P)); +re_apply({pclosure,CE}, More, S, P) -> + re_apply(CE, [{kclosure,CE}|More], S, P); +re_apply({optional,CE}, More, S, P) -> + re_apply_or(re_apply_more(More, S, P), + re_apply(CE, More, S, P)); +re_apply(bos, More, S, 1) -> re_apply_more(More, S, 1); +re_apply(eos, More, [$\n|S], P) -> re_apply_more(More, S, P); +re_apply(eos, More, [], P) -> re_apply_more(More, [], P); +re_apply({char_class,Cc}, More, [C|S], P) -> + case in_char_class(C, Cc) of + true -> re_apply_more(More, S, P+1); + false -> nomatch + end; +re_apply({comp_class,Cc}, More, [C|S], P) -> + case in_char_class(C, Cc) of + true -> nomatch; + false -> re_apply_more(More, S, P+1) + end; +re_apply(C, More, [C|S], P) when is_integer(C) -> + re_apply_more(More, S, P+1); +re_apply(_RE, _More, _S, _P) -> nomatch. + +%% re_apply_more([RegExp], String, Length) -> re_app_res(). + +re_apply_more([RE|More], S, P) -> re_apply(RE, More, S, P); +re_apply_more([], S, P) -> {match,P,S}. + +%% in_char_class(Char, Class) -> bool(). + +in_char_class(C, [{C1,C2}|_Cc]) when C >= C1, C =< C2 -> true; +in_char_class(C, [C|_Cc]) -> true; +in_char_class(C, [_|Cc]) -> in_char_class(C, Cc); +in_char_class(_C, []) -> false. + +%% re_apply_or(Match1, Match2) -> re_app_res(). +%% If we want the best match then choose the longest match, else just +%% choose one by trying sequentially. + +re_apply_or({match,P1,S1}, {match,P2,_S2}) when P1 >= P2 -> {match,P1,S1}; +re_apply_or({match,_P1,_S1}, {match,P2,S2}) -> {match,P2,S2}; +re_apply_or(nomatch, R2) -> R2; +re_apply_or(R1, nomatch) -> R1. + + +matches(S, RE, St) -> + case first_match(RE, S, St) of + {St1,0} -> + [{St1,0}|matches(string:substr(S, St1+2-St), RE, St1+1)]; + {St1,L1} -> + [{St1,L1}|matches(string:substr(S, St1+L1+1-St), RE, St1+L1)]; + nomatch -> + [] + end. + +sub_match(S, RE, St) -> + case first_match(RE, S, St) of + {St1,L1} -> [{St1,L1}]; + nomatch -> [] + end. + +sub_repl([{St,L}|Ss], Rep, S, Pos) -> + Rs = sub_repl(Ss, Rep, S, St+L), + string:substr(S, Pos, St-Pos) ++ + sub_repl(Rep, string:substr(S, St, L), Rs); +sub_repl([], _Rep, S, Pos) -> + string:substr(S, Pos). + +sub_repl([$&|Rep], M, Rest) -> M ++ sub_repl(Rep, M, Rest); +sub_repl("\\&" ++ Rep, M, Rest) -> [$&|sub_repl(Rep, M, Rest)]; +sub_repl([C|Rep], M, Rest) -> [C|sub_repl(Rep, M, Rest)]; +sub_repl([], _M, Rest) -> Rest. + +split_apply(S, RE, Trim) -> split_apply(S, 1, RE, Trim, []). + +split_apply([], _P, _RE, true, []) -> + []; +split_apply([], _P, _RE, _T, Sub) -> + [lists:reverse(Sub)]; +split_apply(S, P, RE, T, Sub) -> + case re_apply(S, P, RE) of + {match,P,_Rest} -> + split_apply(tl(S), P+1, RE, T, [hd(S)|Sub]); + {match,P1,Rest} -> + [lists:reverse(Sub)|split_apply(Rest, P1, RE, T, [])]; + nomatch -> + split_apply(tl(S), P+1, RE, T, [hd(S)|Sub]) + end. diff --git a/lib/inets/src/inets_app/inets_service.erl b/lib/inets/src/inets_app/inets_service.erl new file mode 100644 index 0000000000..3499314d54 --- /dev/null +++ b/lib/inets/src/inets_app/inets_service.erl @@ -0,0 +1,65 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2007-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% + +-module(inets_service). + +-export([behaviour_info/1]). + +behaviour_info(callbacks) -> + [{start_standalone, 1}, + {start_service, 1}, + {stop_service, 1}, + {services, 0}, + {service_info, 1}]; +behaviour_info(_) -> + undefined. + +%% Starts service stand-alone +%% start_standalone(Config) -> % {ok, Pid} | {error, Reason} +%% :start_link(Config). + +%% Starts service as part of inets +%% start_service(Config) -> % {ok, Pid} | {error, Reason} +%% :start_child(Config). +%% Stop service +%% stop_service(Pid) -> % ok | {error, Reason} +%% :stop_child(maybe_map_pid_to_other_ref(Pid)). +%% +%% :stop_child(Ref) -> +%% Id = id(Ref), +%% case supervisor:terminate_child(?MODULE, Id) of +%% ok -> +%% supervisor:delete_child(?MODULE, Id); +%% Error -> +%% Error +%% end. + +%% Returns list of running services. Services started as stand alone +%% are not listed +%% services() -> % [{Service, Pid}] +%% Exampel: +%% services() -> +%% [{httpc, Pid} || {_, Pid, _, _} <- +%% supervisor:which_children(httpc_profile_sup)]. + + +%% service_info() -> [{Property, Value}] | {error, Reason} +%% ex: http:service_info() -> [{profile, ProfileName}] +%% httpd:service_info() -> [{host, Host}, {port, Port}] diff --git a/lib/inets/src/inets_app/inets_sup.erl b/lib/inets/src/inets_app/inets_sup.erl new file mode 100644 index 0000000000..20d5ef343e --- /dev/null +++ b/lib/inets/src/inets_app/inets_sup.erl @@ -0,0 +1,117 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 1997-2009. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% +%% +%%---------------------------------------------------------------------- +%% Purpose: The top supervisor for the inets application +%%---------------------------------------------------------------------- + +-module(inets_sup). + +-behaviour(supervisor). + +-export([init/1]). + +%%%========================================================================= +%%% Supervisor callback +%%%========================================================================= +init([]) -> + SupFlags = {one_for_one, 10, 3600}, + Children = children(), + {ok, {SupFlags, Children}}. + +%%%========================================================================= +%%% Internal functions +%%%========================================================================= +get_services() -> + case (catch application:get_env(inets, services)) of + {ok, Services} -> + Services; + _ -> + [] + end. + +children() -> + Services = get_services(), + HttpdServices = [Service || Service <- Services, is_httpd(Service)], + HttpcServices = [Service || Service <- Services, is_httpc(Service)], + TftpdServices = [Service || Service <- Services, is_tftpd(Service)], + [ftp_child_spec(), httpc_child_spec(HttpcServices), + httpd_child_spec(HttpdServices), tftpd_child_spec(TftpdServices)]. + +ftp_child_spec() -> + Name = ftp_sup, + StartFunc = {ftp_sup, start_link, []}, + Restart = permanent, + Shutdown = infinity, + Modules = [ftp_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + + +httpc_child_spec(HttpcServices0) -> + HttpcServices = default_profile(HttpcServices0, []), + Name = httpc_sup, + StartFunc = {httpc_sup, start_link, [HttpcServices]}, + Restart = permanent, + Shutdown = infinity, + Modules = [httpc_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +httpd_child_spec(HttpdServices) -> + Name = httpd_sup, + StartFunc = {httpd_sup, start_link, [HttpdServices]}, + Restart = permanent, + Shutdown = infinity, + Modules = [httpd_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +tftpd_child_spec(TftpServices) -> + Name = tftp_sup, + StartFunc = {tftp_sup, start_link, [TftpServices]}, + Restart = permanent, + Shutdown = infinity, + Modules = [tftp_sup], + Type = supervisor, + {Name, StartFunc, Restart, Shutdown, Type, Modules}. + +is_httpd({httpd, _}) -> + true; +is_httpd({httpd, _, _}) -> + true; +is_httpd(_) -> + false. + +is_httpc({httpc, _}) -> + true; +is_httpc(_) -> + false. + +is_tftpd({tftpd, _}) -> + true; +is_tftpd(_) -> + false. + +default_profile([], Acc) -> + [{httpc, {default, only_session_cookies}} | Acc]; +default_profile([{httpc, {default, _}} | _] = Profiles, Acc) -> + Profiles ++ Acc; +default_profile([Profile | Profiles], Acc) -> + default_profile(Profiles, [Profile | Acc]). -- cgit v1.2.3