From 84c4d93ca5d5c7abccdddceb4629bf5de8222ede Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Thu, 17 Jun 2004 21:29:24 +0000 Subject: [PATCH] * src/web/ejabberd_web_admin.erl: Added configuration of listened ports * src/ejabberd_listener.erl: Added API for configuration of port listeners * src/web/ejabberd_web_admin.erl: Fixed "Stop" button on node management page SVN Revision: 238 --- ChangeLog | 10 +++ src/ejabberd_listener.erl | 72 +++++++++++++++----- src/web/ejabberd_web_admin.erl | 116 ++++++++++++++++++++++++++++++++- 3 files changed, 180 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5f33578dd..994eb4f83 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2004-06-18 Alexey Shchepin + + * src/web/ejabberd_web_admin.erl: Added configuration of listened + ports + * src/ejabberd_listener.erl: Added API for configuration of port + listeners + + * src/web/ejabberd_web_admin.erl: Fixed "Stop" button on node + management page + 2004-05-22 Alexey Shchepin * src/msgs/nl.msg: Dutch translation (thanks to Sander Devrieze) diff --git a/src/ejabberd_listener.erl b/src/ejabberd_listener.erl index bde4d6b48..2bb526cb3 100644 --- a/src/ejabberd_listener.erl +++ b/src/ejabberd_listener.erl @@ -14,7 +14,9 @@ init/3, init_ssl/4, start_listener/3, - stop_listener/1 + stop_listener/1, + add_listener/3, + delete_listener/1 ]). -include("ejabberd.hrl"). @@ -33,7 +35,7 @@ init(_) -> fun({Port, Module, Opts}) -> {Port, {?MODULE, start, [Port, Module, Opts]}, - permanent, + transient, brutal_kill, worker, [?MODULE]} @@ -63,13 +65,21 @@ init(Port, Module, Opts) -> (inet) -> true; (_) -> false end, Opts), - {ok, ListenSocket} = gen_tcp:listen(Port, [binary, - {packet, 0}, - {active, false}, - {reuseaddr, true}, - {nodelay, true} | - SockOpts]), - accept(ListenSocket, Module, Opts). + + Res = gen_tcp:listen(Port, [binary, + {packet, 0}, + {active, false}, + {reuseaddr, true}, + {nodelay, true} | + SockOpts]), + case Res of + {ok, ListenSocket} -> + accept(ListenSocket, Module, Opts); + {error, Reason} -> + ?ERROR_MSG("Failed to open socket for ~p: ~p", + [{Port, Module, Opts}, Reason]), + error + end. accept(ListenSocket, Module, Opts) -> case gen_tcp:accept(ListenSocket) of @@ -104,12 +114,19 @@ init_ssl(Port, Module, Opts, SSLOpts) -> ({ciphers, _}) -> true; (_) -> false end, Opts), - {ok, ListenSocket} = ssl:listen(Port, [binary, - {packet, 0}, - {active, false}, - {nodelay, true} | - SockOpts ++ SSLOpts]), - accept_ssl(ListenSocket, Module, Opts). + Res = ssl:listen(Port, [binary, + {packet, 0}, + {active, false}, + {nodelay, true} | + SockOpts ++ SSLOpts]), + case Res of + {ok, ListenSocket} -> + accept_ssl(ListenSocket, Module, Opts); + {error, Reason} -> + ?ERROR_MSG("Failed to open socket for ~p: ~p", + [{Port, Module, Opts}, Reason]), + error + end. accept_ssl(ListenSocket, Module, Opts) -> case ssl:accept(ListenSocket, 200) of @@ -136,7 +153,7 @@ accept_ssl(ListenSocket, Module, Opts) -> start_listener(Port, Module, Opts) -> ChildSpec = {Port, {?MODULE, start, [Port, Module, Opts]}, - permanent, + transient, brutal_kill, worker, [?MODULE]}, @@ -146,3 +163,26 @@ stop_listener(Port) -> supervisor:terminate_child(ejabberd_listeners, Port), supervisor:delete_child(ejabberd_listeners, Port). +add_listener(Port, Module, Opts) -> + Ports = case ejabberd_config:get_local_option(listen) of + undefined -> + []; + Ls -> + Ls + end, + Ports1 = lists:keydelete(Port, 1, Ports), + Ports2 = [{Port, Module, Opts} | Ports1], + ejabberd_config:add_local_option(listen, Ports2), + start_listener(Port, Module, Opts). + +delete_listener(Port) -> + Ports = case ejabberd_config:get_local_option(listen) of + undefined -> + []; + Ls -> + Ls + end, + Ports1 = lists:keydelete(Port, 1, Ports), + ejabberd_config:add_local_option(listen, Ports1), + stop_listener(Port). + diff --git a/src/web/ejabberd_web_admin.erl b/src/web/ejabberd_web_admin.erl index c021fde2b..93e80b6a2 100644 --- a/src/web/ejabberd_web_admin.erl +++ b/src/web/ejabberd_web_admin.erl @@ -42,6 +42,12 @@ {"name", Name}, {"value", Value}])). -define(INPUTT(Type, Name, Value), ?INPUT(Type, Name, ?T(Value))). +-define(INPUTS(Type, Name, Value, Size), + ?XA("input", [{"type", Type}, + {"name", Name}, + {"value", Value}, + {"size", Size}])). +-define(INPUTST(Type, Name, Value, Size), ?INPUT(Type, Name, ?T(Value), Size)). make_xhtml(Els, Lang) -> {200, [html], @@ -1184,6 +1190,7 @@ get_node(Node, [], Query, Lang) -> [?XE("ul", [?LI([?ACT("db/", "DB Management")]), ?LI([?ACT("backup/", "Backup Management")]), + ?LI([?ACT("ports/", "Listened Ports Management")]), ?LI([?ACT("stats/", "Statistics")]) ]), ?XAE("form", [{"method", "post"}], @@ -1304,6 +1311,28 @@ get_node(Node, ["backup"], Query, Lang) -> ]) ])])]; +get_node(Node, ["ports"], Query, Lang) -> + Ports = rpc:call(Node, ejabberd_config, get_local_option, [listen]), + Res = case catch node_ports_parse_query(Node, Ports, Query) of + submitted -> + ok; + {'EXIT', _Reason} -> + error; + _ -> + nothing + end, + NewPorts = lists:sort( + rpc:call(Node, ejabberd_config, get_local_option, [listen])), + [?XC("h1", "Listened Ports at " ++ atom_to_list(Node))] ++ + case Res of + ok -> [?C("submitted"), ?P]; + error -> [?C("bad format"), ?P]; + nothing -> [] + end ++ + [?XAE("form", [{"method", "post"}], + [node_ports_to_xhtml(NewPorts, Lang)]) + ]; + get_node(Node, ["stats"], Query, Lang) -> UpTime = rpc:call(Node, erlang, statistics, [wall_clock]), UpTimeS = io_lib:format("~.3f", [element(1, UpTime)/1000]), @@ -1361,9 +1390,9 @@ node_parse_query(Node, Query) -> ok end; _ -> - case lists:keysearch("delete", 1, Query) of + case lists:keysearch("stop", 1, Query) of {value, _} -> - case rpc:call(Node, init, restart, []) of + case rpc:call(Node, init, stop, []) of {badrpc, _Reason} -> error; _ -> @@ -1470,3 +1499,86 @@ node_backup_parse_query(Node, Query) -> end, nothing, ["store", "restore", "fallback", "dump", "load"]). +node_ports_to_xhtml(Ports, Lang) -> + ?XAE("table", [], + [?XE("thead", + [?XE("tr", + [?XCT("td", "Port"), + ?XCT("td", "Module"), + ?XCT("td", "Options") + ])]), + ?XE("tbody", + lists:map( + fun({Port, Module, Opts} = E) -> + SPort = integer_to_list(Port), + SModule = atom_to_list(Module), + ID = term_to_id(E), + ?XE("tr", + [?XC("td", SPort), + ?XE("td", [?INPUT("text", "module" ++ SPort, + SModule)]), + ?XE("td", [?INPUTS("text", "opts" ++ SPort, + term_to_string(Opts), "40")]), + ?XE("td", [?INPUTT("submit", "add" ++ SPort, + "Update")]), + ?XE("td", [?INPUTT("submit", "delete" ++ SPort, + "Delete")]) + ] + ) + end, Ports) ++ + [?XE("tr", + [?XE("td", [?INPUTS("text", "portnew", "", "6")]), + ?XE("td", [?INPUT("text", "modulenew", "")]), + ?XE("td", [?INPUTS("text", "optsnew", "", "40")]), + ?XAE("td", [{"colspan", "2"}], + [?INPUTT("submit", "addnew", "Add New")]) + ] + )] + )]). + + +node_ports_parse_query(Node, Ports, Query) -> + lists:foreach( + fun({Port, _Module1, _Opts1}) -> + SPort = integer_to_list(Port), + case lists:keysearch("add" ++ SPort, 1, Query) of + {value, _} -> + {{value, {_, SModule}}, {value, {_, SOpts}}} = + {lists:keysearch("module" ++ SPort, 1, Query), + lists:keysearch("opts" ++ SPort, 1, Query)}, + Module = list_to_atom(SModule), + {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), + {ok, Opts} = erl_parse:parse_term(Tokens), + ejabberd_listener:delete_listener(Port), + ejabberd_listener:add_listener(Port, Module, Opts), + throw(submitted); + _ -> + case lists:keysearch("delete" ++ SPort, 1, Query) of + {value, _} -> + ejabberd_listener:delete_listener(Port), + throw(submitted); + _ -> + ok + end + end + end, Ports), + case lists:keysearch("addnew", 1, Query) of + {value, _} -> + {{value, {_, SPort}}, + {value, {_, SModule}}, + {value, {_, SOpts}}} = + {lists:keysearch("portnew", 1, Query), + lists:keysearch("modulenew", 1, Query), + lists:keysearch("optsnew", 1, Query)}, + Port = list_to_integer(SPort), + Module = list_to_atom(SModule), + {ok, Tokens, _} = erl_scan:string(SOpts ++ "."), + {ok, Opts} = erl_parse:parse_term(Tokens), + ejabberd_listener:add_listener(Port, Module, Opts), + throw(submitted); + _ -> + ok + end. + + +