diff options
author | Alexey Shchepin <alexey@process-one.net> | 2003-11-11 20:51:04 +0000 |
---|---|---|
committer | Alexey Shchepin <alexey@process-one.net> | 2003-11-11 20:51:04 +0000 |
commit | c248bffd54ed08034f22e98e13b9612f685592d4 (patch) | |
tree | 59f9731a2dca9d1fd328abec4642671e07717f36 /doc | |
parent | * src/ejabberd.cfg.example: Updated (diff) |
* 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
Diffstat (limited to '')
-rw-r--r-- | doc/dev.html | 364 | ||||
-rw-r--r-- | doc/dev.tex | 378 |
2 files changed, 742 insertions, 0 deletions
diff --git a/doc/dev.html b/doc/dev.html new file mode 100644 index 000000000..ad12f39dd --- /dev/null +++ b/doc/dev.html @@ -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> diff --git a/doc/dev.tex b/doc/dev.tex new file mode 100644 index 000000000..af9340f15 --- /dev/null +++ b/doc/dev.tex @@ -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} |