1 // ANNA - Anna is Not Nothingness Anymore //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo //
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 //
9 #include <anna/diameter.comm/ClientSession.hpp>
10 #include <anna/diameter.comm/Entity.hpp>
11 #include <anna/diameter.comm/Engine.hpp>
12 #include <anna/diameter.comm/OamModule.hpp>
13 #include <anna/diameter/codec/functions.hpp>
14 #include <anna/diameter/helpers/base/defines.hpp>
15 #include <anna/core/functions.hpp>
16 #include <anna/statistics/Engine.hpp>
17 #include <anna/time/functions.hpp>
19 #include <anna/core/tracing/Logger.hpp>
20 #include <anna/core/functions.hpp>
21 #include <anna/core/tracing/TraceMethod.hpp>
27 using namespace anna::diameter;
28 using namespace anna::diameter::comm;
31 void Server::initialize() throw() {
34 a_clientSessions.clear(); // importante (el recycler creo que no lo tocaba)
36 a_maxClientSessions = 1; // mono client connection
37 a_lastIncomingActivityTime = (anna::Millisecond)0;
38 a_lastOutgoingActivityTime = (anna::Millisecond)0;
39 a_statisticsAccumulator = anna::statistics::Engine::instantiate().createAccumulator();
40 a_lastUsedResource = NULL;
43 void Server::initializeStatisticConcepts() throw() {
45 std::string realmName = a_engine ? a_engine->getRealm() : "unknown"; // it should be known (createServer)
48 anna::statistics::Engine& statsEngine = anna::statistics::Engine::instantiate();
49 // Concepts descriptions:
50 std::string serverAsString = anna::functions::socketLiteralAsString(a_socket.first, a_socket.second);
51 std::string c1desc = "Diameter processing time (for requests) at servers on "; c1desc += serverAsString; c1desc += " for realm '"; c1desc += realmName; c1desc += "'";
52 std::string c2desc = "Diameter message sizes received from servers on "; c2desc += serverAsString; c2desc += " for realm '"; c2desc += realmName; c2desc += "'";
54 a_processing_time__StatisticConceptId = statsEngine.addConcept(c1desc.c_str(), "ms", true/* integer values */);
55 a_received_message_size__StatisticConceptId = statsEngine.addConcept(c2desc.c_str(), "bytes", true/* integer values */);
58 void Server::resetStatistics() throw() {
59 a_statisticsAccumulator->reset();
62 void Server::updateProcessingTimeStatisticConcept(const double &value) throw() {
63 a_statisticsAccumulator->process(a_processing_time__StatisticConceptId, value);
64 LOGDEBUG(anna::Logger::debug(a_statisticsAccumulator->asString(), ANNA_FILE_LOCATION));
67 void Server::updateReceivedMessageSizeStatisticConcept(const double &value) throw() {
68 a_statisticsAccumulator->process(a_received_message_size__StatisticConceptId, value);
69 //LOGDEBUG(anna::Logger::debug(a_statisticsAccumulator->asString(), ANNA_FILE_LOCATION));
73 void Server::assertReady() throw(anna::RuntimeException) {
74 if(a_clientSessions.size() != a_maxClientSessions) {
75 std::string msg(asString());
76 msg += " | Non-configured server: you must add the remaining client-sessions before any operation (bind, send, etc.)";
77 throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
82 void Server::addClientSession(int socketId)
83 throw(anna::RuntimeException) {
84 if(a_clientSessions.size() == a_maxClientSessions) {
87 std::string msg = "Maximum number of client-sessions reached for this server (";
88 msg += anna::functions::asString(a_maxClientSessions);
90 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
96 throw anna::RuntimeException("Invalid engine reference (NULL)", ANNA_FILE_LOCATION);
98 ClientSession *s = a_engine->createClientSession(this, socketId);
99 a_clientSessions.push_back(s);
102 int Server::getOTARequests() const throw() {
105 for(std::vector<ClientSession*>::const_iterator it = begin(); it != end(); it++)
106 result += (*it)->getOTARequests();
112 bool Server::send(const Message* message, int socketId) throw(anna::RuntimeException) {
113 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "send", ANNA_FILE_LOCATION));
115 bool fixedSocket = (socketId != -1);
116 int clientSessions = getNumberOfClientSessions();
118 for(int k = 0; k < clientSessions; k++) { // try round-robin only over one cycle,
119 // no matter where you are: don't repeat same socket
121 a_lastUsedResource = a_engine->findClientSession(a_socket.first /*ip*/, a_socket.second /*port*/, socketId); // exception if not found
123 if(a_deliveryIterator == end()) a_deliveryIterator = begin();
125 a_lastUsedResource = (*a_deliveryIterator);
127 if(clientSessions > 1) a_deliveryIterator++; // Round robin
132 const Response* response = a_lastUsedResource->send(message);
133 return true; // no matter if response is NULL (answers, i.e.) or not.
134 } catch(anna::RuntimeException &ex) {
136 std::string msg = ex.getText();
137 msg += " | Send failed on socket id ";
138 msg += anna::functions::asString(a_lastUsedResource->getSocketId());
139 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
143 // Specific socket sending doesn't try
144 if(fixedSocket) return false;
151 bool Server::broadcast(const Message* message) throw(anna::RuntimeException) {
152 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "broadcast", ANNA_FILE_LOCATION));
154 const Response* response;
157 for(std::vector<ClientSession*>::iterator it = begin(); it != end(); it++) {
159 response = (*it)->send(message);
160 } catch(anna::RuntimeException &ex) {
170 bool Server::bind() throw(anna::RuntimeException) {
171 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "bind", ANNA_FILE_LOCATION));
173 a_deliveryIterator = begin();
174 bool result = true; // all OK return
176 for(std::vector<ClientSession*>::iterator it = begin(); it != end(); it++) {
179 } catch(anna::RuntimeException &ex) {
188 void Server::raiseAutoRecovery(bool autoRecovery) throw(anna::RuntimeException) {
189 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "raiseAutoRecovery", ANNA_FILE_LOCATION));
191 a_deliveryIterator = begin();
193 for(std::vector<ClientSession*>::iterator it = begin(); it != end(); it++)
194 (*it)->setAutoRecovery(autoRecovery);
197 void Server::setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw() {
198 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "setClassCodeTimeout", ANNA_FILE_LOCATION));
201 for(std::vector<ClientSession*>::iterator it = begin(); it != end(); it++) {
203 (*it)->setClassCodeTimeout(v, millisecond);
204 } catch(anna::RuntimeException &ex) {
211 // Private close/destroy method
212 void Server::close(bool destroy) throw(anna::RuntimeException) {
213 LOGMETHOD(anna::TraceMethod tttm("diameter::comm::Server", "close", ANNA_FILE_LOCATION));
216 throw anna::RuntimeException("Invalid engine reference (NULL)", ANNA_FILE_LOCATION);
220 for(std::vector<ClientSession*>::iterator it = begin(); it != end(); it++)
221 a_engine->closeClientSession(*it, destroy);
225 void Server::childIdle() const throw() {
226 // Check father entity idleness:
227 if(idle()) a_parent->childIdle();
231 void Server::hide() throw() {
232 for(std::vector<ClientSession*>::iterator it = begin(); it != end(); it++)
236 void Server::show() throw() {
237 for(std::vector<ClientSession*>::iterator it = begin(); it != end(); it++)
241 bool Server::hidden() const throw() {
242 for(std::vector<ClientSession*>::const_iterator it = begin(); it != end(); it++)
243 if((*it)->shown()) return false;
247 bool Server::shown() const throw() {
248 for(std::vector<ClientSession*>::const_iterator it = begin(); it != end(); it++)
249 if((*it)->hidden()) return false;
256 std::string Server::socketAsString() const throw() {
257 std::string result = getAddress();
259 result += anna::functions::asString(getPort());
264 std::string Server::asString() const throw() {
265 std::string result("diameter::comm::Server { ");
266 result += " | Parent Entity: ";
267 result += a_parent->getDescription();
268 result += " | Server Address: ";
269 result += a_socket.first;
270 result += " | Server Port: ";
271 result += anna::functions::asString(a_socket.second);
272 result += " | Available: ";
273 result += a_available ? "yes" : "no";
274 result += " | Max client-sessions supported: ";
275 result += anna::functions::asString(a_maxClientSessions);
276 result += " | Currently configured client-sessions: ";
277 result += anna::functions::asString(a_clientSessions.size());
278 result += anna::functions::asString(" | OTA requests: %d%s", getOTARequests(), idle() ? " (idle)" : "");
279 result += " | Last Incoming Activity Time: ";
280 result += a_lastIncomingActivityTime.asString();
281 result += " | Last Outgoing Activity Time: ";
282 result += a_lastOutgoingActivityTime.asString();
283 result += " | Hidden: ";
284 result += (hidden() ? "yes" : "no");
286 result += a_statisticsAccumulator->asString();
288 for(std::vector<ClientSession*>::const_iterator it = begin(); it != end(); it++) {
290 result += (*it)->asString();
296 anna::xml::Node* Server::asXML(anna::xml::Node* parent) const throw() {
297 anna::xml::Node* result = parent->createChild("diameter.Server");
298 result->createAttribute("ParentEntity", a_parent->getDescription());
299 result->createAttribute("ServerAddress", a_socket.first);
300 result->createAttribute("ServerPort", anna::functions::asString(a_socket.second));
301 result->createAttribute("Available", a_available ? "yes" : "no");
302 result->createAttribute("MaxClientSessionsSupported", anna::functions::asString(a_maxClientSessions));
303 result->createAttribute("CurrentlyConfiguredClientSessions", anna::functions::asString(a_clientSessions.size()));
304 result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
305 result->createAttribute("LastIncomingActivityTime", a_lastIncomingActivityTime.asString());
306 result->createAttribute("LastOutgoingActivityTime", a_lastOutgoingActivityTime.asString());
307 result->createAttribute("Hidden", hidden() ? "yes" : "no");
309 anna::xml::Node* stats = result->createChild("Statistics");
310 a_statisticsAccumulator->asXML(stats);
311 anna::xml::Node* clientSessions = result->createChild("Server.ClientSessions");
313 for(std::vector<ClientSession*>::const_iterator it = begin(); it != end(); it++)
314 (*it)->asXML(clientSessions);
320 void Server::eventPeerShutdown(const ClientSession *clientSession) throw() {
321 // Inform father entity:
322 a_parent->eventPeerShutdown(clientSession);
325 void Server::eventRequestRetransmission(const ClientSession* clientSession, Message *request) throw() {
326 // Inform father entity:
327 a_parent->eventRequestRetransmission(clientSession, request);
330 void Server::eventResponse(const Response& response) throw(anna::RuntimeException) {
331 // Inform father entity:
332 a_parent->eventResponse(response);
335 void Server::eventRequest(ClientSession *clientSession, const anna::DataBlock & request) throw(anna::RuntimeException) {
336 // Inform father entity:
337 a_parent->eventRequest(clientSession, request);
340 void Server::eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock & response) throw(anna::RuntimeException) {
341 // Inform father entity:
342 a_parent->eventUnknownResponse(clientSession, response);
345 void Server::eventDPA(ClientSession *clientSession, const anna::DataBlock & response) throw(anna::RuntimeException) {
346 // Inform father entity:
347 a_parent->eventDPA(clientSession, response);
351 void Server::availabilityLost() throw() {
353 std::string socket = anna::functions::socketLiteralAsString(a_socket.first, a_socket.second);
355 std::string msg = "diameter::comm::Server { Socket: ";
357 msg += " } has lost its availability";
358 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
361 OamModule &oamModule = OamModule::instantiate();
362 oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverServerDefinedAs__s__, socket.c_str());
363 oamModule.count(OamModule::Counter::LostAvailabilityOverServer);
364 a_engine->availabilityLost(this);
365 a_parent->refreshAvailability();
369 void Server::availabilityRecovered() throw() {
371 std::string socket = anna::functions::socketLiteralAsString(a_socket.first, a_socket.second);
373 std::string msg = "diameter::comm::Server { Socket: ";
375 msg += " } has recovered its availability";
376 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
379 OamModule &oamModule = OamModule::instantiate();
380 oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverServerDefinedAs__s__, socket.c_str());
381 oamModule.count(OamModule::Counter::RecoveredAvailabilityOverServer);
382 a_engine->availabilityRecovered(this);
383 a_parent->refreshAvailability();
388 bool Server::refreshAvailability() throw() {
390 if(a_available) { // check not-bound state for all client-sessions:
393 for(std::vector<ClientSession*>::const_iterator it = begin(); it != end(); it++)
395 //if ((*it)->getState() == ClientSession::State::Bound) { isolate = false; break; }
396 if((*it)->getState() != ClientSession::State::Closed) { isolate = false; break; }
406 // Here not available
407 for(std::vector<ClientSession*>::const_iterator it = begin(); it != end(); it++)
408 if((*it)->getState() == ClientSession::State::Bound) {
409 availabilityRecovered();
417 //------------------------------------------------------------------------------
418 //---------------------------------------- Server::updateIncomingActivityTime()
419 //------------------------------------------------------------------------------
420 void Server::updateIncomingActivityTime() throw() {
421 a_lastIncomingActivityTime = anna::functions::millisecond();
424 std::string msg = "Updated INCOMING activity on server (milliseconds unix): ";
425 msg += anna::functions::asString(a_lastIncomingActivityTime.getValue());
426 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
428 a_parent->updateIncomingActivityTime();
432 //------------------------------------------------------------------------------
433 //---------------------------------------- Server::updateOutgoingActivityTime()
434 //------------------------------------------------------------------------------
435 void Server::updateOutgoingActivityTime(void) throw() {
436 a_lastOutgoingActivityTime = anna::functions::millisecond();
439 std::string msg = "Updated OUTGOING activity on server (milliseconds unix): "; msg += anna::functions::asString(a_lastOutgoingActivityTime.getValue());
440 anna::Logger::debug(msg, ANNA_FILE_LOCATION);
442 a_parent->updateOutgoingActivityTime();