1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
9 #include <anna/core/tracing/Logger.hpp>
10 #include <anna/core/tracing/TraceMethod.hpp>
12 #include <anna/xml/Node.hpp>
14 #include <anna/comm/Communicator.hpp>
15 #include <anna/comm/Server.hpp>
16 #include <anna/comm/ClientSocket.hpp>
17 #include <anna/comm/Host.hpp>
18 #include <anna/comm/Device.hpp>
19 #include <anna/comm/functions.hpp>
20 #include <anna/comm/internal/RemoteConnection.hpp>
25 comm::Server::Server(const string& name, const comm::Host& host, const int remotePort, const bool autoRecovery, comm::TransportFactory* transportFactory) :
28 a_remotePort(remotePort),
29 a_autoRecovery(autoRecovery),
30 a_transportFactory(transportFactory),
32 a_msMaxConnectionDelay(ClientSocket::DefaultMaxConnectionDelay),
33 a_msMaxWriteDelay(ClientSocket::DefaultMaxWriteDelay),
34 a_receiverFactory(NULL),
35 a_ignoreIncomingMessages(false),
37 // La a_sequence se usa para diferenciar en las trazas y demás las conexiones que puede haber contra un mismo (IP, port)
38 // Se establece desde comm::Host
42 //----------------------------------------------------------------------------------------
43 // (1) Para asegurar que el comm::handler::RemoteConnection no lo mete en la lista de
44 // servidores pendientes de recuperar.
45 //----------------------------------------------------------------------------------------
46 comm::Server::~Server() {
47 if(a_clientSocket == NULL)
50 bool* autoRecovery = const_cast <bool*>(&a_autoRecovery);
51 *autoRecovery = false;
54 Communicator* communicator = functions::component <Communicator> (ANNA_FILE_LOCATION);
55 communicator->detach(a_clientSocket);
56 } catch(Exception& ex) {
62 * Se invoca desde com::handle::RemoteConnection::finalize
63 * [Tx] -> Communicator
65 * El socket se cierra protegido por esta SSCC para asegurar que los recursos se usan/bloquean en el mismo
66 * orden que el usado en el Server::connect.
68 void comm::Server::reset()
69 throw(RuntimeException) {
70 // La SSCC se establece en el método que invoca a éste
71 // Guard guard (*this, "comm::Server::reset");
72 if(a_clientSocket == NULL)
75 a_clientSocket->close();
76 delete a_clientSocket;
77 a_clientSocket = NULL;
80 void comm::Server::setReceiverFactory(comm::ReceiverFactory& receiverFactory)
82 a_receiverFactory = &receiverFactory;
84 if(a_clientSocket != NULL)
85 a_clientSocket->setReceiverFactory(receiverFactory);
89 * El punto conflictivo de llamada es desde el comm::ConnectionRecover::tryRecover
91 * [T1] -> Communicator
93 * (1) La instancia RemoteConnection se libera en el handler::RemoteConnection::finalize.
94 * (2) La espera maxima solo se aplica si ha sido modificada .
95 * (3) La espera para la escritura sobre buffer de salida llenos solo se aplica si ha sido modificada.
97 * Lista de llamadas en 1.11.07
99 [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (90) | thr: 0xb7819b20 | Guard::lock | Reference: (0x9f86090): comm::Host::createServer
101 [19/11/2009 13:22:07] Information | comm.Host.cc (91) | thr: 0xb7819b20 | comm::Host::createServer | comm::Server { ...
103 [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (90) | thr: 0xb7819b20 | Guard::lock | Reference: (0x9f865b0): comm::Server::connect
105 [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (90) | thr: 0xb7819b20 | Guard::lock | Reference: (0xbfd67ea8): comm::Communicator::attach (RemoteConnection)
107 [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (90) | thr: 0xb7819b20 | Guard::lock | Reference: (0x9f86608): anna::comm::ClientSocket (connect)
109 [19/11/2009 13:22:07] Debug | comm.Socket.cc (171) | thr: 0xb7819b20 | anna::comm::Socket::open | comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { <null> } | Bound: false } | RcvBufferSize: -1 bytes | Status: None | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } }
111 [19/11/2009 13:22:07] Debug | comm.Socket.cc (219) | thr: 0xb7819b20 | anna::comm::Socket::setBlockingMode | Current: false | Previous: true
113 [19/11/2009 13:22:07] Debug | comm.ClientSocket.cc (286) | thr: 0xb7819b20 | anna::comm::ClientSocket::connect | comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { <null> } | Bound: false } | RcvBufferSize: 87380 bytes | Status: Connected | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } }
115 [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (78) | thr: 0xb7819b20 | Guard::deactivate | Reference: (0x9f86608): anna::comm::ClientSocket (connect)
117 [19/11/2009 13:22:07] Notice | comm.Communicator.cc (714) | thr: 0xb7819b20 | comm::Communicator::eventCreateConnection | comm::Server { anna::Resource { Nombre: 127.0.0.1:2000 | Habilitado: true | Disponible: true } | Auto-Recovery: false | comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { <null> } | Bound: false } | RcvBufferSize: 87380 bytes | Status: Connected | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } } }
119 [19/11/2009 13:22:07] Debug | comm.Communicator.cc (213) | thr: 0xb7819b20 | comm::Communicator::attach | comm::handler::RemoteConnection { comm::Handler { anna::Runnable { Id: Handler4 | Running: false | RequestedStop: false } | fd: 4 } | comm::RemoteConnection { comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { <null> } | Bound: false } | RcvBufferSize: 87380 bytes | Status: Connected | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } } } }
121 [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (78) | thr: 0xb7819b20 | Guard::deactivate | Reference: (0xbfd67ea8): comm::Communicator::attach (RemoteConnection)
123 [19/11/2009 13:22:07] Debug | comm.Server.cc (163) | thr: 0xb7819b20 | anna::comm::Server::connect | comm::Server { anna::Resource { Nombre: 127.0.0.1:2000 | Habilitado: true | Disponible: true } | Auto-Recovery: false | comm::ClientSocket { comm::Socket { Domain: Inet | Type: Stream | comm::TransportFactory { Name: anna::comm::SureTransport | OverQuotaSize: 0 bytes } | fd: 4 | LocalPoint: { <null> } | Bound: false } | RcvBufferSize: 87380 bytes | Status: Connected | MaxConDelay: 200 ms | Reserved: 0 | Pending: 0 | Offset: 0 | ExpectedSize: -1 | Punto remoto: { comm::INetAddress { comm::Device { IP: 127.0.0.1 | Status: Up } | Port: 2000 } } } }
125 [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (78) | thr: 0xb7819b20 | Guard::deactivate | Reference: (0x9f865b0): comm::Server::connect
127 [19/11/2009 13:22:07] Local7 | mt.db/Guard.cc (78) | thr: 0xb7819b20 | Guard::deactivate | Reference: (0x9f86090): comm::Host::createServer
130 void comm::Server::connect()
131 throw(RuntimeException) {
132 LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Server", "connect", ANNA_FILE_LOCATION));
133 Communicator* communicator = functions::component <Communicator> (ANNA_FILE_LOCATION);
135 * Para asegurar el mismo orden de bloqueo a la hora de tratar la desconexión.
137 Guard guard(communicator, "comm::Communicator from comm::Server::connect");
138 Guard guard2(*this, "comm::Server::connect");
140 if(a_clientSocket != NULL && a_clientSocket->isConnected() == true)
143 Host::const_device_iterator ii;
144 Host::const_device_iterator maxii = a_host.device_end();
147 for(ii = a_host.device_begin(); ii != maxii; ii ++)
148 counter += (Host::device(ii)->getStatus() == Device::Status::Up);
151 const Millisecond msMaxConnectionDelay = a_msMaxConnectionDelay / counter;
152 RemoteConnection* remoteConnection = NULL;
154 for(ii = a_host.device_begin(); ii != maxii && a_clientSocket == NULL; ii ++) {
155 a_clientSocket = allocateClientSocket(INetAddress(Host::device(ii), a_remotePort), a_transportFactory);
157 if(msMaxConnectionDelay != 0)
158 a_clientSocket->setMaxConnectionDelay(msMaxConnectionDelay); // (2)
160 if(a_clientSocket->getMaxWriteDelay() != a_msMaxWriteDelay)
161 a_clientSocket->setMaxWriteDelay(a_msMaxWriteDelay); // (3)
163 if(a_receiverFactory != NULL)
164 a_clientSocket->setReceiverFactory(*a_receiverFactory);
166 a_clientSocket->setIgnoreIncomingMessages(a_ignoreIncomingMessages);
167 remoteConnection = new RemoteConnection(this, a_clientSocket); // (1)
170 communicator->attach(remoteConnection);
171 } catch(RuntimeException& ex) {
172 delete a_clientSocket;
173 delete remoteConnection;
174 a_clientSocket = NULL;
180 if(a_clientSocket == NULL) {
181 string msg(asString());
182 msg += " | Cannot connect to server";
183 throw RuntimeException(msg, ANNA_FILE_LOCATION);
187 string msg("anna::comm::Server::connect | ");
189 Logger::debug(msg, ANNA_FILE_LOCATION)
193 //---------------------------------------------------------------------------------------
194 // (1) Mejora de la version 1.0.8 -> Si el Server no tiene reconexion automatica pero
195 // se intenta usar => se intenta volver a conectar antes de dar el fallo.
196 //---------------------------------------------------------------------------------------
197 comm::ClientSocket* comm::Server::send(Message& message)
198 throw(RuntimeException) {
199 LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::Server", "send", ANNA_FILE_LOCATION));
200 Guard guard(*this, "comm::Server::send");
201 const bool available = isAvailable();
202 const bool enabled = isEnabled();
204 if(a_autoRecovery == false && available == false && enabled == true) // (1)
207 if(available == false || enabled == false) {
208 string msg(asString());
209 msg += " | Server unavailable";
210 throw RuntimeException(msg, ANNA_FILE_LOCATION);
213 a_clientSocket->send(message);
214 return a_clientSocket;
217 comm::ClientSocket* comm::Server::send(Message* message)
218 throw(RuntimeException) {
220 throw RuntimeException("anna::comm::Server::send | Cannot send a NULL message", ANNA_FILE_LOCATION);
222 return send(*message);
225 void comm::Server::setAutoRecovery(bool autoRecovery) throw() {
226 bool* ar = const_cast <bool*>(&a_autoRecovery);
230 bool comm::Server::isAvailable() const
231 throw(RuntimeException) {
232 // Guard guard (*this, "comm::Server::isAvailable");
233 return (a_clientSocket == NULL) ? false : (a_clientSocket->isConnected() && (a_clientSocket->isClosedPending() == false));
236 // Este metodo sea re-escrito en commsec::Server::allocateClientSocket para devolver un commsec::RemoteConnection
237 comm::ClientSocket* comm::Server::allocateClientSocket(const comm::INetAddress& in, comm::TransportFactory* transportFactory) const
239 return new ClientSocket(in, transportFactory);
242 string comm::Server::asString() const
244 string result("comm::Server { ");
245 result += Resource::asString();
246 result += " | Sequence: ";
247 result += functions::asString(a_sequence);
248 result += " | Auto-Recovery: ";
249 result += functions::asString(a_autoRecovery);
252 if(a_clientSocket == NULL) {
254 result += a_host.getName();
255 result += functions::asString(" | RemotePort: %d", a_remotePort);
257 result += a_clientSocket->asString();
259 return result += " }";
262 xml::Node* comm::Server::asXML(xml::Node* parent) const
263 throw(RuntimeException) {
264 xml::Node* result = parent->createChild("comm.Server");
265 result->createAttribute("Host", a_host.getName());
266 result->createAttribute("Sequence", a_sequence);
267 comm::Resource::asAttribute(result);
268 result->createAttribute("AutoRecovery", functions::asString(a_autoRecovery));
269 result->createAttribute("RemotePort", a_remotePort);
270 result->createAttribute("IgnoreIncomingMessages", functions::asString(a_ignoreIncomingMessages));
272 if(a_clientSocket != NULL)
273 result->createAttribute("fd", a_clientSocket->getfd());