aboutsummaryrefslogtreecommitdiffstats
path: root/lib/inets/src/inets_app
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/inets/src/inets_app
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/inets/src/inets_app')
-rw-r--r--lib/inets/src/inets_app/Makefile121
-rw-r--r--lib/inets/src/inets_app/inets.app.src110
-rw-r--r--lib/inets/src/inets_app/inets.appup.src50
-rw-r--r--lib/inets/src/inets_app/inets.config2
-rw-r--r--lib/inets/src/inets_app/inets.erl740
-rw-r--r--lib/inets/src/inets_app/inets_app.erl30
-rw-r--r--lib/inets/src/inets_app/inets_internal.hrl49
-rw-r--r--lib/inets/src/inets_app/inets_regexp.erl413
-rw-r--r--lib/inets/src/inets_app/inets_service.erl65
-rw-r--r--lib/inets/src/inets_app/inets_sup.erl117
10 files changed, 1697 insertions, 0 deletions
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}
+%% <service>:start_link(Config).
+
+%% Starts service as part of inets
+%% start_service(Config) -> % {ok, Pid} | {error, Reason}
+%% <service_sup>:start_child(Config).
+%% Stop service
+%% stop_service(Pid) -> % ok | {error, Reason}
+%% <service_sup>:stop_child(maybe_map_pid_to_other_ref(Pid)).
+%%
+%% <service_sup>: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]).