1 // ANNA - Anna is Not 'N' Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
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 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.
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 Implementa los socket cliente (tambien conocidos como @ref Socket) que nuestra
64 aplicacion tiene establecidos con un punto remoto, donde habra un ServerSocket
65 aceptando peticiones de conexion.
67 class ClientSocket : public Socket {
70 Numero de milisegundos por defecto que espera antes de dar por fallida una conexion con
71 otro proceso servidor.
73 static const Millisecond DefaultMaxConnectionDelay;
76 Numero de milisegundos por defecto que queda bloqueado un proceso a la espera de poder
77 escribir en un socket cuyo buffer de salida esta lleno.
79 static const Millisecond DefaultMaxWriteDelay;
82 Crea un socket cliente liberado.
83 \param transportFactory factoria de protocolos de transporte a usar por este sockets.
84 \param domain Dominio del socket.
85 \param type Tipo de socket.
86 \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo.
88 ClientSocket(TransportFactory* transportFactory = NULL, Domain::_v domain = Socket::Domain::Inet, Type::_v type = Socket::Type::Stream) :
89 Socket(domain, type, transportFactory),
92 a_ignoreIncomingMessages(false) {
97 Crea un socket cliente que sera conectado remotamente a la direccion y puerto indicado.
99 \param remoteAddress direccion de red remota a la que conectar.
100 \param transportFactory factoria de protocolos de transporte a usar por este sockets.
101 \param type Tipo de socket.
102 \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo.
104 ClientSocket(const INetAddress& remoteAddress, TransportFactory* transportFactory = NULL, const Type::_v type = Socket::Type::Stream) :
105 Socket(Socket::Domain::Inet, type, transportFactory),
106 a_remoteAccessPoint(remoteAddress),
109 a_ignoreIncomingMessages(false) {
114 Crea un socket cliente que sera conectado al archivo indicado.
116 \param path Ruta del archivo que vamos a usar para transferir datos ataves de este socket.
117 \param type Tipo de socket.
119 ClientSocket(const std::string& path, const Type::_v type = Socket::Type::Stream) :
121 a_remoteAccessPoint(path),
124 a_ignoreIncomingMessages(false) {
129 Crea un socket cliente conectado al servidor indicado por la direccion y puerto remoto. Ademas el socket cliente
130 seria conectado localmente (ver @ref Socket::bind) a la direccion y puerto locales indicados.
132 \param transportFactory factoria de protocolos de transporte a usar por este sockets.
133 \param remoteAddress direccion del servidor.
134 \param localAddress Puede ser usado para limitar la direccion por la que atendiende peticiones un servidor de socket
135 instalado en una maquina con mas de una direccion.
136 compartido por mas de un proceso activo.
137 \param type Tipo de socket.
138 \warning La factoria de protocolos debe estar disponible mientras el Socket esta activo.
140 ClientSocket(const INetAddress& remoteAddress, const INetAddress& localAddress, TransportFactory* transportFactory = NULL, const Type::_v type = Socket::Type::Stream) :
141 Socket(localAddress, type, transportFactory),
142 a_remoteAccessPoint(remoteAddress),
145 a_ignoreIncomingMessages(false) {
152 virtual ~ClientSocket() { close(); }
155 Devuelve la direccion remota del socket.
156 \return La direccion remota del socket.
158 const AccessPoint& getRemoteAccessPoint() const throw() { return a_remoteAccessPoint; }
161 Devuelve el estado de conexion de este socket.
162 \return \em true si el socket mantiene la conexion realizada mediante el metodo #connect o
163 \em false en otro caso.
165 bool isConnected() const throw() { return (a_status & Status::Connected) != 0; }
168 Devuelve el estado del contenido del socket.
169 \return \em true si el socket mantiene el sincronismo o \em false en otro caso.
171 bool isSynchronized() const throw() { return (a_status & Status::Corrupt) == 0; }
174 Devuelve el estado del contenido del socket.
175 \return \em true si el socket NO mantiene el sincronismo o \em false en otro caso.
177 bool isCorrupt() const throw() { return (a_status & Status::Corrupt); }
180 * Devuelve el estado de cierre del socket.
181 * \return \em true si el socket está a la espera de ser cerrado o \em false en otro caso.
183 bool isClosedPending() const throw() { return (a_status & Status::ClosePending) != 0; }
186 Devuelve la instancia de anna::comm::Server asociado a una conexion remota iniciada por
188 \return la instancia de anna::comm::Server asociado a una conexion remota iniciada por
190 \warning Puede ser NULL en caso de que este ClientSocket corresponda a una conexion local
191 establecida por un proceso remoto contra un ServerSocket de nuestra aplicacion.
193 Server* getServer() throw(RuntimeException);
196 Devuelve el numero maximo de milisegundos esperados para obtener conexion al invocar
198 \return el numero maximo de milisegundos esperados para obtener conexion al invocar
201 const Millisecond &getMaxConnectionDelay() const throw() { return a_msMaxConnectionDelay; }
204 Devuelve el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera
205 de escribir en un socket cuyo buffer de salida esta lleno.
206 \return Devuelve el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera
207 de escribir en un socket cuyo buffer de salida esta lleno.
209 const Millisecond &getMaxWriteDelay() const throw() { return a_msMaxWriteDelay; }
212 Obtiene toda la informacion referente a este socket a partir de la conexion realizada atraves del \em fd
213 recibido como parametro.
214 \param fd File descriptor correspondiente a una conexion local.
215 \warning Exclusivamente uso interno.
217 virtual void setfd(const int fd) throw(RuntimeException);
220 Establece el numero maximo de milisegundos esperados para obtener la conexion al
221 invocar al metodo #connect.
222 \param msMaxConnectionDelay Numero de milisegundos esperados para obtener conexion.
224 \see anna::comm::Server::setMaxConnectionDelay.
226 void setMaxConnectionDelay(const Millisecond &msMaxConnectionDelay)
228 a_msMaxConnectionDelay = msMaxConnectionDelay;
232 Establece el numero maximo de milisegundos que queda bloqueado el proceso/thread a la espera
233 de escribir en un socket cuyo buffer de salida esta lleno.
235 \param msMaxWriteDelay Numero de milisegundos esperados en caso de que el buffer del socket se llene.
237 void setMaxWriteDelay(const Millisecond &msMaxWriteDelay) throw() { a_msMaxWriteDelay = msMaxWriteDelay; }
240 * Devuelve \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso.
241 * \return \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso.
243 bool getIgnoreIncomingMessages() const throw() { return a_ignoreIncomingMessages; }
246 * Establece el indicador que provoca ignorar los mensajes entrantes.
247 * \param ignoreIncomingMessages \em true si el indicador que ignora los mensajes entrantes está activo, o \em false en otro caso.
249 void setIgnoreIncomingMessages(const bool ignoreIncomingMessages) throw() { a_ignoreIncomingMessages = ignoreIncomingMessages; }
252 Intenta la conexion remota con la direccion indicada en el constructor.
254 virtual void connect() throw(RuntimeException);
257 Envia el mensaje recibido como parametro. Al bloque de datos correspondiente a la
258 codificacion del mensaje se incorpora la informacion necesaria para el protocolo
259 de la capa de transporte indicado en el constuctor.
261 \param message Mensaje que vamos codificar para enviar a la capa de transporte.
263 void send(Message& message) throw(RuntimeException);
266 Envia el mensaje recibido como parametro. Al bloque de datos correspondiente a la
267 codificacion del mensaje se incorpora la informacion necesaria para el protocolo
268 de la capa de transporte indicado en el constuctor.
270 \param message Mensaje que vamos codificar para enviar a la capa de transporte.
272 void send(Message* message) throw(RuntimeException);
275 Espera la llegada de mensajes por este ClientSocket durante un numero de milisegundos
276 recibido como parametro o hasta que llegue un mensaje. Un ejemplo de uso, que deberia
277 ser completado con el control de condiciones de error podria ser:
281 void f (anna::ClientSocket* clientSocket)
282 throw (anna::RuntimeException)
284 anna::Guard (clientSocket);
286 if (clientSocket->wait (2000) == ClientSocket::Notify::ReceiveData) {
289 while ((data = clientSocket->fetch ()) != NULL) {
291 ..... procesa los datos ....
299 \param timeout Numero de milisegundos en que va a quedar bloqueado a la espera de
300 obtener el primer mensaje.
301 \param receive Un valor \em true indica que se tratara el mensaje detectado, un \em false
302 indica que solo esperara la llegada de un bloque de datos, pero no se procesara en absoluto, solo
303 devolvera Notify::ReceiveData.
305 \return El resultado de la espera. En caso de no haber recibido ningun mensaje
306 devolvera comm::Socket::Notify::None.
308 \warning \li El hilo de ejecucion que invoque a este metodo queda bloqueado durante el
309 tiempo que indica el 'timeout' o hasta que llegue un mensaje.
310 \li La invocacion al metodo #receive y al #fetch deben estar protegidas por la misma
313 Notify::_v wait(const Millisecond &timeout, const bool receive = true) throw(RuntimeException);
316 Elimina el contenido del buffer de recepcion.
318 void forgot() throw();
321 Obtiene la capa de transporte asociada a este ClientSocket.
322 \return la capa de transporte asociada a este ClientSocket.
324 Transport* getTransport() throw(RuntimeException) {
325 return (a_transport != NULL) ? a_transport : reserveTransport();
329 Obtiene el receptor asociado a este ClientSocket. Puede ser NULL
330 \return el receptor asociado a este ClientSocket.Puede ser NULL
331 \warning Exclusivamente uso interno.
333 Receiver* getReceiver() throw(RuntimeException) {
334 return (a_receiver != NULL) ? a_receiver : ((a_receiverFactory == NULL) ? NULL : reserveReceiver());
338 * Establece el receptor externo que tratara los mensajes recibidos por este socket.
339 * Si el receptor se establece directamente por el usuario, sin tener una factoria de receptores
340 * intermedia, invoca directamente al metodo anna::comm::Receiver::initialize.
341 * \param receive La instancia del receptor externo que tratar los mensajes de este socket.
343 void setReceiver(Receiver* receive) throw(RuntimeException);
346 Activa la solicitud de cierre del socket, que se llevara a cabo cuando el nucleo considere
347 que se puede realizar de forma segura, desde el punto de vista de la informacion bloqueada
348 por secciones criticas en los distintos componentes, que hacen uso del socket.
350 void requestClose() throw();
353 Devuelve el estado de la solicitud de cierre del socket.
354 \return el estado de la solicitud de cierre del socket.
356 bool hasRequestedClose() const throw() { return (a_status & Status::ClosePending) != 0; }
359 Devuelve una cadena con la informacin referente a este socket.
360 \return Una cadena con la informacin referente a este socket.
362 virtual std::string asString() const throw();
365 Devuelve un nodo XML con la informacin referente a este objeto.
366 \param parent Nodo XML a partir del cual introducir la informacin.
367 \return Un nodo XML con la informacin referente a este objeto.
369 virtual xml::Node* asXML(xml::Node* parent) const throw(RuntimeException);
372 Devuelve el nombre logico de esta clase.
373 \return el nombre logico de esta clase.
375 static const char* className() throw() { return "anna::comm::ClientSocket"; }
379 enum _v { None = 0, Connected = 1, Corrupt = 2, ClosePending = 4, Working = 8 };
381 static std::string asString(const int status) throw();
384 Transport* a_transport;
385 AccessPoint a_remoteAccessPoint;
388 Devuelve el numero de bytes contenido en el buffer intermedio de recepcion.
389 \return El numero de bytes contenido en el buffer intermedio de recepcion.
391 int getBufferSize() const throw() { return a_data.getSize() - a_offset; }
394 Devuelve el numero maximo de bytes que puede tener en el buffer intermedio de recepcion.
395 \return el numero maximo de bytes que puede tener en el buffer intermedio de recepcion.
397 int getReceiveBufferSize() const throw() { return a_rcvBufferSize; }
400 Obtiene los parametros de funcionamiento del Socket.
401 \warning Exclusivamente uso interno.
403 void getSocketOptions() throw(RuntimeException);
406 Recupera el ultimo mensaje recibido.
407 El invocador debera haber establecido la forma de asegurar que hay que hay datos
408 disponibles. Ademas debera establecer el tratamiento adecuado para cada uno
409 de los posibles resultados.
410 \return El resultado de la operacion.
411 \warning La invocacion al metodo #receive y al #fetch deben estar protegidas por la
412 misma seccion critica. Por ejemplo:
416 void f (anna::ClientSocket* clientSocket)
417 throw (anna::RuntimeException)
419 anna::Guard (clientSocket);
421 if (clientSocket->receive () == ClientSocket::Notify::ReceiveData) {
424 while ((data = clientSocket->fetch ()) != NULL) {
426 ..... procesa los datos ....
434 Notify::_v receive() throw(RuntimeException);
437 Recupera el ultimo bloque de datos recuperado mediante el metodo #receive o #wait.
438 El bloque de datos deberia ser interpretado segun las reglas de la capa de transporte
439 asociada a este ClientSocket.
441 \return El ultimo bloque recuperado mediante el metodo #receive o #wait. Puede ser NULL si no hay
442 disponible ningun bloque.
444 \warning Exclusivamente uso interno. Debe invocarse con una seccion
445 critica activa sobre el ClientSocket.
447 const DataBlock* fetch() throw(RuntimeException);
449 void activate(const Status::_v v) throw() { a_status |= v; }
450 void deactivate(const Status::_v v) throw() { a_status &= ~v; }
451 void deactivate(const int v) throw() { a_status &= ~v; }
453 virtual int do_connect(const sockaddr*, const int len) throw(RuntimeException);
454 virtual void do_write(const DataBlock&) throw(RuntimeException);
455 virtual int do_read(const char* data, const int size) throw(RuntimeException);
456 virtual void do_close() throw();
459 struct PendingBytes {
460 Millisecond validUntil;
463 PendingBytes() { validUntil = 0; bytesToRead = 0; }
466 //-----------------------------------------------------------------------------------------
467 // a_status : Combinacion de bit's que indica el estado de la instancia.
468 // a_expectedSize: Numero de bytes esperados. valdra -1 si todavia no hay informacion
470 // a_data: Ultimo bloque de datos leido. Puede contener un numero indeterminado de mensajes
471 // a_buffer: Referencia al espacio que ocupa el mensaje que estamos tratanto. Apunta
472 // a un espacio dentro de 'a_data'-
473 // a_reader: Buffer usado para leer los datos del Socket.
474 // a_offset: Desplazamiento que hay que aplicar sobre los datos contenidos en 'a_data'.
475 // a_cachedServer: Ultimo server calculado en el metodo getServer.
476 //-----------------------------------------------------------------------------------------
483 comm::Server* a_cachedServer;
484 Millisecond a_msMaxConnectionDelay;
485 Millisecond a_msMaxWriteDelay;
487 Receiver* a_receiver;
488 mutable PendingBytes a_pendingBytes;
489 bool a_ignoreIncomingMessages;
491 void initialize() throw();
492 void calculeExpectedSize(const DataBlock&) throw();
493 Transport* reserveTransport() throw(RuntimeException);
494 Transport* unsafe_reserveTransport() throw(RuntimeException);
495 Receiver* reserveReceiver() throw(RuntimeException);
496 int getTotalPendingBytes() const throw();
498 friend class Communicator;
499 // unsafe_reserveTransport
502 friend class CongestionController;
503 friend class handler::MetaClientSocket;
504 friend class handler::DatagramSocket;