First commit
[anna.git] / include / anna / comm / Handler.hpp
1 // ANNA - Anna is Not 'N' Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 #ifndef anna_comm_Handler_hpp
38 #define anna_comm_Handler_hpp
39
40 #include <netinet/in.h>
41
42 #include <anna/core/mt/Runnable.hpp>
43 #include <anna/core/util/Millisecond.hpp>
44 #include <anna/core/util/Microsecond.hpp>
45
46 namespace anna {
47
48 namespace xml {
49 class Node;
50 }
51
52 namespace comm {
53
54 class Communicator;
55 class Transport;
56 class ClientSocket;
57
58 /**
59    Controlador de comunicaciones generico.
60 */
61 class Handler : public Runnable {
62 public:
63   using Runnable::initialize;
64   using Runnable::run;
65   using Runnable::setIsRunning;
66
67   /**
68      Mascara que define el funcionamiento de los manejadores de mensajes.
69   */
70   struct Support { enum _v { None = 0, CongestionControl = 1 }; };
71
72   /**
73      Tipo de controladores predefinidos.
74   */
75   struct Type {
76     enum _v {
77       ServerSocket,  /**< Controlador para ServerSocket */
78       LocalConnection,  /**< Controlador para LocalConnection */
79       RemoteConnection,  /**< Controlador para RemoteConnection */
80       DatagramSocket,  /**< Controlador para DatagramSocket */
81       BinderSocket,  /**< Controlador para comm::BinderSocket usado para compartir direcciones IPs. */
82       Custom,  /**< Controlador definido por el usuario */
83       ClientSocket /**< Controlador para un ClientSocket directo (sin uso intermedio de Server */
84     };
85   };
86
87   /**
88      Devuelve el tipo de controlador.
89      \return el tipo de controlador.
90   */
91   Type::_v getType() const throw() { return a_type; }
92
93   /**
94      Devuelve el descriptor de fichero asociado a este controlador.
95      \return el descriptor de fichero asociado a este controlador.
96   */
97   int getfd() const throw() { return a_fd; }
98
99   /**
100      Devuelve \em true si el descriptor de fichero asociado a este controlador soporta
101      control de congestion o \em false en otro caso.
102      \return \em true si el descriptor de fichero asociado a este controlador soporta
103      control de congestion o \em false en otro caso.
104   */
105   bool supportCongestionControl() const throw() { return (a_support & Support::CongestionControl) != 0; }
106
107   /**
108      Devuelve \em true si este manejador soporta control de temporizacion o \em false en otro
109      caso.
110      \return \em true si este manejador soporta control de temporizacion o \em false en otro
111      caso.
112   */
113   bool supportTimeout() const throw() { return a_timeout > 0; }
114
115   /**
116      Operador de comparacion.
117      \param fd Descriptor de fichero con el que comparar.
118      \return \em true si el fd recibido es igual al establecido con #setfd o \em false en caso contrario.
119   */
120   bool operator == (const int fd) const throw() { return a_fd == fd; }
121
122   /**
123     Metodo invocado por el comunicador cuando detectado actividad en el descriptor de
124     fichero asociado a este controlador.
125   */
126   virtual void apply() throw(RuntimeException) = 0;
127
128   /**
129      Devuelve el ClientSocket asociado a este manejador de conexiones.
130      \return El ClientSocket asociado a este manejador de conexiones. Puede ser NULL.
131      \warning Uso interno. Se necesita para poder cooperar con el anna::comm::CongestionController.
132   */
133   virtual ClientSocket* getClientSocket() throw() { return NULL; }
134
135   /**
136      Devuelve una cadena con la informacion referente a esta instancia.
137      \return una cadena con la informacion referente a esta instancia.
138   */
139   virtual std::string asString() const throw();
140
141   /**
142      Devuelve un documento XML con la informacion referente a esta instancia.
143      \return un documento XML con la informacion referente a esta instancia.
144   */
145   virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException);
146
147   /**
148      Amplia la informacion XML del nodo recibido como parametro.
149      \param node Nodo XML en el que incorporar los atributos.
150   */
151   void asAttribute(xml::Node* node) const throw(RuntimeException);
152
153 protected:
154   /**
155      Instancia del comunicador puede ser NULL.
156   */
157   Communicator* a_communicator;
158
159   /**
160      Constructor.
161      \param communicator Comunicador asociado a este controlador.
162      \param type Tipo de Comunicador.
163      \param support Una combinacion de los valores de Handler::Support.
164   */
165   Handler(Communicator* communicator, const Type::_v type, const int support = Support::CongestionControl) :
166     a_communicator(communicator),
167     a_type(type),
168     a_support(support),
169     a_fd(-1),
170     a_timeout(0),
171     a_maxTime(0),
172     a_loop(0)
173   {;}
174
175   /**
176      Constructor.
177      \param type Tipo de Comunicador.
178      \param support Una combinacion de los valores de Handler::Support.
179   */
180   Handler(const Type::_v type, const int support = Support::CongestionControl) :
181     a_communicator(NULL),
182     a_type(type),
183     a_support(support),
184     a_fd(-1),
185     a_timeout(0),
186     a_maxTime(0),
187     a_loop(0)
188   {;}
189
190   /**
191      Establecer el descriptor de fichero asociado a este controlador.
192      \param fd Descriptor de fichero asociado a este controlador.
193      \warning La implementacion del metodo initialize debe invocar a este metodo
194      con descriptor de fichero valido.
195   */
196   void setfd(const int fd) throw() { setId(anna::functions::asText("Handler", a_fd = fd)); }
197
198   /**
199      Establece el numero de milisegundos maximo que puede estar este manejador sin
200      recibir mensajes antes de ser cerrado por el nucleo.
201      \param timeout Numero de milisegundos maximo sin recibir mensajes.
202   */
203   void setTimeout(const Millisecond &timeout) throw() {
204     a_timeout = timeout;
205     a_maxTime = functions::hardwareClock() + a_timeout;
206   }
207
208   /**
209      En los manejadores que pueden recibir mas de una peticion en cada llamada a apply este
210      metodo debe ser invocado para saber si debe dejar de procesar mensajes.
211   */
212   bool canContinue() const throw() { return hasRequestedStop() == false; }
213
214   /**
215      Metodo con el que podemos redefinir el comportamiento cuando recibe la notificacion de
216      que una IP ha dejado de estar disponible.
217      \param address Direccion IP que ha dejado de estar disponible.
218      \warning Se invoca automaticamente desde el comunicador.
219   */
220   virtual void breakAddress(const in_addr_t& address) throw() {;}
221
222   /**
223      Metodo con el que podemos redefinir el comportamiento cuando recibe la notificacion de
224      que una IP esta disponible.
225      \param address Direccion IP que ha pasado a estar disponible.
226      \warning Se invoca automaticamente desde el comunicador.
227   */
228   virtual void recoverAddress(const in_addr_t& address) throw() {;}
229
230   /**
231    * Método que se invoca periódicamente para comprobar si tenemos pendiente el cierre de la conexión
232    * con el canal asociado a este manejador, cuando el fd asociado al manejador de recibe actividad.
233    *
234    * \return \em true Si termina la conexión o \em false en otro caso.
235    */
236   virtual bool testClose() throw(RuntimeException) { return false;}
237
238   /**
239      Metodo con el que podemos redefinir el comportamiento cuando recibe la notificacion de
240      que el componente asociado a este controlador ha dejado de estar operativo.
241      \warning Se invoca automaticamente desde el comunicador al invocar al metodo
242      \em detach correspondiente.
243   */
244   virtual void finalize() throw() {;}
245
246   /**
247    * Metodo con el que podemos redefinir el comportamiento cuando recibe la notificacion de
248    * que el componente asociado a este controlador ha sido duplicado en un proceso hijo.
249    * \warning Exclusivamente uso interno.
250   */
251   virtual void clone() throw(RuntimeException) {;}
252
253 private:
254   const Type::_v a_type;
255   const int a_support;
256   int a_fd;
257   Microsecond a_timeout;
258   Microsecond a_maxTime;
259   int a_loop;
260
261   Handler(const Handler&);
262   void do_action() throw(RuntimeException);
263   void beat(const Microsecond& now) throw() { a_maxTime = now + a_timeout; }
264   bool isTimeout(const Microsecond& now) { return a_maxTime > 0 && a_maxTime <= now; }
265
266   friend class Communicator;
267 };
268
269 }
270 }
271
272 #endif
273