Updated license
[anna.git] / source / comm / handler / LocalConnection.cpp
1 // ANNA - Anna is Not Nothingness 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/mt/Guard.hpp>
40 #include <anna/core/tracing/TraceMethod.hpp>
41
42 #include <anna/xml/Node.hpp>
43 #include <anna/xml/Attribute.hpp>
44
45 #include <anna/comm/internal/LocalConnection.hpp>
46 #include <anna/comm/Communicator.hpp>
47 #include <anna/comm/Device.hpp>
48 #include <anna/comm/ServerSocket.hpp>
49 #include <anna/comm/ClientSocket.hpp>
50 #include <anna/comm/Receiver.hpp>
51 #include <anna/comm/CongestionController.hpp>
52
53 #include <anna/comm/handler/LocalConnection.hpp>
54
55 using namespace std;
56 using namespace anna;
57
58 void comm::handler::LocalConnection::initialize()
59 throw(RuntimeException) {
60   LOGMETHOD(TraceMethod traceMethod("comm::handler::LocationConnection", "initialize", ANNA_FILE_LOCATION));
61
62   if(a_localConnection == NULL) {
63     string msg(asString());
64     msg += " | comm::LocalConnection was not established";
65     throw RuntimeException(msg, ANNA_FILE_LOCATION);
66   }
67
68   if(a_localConnection->getClientSocket()  == NULL) {
69     string msg(asString());
70     msg += " | comm::ClientSocket was not established";
71     throw RuntimeException(msg, ANNA_FILE_LOCATION);
72   }
73
74   setfd(a_localConnection->getClientSocket()->getfd());
75   CongestionController::instantiate().incrementIncomingSocket();
76 }
77
78 comm::ClientSocket* comm::handler::LocalConnection::getClientSocket()
79 throw() {
80   return (a_localConnection != NULL) ? a_localConnection->getClientSocket() : NULL;
81 }
82
83 /*
84  * Se invoca desde Communicator::detach.
85
86 <Method Id="comm::handler::MetaClientSocket::apply" File="handler.db/comm.handler.MetaClientSocket.cc" Line="45" LineNo="281">
87     <Guard Id="0x68ccd0" Name="comm::ClientSocket from comm::handler::MetaClientSocket::apply" LineNo="283"/>
88          <Guard Id="0x68c6a0" Name="comm::Communicator::detach" LineNo="289">
89          <Method Id="comm::handler::LocationConnection::finalize" File="handler.db/comm.handler.LocalConnection.cc" Line="78" LineNo="293">
90             <Guard Id="0x68ccd0" Name="comm::Socket::close" LineNo="295">
91                   <Guard Id="0x6818e0" Name="PN7anna4comm16TransportFactoryE" LineNo="297"/>
92              </Guard>
93         <Guard Id="0x68c678" Name="N7anna12SafeRecyclerINS_4comm15LocalConnectionENS_9AllocatorIS2_EEEE::release (T*)" LineNo="305"/>
94         </Method>
95      </Guard>
96 </Method>
97
98  */
99 void comm::handler::LocalConnection::finalize()
100 throw() {
101   LOGMETHOD(TraceMethod traceMethod("comm::handler::LocationConnection", "finalize", ANNA_FILE_LOCATION));
102
103   if(a_localConnection == NULL)
104     return;
105
106   comm::ClientSocket* clientSocket = a_localConnection->getClientSocket();
107
108   if(clientSocket != NULL) {
109     // Notificacion al Receiver (EDU Julio 2012)
110     Receiver* receiver;
111
112     if((receiver = clientSocket->getReceiver()) != NULL)
113       receiver->eventBreakLocalConnection(*clientSocket);
114
115     a_communicator->eventBreakLocalConnection(*clientSocket);
116     clientSocket->close();
117   }
118
119   comm::ServerSocket* serverSocket = a_localConnection->getServerSocket();
120
121   if(serverSocket != NULL) {
122     // serverSocket->eventBreakLocalConnection (a_localConnection); // @Eduardo (independence from communicator)
123     //
124     // Este lo quito porque ya tenemos el Receiver del clientSocket y eso cubre los dos tipos de politica de gestion de conexiones:
125     //
126     // (1) Un proceso servidor que admite N conexiones puede controlar las gestionadas mediante cierre/apertura del servidor de escucha (ServerSocket)
127     //     Cuando llega al máximo configurado, hace un detach del comunicador (desaparece el LISTEN): communicator::detach(anna::comm::ServerSocket*)
128     //     Cuando se rompe una conexion, se hace el attach del comunicador (aparece de nuevo el LISTEN): communicator::attach(anna::comm::ServerSocket*)
129     //
130     // (2) Un proceso servidor que admite N conexiones puede controlar las gestionadas mediante control de aceptacion devolviendo true o false al metodo
131     //     virtual (eventAcceptConnection), void comm::handler::ServerSocket::apply ():
132     //
133     //               bool accept = a_communicator->eventAcceptConnection (*localConnection->getClientSocket ());
134     //
135     //               // @Eduardo (independence from communicator)
136     //               if (accept) accept = a_serverSocket->eventAcceptConnection(*localConnection->getClientSocket ());
137     //
138     // Problemas:
139     // (1) En este caso, si hemos ocupado todas las conexiones y no tenemos escucha, el ServerSocket ha desaparecido (es NULL) entonces NO INVOCARIA AL
140     //     'serverSocket->eventBreakLocalConnection (a_localConnection);' porque no pasa por este bloque (serverSocket es NULL) y la aplicación no puede ser notificada.
141     //     Pero si la aplicacion establece un receiver al clientSocket recibido en el eventAcceptConnection, si sería notificada. Quito por lo tanto la notificacion
142     //     'serverSocket->eventBreakLocalConnection (a_localConnection)', porque si la politica es la (2), la aplicación sería notificada dos veces, lo cual no es deseable.
143     //
144     // (2) El problema de este metodo es el consumo de recursos, y sobre todo, que el cliente va a conectar y enviar paquetes que luego se sabe que no
145     //     van a ninguna parte porque el accept devolverá un false y se cerrara dicha conexion. Es preferible que el cliente vea un connection refused
146     //     por no existir un LISTEN
147     //
148     serverSocket->release(a_localConnection);
149   }
150
151   a_localConnection = NULL;
152   CongestionController::instantiate().decrementIncomingSocket();
153 }
154
155 string comm::handler::LocalConnection::asString() const
156 throw() {
157   string result("comm::handler::LocalConnection { ");
158   result += comm::Handler::asString();
159   result += " | ";
160   result += functions::asString(a_localConnection);
161   return result += " }";
162 }
163
164 xml::Node* comm::handler::LocalConnection::asXML(xml::Node* parent) const
165 throw() {
166   xml::Node* result = parent->createChild("comm.handler.LocalConnection");
167   comm::Handler::asAttribute(result);
168
169   if(a_localConnection)
170     a_localConnection->asXML(result);
171
172   return result;
173 }
174
175