1 // ANNA - Anna is Not Nothingness Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // http://redmine.teslayout.com/projects/anna-suite
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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
17 // * Neither the name of the copyright holder 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.
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.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_comm_ClientSocket_hpp
38 #define anna_comm_ClientSocket_hpp
40 #include <anna/comm/Socket.hpp>
41 #include <anna/comm/Buffer.hpp>
42 #include <anna/comm/Transport.hpp>
43 #include <anna/core/util/Millisecond.hpp>
54 class CongestionController;
58 class MetaClientSocket;
63 Implements client sockets (aka @ref Socket) established by our application with a remote endpoint
64 where a ServerSocket is accepting connection requests.
66 class ClientSocket : public Socket {
69 Numero de milisegundos por defecto que espera antes de dar por fallida una conexion con
70 otro proceso servidor.
72 static const Millisecond DefaultMaxConnectionDelay;
75 Numero de milisegundos por defecto que queda bloqueado un proceso a la espera de poder
76 escribir en un socket cuyo buffer de salida esta lleno.
78 static const Millisecond DefaultMaxWriteDelay;
81 Crea un socket cliente liberado.
82 \param transportFactory factoria de protocolos de transporte a usar por este sockets.
83 \param domain Dominio del socket.
84 \param type Tipo de socket.
85 \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo.
87 ClientSocket(TransportFactory* transportFactory = NULL, Domain::_v domain = Socket::Domain::Inet, Type::_v type = Socket::Type::Stream) :
88 Socket(domain, type, transportFactory),
91 a_ignoreIncomingMessages(false) {
96 Crea un socket cliente que sera conectado remotamente a la direccion y puerto indicado.
98 \param remoteAddress direccion de red remota a la que conectar.
99 \param transportFactory factoria de protocolos de transporte a usar por este sockets.
100 \param type Tipo de socket.
101 \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo.
103 ClientSocket(const INetAddress& remoteAddress, TransportFactory* transportFactory = NULL, const Type::_v type = Socket::Type::Stream) :
104 Socket(Socket::Domain::Inet, type, transportFactory),
105 a_remoteAccessPoint(remoteAddress),
108 a_ignoreIncomingMessages(false) {
113 Crea un socket cliente que sera conectado al archivo indicado.
115 \param path Ruta del archivo que vamos a usar para transferir datos ataves de este socket.
116 \param type Tipo de socket.
118 ClientSocket(const std::string& path, const Type::_v type = Socket::Type::Stream) :
120 a_remoteAccessPoint(path),
123 a_ignoreIncomingMessages(false) {
128 Crea un socket cliente conectado al servidor indicado por la direccion y puerto remoto. Ademas el socket cliente
129 seria conectado localmente (ver @ref Socket::bind) a la direccion y puerto locales indicados.
131 \param transportFactory factoria de protocolos de transporte a usar por este sockets.
132 \param remoteAddress direccion del servidor.
133 \param localAddress Puede ser usado para limitar la direccion por la que atendiende peticiones un servidor de socket
134 instalado en una maquina con mas de una direccion.
135 compartido por mas de un proceso activo.
136 \param type Tipo de socket.
137 \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo.
139 ClientSocket(const INetAddress& remoteAddress, const INetAddress& localAddress, TransportFactory* transportFactory = NULL, const Type::_v type = Socket::Type::Stream) :
140 Socket(localAddress, type, transportFactory),
141 a_remoteAccessPoint(remoteAddress),
144 a_ignoreIncomingMessages(false) {
151 virtual ~ClientSocket() { close(); }
154 Devuelve la direccion remota del socket.
155 \return La direccion remota del socket.
157 const AccessPoint& getRemoteAccessPoint() const throw() { return a_remoteAccessPoint; }
160 Devuelve el estado de conexion de este socket.
161 \return \em true si el socket mantiene la conexion realizada mediante el metodo #connect o
162 \em false en otro caso.
164 bool isConnected() const throw() { return (a_status & Status::Connected) != 0; }
167 Devuelve el estado del contenido del socket.
168 \return \em true si el socket mantiene el sincronismo o \em false en otro caso.
170 bool isSynchronized() const throw() { return (a_status & Status::Corrupt) == 0; }
173 Devuelve el estado del contenido del socket.
174 \return \em true si el socket NO mantiene el sincronismo o \em false en otro caso.
176 bool isCorrupt() const throw() { return (a_status & Status::Corrupt); }
179 * Devuelve el estado de cierre del socket.
180 * \return \em true si el socket está a la espera de ser cerrado o \em false en otro caso.
182 bool isClosedPending() const throw() { return (a_status & Status::ClosePending) != 0; }
185 Devuelve la instancia de anna::comm::Server asociado a una conexion remota iniciada por
187 \return la instancia de anna::comm::Server asociado a una conexion remota iniciada por
189 \warning Puede ser NULL en caso de que este ClientSocket corresponda a una conexion local
190 establecida por un proceso remoto contra un ServerSocket de nuestra aplicacion.
192 Server* getServer() throw(RuntimeException);
195 Devuelve el numero maximo de milisegundos esperados para obtener conexion al invocar
197 \return el numero maximo de milisegundos esperados para obtener conexion al invocar
200 const Millisecond &getMaxConnectionDelay() const throw() { return a_msMaxConnectionDelay; }
203 Devuelve el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera
204 de escribir en un socket cuyo buffer de salida esta lleno.
205 \return Devuelve el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera
206 de escribir en un socket cuyo buffer de salida esta lleno.
208 const Millisecond &getMaxWriteDelay() const throw() { return a_msMaxWriteDelay; }
211 Obtiene toda la informacion referente a este socket a partir de la conexion realizada atraves del \em fd
212 recibido como parametro.
213 \param fd File descriptor correspondiente a una conexion local.
214 \warning Exclusivamente uso interno.
216 virtual void setfd(const int fd) throw(RuntimeException);
219 Establece el numero maximo de milisegundos esperados para obtener la conexion al
220 invocar al metodo #connect.
221 \param msMaxConnectionDelay Numero de milisegundos esperados para obtener conexion.
223 \see anna::comm::Server::setMaxConnectionDelay.
225 void setMaxConnectionDelay(const Millisecond &msMaxConnectionDelay)
227 a_msMaxConnectionDelay = msMaxConnectionDelay;
231 Establece el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera
232 de escribir en un socket cuyo buffer de salida esta lleno.
234 \param msMaxWriteDelay Numero de milisegundos esperados en caso de que el buffer del socket se llene.
236 void setMaxWriteDelay(const Millisecond &msMaxWriteDelay) throw() { a_msMaxWriteDelay = msMaxWriteDelay; }
239 * Devuelve \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso.
240 * \return \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso.
242 bool getIgnoreIncomingMessages() const throw() { return a_ignoreIncomingMessages; }
245 * Establece el indicador que provoca ignorar los mensajes entrantes.
246 * \param ignoreIncomingMessages \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso.
248 void setIgnoreIncomingMessages(const bool ignoreIncomingMessages) throw() { a_ignoreIncomingMessages = ignoreIncomingMessages; }
251 Intenta la conexion remota con la direccion indicada en el constructor.
253 virtual void connect() throw(RuntimeException);
256 Envia el mensaje recibido como parametro. Al bloque de datos correspondiente a la
257 codificacion del mensaje se incorpora la informacion necesaria para el protocolo
258 de la capa de transporte indicado en el constuctor.
260 \param message Mensaje que vamos codificar para enviar a la capa de transporte.
262 void send(Message& message) throw(RuntimeException);
265 Envia el mensaje recibido como parametro. Al bloque de datos correspondiente a la
266 codificacion del mensaje se incorpora la informacion necesaria para el protocolo
267 de la capa de transporte indicado en el constuctor.
269 \param message Mensaje que vamos codificar para enviar a la capa de transporte.
271 void send(Message* message) throw(RuntimeException);
274 Espera la llegada de mensajes por este ClientSocket durante un numero de milisegundos
275 recibido como parametro o hasta que llegue un mensaje. Un ejemplo de uso, que deberia
276 ser completado con el control de condiciones de error podria ser:
280 void f (anna::ClientSocket* clientSocket)
281 throw (anna::RuntimeException)
283 anna::Guard (clientSocket);
285 if (clientSocket->wait (2000) == ClientSocket::Notify::ReceiveData) {
288 while ((data = clientSocket->fetch ()) != NULL) {
290 ..... procesa los datos ....
298 \param timeout Numero de milisegundos en que va a quedar bloqueado a la espera de
299 obtener el primer mensaje.
300 \param receive Un valor \em true indica que se tratara el mensaje detectado, un \em false
301 indica que solo esperara la llegada de un bloque de datos, pero no se procesara en absoluto, solo
302 devolvera Notify::ReceiveData.
304 \return El resultado de la espera. En caso de no haber recibido ningun mensaje
305 devolvera comm::Socket::Notify::None.
307 \warning \li El hilo de ejecucion que invoque a este metodo queda bloqueado durante el
308 tiempo que indica el 'timeout' o hasta que llegue un mensaje.
309 \li La invocacion al metodo #receive y al #fetch deben estar protegidas por la misma
312 Notify::_v wait(const Millisecond &timeout, const bool receive = true) throw(RuntimeException);
315 Elimina el contenido del buffer de recepcion.
317 void forgot() throw();
320 Obtiene la capa de transporte asociada a este ClientSocket.
321 \return la capa de transporte asociada a este ClientSocket.
323 Transport* getTransport() throw(RuntimeException) {
324 return (a_transport != NULL) ? a_transport : reserveTransport();
328 Obtiene el receptor asociado a este ClientSocket. Puede ser NULL
329 \return el receptor asociado a este ClientSocket.Puede ser NULL
330 \warning Exclusivamente uso interno.
332 Receiver* getReceiver() throw(RuntimeException) {
333 return (a_receiver != NULL) ? a_receiver : ((a_receiverFactory == NULL) ? NULL : reserveReceiver());
337 * Establece el receptor externo que tratara los mensajes recibidos por este socket.
338 * Si el receptor se establece directamente por el usuario, sin tener una factoria de receptores
339 * intermedia, invoca directamente al metodo anna::comm::Receiver::initialize.
340 * \param receive La instancia del receptor externo que tratar los mensajes de este socket.
342 void setReceiver(Receiver* receive) throw(RuntimeException);
345 Activa la solicitud de cierre del socket, que se llevara a cabo cuando el nucleo considere
346 que se puede realizar de forma segura, desde el punto de vista de la informacion bloqueada
347 por secciones criticas en los distintos componentes, que hacen uso del socket.
349 void requestClose() throw();
352 Devuelve el estado de la solicitud de cierre del socket.
353 \return el estado de la solicitud de cierre del socket.
355 bool hasRequestedClose() const throw() { return (a_status & Status::ClosePending) != 0; }
358 Devuelve una cadena con la informacin referente a este socket.
359 \return Una cadena con la informacin referente a este socket.
361 virtual std::string asString() const throw();
364 Devuelve un nodo XML con la informacin referente a este objeto.
365 \param parent Nodo XML a partir del cual introducir la informacin.
366 \return Un nodo XML con la informacin referente a este objeto.
368 virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException);
371 Devuelve el nombre logico de esta clase.
372 \return el nombre logico de esta clase.
374 static const char* className() throw() { return "anna::comm::ClientSocket"; }
378 enum _v { None = 0, Connected = 1, Corrupt = 2, ClosePending = 4, Working = 8 };
380 static std::string asString(const int status) throw();
383 Transport* a_transport;
384 AccessPoint a_remoteAccessPoint;
387 Devuelve el numero de bytes contenido en el buffer intermedio de recepcion.
388 \return El numero de bytes contenido en el buffer intermedio de recepcion.
390 int getBufferSize() const throw() { return a_data.getSize() - a_offset; }
393 Devuelve el numero maximo de bytes que puede tener en el buffer intermedio de recepcion.
394 \return el numero maximo de bytes que puede tener en el buffer intermedio de recepcion.
396 int getReceiveBufferSize() const throw() { return a_rcvBufferSize; }
399 Obtiene los parametros de funcionamiento del Socket.
400 \warning Exclusivamente uso interno.
402 void getSocketOptions() throw(RuntimeException);
405 Recupera el ultimo mensaje recibido.
406 El invocador debera haber establecido la forma de asegurar que hay que hay datos
407 disponibles. Ademas debera establecer el tratamiento adecuado para cada uno
408 de los posibles resultados.
409 \return El resultado de la operacion.
410 \warning La invocacion al metodo #receive y al #fetch deben estar protegidas por la
411 misma seccion critica. Por ejemplo:
415 void f (anna::ClientSocket* clientSocket)
416 throw (anna::RuntimeException)
418 anna::Guard (clientSocket);
420 if (clientSocket->receive () == ClientSocket::Notify::ReceiveData) {
423 while ((data = clientSocket->fetch ()) != NULL) {
425 ..... procesa los datos ....
433 Notify::_v receive() throw(RuntimeException);
436 Recupera el ultimo bloque de datos recuperado mediante el metodo #receive o #wait.
437 El bloque de datos deberia ser interpretado segun las reglas de la capa de transporte
438 asociada a este ClientSocket.
440 \return El ultimo bloque recuperado mediante el metodo #receive o #wait. Puede ser NULL si no hay
441 disponible ningun bloque.
443 \warning Exclusivamente uso interno. Debe invocarse con una seccion
444 critica activa sobre el ClientSocket.
446 const DataBlock* fetch() throw(RuntimeException);
448 void activate(const Status::_v v) throw() { a_status |= v; }
449 void deactivate(const Status::_v v) throw() { a_status &= ~v; }
450 void deactivate(const int v) throw() { a_status &= ~v; }
452 virtual int do_connect(const sockaddr*, const int len) throw(RuntimeException);
453 virtual void do_write(const DataBlock&) throw(RuntimeException);
454 virtual int do_read(const char* data, const int size) throw(RuntimeException);
455 virtual void do_close() throw();
458 struct PendingBytes {
459 Millisecond validUntil;
462 PendingBytes() { validUntil = 0; bytesToRead = 0; }
465 //-----------------------------------------------------------------------------------------
466 // a_status : Combinacion de bit's que indica el estado de la instancia.
467 // a_expectedSize: Numero de bytes esperados. valdra -1 si todavia no hay informacion
469 // a_data: Ultimo bloque de datos leido. Puede contener un numero indeterminado de mensajes
470 // a_buffer: Referencia al espacio que ocupa el mensaje que estamos tratanto. Apunta
471 // a un espacio dentro de 'a_data'-
472 // a_reader: Buffer usado para leer los datos del Socket.
473 // a_offset: Desplazamiento que hay que aplicar sobre los datos contenidos en 'a_data'.
474 // a_cachedServer: Ultimo server calculado en el metodo getServer.
475 //-----------------------------------------------------------------------------------------
482 comm::Server* a_cachedServer;
483 Millisecond a_msMaxConnectionDelay;
484 Millisecond a_msMaxWriteDelay;
486 Receiver* a_receiver;
487 mutable PendingBytes a_pendingBytes;
488 bool a_ignoreIncomingMessages;
490 void initialize() throw();
491 void calculeExpectedSize(const DataBlock&) throw();
492 Transport* reserveTransport() throw(RuntimeException);
493 Transport* unsafe_reserveTransport() throw(RuntimeException);
494 Receiver* reserveReceiver() throw(RuntimeException);
495 int getTotalPendingBytes() const throw();
497 friend class Communicator;
498 // unsafe_reserveTransport
501 friend class CongestionController;
502 friend class handler::MetaClientSocket;
503 friend class handler::DatagramSocket;