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