First commit
[anna.git] / source / comm / handler / MetaClientSocket.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/tracing/TraceMethod.hpp>
39
40 #include <anna/comm/Communicator.hpp>
41 #include <anna/comm/ClientSocket.hpp>
42 #include <anna/comm/Transport.hpp>
43 #include <anna/comm/Device.hpp>
44 #include <anna/comm/Receiver.hpp>
45
46 #include <anna/comm/handler/MetaClientSocket.hpp>
47
48 using namespace std;
49 using namespace anna;
50
51 /*
52  * Este método se ejecuta desde un único thread (Tx). Cada socket tiene asociado un thread que lo trata.
53  */
54 void comm::handler::MetaClientSocket::apply()
55 throw(RuntimeException) {
56   LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::handler::MetaClientSocket", "apply", ANNA_FILE_LOCATION));
57   comm::ClientSocket* clientSocket = getClientSocket();
58
59   if(clientSocket == NULL) {
60     string msg("comm::handler::MetaClientSocket::apply | fd: ");
61     msg += functions::asString(getfd());
62     msg += " | getClientSocket returns NULL";
63     Logger::warning(msg, ANNA_FILE_LOCATION);
64     a_communicator->detach(this);
65     return;
66   }
67
68   /*
69    * En MT se ha comprobado que hay alguna combinaci�n en la que se llega a tratar un socket que ha sido cerrado previamente.
70    */
71   if(clientSocket->isOpened() == false) {
72     string msg("comm::handler::MetaClientSocket::apply | fd: ");
73     msg += functions::asString(getfd());
74     msg += " | Detected incoming socket overload";
75     Logger::error(msg, ANNA_FILE_LOCATION);
76     requestStop();
77     return;
78   }
79
80   bool mustDetach(false);
81   {
82     Guard guard(clientSocket, "comm::ClientSocket from comm::handler::MetaClientSocket::apply");
83     comm::ClientSocket::Notify::_v notify = clientSocket->receive();
84
85     if(notify == comm::ClientSocket::Notify::ReceiveData) {
86       const Message* message;
87       const DataBlock* dataBlock;
88       int messageCounter = 0;
89       Transport* transport = clientSocket->getTransport();
90       Receiver* receiver = clientSocket->getReceiver();
91       clientSocket->activate(comm::ClientSocket::Status::Working);
92
93       while(canContinue() == true && (dataBlock = clientSocket->fetch()) != NULL) {
94         try {
95           try {
96             message = transport->decode(*dataBlock);                          // (4)
97           } catch(RuntimeException& ex) {
98             ex.trace();
99             clientSocket->activate(comm::ClientSocket::Status::Corrupt);
100             message = NULL;
101             break;
102           }
103
104           if(message != NULL) {
105             messageCounter ++;
106
107             if(receiver == NULL)
108               a_communicator->eventReceiveMessage(*clientSocket, *message);
109             else
110               receiver->apply(*clientSocket, *message);
111           }
112         } catch(RuntimeException& ex) {
113           ex.trace();
114         }
115       }
116
117       LOGLOCAL6(
118         string msg("comm::handler::MetaClientSocket::apply | fd: ");
119         msg += functions::asString(getfd());
120         msg += functions::asText(" | Message Counter: ", messageCounter);
121         Logger::write(Logger::Local6, msg, ANNA_FILE_LOCATION);
122       );
123       clientSocket->deactivate(comm::ClientSocket::Status::Working);
124
125       if(clientSocket->hasRequestedClose() == true || clientSocket->isCorrupt()) {
126         if(clientSocket->isCorrupt()) {
127           string msg(clientSocket->asString());
128           msg += " | ClientSocket was closed because of wrong message";
129           Logger::error(msg, ANNA_FILE_LOCATION);
130           a_communicator->eventDiscardConnection(*clientSocket);
131         }
132
133         mustDetach = true;
134       }
135     } else if(notify == comm::ClientSocket::Notify::Close || notify == comm::ClientSocket::Notify::Corrupt) {  // (2)
136       if(clientSocket->isCorrupt()) {
137         string msg(clientSocket->asString());
138         msg += " | ClientSocket was closed because of wrong message";
139         Logger::error(msg, ANNA_FILE_LOCATION);
140         a_communicator->eventDiscardConnection(*clientSocket);
141       }
142
143       mustDetach = true;
144     }
145   }
146
147   /*
148    * Termina llamando al XXX::finalize sobre-escrito por la clase heredada de esta
149    */
150   if(mustDetach == true)
151     a_communicator->detach(this);
152 }
153
154 //virtual
155 bool comm::handler::MetaClientSocket::testClose()
156 throw(RuntimeException) {
157   LOGMETHOD(TraceMethod tm(Logger::Local7, "comm::handler::MetaClientSocket", "testClose", ANNA_FILE_LOCATION));
158   comm::ClientSocket* clientSocket = getClientSocket();
159
160   if(clientSocket == NULL) {
161     string msg("comm::handler::MetaClientSocket::testClose | fd: ");
162     msg += functions::asString(getfd());
163     msg += " | getClientSocket returns NULL";
164     Logger::warning(msg, ANNA_FILE_LOCATION);
165     a_communicator->detach(this);
166     return false;
167   }
168
169   bool mustClose;
170   {
171     Guard guard(clientSocket, "comm::ClientSocket from comm::handler::MetaClientSocket::testClose");
172     mustClose = clientSocket->hasRequestedClose();
173   }
174
175   /*
176    * Termina llamando al XXX::finalize sobre-escrito por la clase heredada de esta
177    */
178   if(mustClose == true)
179     a_communicator->detach(this);
180
181   return mustClose;
182 }
183
184 /*
185  * Este metodo se invoca cuando algun elemento externo detecta la caída de toda la red 'address'
186  *
187  * Por lo que se puede invocar desde cualquier otro thread no reconocido.
188  */
189 void comm::handler::MetaClientSocket::breakAddress(const in_addr_t& address)
190 throw() {
191   comm::ClientSocket* clientSocket = getClientSocket();
192
193   if(clientSocket == NULL) {
194     string msg(asString());
195     msg += " | getClientSocket returns NULL";
196     throw RuntimeException(msg, ANNA_FILE_LOCATION);
197   }
198
199   {
200     Guard guard(clientSocket, "comm::ClientSocket from comm::handler::MetaClientSocket::breakAddress");
201     const comm::AccessPoint& accessPoint = clientSocket->getRemoteAccessPoint();
202     const comm::Device* device = accessPoint.getINetAddress().getDevice(false);
203
204     if(device == NULL)
205       return;
206
207     if(device->getAddress() != address)
208       return;
209
210     LOGDEBUG(
211       string msg("comm::handler::MetaClientSocket::breakAddress | ");
212       msg += clientSocket->asString();
213       Logger::debug(msg, ANNA_FILE_LOCATION);
214     );
215   }
216
217   /*
218    * Termina llamando al XXX::finalize sobre-escrito por la clase heredada de esta
219    */
220   a_communicator->detach(clientSocket);
221 }
222