5c06bafb2a10fb3364e7f98d7785dfc68fa7ae86
[anna.git] / include / anna / comm / Transport.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_Transport_hpp
38 #define anna_comm_Transport_hpp
39
40 #include <anna/core/RuntimeException.hpp>
41 #include <anna/core/DataBlock.hpp>
42
43 namespace anna {
44
45 namespace comm {
46
47 class Communicator;
48 class Message;
49
50 /**
51    Clase generica para definir la capa de transporte de cualquier protocolo de comunicaciones.
52
53    Estructura basica que nos permite ordenar el proceso de analizar un mensaje recibido desde
54    cualquier medio. El protocolo conoce los detalles semanticos del mensaje que ha recibido,
55    es decir, conoce como interpretar cada uno de los bytes que componen el mensaje, cuando un
56    mensaje esta completo.
57
58    El principal problema de cualquier protocolo externo a la hora de recibir es conocer cual
59    es el tamao de un determinado mensaje.
60
61    Todos los metodos que se deberian reescribir en las clases heredadas se invocan desde un
62    metodo MT-safe que se encarga de evitar accesos simultaneos desde varios threads, lo cual,
63    evita que tengamos que preocuparnos por establecer secciones criticas en cada uno de los
64    metodos reescritos.
65
66    \warning Los supuestos bajo los que se diseñó éste protocolo facilitan el desarrollo de
67    clases que ofrecen un gran rendimiento, pero imposibilitan el desarrollo del sistema de
68    re-sincronización en caso de que alguno de los mensajes no cumpla los supuestos.
69    Es decir, si nos llega un mensaje errneo nuestro proceso no sera capaz de volver a
70    sincronizarse nunca mas.
71 */
72 class Transport {
73 public:
74   /**
75      Numero de bytes maximo que puede mantener cada ClientSocket sin identificar
76      un mensaje propio del protocolo.
77   */
78   WHEN_SINGLETHREAD(
79     static const int DefaultOverQuotaSize = 2048;
80   )
81   WHEN_MULTITHREAD(
82     static const int DefaultOverQuotaSize = 8192;
83   )
84
85   /**
86      Devuelve \em true si la capa de transporte tiene activado el sistema de control
87      de temporizacion.
88   */
89   bool enableTimeout() const throw() { return a_enableTimeout; }
90
91   /**
92      Activa el control de temporización para los ClientSocket que fueron creados
93      usando esta capa de transporte. Los ClientSocket creados usando esta capa
94      de transporte se cerraran automaticamente si no se detecta actividad en
95      un determinado periodo de tiempo.
96      \see Communicator::setTimeout.
97   */
98   void activateTimeout() throw() { a_enableTimeout = true; }
99
100   /**
101      Activa el control de temporizacion para los ClientSocket que fueron creados
102      usando esta capa de transporte.
103   */
104   void deactivateTimeout() throw() { a_enableTimeout = false; }
105
106   /**
107      Devuelve el mensaje de entrada asociado.
108      \return La instancia del mensaje de entrada asociado.
109      \warning Exclusivamente de uso interno.
110   */
111   Message* getInputMessage() throw(RuntimeException) {
112     return (a_inputMessage == NULL) ? nullInputMessage() : a_inputMessage;
113   }
114
115   /**
116      Devuevel el numero bytes que reserva este protocolo para el buffer de memoria intermedia.
117      \return el numero bytes que reserva este protocolo para el buffer de memoria intermedia.
118   */
119   int getOverQuotaSize() const throw() { return a_overQuotaSize; }
120
121   /**
122     Establece el numero de bytes que puede mantener este procotolo para cada uno de los
123     ClientSocket sin que se halla identificado el mensaje como propio del protocolo.
124     Si el numero de bytes guardados en la memoria intermedia sobrepasa este numero de
125     bytes se cerrara la conexion con el ClientSocket.
126
127     \param overQuotaSize Numero de maximo de bytes que podemos mantener en la memoria intermedia.
128   */
129   void setOverQuotaSize(const int overQuotaSize) throw() { a_overQuotaSize = (overQuotaSize >= MinOverQuotaSize) ? overQuotaSize : MinOverQuotaSize; }
130
131   /**
132      Debe calcular el tamao previsto del mensaje actual.
133
134      Si se detecta una anomalia irrecuperable en el mensaje debe devolver una excepcion
135      para indicar el error.
136
137      @param dataBlock Bloque con la parte del mensaje disponible hasta el momento.
138
139      @return Si con la informacion disponible no puede establecer la longitud del
140      mensaje devolvera -1 en otro caso devolvera la longitud prevista del mensaje.
141
142      \warning
143         Si el protocolo de transporte implementado detecta problemas al calcular la
144         longitud del mensaje recibido y lanza una excepcion en este metodo el ClientSocket
145         activara los sistemas de recuperacion, si es posible.
146   */
147   virtual int calculeSize(const DataBlock& dataBlock) throw(RuntimeException) = 0;
148
149   /**
150      Debe establecer el modo en que el protocolo va a verificar que el mensaje obtenido
151      coincide con el patrn esperado e interpretar el contenido del mensaje.
152      Este metodo slo se invoca cuando se considera que el mensaje actual esta completo.
153
154      Si se detecta una anomalia irrecuperable en el mensaje debe devolver una excepcion
155      para indicar el error.
156
157      @param message Bloque con lo que hasta el momento se considera el ltimo mensaje recibido
158      por completo.
159
160      \return Un bloque de memoria que contiene el mensaje recibido codificado segn las reglas del
161      protocolo este protocolo de transporte
162   */
163   virtual const Message* decode(const DataBlock& message) throw(RuntimeException) = 0;
164
165   /**
166      Debe establecer la forma en el protocolo va a preparar el envio a la capa de transporte.
167
168      @param message Bloque de datos con la codificacin obtenida mediante cualquiera de los
169      codec disponibles (Ver @ref Codec).
170
171      @return El bloque de memoria con el mensaje que sera enviado a la capa de transporte.
172
173      \warning De no indicarse ninguna otra implementacin devolvera el mensaje tal y como
174      sea recibido.
175   */
176   virtual const DataBlock& code(Message& message) throw(RuntimeException) = 0;
177
178   /**
179      Metodo que inicializa el estado de esta capa de transporte. Sera invocado automaticamente por el
180      nucleo anna.comm.
181   */
182   virtual void clear() throw() { a_forCode.clear(); }
183
184 protected:
185   DataBlock a_forCode; /**< Bloque de memoria usado para guardar el contenido de la codificacion */
186
187   /**
188      Constructor.
189      \param autoSynchronize Indica si el el protocolo instancia permite la sincronizacion automatica.
190      \param overQuotaSize Longitud maxima que puede contener el buffer intermedio antes de cerrar el socket
191       por considerar que no puede sincronizarlo.
192   */
193   Transport() :
194     a_inputMessage(NULL),
195     a_forCode(true),
196     a_enableTimeout(false) {
197     a_overQuotaSize = DefaultOverQuotaSize;
198   }
199
200   /**
201      Establece la instancia del mensaje asociada a este transporte.
202      \param inputMessage Instancia del mensaje a asociar.
203   */
204   void setInputMessage(Message* inputMessage) throw() { a_inputMessage = inputMessage; }
205
206 private:
207   static const int MinOverQuotaSize = 512;
208
209   int a_overQuotaSize;
210   Message* a_inputMessage;
211   bool a_enableTimeout;
212
213   static Message* nullInputMessage() throw(RuntimeException);
214 };
215
216 }
217 }
218
219 #endif