* src/web/ejabberd_http.erl: Added options for enabling HTTP

polling and admin interface
* src/web/ejabberd_web.erl: Likewise
* src/ejabberd.cfg.example: Updated

* src/web/ejabberd_web_admin.erl: Updated

* doc/guide.tex: Updated

SVN Revision: 236
This commit is contained in:
Alexey Shchepin 2004-05-22 19:48:35 +00:00
parent 78a673f526
commit 0b4539caa1
7 changed files with 330 additions and 52 deletions

View File

@ -1,3 +1,14 @@
2004-05-22 Alexey Shchepin <alexey@sevcom.net>
* src/web/ejabberd_http.erl: Added options for enabling HTTP
polling and admin interface
* src/web/ejabberd_web.erl: Likewise
* src/ejabberd.cfg.example: Updated
* src/web/ejabberd_web_admin.erl: Updated
* doc/guide.tex: Updated
2004-05-17 Alexey Shchepin <alexey@sevcom.net>
* src/mod_muc/mod_muc.erl: Added access rules for using serveice

View File

@ -455,11 +455,23 @@ The following options are defined:
<DT><CODE><B>ejabberd_service</B></CODE><DD> This module serves connections from Jabber
services (i.&nbsp;e. that use the <TT>jabber:component:accept</TT> namespace).
</DL>
For example, the following configuration defines that C2S connections are
listened on port 5222 and 5223 (SSL) and denied for user ``<TT>bad</TT>'', S2S
on port 5269, and that service <TT>conference.example.org</TT> must be
connected to port 8888 with a password ``<TT>secret</TT>''. Also all users
except admins have traffic limit 1000&nbsp;b/s.
For example, the following configuration defines that:
<UL><LI>
C2S connections are listened on port 5222 and 5223 (SSL) and denied for
user ``<TT>bad</TT>''
<LI>S2S connections are listened on port 5269
<LI>All users except admins have traffic limit 1000&nbsp;B/s
<LI>AIM service <TT>aim.example.org</TT> is connected to port 5233 with
password ``<TT>aimsecret</TT>''
<LI>JIT services <TT>icq.example.org</TT> and <TT>sms.example.org</TT> are
connected to port 5234 with password ``<TT>jitsecret</TT>''
<LI>MSN service <TT>msn.example.org</TT> is connected to port 5235 with
password ``<TT>msnsecret</TT>''
<LI>YAHOO service <TT>yahoo.example.org</TT> is connected to port 5236 with
password ``<TT>yahoosecret</TT>''
<LI>ILE service <TT>ile.example.org</TT> is connected to port 5237 with
password ``<TT>ilesecret</TT>''
</UL>
<PRE>
{acl, blocked, {user, "bad"}}.
{access, c2s, [{deny, blocked},
@ -467,14 +479,62 @@ except admins have traffic limit 1000&nbsp;b/s.
{shaper, normal, {maxrate, 1000}}.
{access, c2s_shaper, [{none, admin},
{normal, all}]}.
{listen, [{5222, ejabberd_c2s, [{access, c2s},
{shaper, c2s_shaper}]},
{5223, ejabberd_c2s, [{access, c2s},
{ssl, [{certfile, "/path/to/ssl.pem"}]}]},
{5269, ejabberd_s2s_in, []},
{8888, ejabberd_service,
[{hosts, ["conference.example.org"], [{password, "secret"}]}]}
]}.
{listen,
[{5222, ejabberd_c2s, [{access, c2s}, {shaper, c2s_shaper}]},
{5223, ejabberd_c2s, [{access, c2s},
ssl, {certfile, "/path/to/ssl.pem"}]},
{5269, ejabberd_s2s_in, []},
{5233, ejabberd_service, [{host, "aim.example.org",
[{password, "aimsecret"}]}]},
{5234, ejabberd_service, [{hosts, ["icq.example.org", "sms.example.org"],
[{password, "jitsecret"}]}]},
{5235, ejabberd_service, [{host, "msn.example.org",
[{password, "msnsecret"}]}]},
{5236, ejabberd_service, [{host, "yahoo.example.org",
[{password, "yahoosecret"}]}]},
{5237, ejabberd_service, [{host, "gg.example.org",
[{password, "ggsecret"}]}]},
{5238, ejabberd_service, [{host, "ile.example.org",
[{password, "ilesecret"}]}]}
]
}.
</PRE>Note, that for jabberd14- or wpjabberd-based services you need to make the
transports log and do xdb by themselves:
<PRE>
&lt;!--
You need to add elogger and rlogger entries here when using ejabberd.
In this case the transport will do the logging.
--&gt;
&lt;log id='elogger'&gt;
&lt;host/&gt;
&lt;logtype/&gt;
&lt;format&gt;%d: [%t] (%h): %s&lt;/format&gt;
&lt;file&gt;/var/log/jabber/error/aim-t.log&lt;/file&gt;
&lt;/log&gt;
&lt;log id='rlogger'&gt;
&lt;host/&gt;
&lt;logtype&gt;record&lt;/logtype&gt;
&lt;format&gt;%d %h %s&lt;/format&gt;
&lt;file&gt;/var/log/jabber/record/aim-t.log&lt;/file&gt;
&lt;/log&gt;
&lt;!--
Some Jabber server implementations do not provide
XDB services (for example jabberd 2.0 and ejabberd).
AIM-t is loaded into handle all XDB requests.
--&gt;
&lt;xdb id="xdb"&gt;
&lt;host/&gt;
&lt;load&gt;
&lt;xdb_file&gt;/usr/lib/jabber/xdb_file.so&lt;/xdb_file&gt; &lt;!-- this is a lib of wpjabber or jabberd --&gt;
&lt;/load&gt;
&lt;xdb_file xmlns="jabber:config:xdb_file"&gt;
&lt;spool&gt;&lt;jabberd:cmdline flag='s'&gt;/var/spool/jabber&lt;/jabberd:cmdline&gt;&lt;/spool&gt;
&lt;/xdb_file&gt;
&lt;/xdb&gt;
</PRE>
<!--TOC subsubsection Modules-->

View File

@ -437,11 +437,23 @@ Currently three modules are implemented:
services (i.\,e.\ that use the \texttt{jabber:component:accept} namespace).
\end{description}
For example, the following configuration defines that C2S connections are
listened on port 5222 and 5223 (SSL) and denied for user ``\texttt{bad}'', S2S
on port 5269, and that service \texttt{conference.example.org} must be
connected to port 8888 with a password ``\texttt{secret}''. Also all users
except admins have traffic limit 1000\,b/s.
For example, the following configuration defines that:
\begin{itemize}
\item C2S connections are listened on port 5222 and 5223 (SSL) and denied for
user ``\texttt{bad}''
\item S2S connections are listened on port 5269
\item All users except admins have traffic limit 1000\,B/s
\item AIM service \texttt{aim.example.org} is connected to port 5233 with
password ``\texttt{aimsecret}''
\item JIT services \texttt{icq.example.org} and \texttt{sms.example.org} are
connected to port 5234 with password ``\texttt{jitsecret}''
\item MSN service \texttt{msn.example.org} is connected to port 5235 with
password ``\texttt{msnsecret}''
\item YAHOO service \texttt{yahoo.example.org} is connected to port 5236 with
password ``\texttt{yahoosecret}''
\item ILE service \texttt{ile.example.org} is connected to port 5237 with
password ``\texttt{ilesecret}''
\end{itemize}
\begin{verbatim}
{acl, blocked, {user, "bad"}}.
{access, c2s, [{deny, blocked},
@ -449,17 +461,64 @@ except admins have traffic limit 1000\,b/s.
{shaper, normal, {maxrate, 1000}}.
{access, c2s_shaper, [{none, admin},
{normal, all}]}.
{listen, [{5222, ejabberd_c2s, [{access, c2s},
{shaper, c2s_shaper}]},
{5223, ejabberd_c2s, [{access, c2s},
ssl, {certfile, "/path/to/ssl.pem"}]},
{5269, ejabberd_s2s_in, []},
{8888, ejabberd_service,
[{hosts, ["conference.example.org"], [{password, "secret"}]}]}
]}.
{listen,
[{5222, ejabberd_c2s, [{access, c2s}, {shaper, c2s_shaper}]},
{5223, ejabberd_c2s, [{access, c2s},
ssl, {certfile, "/path/to/ssl.pem"}]},
{5269, ejabberd_s2s_in, []},
{5233, ejabberd_service, [{host, "aim.example.org",
[{password, "aimsecret"}]}]},
{5234, ejabberd_service, [{hosts, ["icq.example.org", "sms.example.org"],
[{password, "jitsecret"}]}]},
{5235, ejabberd_service, [{host, "msn.example.org",
[{password, "msnsecret"}]}]},
{5236, ejabberd_service, [{host, "yahoo.example.org",
[{password, "yahoosecret"}]}]},
{5237, ejabberd_service, [{host, "gg.example.org",
[{password, "ggsecret"}]}]},
{5238, ejabberd_service, [{host, "ile.example.org",
[{password, "ilesecret"}]}]}
]
}.
\end{verbatim}
Note, that for jabberd14- or wpjabberd-based services you need to make the
transports log and do xdb by themselves:
\begin{verbatim}
<!--
You need to add elogger and rlogger entries here when using ejabberd.
In this case the transport will do the logging.
-->
<log id='elogger'>
<host/>
<logtype/>
<format>%d: [%t] (%h): %s</format>
<file>/var/log/jabber/error/aim-t.log</file>
</log>
<log id='rlogger'>
<host/>
<logtype>record</logtype>
<format>%d %h %s</format>
<file>/var/log/jabber/record/aim-t.log</file>
</log>
<!--
Some Jabber server implementations do not provide
XDB services (for example jabberd 2.0 and ejabberd).
AIM-t is loaded into handle all XDB requests.
-->
<xdb id="xdb">
<host/>
<load>
<xdb_file>/usr/lib/jabber/xdb_file.so</xdb_file> <!-- this is a lib of wpjabber or jabberd -->
</load>
<xdb_file xmlns="jabber:config:xdb_file">
<spool><jabberd:cmdline flag='s'>/var/spool/jabber</jabberd:cmdline></spool>
</xdb_file>
</xdb>
\end{verbatim}
\subsubsection{Modules}

View File

@ -91,8 +91,9 @@
[{5222, ejabberd_c2s, [{access, c2s}, {shaper, c2s_shaper}]},
{5223, ejabberd_c2s, [{access, c2s}, ssl, {certfile, "./ssl.pem"}]},
{5269, ejabberd_s2s_in, [{shaper, s2s_shaper}]},
{5280, ejabberd_http, [http_poll, web_admin]},
{8888, ejabberd_service, [{access, all},
{hosts, ["conference.e.localhost", "muc.e.localhost"],
{hosts, ["icq.localhost", "sms.localhost"],
[{password, "secret"}]}]}
]}.

View File

@ -25,7 +25,9 @@
request_path,
request_auth,
request_content_length,
request_lang = "en"
request_lang = "en",
use_http_poll = false,
use_web_admin = false
}).
@ -49,9 +51,15 @@ start_link({SockMod, Socket}, Opts) ->
ssl ->
ssl:setopts(Socket, [{packet, http}, {recbuf, 8192}])
end,
UseHTTPPoll = lists:member(http_poll, Opts),
UseWebAdmin = lists:member(web_admin, Opts),
io:format("S: ~p~n", [{UseHTTPPoll, UseWebAdmin}]),
{ok, proc_lib:spawn_link(ejabberd_http,
receive_headers,
[#state{sockmod = SockMod, socket = Socket}])}.
[#state{sockmod = SockMod,
socket = Socket,
use_http_poll = UseHTTPPoll,
use_web_admin = UseWebAdmin}])}.
send_text(State, Text) ->
@ -93,7 +101,10 @@ receive_headers(State) ->
ssl ->
ssl:setopts(Socket, [{packet, http}])
end,
receive_headers(#state{sockmod = SockMod, socket = Socket});
receive_headers(#state{sockmod = SockMod,
socket = Socket,
use_http_poll = State#state.use_http_poll,
use_web_admin = State#state.use_web_admin});
{error, _Reason} ->
ok;
_ ->
@ -105,7 +116,9 @@ receive_headers(State) ->
process_request(#state{request_method = 'GET',
request_path = {abs_path, Path},
request_auth = Auth,
request_lang = Lang}) ->
request_lang = Lang,
use_http_poll = UseHTTPPoll,
use_web_admin = UseWebAdmin}) ->
User = case Auth of
{U, P} ->
case ejabberd_auth:check_password(U, P) of
@ -136,7 +149,10 @@ process_request(#state{request_method = 'GET',
q = LQuery,
user = User,
lang = Lang},
case ejabberd_web:process_get(Request) of
io:format("~p~n", [{{UseHTTPPoll, UseWebAdmin},
Request}]),
case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},
Request) of
El when element(1, El) == xmlelement ->
make_xhtml_output(200, [], El);
{Status, Headers, El} when
@ -157,7 +173,10 @@ process_request(#state{request_method = 'POST',
request_content_length = Len,
request_lang = Lang,
sockmod = SockMod,
socket = Socket} = State) when is_integer(Len) ->
socket = Socket,
use_http_poll = UseHTTPPoll,
use_web_admin = UseWebAdmin} = State)
when is_integer(Len) ->
User = case Auth of
{U, P} ->
case ejabberd_auth:check_password(U, P) of
@ -197,7 +216,8 @@ process_request(#state{request_method = 'POST',
user = User,
data = Data,
lang = Lang},
case ejabberd_web:process_get(Request) of
case ejabberd_web:process_get({UseHTTPPoll, UseWebAdmin},
Request) of
El when element(1, El) == xmlelement ->
make_xhtml_output(200, [], El);
{Status, Headers, El} when

View File

@ -12,7 +12,7 @@
%% External exports
-export([make_xhtml/1,
process_get/1]).
process_get/2]).
-include("ejabberd.hrl").
-include("jlib.hrl").
@ -49,7 +49,8 @@ make_xhtml(Els) ->
{"value", Value}])).
process_get(#request{user = User,
process_get({_, true},
#request{user = User,
path = ["admin" | RPath],
q = Query,
lang = Lang} = Request) ->
@ -69,13 +70,14 @@ process_get(#request{user = User,
[{xmlcdata, "401 Unauthorized"}]}])}
end;
process_get(#request{user = User,
process_get({true, _},
#request{user = User,
path = ["http-poll" | RPath],
q = Query,
lang = Lang} = Request) ->
ejabberd_http_poll:process_request(Request#request{path = RPath});
process_get(_Request) ->
process_get(_, _Request) ->
{404, [], make_xhtml([?XC("h1", "Not found")])}.

View File

@ -1,7 +1,7 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_web_admin.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net>
%%% Purpose :
%%% Purpose : Administration web interface
%%% Created : 9 Apr 2004 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id$
%%%----------------------------------------------------------------------
@ -543,7 +543,7 @@ process_admin(#request{user = User,
ACLs = lists:flatten(io_lib:format("~p.", [ets:tab2list(acl)])),
make_xhtml([?XCT("h1", "ejabberd ACLs configuration")] ++
case Res of
ok -> [?CT("submited"), ?P];
ok -> [?CT("submitted"), ?P];
error -> [?CT("bad format"), ?P];
nothing -> []
end ++
@ -584,7 +584,7 @@ process_admin(#request{method = Method,
ACLs = lists:keysort(2, ets:tab2list(acl)),
make_xhtml([?XCT("h1", "ejabberd ACLs configuration")] ++
case Res of
ok -> [?CT("submited"), ?P];
ok -> [?CT("submitted"), ?P];
error -> [?CT("bad format"), ?P];
nothing -> []
end ++
@ -651,7 +651,7 @@ process_admin(#request{user = User,
[{{access, '$1', '$2'}}]}])])),
make_xhtml([?XC("h1", "ejabberd access rules configuration")] ++
case Res of
ok -> [?C("submited"), ?P];
ok -> [?C("submitted"), ?P];
error -> [?C("bad format"), ?P];
nothing -> []
end ++
@ -689,7 +689,7 @@ process_admin(#request{method = Method,
[{{access, '$1', '$2'}}]}]),
make_xhtml([?XC("h1", "ejabberd access rules configuration")] ++
case Res of
ok -> [?C("submited"), ?P];
ok -> [?C("submitted"), ?P];
error -> [?C("bad format"), ?P];
nothing -> []
end ++
@ -730,7 +730,7 @@ process_admin(#request{method = Method,
make_xhtml([?XC("h1",
"'" ++ SName ++ "' access rule configuration")] ++
case Res of
ok -> [?C("submited"), ?P];
ok -> [?C("submitted"), ?P];
error -> [?C("bad format"), ?P];
nothing -> []
end ++
@ -1103,7 +1103,7 @@ user_info(User, Query, Lang) ->
?INPUTT("submit", "chpassword", "Change Password")],
[?XC("h1", "User: " ++ User)] ++
case Res of
ok -> [?C("submited"), ?P];
ok -> [?C("submitted"), ?P];
error -> [?C("bad format"), ?P];
nothing -> []
end ++
@ -1174,12 +1174,23 @@ search_running_node(SNode, [Node | Nodes]) ->
end.
get_node(Node, [], Query, Lang) ->
[?XC("h1", "Node: " ++ atom_to_list(Node)),
?XE("ul",
[?LI([?ACT("db/", "DB Management")]),
?LI([?ACT("backup/", "Backup Management")]),
?LI([?ACT("statistics/", "Statistics")])
])];
Res = node_parse_query(Node, Query),
[?XC("h1", "Node: " ++ atom_to_list(Node))] ++
case Res of
ok -> [?C("submitted"), ?P];
error -> [?C("bad format"), ?P];
nothing -> []
end ++
[?XE("ul",
[?LI([?ACT("db/", "DB Management")]),
?LI([?ACT("backup/", "Backup Management")]),
?LI([?ACT("stats/", "Statistics")])
]),
?XAE("form", [{"method", "post"}],
[?INPUTT("submit", "restart", "Restart"),
?C(" "),
?INPUTT("submit", "stop", "Stop")])
];
get_node(Node, ["db"], Query, Lang) ->
case rpc:call(Node, mnesia, system_info, [tables]) of
@ -1224,7 +1235,7 @@ get_node(Node, ["db"], Query, Lang) ->
end, STables),
[?XC("h1", "DB Tables at " ++ atom_to_list(Node))] ++
case Res of
ok -> [?C("submited"), ?P];
ok -> [?C("submitted"), ?P];
error -> [?C("bad format"), ?P];
nothing -> []
end ++
@ -1249,6 +1260,7 @@ get_node(Node, ["db"], Query, Lang) ->
end;
get_node(Node, ["backup"], Query, Lang) ->
Res = node_backup_parse_query(Node, Query),
[?XC("h1", "Backup Management at " ++ atom_to_list(Node)),
?XAE("form", [{"method", "post"}],
[?XAE("table", [],
@ -1292,10 +1304,77 @@ get_node(Node, ["backup"], Query, Lang) ->
])
])])];
get_node(Node, ["stats"], Query, Lang) ->
UpTime = rpc:call(Node, erlang, statistics, [wall_clock]),
UpTimeS = io_lib:format("~.3f", [element(1, UpTime)/1000]),
CPUTime = rpc:call(Node, erlang, statistics, [runtime]),
CPUTimeS = io_lib:format("~.3f", [element(1, CPUTime)/1000]),
Users = length(
rpc:call(Node, ejabberd_sm, dirty_get_my_sessions_list, [])),
TransactionsCommited =
rpc:call(Node, mnesia, system_info, [transaction_commits]),
TransactionsAborted =
rpc:call(Node, mnesia, system_info, [transaction_failures]),
TransactionsRestarted =
rpc:call(Node, mnesia, system_info, [transaction_restarts]),
TransactionsLogged =
rpc:call(Node, mnesia, system_info, [transaction_log_writes]),
[?XC("h1", atom_to_list(Node) ++ " statistics"),
?XAE("table", [],
[?XE("tbody",
[?XE("tr", [?XCT("td", "Uptime"),
?XAC("td", [{"class", "alignright"}],
UpTimeS)]),
?XE("tr", [?XCT("td", "CPU Time"),
?XAC("td", [{"class", "alignright"}],
CPUTimeS)]),
?XE("tr", [?XCT("td", "Authentificated users"),
?XAC("td", [{"class", "alignright"}],
integer_to_list(Users))]),
?XE("tr", [?XCT("td", "Transactions commited"),
?XAC("td", [{"class", "alignright"}],
integer_to_list(TransactionsCommited))]),
?XE("tr", [?XCT("td", "Transactions aborted"),
?XAC("td", [{"class", "alignright"}],
integer_to_list(TransactionsAborted))]),
?XE("tr", [?XCT("td", "Transactions restarted"),
?XAC("td", [{"class", "alignright"}],
integer_to_list(TransactionsRestarted))]),
?XE("tr", [?XCT("td", "Transactions logged"),
?XAC("td", [{"class", "alignright"}],
integer_to_list(TransactionsLogged))])
])
])];
get_node(Node, NPath, Query, Lang) ->
[?XC("h1", "Not found")].
node_parse_query(Node, Query) ->
case lists:keysearch("restart", 1, Query) of
{value, _} ->
case rpc:call(Node, init, restart, []) of
{badrpc, _Reason} ->
error;
_ ->
ok
end;
_ ->
case lists:keysearch("delete", 1, Query) of
{value, _} ->
case rpc:call(Node, init, restart, []) of
{badrpc, _Reason} ->
error;
_ ->
ok
end;
_ ->
nothing
end
end.
db_storage_select(ID, Opt, Lang) ->
?XAE("select", [{"name", "table" ++ ID}],
lists:map(
@ -1345,3 +1424,49 @@ node_db_parse_query(Node, Tables, Query) ->
end, Tables),
ok.
node_backup_parse_query(Node, Query) ->
lists:foldl(
fun(Action, nothing) ->
case lists:keysearch(Action, 1, Query) of
{value, _} ->
case lists:keysearch(Action ++ "path", 1, Query) of
{value, {_, Path}} ->
Res =
case Action of
"store" ->
rpc:call(Node, mnesia,
backup, [Path]);
"restore" ->
rpc:call(Node, mnesia,
restore,
[Path, [{default_op,
keep_tables}]]);
"fallback" ->
rpc:call(Node, mnesia,
install_fallback, [Path]);
"dump" ->
rpc:call(Node, mnesia,
dump_to_textfile, [Path]);
"load" ->
rpc:call(Node, mnesia,
load_textfile, [Path])
end,
case Res of
{error, _Reason} ->
error;
{badrpc, _Reason} ->
error;
_ ->
ok
end;
_ ->
error
end;
_ ->
nothing
end;
(_Action, Res) ->
Res
end, nothing, ["store", "restore", "fallback", "dump", "load"]).