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