Solve legacy problem with clear operation (coredump with running threads)
[anna.git] / source / comm / handler / ServerSocket.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
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 //
7
8
9 #include <anna/core/tracing/Logger.hpp>
10 #include <anna/core/functions.hpp>
11 #include <anna/core/tracing/TraceMethod.hpp>
12
13 #include <anna/xml/Node.hpp>
14 #include <anna/xml/Attribute.hpp>
15
16 #include <anna/comm/ServerSocket.hpp>
17 #include <anna/comm/Communicator.hpp>
18 #include <anna/comm/internal/LocalConnection.hpp>
19 #include <anna/comm/ClientSocket.hpp>
20 #include <anna/comm/Device.hpp>
21
22 #include <anna/comm/handler/ServerSocket.hpp>
23 #include <anna/comm/handler/Manager.hpp>
24
25 using namespace std;
26 using namespace anna;
27
28 void comm::handler::ServerSocket::initialize()
29 throw(RuntimeException) {
30   LOGMETHOD(TraceMethod traceMethod("comm::handler::ServerSocket", "initialize", ANNA_FILE_LOCATION));
31
32   if(a_serverSocket == NULL) {
33     string msg(asString());
34     msg += " | comm::ServerSocket was not established";
35     throw RuntimeException(msg, ANNA_FILE_LOCATION);
36   }
37
38   if(a_serverSocket->isBound() == false)
39     a_serverSocket->bind();
40
41   setfd(a_serverSocket->getfd());
42   a_serverSocket->prepare();
43   a_serverSocket->setBlockingMode(false);
44 }
45
46 /*
47 // Cuando un ServerSocket recibe actividad en el fd sólo puede ser para
48 // recibir una solicitud de conexión de un proceso remoto, que estará
49 // instanciando un ClientSocket contra este.
50 //
51 // (1) Esta situacion se ha dado cuando hemos probado varios servidores
52 // en modo compartido.
53 //
54 // Se invoca desde [Tx] -> <null>
55 // La secuencia de bloqueo tiene que coincidir con la del método comm::handler::LocalConnection::finalize:
56
57 <Method Id="comm::handler::MetaClientSocket::apply" File="handler.db/comm.handler.MetaClientSocket.cc" Line="45" LineNo="281">
58     <Guard Id="0x68ccd0" Name="comm::ClientSocket from comm::handler::MetaClientSocket::apply" LineNo="283"/>
59     <Guard Id="0x68c6a0" Name="comm::Communicator::detach" LineNo="289">
60        <Method Id="comm::handler::LocationConnection::finalize" File="handler.db/comm.handler.LocalConnection.cc" Line="78" LineNo="293">
61          <Guard Id="0x68ccd0" Name="comm::Socket::close" LineNo="295">
62             <Guard Id="0x6818e0" Name="PN7anna4comm16TransportFactoryE" LineNo="297"/>
63          </Guard>
64          <Guard Id="0x68c678" Name="N7anna12SafeRecyclerINS_4comm15LocalConnectionENS_9AllocatorIS2_EEEE::release (T*)" LineNo="305"/>
65         </Method>
66     </Guard>
67 </Method>
68
69 // para eso bloqueamos el comm::Communicator.
70 */
71 void comm::handler::ServerSocket::apply()
72 throw(RuntimeException) {
73   LOGMETHOD(TraceMethod traceMethod("handler::ServerSocket", "apply", ANNA_FILE_LOCATION));
74   Guard guard(a_communicator, "Communicator from handler::ServerSocket");
75   comm::LocalConnection* localConnection = a_serverSocket->accept();
76
77   if(localConnection == NULL)                                          // (1)
78     return;
79
80   bool accept = a_communicator->eventAcceptConnection(*localConnection->getClientSocket());
81
82   // @Eduardo (independence from communicator)
83   if(accept) accept = a_serverSocket->eventAcceptConnection(*localConnection->getClientSocket());
84
85   // Ver comentarios adicionales en void comm::handler::LocalConnection::finalize ()
86
87   if(accept == false) {
88     LOGWARNING(
89       string msg(localConnection->asString());
90       msg += " | Service denied";
91       Logger::warning(msg, ANNA_FILE_LOCATION);
92     );
93     localConnection->getClientSocket()->close();
94     a_serverSocket->release(localConnection);
95   } else {
96     try {
97       a_communicator->attach(localConnection);
98     } catch(RuntimeException&) {
99       localConnection->getClientSocket()->close();
100       a_serverSocket->release(localConnection);
101       throw;
102     }
103   }
104 }
105
106 //--------------------------------------------------------------------------
107 // Si cae la dirección en la que está escuchando finalizamos todos los
108 // que tengan establecidos contra este ServerSocket.
109 //--------------------------------------------------------------------------
110 void comm::handler::ServerSocket::breakAddress(const in_addr_t& address)
111 throw() {
112   LOGMETHOD(TraceMethod traceMethod("comm::handler::ServerSocket", "breakAddress", ANNA_FILE_LOCATION));
113   const comm::AccessPoint& accessPoint = a_serverSocket->getLocalAccessPoint();
114   const comm::Device* device = accessPoint.getINetAddress().getDevice(false);
115
116   if(device == NULL)
117     return;
118
119   if(device->getAddress() != address)
120     return;
121
122   Guard guard(a_serverSocket, "comm::handler::ServerSocket::breakAddress");
123   /**
124    * Trabaja sobre una copia para no perder la referencia cuando se elimine un miembro de la lista original
125    */
126   typedef vector <comm::LocalConnection*> work_container;
127   typedef work_container::iterator work_iterator;
128   work_container ww;
129
130   for(comm::ServerSocket::iterator ii = a_serverSocket->begin(), maxii = a_serverSocket->end(); ii != maxii; ii ++)
131     ww.push_back(comm::ServerSocket::localConnection(ii));
132
133   int n = 0;
134
135   for(work_iterator ii = ww.begin(), maxii = ww.end(); ii != maxii; ii ++) {
136     a_communicator->detach((*ii)->getClientSocket());
137     n ++;
138   }
139
140   LOGDEBUG(
141     string msg("comm::handler::ServerSocket::breakAddress | ");
142     msg += a_serverSocket->asString();
143     msg += " | Clients number: ";
144     msg += functions::asString(n);
145     Logger::debug(msg, ANNA_FILE_LOCATION);
146   );
147 }
148
149 /**
150  * No cierra las conexiones locales que hayan partido desde este ServerSocket, porque tambien cerriamos el
151  * MainHandler cuando se use el Communicator::Clone.
152  */
153 void comm::handler::ServerSocket::finalize()
154 throw() {
155   LOGMETHOD(TraceMethod traceMethod("comm::handler::ServerSocket", "finalize", ANNA_FILE_LOCATION));
156
157   if(a_serverSocket == NULL)
158     return;
159
160   for(comm::ServerSocket::iterator ii = a_serverSocket->begin(), maxii = a_serverSocket->end(); ii != maxii; ii ++)
161     comm::ServerSocket::localConnection(ii)->setServerSocket(NULL);
162
163   a_serverSocket->close();
164   a_serverSocket = NULL;
165 }
166
167 string comm::handler::ServerSocket::asString() const
168 throw() {
169   string result("comm::handler::ServerSocket { ");
170   result += comm::Handler::asString();
171   result += " | ";
172   result += functions::asString(a_serverSocket);
173   return result += " }";
174 }
175
176 xml::Node* comm::handler::ServerSocket::asXML(xml::Node* parent) const
177 throw() {
178   xml::Node* result = parent->createChild("comm.handler.ServerSocket");
179   comm::Handler::asAttribute(result);
180
181   if(a_serverSocket)
182     a_serverSocket->asXML(result);
183
184   return result;
185 }
186
187