mirror of
https://github.com/processone/ejabberd.git
synced 2024-12-24 17:29:28 +01:00
* doc/dev.tex: Developers documentation (not completed)
* src/ejabberd_c2s.erl: Better handling of malformed JIDs * src/mod_register.erl (try_register/2): Now returns "jid malformed" error if user name is invalid SVN Revision: 174
This commit is contained in:
parent
b18ed05e92
commit
c248bffd54
11
ChangeLog
11
ChangeLog
@ -1,3 +1,12 @@
|
||||
2003-11-11 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* doc/dev.tex: Developers documentation (not completed)
|
||||
|
||||
* src/ejabberd_c2s.erl: Better handling of malformed JIDs
|
||||
|
||||
* src/mod_register.erl (try_register/2): Now returns "jid
|
||||
malformed" error if user name is invalid
|
||||
|
||||
2003-11-10 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
* src/ejabberd.cfg.example: Updated
|
||||
@ -11,7 +20,7 @@
|
||||
|
||||
* src/mod_muc/mod_muc_room.erl: Bugfix
|
||||
|
||||
* src/ejabberd_sm.erl (route_message): Bugfix
|
||||
* src/ejabberd_sm.erl (route_message/3): Bugfix
|
||||
|
||||
2003-11-09 Alexey Shchepin <alexey@sevcom.net>
|
||||
|
||||
|
364
doc/dev.html
Normal file
364
doc/dev.html
Normal file
@ -0,0 +1,364 @@
|
||||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
|
||||
"http://www.w3.org/TR/REC-html40/loose.dtd">
|
||||
<HTML>
|
||||
<HEAD><TITLE>Ejabberd Developers Guide</TITLE>
|
||||
|
||||
<META http-equiv="Content-Type" content="text/html; charset=ISO8859-1">
|
||||
<META name="GENERATOR" content="hevea 1.06">
|
||||
</HEAD>
|
||||
<BODY >
|
||||
<!--HEVEA command line is: /usr/bin/hevea -charset ISO8859-1 dev.tex -->
|
||||
<!--HTMLHEAD-->
|
||||
<!--ENDHTML-->
|
||||
<!--PREFIX <ARG ></ARG>-->
|
||||
<!--CUT DEF section 1 -->
|
||||
|
||||
|
||||
|
||||
<H1 ALIGN=center>Ejabberd Developers Guide</H1>
|
||||
|
||||
<H3 ALIGN=center>Alexey Shchepin<BR>
|
||||
<A HREF="mailto:alexey@sevcom.net"><TT>mailto:alexey@sevcom.net</TT></A><BR>
|
||||
<A HREF="xmpp:aleksey@jabber.ru"><TT>xmpp:aleksey@jabber.ru</TT></A></H3>
|
||||
|
||||
<H3 ALIGN=center>September 10, 2003</H3><DIV ALIGN=center>
|
||||
|
||||
<IMG SRC="logo.png">
|
||||
|
||||
|
||||
</DIV><BR>
|
||||
<BR>
|
||||
|
||||
|
||||
<!--TOC section Table of Contents-->
|
||||
|
||||
<H2>Table of Contents</H2><!--SEC END -->
|
||||
|
||||
<UL><LI>
|
||||
<A HREF="#htoc1">1 Introduction</A>
|
||||
<UL><LI>
|
||||
<A HREF="#htoc2">1.1 How it works</A>
|
||||
<UL><LI>
|
||||
<A HREF="#htoc3">1.1.1 Router</A>
|
||||
<LI><A HREF="#htoc4">1.1.2 Local Router</A>
|
||||
<LI><A HREF="#htoc5">1.1.3 Session Manager</A>
|
||||
<LI><A HREF="#htoc6">1.1.4 S2S Manager</A>
|
||||
</UL>
|
||||
</UL>
|
||||
<LI><A HREF="#htoc7">2 XML representation</A>
|
||||
<LI><A HREF="#htoc8">3 Module <TT>xml</TT></A>
|
||||
<LI><A HREF="#htoc9">4 <TT>ejabberd</TT> modules</A>
|
||||
<UL><LI>
|
||||
<A HREF="#htoc10">4.1 <CODE>gen_mod</CODE> behaviour</A>
|
||||
<LI><A HREF="#htoc11">4.2 Module <CODE>gen_iq_handler</CODE></A>
|
||||
<LI><A HREF="#htoc12">4.3 Services</A>
|
||||
</UL>
|
||||
</UL>
|
||||
|
||||
<!--TOC section Introduction-->
|
||||
|
||||
<H2><A NAME="htoc1">1</A> Introduction</H2><!--SEC END -->
|
||||
|
||||
<A NAME="sec:intro"></A>
|
||||
<TT>ejabberd</TT> is a Free and Open Source fault-tolerant distributed Jabber
|
||||
server. It is writen mostly in Erlang.<BR>
|
||||
<BR>
|
||||
The main features of <TT>ejabberd</TT> is:
|
||||
<UL><LI>
|
||||
Works on most of popular platforms: *nix (tested on Linux and FreeBSD)
|
||||
and Win32
|
||||
<LI>Distributed: You can run <TT>ejabberd</TT> on a cluster of machines and all of
|
||||
them will serve one Jabber domain.
|
||||
<LI>Fault-tolerance: You can setup an <TT>ejabberd</TT> cluster so that all the
|
||||
information required for a properly working service will be stored
|
||||
permanently on more than one node. This means that if one of the nodes
|
||||
crashes, then the others will continue working without disruption.
|
||||
You can also add or replace more nodes ``on the fly''.
|
||||
<LI>Built-in <A HREF="http://www.jabber.org/jeps/jep-0045.html">Multi-User
|
||||
Chat</A> service
|
||||
<LI>Built-in IRC transport
|
||||
<LI>Built-in
|
||||
<A HREF="http://www.jabber.org/jeps/jep-0060.html">Publish-Subscribe</A>
|
||||
service
|
||||
<LI>Built-in Jabber Users Directory service based on users vCards
|
||||
<LI>Support for
|
||||
<A HREF="http://www.jabber.org/jeps/jep-0030.html">JEP-0030</A>
|
||||
(Service Discovery).
|
||||
<LI>Support for
|
||||
<A HREF="http://www.jabber.org/jeps/jep-0039.html">JEP-0039</A>
|
||||
(Statistics Gathering).
|
||||
<LI>Support for <TT>xml:lang</TT> attribute in many XML elements
|
||||
</UL>
|
||||
<!--TOC subsection How it works-->
|
||||
|
||||
<H3><A NAME="htoc2">1.1</A> How it works</H3><!--SEC END -->
|
||||
|
||||
<A NAME="sec:howitworks"></A>
|
||||
A Jabber domain is served by one or more <TT>ejabberd</TT> nodes. These nodes can
|
||||
be run on different machines that are connected via a network. They all must
|
||||
have the ability to connect to port 4369 of all another nodes, and must have
|
||||
the same magic cookie (see Erlang/OTP documentation, in other words the file
|
||||
<TT>~ejabberd/.erlang.cookie</TT> must be the same on all nodes). This is
|
||||
needed because all nodes exchange information about connected users, S2S
|
||||
connections, registered services, etc...<BR>
|
||||
<BR>
|
||||
Each <TT>ejabberd</TT> node have following modules:
|
||||
<UL><LI>
|
||||
router;
|
||||
<LI>local router.
|
||||
<LI>session manager;
|
||||
<LI>S2S manager;
|
||||
</UL>
|
||||
<!--TOC subsubsection Router-->
|
||||
|
||||
<H4><A NAME="htoc3">1.1.1</A> Router</H4><!--SEC END -->
|
||||
|
||||
This module is the main router of Jabber packets on each node. It routes
|
||||
them based on their destinations domains. It has two tables: local and global
|
||||
routes. First, domain of packet destination searched in local table, and if it
|
||||
found, then the packet is routed to appropriate process. If no, then it
|
||||
searches in global table, and is routed to the appropriate <TT>ejabberd</TT> node or
|
||||
process. If it does not exists in either tables, then it sent to the S2S
|
||||
manager.<BR>
|
||||
<BR>
|
||||
<!--TOC subsubsection Local Router-->
|
||||
|
||||
<H4><A NAME="htoc4">1.1.2</A> Local Router</H4><!--SEC END -->
|
||||
|
||||
This module routes packets which have a destination domain equal to this server
|
||||
name. If destination JID has a non-empty user part, then it routed to the
|
||||
session manager, else it is processed depending on it's content.<BR>
|
||||
<BR>
|
||||
<!--TOC subsubsection Session Manager-->
|
||||
|
||||
<H4><A NAME="htoc5">1.1.3</A> Session Manager</H4><!--SEC END -->
|
||||
|
||||
This module routes packets to local users. It searches for what user resource
|
||||
packet must be sended via presence table. If this resource is connected to
|
||||
this node, it is routed to C2S process, if it connected via another node, then
|
||||
the packet is sent to session manager on that node.<BR>
|
||||
<BR>
|
||||
<!--TOC subsubsection S2S Manager-->
|
||||
|
||||
<H4><A NAME="htoc6">1.1.4</A> S2S Manager</H4><!--SEC END -->
|
||||
|
||||
This module routes packets to other Jabber servers. First, it checks if an
|
||||
open S2S connection from the domain of the packet source to the domain of
|
||||
packet destination already exists. If it is open on another node, then it
|
||||
routes the packet to S2S manager on that node, if it is open on this node, then
|
||||
it is routed to the process that serves this connection, and if a connection
|
||||
does not exist, then it is opened and registered.<BR>
|
||||
<BR>
|
||||
<!--TOC section XML representation-->
|
||||
|
||||
<H2><A NAME="htoc7">2</A> XML representation</H2><!--SEC END -->
|
||||
|
||||
<A NAME="sec:xmlrepr"></A>
|
||||
Each XML stanza represented as following tuple:
|
||||
<PRE>
|
||||
XMLElement = {xmlelement, Name, Attrs, [ElementOrCDATA]}
|
||||
Name = string()
|
||||
Attrs = [Attr]
|
||||
Attr = {Key, Val}
|
||||
Key = string()
|
||||
Val = string()
|
||||
ElementOrCDATA = XMLElement | CDATA
|
||||
CDATA = {xmlcdata, string()}
|
||||
</PRE>E. g. this stanza:
|
||||
<PRE>
|
||||
<message to='test@conference.e.localhost' type='groupchat'>
|
||||
<body>test</body>
|
||||
</message>
|
||||
</PRE>represented as following structure:
|
||||
<PRE>
|
||||
{xmlelement, "message",
|
||||
[{"to", "test@conference.e.localhost"},
|
||||
{"type", "groupchat"}],
|
||||
[{xmlelement, "body",
|
||||
[],
|
||||
[{xmlcdata, "test"}]}]}}
|
||||
</PRE>
|
||||
<!--TOC section Module <TT>xml</TT>-->
|
||||
|
||||
<H2><A NAME="htoc8">3</A> Module <TT>xml</TT></H2><!--SEC END -->
|
||||
|
||||
<A NAME="sec:xmlmod"></A>
|
||||
<DL COMPACT=compact><DT>
|
||||
<CODE><B>element_to_string(El) -> string()</B></CODE><DD>
|
||||
<PRE>
|
||||
El = XMLElement
|
||||
</PRE>Returns string representation of XML stanza <TT>El</TT>.<BR>
|
||||
<BR>
|
||||
<DT><CODE><B>crypt(S) -> string()</B></CODE><DD>
|
||||
<PRE>
|
||||
S = string()
|
||||
</PRE>Returns string which correspond to <TT>S</TT> with encoded XML special
|
||||
characters.<BR>
|
||||
<BR>
|
||||
<DT><CODE><B>remove_cdata(ECList) -> EList</B></CODE><DD>
|
||||
<PRE>
|
||||
ECList = [ElementOrCDATA]
|
||||
EList = [XMLElement]
|
||||
</PRE><TT>EList</TT> is a list of all non-CDATA elements of ECList.<BR>
|
||||
<BR>
|
||||
<DT><CODE><B>get_path_s(El, Path) -> Res</B></CODE><DD>
|
||||
<PRE>
|
||||
El = XMLElement
|
||||
Path = [PathItem]
|
||||
PathItem = PathElem | PathAttr | PathCDATA
|
||||
PathElem = {elem, Name}
|
||||
PathAttr = {attr, Name}
|
||||
PathCDATA = cdata
|
||||
Name = string()
|
||||
Res = string() | XMLElement
|
||||
</PRE>If <TT>Path</TT> is empty, then returns <TT>El</TT>. Else sequentially
|
||||
consider elements of <TT>Path</TT>. Each element is one of:
|
||||
<DL COMPACT=compact><DT>
|
||||
<CODE><B>{elem, Name}</B></CODE><DD> <TT>Name</TT> is name of subelement of
|
||||
<TT>El</TT>, if such element exists, then this element considered in
|
||||
following steps, else returns empty string.
|
||||
<DT><CODE><B>{attr, Name}</B></CODE><DD> If <TT>El</TT> have attribute <TT>Name</TT>, then
|
||||
returns value of this attribute, else returns empty string.
|
||||
<DT><CODE><B>cdata</B></CODE><DD> Returns CDATA of <TT>El</TT>.
|
||||
</DL><BR>
|
||||
<BR>
|
||||
<DT><B>TODO:</B><DD>
|
||||
<PRE>
|
||||
get_cdata/1, get_tag_cdata/1
|
||||
get_attr/2, get_attr_s/2
|
||||
get_tag_attr/2, get_tag_attr_s/2
|
||||
get_subtag/2
|
||||
</PRE></DL>
|
||||
<!--TOC section <TT>ejabberd</TT> modules-->
|
||||
|
||||
<H2><A NAME="htoc9">4</A> <TT>ejabberd</TT> modules</H2><!--SEC END -->
|
||||
|
||||
<A NAME="sec:emods"></A>
|
||||
<!--TOC subsection <CODE>gen_mod</CODE> behaviour-->
|
||||
|
||||
<H3><A NAME="htoc10">4.1</A> <CODE>gen_mod</CODE> behaviour</H3><!--SEC END -->
|
||||
|
||||
<A NAME="sec:genmod"></A>
|
||||
TBD<BR>
|
||||
<BR>
|
||||
<!--TOC subsection Module <CODE>gen_iq_handler</CODE>-->
|
||||
|
||||
<H3><A NAME="htoc11">4.2</A> Module <CODE>gen_iq_handler</CODE></H3><!--SEC END -->
|
||||
|
||||
<A NAME="sec:geniqhandl"></A>
|
||||
The module <CODE>gen_iq_handler</CODE> allows to easily write handlers for IQ packets
|
||||
of particular XML namespaces that addressed to server or to users bare JIDs.<BR>
|
||||
<BR>
|
||||
In this module the following functions are defined:
|
||||
<DL COMPACT=compact><DT>
|
||||
<CODE><B>add_iq_handler(Component, NS, Module, Function, Type)</B></CODE><DD>
|
||||
<PRE>
|
||||
Component = Module = Function = atom()
|
||||
NS = string()
|
||||
Type = no_queue | one_queue | parallel
|
||||
</PRE>Registers function <CODE>Module:Function</CODE> as handler for IQ packets that
|
||||
contain child of namespace <CODE>NS</CODE> in <CODE>Component</CODE>. Queueing
|
||||
discipline is <CODE>Type</CODE>. There are at least two components defined:
|
||||
<DL COMPACT=compact><DT>
|
||||
<CODE><B>ejabberd_local</B></CODE><DD> Handles packets that addressed to server JID;
|
||||
<DT><CODE><B>ejabberd_sm</B></CODE><DD> Handles packets that addressed to users bare JIDs.
|
||||
</DL>
|
||||
<DT><CODE><B>remove_iq_handler(Component, NS)</B></CODE><DD>
|
||||
<PRE>
|
||||
Component = atom()
|
||||
NS = string()
|
||||
</PRE>Removes IQ handler for namespace <CODE>NS</CODE> from <CODE>Component</CODE>.
|
||||
</DL>
|
||||
Handler function must have the following type:
|
||||
<DL COMPACT=compact><DT>
|
||||
<CODE><B>Module:Function(From, To, IQ)</B></CODE><DD>
|
||||
<PRE>
|
||||
From = To = jid()
|
||||
</PRE></DL>
|
||||
<PRE>
|
||||
-module(mod_cputime).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/1,
|
||||
stop/0,
|
||||
process_local_iq/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-define(NS_CPUTIME, "ejabberd:cputime").
|
||||
|
||||
start(Opts) ->
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_CPUTIME,
|
||||
?MODULE, process_local_iq, IQDisc).
|
||||
|
||||
stop() ->
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_CPUTIME).
|
||||
|
||||
process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
|
||||
case Type of
|
||||
set ->
|
||||
{iq, ID, error, XMLNS,
|
||||
[SubEl, ?ERR_NOT_ALLOWED]};
|
||||
get ->
|
||||
CPUTime = element(1, erlang:statistics(runtime))/1000,
|
||||
SCPUTime = lists:flatten(io_lib:format("~.3f", CPUTime)),
|
||||
{iq, ID, result, XMLNS,
|
||||
[{xmlelement, "query",
|
||||
[{"xmlns", ?NS_CPUTIME}],
|
||||
[{xmlelement, "cputime", [], [{xmlcdata, SCPUTime}]}]}]}
|
||||
end.
|
||||
</PRE>
|
||||
<!--TOC subsection Services-->
|
||||
|
||||
<H3><A NAME="htoc12">4.3</A> Services</H3><!--SEC END -->
|
||||
|
||||
<A NAME="sec:services"></A>
|
||||
TBD<BR>
|
||||
<BR>
|
||||
TODO: use <CODE>proc_lib</CODE>
|
||||
<PRE>
|
||||
-module(mod_echo).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/1, init/1, stop/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
start(Opts) ->
|
||||
Host = gen_mod:get_opt(host, Opts, "echo." ++ ?MYNAME),
|
||||
register(ejabberd_mod_echo, spawn(?MODULE, init, [Host])).
|
||||
|
||||
init(Host) ->
|
||||
ejabberd_router:register_local_route(Host),
|
||||
loop(Host).
|
||||
|
||||
loop(Host) ->
|
||||
receive
|
||||
{route, From, To, Packet} ->
|
||||
ejabberd_router:route(To, From, Packet),
|
||||
loop(Host);
|
||||
stop ->
|
||||
ejabberd_router:unregister_local_route(Host),
|
||||
ok;
|
||||
_ ->
|
||||
loop(Host)
|
||||
end.
|
||||
|
||||
stop() ->
|
||||
ejabberd_mod_echo ! stop,
|
||||
ok.
|
||||
</PRE>
|
||||
<!--HTMLFOOT-->
|
||||
<!--ENDHTML-->
|
||||
<!--FOOTER-->
|
||||
<HR SIZE=2>
|
||||
<BLOCKQUOTE><EM>This document was translated from L<sup>A</sup>T<sub>E</sub>X by
|
||||
</EM><A HREF="http://pauillac.inria.fr/~maranget/hevea/index.html"><EM>H<FONT SIZE=2><sup>E</sup></FONT>V<FONT SIZE=2><sup>E</sup></FONT>A</EM></A><EM>.
|
||||
</EM></BLOCKQUOTE>
|
||||
</BODY>
|
||||
</HTML>
|
378
doc/dev.tex
Normal file
378
doc/dev.tex
Normal file
@ -0,0 +1,378 @@
|
||||
\documentclass[10pt]{article}
|
||||
|
||||
\usepackage{graphics}
|
||||
\usepackage{hevea}
|
||||
\usepackage{verbatim}
|
||||
|
||||
|
||||
\newcommand{\logoscale}{0.7}
|
||||
\newcommand{\imgscale}{0.58}
|
||||
\newcommand{\insimg}[1]{\insscaleimg{\imgscale}{#1}}
|
||||
|
||||
\newcommand{\insscaleimg}[2]{
|
||||
\imgsrc{#2}{}
|
||||
\begin{latexonly}
|
||||
\scalebox{#1}{\includegraphics{#2}}
|
||||
\end{latexonly}
|
||||
}
|
||||
|
||||
\newcommand{\ns}[1]{\texttt{#1}}
|
||||
\newcommand{\ejabberd}{\texttt{ejabberd}}
|
||||
\newcommand{\Jabber}{Jabber}
|
||||
|
||||
\newcommand{\modregister}{\texttt{mod\_register}}
|
||||
\newcommand{\modroster}{\texttt{mod\_roster}}
|
||||
\newcommand{\modconfigure}{\texttt{mod\_configure}}
|
||||
\newcommand{\moddisco}{\texttt{mod\_disco}}
|
||||
\newcommand{\modstats}{\texttt{mod\_stats}}
|
||||
\newcommand{\modvcard}{\texttt{mod\_vcard}}
|
||||
\newcommand{\modoffline}{\texttt{mod\_offline}}
|
||||
\newcommand{\modecho}{\texttt{mod\_echo}}
|
||||
\newcommand{\modprivate}{\texttt{mod\_private}}
|
||||
\newcommand{\modtime}{\texttt{mod\_time}}
|
||||
\newcommand{\modversion}{\texttt{mod\_version}}
|
||||
c
|
||||
%\setcounter{tocdepth}{3}
|
||||
|
||||
|
||||
\title{Ejabberd Developers Guide}
|
||||
\author{Alexey Shchepin \\
|
||||
\ahrefurl{mailto:alexey@sevcom.net} \\
|
||||
\ahrefurl{xmpp:aleksey@jabber.ru}}
|
||||
\date{September 10, 2003}
|
||||
|
||||
\begin{document}
|
||||
\begin{titlepage}
|
||||
\maketitle{}
|
||||
|
||||
{\centering
|
||||
\insscaleimg{\logoscale}{logo.png}
|
||||
\par
|
||||
}
|
||||
\end{titlepage}
|
||||
%\newpage
|
||||
\tableofcontents{}
|
||||
|
||||
\newpage
|
||||
\section{Introduction}
|
||||
\label{sec:intro}
|
||||
|
||||
\ejabberd{} is a Free and Open Source fault-tolerant distributed \Jabber{}
|
||||
server. It is writen mostly in Erlang.
|
||||
|
||||
The main features of \ejabberd{} is:
|
||||
\begin{itemize}
|
||||
\item Works on most of popular platforms: *nix (tested on Linux and FreeBSD)
|
||||
and Win32
|
||||
\item Distributed: You can run \ejabberd{} on a cluster of machines and all of
|
||||
them will serve one Jabber domain.
|
||||
\item Fault-tolerance: You can setup an \ejabberd{} cluster so that all the
|
||||
information required for a properly working service will be stored
|
||||
permanently on more than one node. This means that if one of the nodes
|
||||
crashes, then the others will continue working without disruption.
|
||||
You can also add or replace more nodes ``on the fly''.
|
||||
\item Built-in \footahref{http://www.jabber.org/jeps/jep-0045.html}{Multi-User
|
||||
Chat} service
|
||||
\item Built-in IRC transport
|
||||
\item Built-in
|
||||
\footahref{http://www.jabber.org/jeps/jep-0060.html}{Publish-Subscribe}
|
||||
service
|
||||
\item Built-in Jabber Users Directory service based on users vCards
|
||||
\item Support for
|
||||
\footahref{http://www.jabber.org/jeps/jep-0030.html}{JEP-0030}
|
||||
(Service Discovery).
|
||||
\item Support for
|
||||
\footahref{http://www.jabber.org/jeps/jep-0039.html}{JEP-0039}
|
||||
(Statistics Gathering).
|
||||
\item Support for \ns{xml:lang} attribute in many XML elements
|
||||
\end{itemize}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
\subsection{How it works}
|
||||
\label{sec:howitworks}
|
||||
|
||||
|
||||
|
||||
A \Jabber{} domain is served by one or more \ejabberd{} nodes. These nodes can
|
||||
be run on different machines that are connected via a network. They all must
|
||||
have the ability to connect to port 4369 of all another nodes, and must have
|
||||
the same magic cookie (see Erlang/OTP documentation, in other words the file
|
||||
\texttt{\~{}ejabberd/.erlang.cookie} must be the same on all nodes). This is
|
||||
needed because all nodes exchange information about connected users, S2S
|
||||
connections, registered services, etc\ldots
|
||||
|
||||
|
||||
|
||||
Each \ejabberd{} node have following modules:
|
||||
\begin{itemize}
|
||||
\item router;
|
||||
\item local router.
|
||||
\item session manager;
|
||||
\item S2S manager;
|
||||
\end{itemize}
|
||||
|
||||
|
||||
\subsubsection{Router}
|
||||
|
||||
This module is the main router of \Jabber{} packets on each node. It routes
|
||||
them based on their destinations domains. It has two tables: local and global
|
||||
routes. First, domain of packet destination searched in local table, and if it
|
||||
found, then the packet is routed to appropriate process. If no, then it
|
||||
searches in global table, and is routed to the appropriate \ejabberd{} node or
|
||||
process. If it does not exists in either tables, then it sent to the S2S
|
||||
manager.
|
||||
|
||||
|
||||
\subsubsection{Local Router}
|
||||
|
||||
This module routes packets which have a destination domain equal to this server
|
||||
name. If destination JID has a non-empty user part, then it routed to the
|
||||
session manager, else it is processed depending on it's content.
|
||||
|
||||
|
||||
\subsubsection{Session Manager}
|
||||
|
||||
This module routes packets to local users. It searches for what user resource
|
||||
packet must be sended via presence table. If this resource is connected to
|
||||
this node, it is routed to C2S process, if it connected via another node, then
|
||||
the packet is sent to session manager on that node.
|
||||
|
||||
|
||||
\subsubsection{S2S Manager}
|
||||
|
||||
This module routes packets to other \Jabber{} servers. First, it checks if an
|
||||
open S2S connection from the domain of the packet source to the domain of
|
||||
packet destination already exists. If it is open on another node, then it
|
||||
routes the packet to S2S manager on that node, if it is open on this node, then
|
||||
it is routed to the process that serves this connection, and if a connection
|
||||
does not exist, then it is opened and registered.
|
||||
|
||||
|
||||
|
||||
|
||||
\section{XML representation}
|
||||
\label{sec:xmlrepr}
|
||||
|
||||
Each XML stanza represented as following tuple:
|
||||
\begin{verbatim}
|
||||
XMLElement = {xmlelement, Name, Attrs, [ElementOrCDATA]}
|
||||
Name = string()
|
||||
Attrs = [Attr]
|
||||
Attr = {Key, Val}
|
||||
Key = string()
|
||||
Val = string()
|
||||
ElementOrCDATA = XMLElement | CDATA
|
||||
CDATA = {xmlcdata, string()}
|
||||
\end{verbatim}
|
||||
E.\,g. this stanza:
|
||||
\begin{verbatim}
|
||||
<message to='test@conference.e.localhost' type='groupchat'>
|
||||
<body>test</body>
|
||||
</message>
|
||||
\end{verbatim}
|
||||
represented as following structure:
|
||||
\begin{verbatim}
|
||||
{xmlelement, "message",
|
||||
[{"to", "test@conference.e.localhost"},
|
||||
{"type", "groupchat"}],
|
||||
[{xmlelement, "body",
|
||||
[],
|
||||
[{xmlcdata, "test"}]}]}}
|
||||
\end{verbatim}
|
||||
|
||||
|
||||
|
||||
\section{Module \texttt{xml}}
|
||||
\label{sec:xmlmod}
|
||||
|
||||
\begin{description}
|
||||
\item[\verb|element_to_string(El) -> string()|]
|
||||
\begin{verbatim}
|
||||
El = XMLElement
|
||||
\end{verbatim}
|
||||
Returns string representation of XML stanza \texttt{El}.
|
||||
|
||||
\item[\verb|crypt(S) -> string()|]
|
||||
\begin{verbatim}
|
||||
S = string()
|
||||
\end{verbatim}
|
||||
Returns string which correspond to \texttt{S} with encoded XML special
|
||||
characters.
|
||||
|
||||
\item[\verb|remove_cdata(ECList) -> EList|]
|
||||
\begin{verbatim}
|
||||
ECList = [ElementOrCDATA]
|
||||
EList = [XMLElement]
|
||||
\end{verbatim}
|
||||
\texttt{EList} is a list of all non-CDATA elements of ECList.
|
||||
|
||||
|
||||
|
||||
\item[\verb|get_path_s(El, Path) -> Res|]
|
||||
\begin{verbatim}
|
||||
El = XMLElement
|
||||
Path = [PathItem]
|
||||
PathItem = PathElem | PathAttr | PathCDATA
|
||||
PathElem = {elem, Name}
|
||||
PathAttr = {attr, Name}
|
||||
PathCDATA = cdata
|
||||
Name = string()
|
||||
Res = string() | XMLElement
|
||||
\end{verbatim}
|
||||
If \texttt{Path} is empty, then returns \texttt{El}. Else sequentially
|
||||
consider elements of \texttt{Path}. Each element is one of:
|
||||
\begin{description}
|
||||
\item[\verb|{elem, Name}|] \texttt{Name} is name of subelement of
|
||||
\texttt{El}, if such element exists, then this element considered in
|
||||
following steps, else returns empty string.
|
||||
\item[\verb|{attr, Name}|] If \texttt{El} have attribute \texttt{Name}, then
|
||||
returns value of this attribute, else returns empty string.
|
||||
\item[\verb|cdata|] Returns CDATA of \texttt{El}.
|
||||
\end{description}
|
||||
|
||||
\item[TODO:]
|
||||
\begin{verbatim}
|
||||
get_cdata/1, get_tag_cdata/1
|
||||
get_attr/2, get_attr_s/2
|
||||
get_tag_attr/2, get_tag_attr_s/2
|
||||
get_subtag/2
|
||||
\end{verbatim}
|
||||
\end{description}
|
||||
|
||||
|
||||
|
||||
|
||||
\section{\ejabberd{} modules}
|
||||
\label{sec:emods}
|
||||
|
||||
|
||||
\subsection{\verb|gen_mod| behaviour}
|
||||
\label{sec:genmod}
|
||||
|
||||
TBD
|
||||
|
||||
\subsection{Module \verb|gen_iq_handler|}
|
||||
\label{sec:geniqhandl}
|
||||
|
||||
The module \verb|gen_iq_handler| allows to easily write handlers for IQ packets
|
||||
of particular XML namespaces that addressed to server or to users bare JIDs.
|
||||
|
||||
In this module the following functions are defined:
|
||||
\begin{description}
|
||||
\item[\verb|add_iq_handler(Component, NS, Module, Function, Type)|]
|
||||
\begin{verbatim}
|
||||
Component = Module = Function = atom()
|
||||
NS = string()
|
||||
Type = no_queue | one_queue | parallel
|
||||
\end{verbatim}
|
||||
Registers function \verb|Module:Function| as handler for IQ packets that
|
||||
contain child of namespace \verb|NS| in \verb|Component|. Queueing
|
||||
discipline is \verb|Type|. There are at least two components defined:
|
||||
\begin{description}
|
||||
\item[\verb|ejabberd_local|] Handles packets that addressed to server JID;
|
||||
\item[\verb|ejabberd_sm|] Handles packets that addressed to users bare JIDs.
|
||||
\end{description}
|
||||
\item[\verb|remove_iq_handler(Component, NS)|]
|
||||
\begin{verbatim}
|
||||
Component = atom()
|
||||
NS = string()
|
||||
\end{verbatim}
|
||||
Removes IQ handler for namespace \verb|NS| from \verb|Component|.
|
||||
\end{description}
|
||||
|
||||
Handler function must have the following type:
|
||||
\begin{description}
|
||||
\item[\verb|Module:Function(From, To, IQ)|]
|
||||
\begin{verbatim}
|
||||
From = To = jid()
|
||||
\end{verbatim}
|
||||
\end{description}
|
||||
|
||||
|
||||
|
||||
\begin{verbatim}
|
||||
-module(mod_cputime).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/1,
|
||||
stop/0,
|
||||
process_local_iq/3]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
-define(NS_CPUTIME, "ejabberd:cputime").
|
||||
|
||||
start(Opts) ->
|
||||
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
|
||||
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_CPUTIME,
|
||||
?MODULE, process_local_iq, IQDisc).
|
||||
|
||||
stop() ->
|
||||
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_CPUTIME).
|
||||
|
||||
process_local_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
|
||||
case Type of
|
||||
set ->
|
||||
{iq, ID, error, XMLNS,
|
||||
[SubEl, ?ERR_NOT_ALLOWED]};
|
||||
get ->
|
||||
CPUTime = element(1, erlang:statistics(runtime))/1000,
|
||||
SCPUTime = lists:flatten(io_lib:format("~.3f", CPUTime)),
|
||||
{iq, ID, result, XMLNS,
|
||||
[{xmlelement, "query",
|
||||
[{"xmlns", ?NS_CPUTIME}],
|
||||
[{xmlelement, "cputime", [], [{xmlcdata, SCPUTime}]}]}]}
|
||||
end.
|
||||
\end{verbatim}
|
||||
|
||||
|
||||
\subsection{Services}
|
||||
\label{sec:services}
|
||||
|
||||
TBD
|
||||
|
||||
|
||||
TODO: use \verb|proc_lib|
|
||||
\begin{verbatim}
|
||||
-module(mod_echo).
|
||||
|
||||
-behaviour(gen_mod).
|
||||
|
||||
-export([start/1, init/1, stop/0]).
|
||||
|
||||
-include("ejabberd.hrl").
|
||||
-include("jlib.hrl").
|
||||
|
||||
start(Opts) ->
|
||||
Host = gen_mod:get_opt(host, Opts, "echo." ++ ?MYNAME),
|
||||
register(ejabberd_mod_echo, spawn(?MODULE, init, [Host])).
|
||||
|
||||
init(Host) ->
|
||||
ejabberd_router:register_local_route(Host),
|
||||
loop(Host).
|
||||
|
||||
loop(Host) ->
|
||||
receive
|
||||
{route, From, To, Packet} ->
|
||||
ejabberd_router:route(To, From, Packet),
|
||||
loop(Host);
|
||||
stop ->
|
||||
ejabberd_router:unregister_local_route(Host),
|
||||
ok;
|
||||
_ ->
|
||||
loop(Host)
|
||||
end.
|
||||
|
||||
stop() ->
|
||||
ejabberd_mod_echo ! stop,
|
||||
ok.
|
||||
\end{verbatim}
|
||||
|
||||
|
||||
|
||||
\end{document}
|
@ -255,12 +255,24 @@ wait_for_auth({xmlstreamelement, El}, StateData) ->
|
||||
{next_state, wait_for_auth, StateData}
|
||||
end;
|
||||
_ ->
|
||||
?INFO_MSG("(~w) Forbidden legacy authentification for ~s",
|
||||
[StateData#state.socket,
|
||||
jlib:jid_to_string(JID)]),
|
||||
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_auth, StateData}
|
||||
if
|
||||
JID == error ->
|
||||
?INFO_MSG(
|
||||
"(~w) Forbidden legacy authentification for "
|
||||
"username '~s' with resource '~s'",
|
||||
[StateData#state.socket, U, R]),
|
||||
Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_auth, StateData};
|
||||
true ->
|
||||
?INFO_MSG(
|
||||
"(~w) Forbidden legacy authentification for ~s",
|
||||
[StateData#state.socket,
|
||||
jlib:jid_to_string(JID)]),
|
||||
Err = jlib:make_error_reply(El, ?ERR_NOT_ALLOWED),
|
||||
send_element(StateData, Err),
|
||||
{next_state, wait_for_auth, StateData}
|
||||
end
|
||||
end;
|
||||
_ ->
|
||||
case jlib:iq_query_info(El) of
|
||||
|
@ -128,6 +128,8 @@ try_register(User, Password) ->
|
||||
ok;
|
||||
{atomic, exists} ->
|
||||
{error, ?ERR_CONFLICT};
|
||||
{error, invalid_jid} ->
|
||||
{error, ?ERR_JID_MALFORMED};
|
||||
{error, _Reason} ->
|
||||
{error, ?ERR_INTERNAL_SERVER_ERROR}
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user