Updated license
[anna.git] / source / diameter.comm / LocalServer.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/diameter.comm/OamModule.hpp>
38 #include <anna/diameter.comm/Engine.hpp>
39 #include <anna/diameter.comm/LocalServer.hpp>
40 #include <anna/diameter.comm/ServerSession.hpp>
41 #include <anna/diameter.comm/ServerSocket.hpp>
42 #include <anna/core/functions.hpp>
43 #include <anna/statistics/Engine.hpp>
44 #include <anna/diameter.comm/TimerManager.hpp>
45
46 #include <anna/core/tracing/Logger.hpp>
47 #include <anna/core/tracing/TraceMethod.hpp>
48 #include <anna/core/functions.hpp>
49 #include <anna/app/functions.hpp>
50 #include <anna/xml/Node.hpp>
51 #include <anna/comm/Communicator.hpp>
52 #include <anna/comm/Network.hpp>
53 #include <anna/comm/Host.hpp>
54 #include <anna/comm/ClientSocket.hpp>
55
56 // STL
57 #include <string>
58
59
60
61 using namespace anna::diameter::comm;
62
63 LocalServer::LocalServer() :
64   //a_key(key),
65   a_description(""),
66   a_maxConnections(-1),
67   a_currentConnections(0),
68   a_allowedInactivityTime(ServerSession::DefaultAllowedInactivityTime),
69   a_engine(NULL),
70   a_serverSocket(NULL),
71   a_category(0),
72   a_lock(false),
73   a_available(false),
74   a_lastUsedResource(NULL) {
75   a_statisticsAccumulator.reset();
76 }
77
78
79 void LocalServer::initializeStatisticConcepts() throw() {
80   // Statistics:
81   anna::statistics::Engine& statsEngine = anna::statistics::Engine::instantiate();
82   // Concepts descriptions:
83   std::string serverAsString = anna::functions::socketLiteralAsString(a_key.first, a_key.second);
84   std::string c1desc = "Diameter processing time (for requests) at clients connected to "; c1desc += serverAsString;
85   std::string c2desc = "Diameter message sizes received from clients connected to "; c2desc += serverAsString;
86   // Registering
87   a_processing_time__StatisticConceptId = statsEngine.addConcept(c1desc.c_str(), "ms", true/* integer values */);
88   a_received_message_size__StatisticConceptId = statsEngine.addConcept(c2desc.c_str(), "bytes", true/* integer values */);
89 }
90
91 void LocalServer::resetStatistics() throw() {
92   a_statisticsAccumulator.reset();
93 }
94
95 void LocalServer::updateProcessingTimeStatisticConcept(const double &value) throw() {
96   a_statisticsAccumulator.process(a_processing_time__StatisticConceptId, value);
97   LOGDEBUG(anna::Logger::debug(a_statisticsAccumulator.asString(), ANNA_FILE_LOCATION));
98 }
99
100 void LocalServer::updateReceivedMessageSizeStatisticConcept(const double &value) throw() {
101   a_statisticsAccumulator.process(a_received_message_size__StatisticConceptId, value);
102   //LOGDEBUG(anna::Logger::debug(a_statisticsAccumulator.asString(), ANNA_FILE_LOCATION));
103 }
104
105
106 ServerSession* LocalServer::allocateServerSession() throw() { return a_serverSessionsRecycler.create(); }
107 void LocalServer::releaseServerSession(ServerSession *serverSession) throw() { a_serverSessionsRecycler.release(serverSession); }
108
109
110 LocalServer::serverSession_iterator LocalServer::serverSession_find(const serverSession_key &key) throw() {
111   return a_serverSessions.find(key);
112 }
113
114
115 LocalServer::serverSession_key LocalServer::getServerSessionKey(const anna::comm::ClientSocket &clientSocket) const throw() {
116   return (anna::functions::exclusiveHash(clientSocket.getRemoteAccessPoint().getINetAddress().serialize()));
117 }
118
119
120 void LocalServer::availabilityLost() throw() {
121   a_available = false;
122   std::string socket = anna::functions::socketLiteralAsString(a_key.first, a_key.second);
123   LOGDEBUG(
124     std::string msg = "diameter::comm::LocalServer { Socket: ";
125     msg += socket;
126     msg += " } has lost its availability";
127     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
128   );
129   // OAM
130   OamModule &oamModule = OamModule::instantiate();
131   oamModule.activateAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServerDefinedAs__s__, socket.c_str());
132   oamModule.count(OamModule::Counter::LostAvailabilityOverLocalServer);
133   a_engine->availabilityLost(this);
134   a_engine->refreshAvailabilityForLocalServers();
135 }
136
137
138 void LocalServer::availabilityRecovered() throw() {
139   a_available = true;
140   std::string socket = anna::functions::socketLiteralAsString(a_key.first, a_key.second);
141   LOGDEBUG(
142     std::string msg = "diameter::comm::LocalServer { Socket: ";
143     msg += socket;
144     msg += " } has recovered its availability";
145     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
146   );
147   // OAM
148   OamModule &oamModule = OamModule::instantiate();
149   oamModule.cancelAlarm(OamModule::Alarm::c_LostAvailabilityOverLocalServerDefinedAs__s__, socket.c_str());
150   oamModule.count(OamModule::Counter::RecoveredAvailabilityOverLocalServer);
151   a_engine->availabilityRecovered(this);
152   a_engine->refreshAvailabilityForLocalServers();
153 }
154
155
156
157 bool LocalServer::refreshAvailability() throw() {
158   // Here available
159   if(a_available) {  // check not-bound state for all server-sessions:
160 //      bool isolate = true;
161 //
162 //      for (const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++)
163 //         if (serverSession(it)->getState() != ServerSession::State::Closed) { isolate = false; break; }
164 //
165 //      if (isolate) {
166 // El problema de lo anterior, es que cuando se acepta una conexion, aun no ha llegado el CER (receive). Un server session
167 // esta en estado "Bound" cuando llega dicho CER y consecuentemente envio un CEA. Nos basaremos en 'a_currentConnections':
168     if(a_currentConnections == 0) {
169       availabilityLost();
170       return true;
171     }
172
173     return false;
174   }
175
176   // Here not available
177 //   for (const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++)
178 //      if (serverSession(it)->getState() == ServerSession::State::Bound) {
179   if(a_currentConnections > 0) {  // really == 0
180     availabilityRecovered();
181     return true;
182   }
183
184   return false;
185 }
186
187
188 void LocalServer::enable(bool unlock) throw(anna::RuntimeException) {
189   // Unlock ?
190   if(unlock) a_lock = false;
191
192   if(a_lock) return;
193
194   if(a_serverSocket && a_serverSocket->isOpened()) return;  // communicator attach twice gets poll bad file descriptor and application stops !
195
196   // Resolve local address:
197   anna::comm::Network& network = anna::comm::Network::instantiate();
198   // Little tricky:
199   anna::comm::Host *host = network.resolve(a_key.first /* addr */);
200   const anna::comm::Device *device = *(host->device_begin());
201   anna::comm::INetAddress localAddress(device, a_key.second /* port */);
202   // Create server socket and assign receiver factory
203   a_serverSocket = new ServerSocket(localAddress, this);
204   a_serverSocket->setCategory(a_category);
205   attach();
206 }
207
208 void LocalServer::attach() throw() {
209   try {
210     // Attach to communicator
211     anna::comm::Communicator * communicator = anna::app::functions::component <anna::comm::Communicator> (ANNA_FILE_LOCATION);
212     communicator->attach((anna::comm::ServerSocket*)a_serverSocket); // invokes handler insert and then initialize -> server socket bind (*)
213     // OAM
214     OamModule &oamModule = OamModule::instantiate();
215     oamModule.count(OamModule::Counter::ServerSocketsOpened);
216   } catch(anna::RuntimeException& ex) {
217     ex.trace(); // fails on (*) (i.e. Address already in use), within communicator attach
218     attachPlanning();
219     a_serverSocket->close();
220   }
221 }
222
223 void LocalServer::attachPlanning() throw() {
224   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "attachPlanning", ANNA_FILE_LOCATION));
225
226   try {
227     TimerManager::instantiate().createTimer(this);
228   } catch(anna::RuntimeException& ex) {
229     ex.trace();
230     anna::Logger::error("CAPTURED EXCEPTION activating attachPlanning timer", ANNA_FILE_LOCATION);
231   }
232 }
233
234
235 void LocalServer::disable(bool lock) throw(anna::RuntimeException) {
236   // Permanent ?
237   a_lock = lock;
238   anna::comm::Communicator * communicator = anna::app::functions::component <anna::comm::Communicator> (ANNA_FILE_LOCATION);
239   communicator->detach((anna::comm::ServerSocket*)a_serverSocket);
240   //delete(a_serverSocket);
241   // OAM
242   OamModule &oamModule = OamModule::instantiate();
243   oamModule.count(OamModule::Counter::ServerSocketsClosed);
244 }
245
246
247 void LocalServer::lostConnection() throw() {
248   a_currentConnections--;
249   enable();
250 }
251
252
253 void LocalServer::newConnection() throw(anna::RuntimeException) {
254   a_currentConnections++;
255
256   // Check capacity
257   if(a_currentConnections == a_maxConnections) {
258     LOGWARNING(anna::Logger::warning("The maximum number of connections allowed over diameter server socket have already been served", ANNA_FILE_LOCATION));
259     disable();
260   }
261
262   // Inform local server (availability changes):
263   bool changes = refreshAvailability();
264   // OAM
265   OamModule &oamModule = OamModule::instantiate();
266   oamModule.count(OamModule::Counter::CreatedConnectionForServerSession);
267 }
268
269
270
271 ServerSession *LocalServer::createServerSession(const anna::comm::ClientSocket &clientSocket) throw(anna::RuntimeException) {
272   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "createServerSession", ANNA_FILE_LOCATION));
273   ServerSession* result(NULL);
274   // First erase deprecated ones:
275   std::vector<const ServerSession*> deprecated_server_sessions;
276   const ServerSession* ss;
277
278   for(const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) {
279     ss = serverSession(it);
280
281     if(ss->a_deprecated)
282       deprecated_server_sessions.push_back(ss);
283   }
284
285   std::vector<const ServerSession*>::iterator dc_ncit;
286   std::vector<const ServerSession*>::iterator dc_min(deprecated_server_sessions.begin());
287   std::vector<const ServerSession*>::iterator dc_max(deprecated_server_sessions.end());
288   serverSession_iterator ii;
289
290   for(dc_ncit = dc_min; dc_ncit != dc_max; dc_ncit++) {
291     ii = serverSession_find((*dc_ncit)->getSocketId());
292     a_serverSessions.erase(ii);
293   }
294
295   // End erase deprecated server sessions
296
297   if((result = allocateServerSession()) == NULL)
298     throw anna::RuntimeException("diameter::comm::LocalServer::allocateServerSession returns NULL", ANNA_FILE_LOCATION);
299
300   // Initialize:
301   result->initialize(); // warning: recycler does not initialize its objects and at least...
302   // Assignments (it could be done at allocate):
303   serverSession_key key = getServerSessionKey(clientSocket);
304   result->setAllowedInactivityTime(getAllowedInactivityTime());
305   result->setClientSocket((anna::comm::ClientSocket*)(&clientSocket));
306   result->a_parent = this;
307   result->a_socketId = key; // de momento...
308   result->initializeSequences(); // después de asignar el LocalServer y el socketId (*)
309   // (*) Las secuencias se basan en la semilla:    srand(::time(NULL) + anna::functions::exclusiveHash(anna::functions::asString("%s:%d|%d", getAddress().c_str(), getPort(), a_socketId)));
310   result->a_engine = a_engine;
311   a_serverSessions.insert(serverSession_value_type(key, result));
312   newConnection();
313   a_deliveryIterator = serverSession_begin();
314   return result;
315 }
316
317
318
319 void LocalServer::closeServerSession(ServerSession* serverSession)
320 throw(anna::RuntimeException) {
321   if(serverSession == NULL)
322     return;
323
324   LOGDEBUG(
325     std::string msg("diameter::comm::LocalServer::closeServerSession | ");
326     msg += serverSession->asString();
327 //      msg += " | Destroy: ";
328 //      msg += (destroy ? "yes" : "no");
329     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
330   );
331   serverSession_iterator ii = serverSession_find(serverSession->getSocketId());
332
333   if(ii == serverSession_end())
334     return;
335
336   try {
337     //serverSession->setState(ServerSession::State::Closing); NOT MANAGED WITH SERVER SESSIONS
338     serverSession->unbind(true /* always forceDisconnect on server sessions ... */);
339     releaseServerSession(serverSession);
340   } catch(anna::RuntimeException& ex) {
341     ex.trace();
342   }
343
344   //a_serverSessions.erase(ii); // IMPORTANTE: posible fuente de cores de este tipo, en relacion con ServerSession::finalize() => delete(this)
345   //   #0  0x0000003ca1c2e26d in raise () from /lib64/tls/libc.so.6
346   //   (gdb) bt
347   //   #0  0x0000003ca1c2e26d in raise () from /lib64/tls/libc.so.6
348   //   #1  0x0000003ca1c2fa6e in abort () from /lib64/tls/libc.so.6
349   //   #2  0x0000003ca8cb1148 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib64/libstdc++.so.6
350   //   #3  0x0000003ca8caf176 in __cxa_call_unexpected () from /usr/lib64/libstdc++.so.6
351   //   #4  0x0000003ca8caf1a3 in std::terminate () from /usr/lib64/libstdc++.so.6
352   //   #5  0x0000003ca8caf1b6 in std::terminate () from /usr/lib64/libstdc++.so.6
353   //   #6  0x0000003ca8caf0c8 in __cxa_call_unexpected () from /usr/lib64/libstdc++.so.6
354   //   #7  0x000000000047a4a7 in anna::diameter::comm::LocalServer::lostConnection (this=0x8aeb10) at comm.db/diameter.comm.LocalServer.cc:200
355   //   #8  0x000000000047a9e6 in anna::diameter::comm::LocalServer::closeServerSession (this=0x8aeb10, serverSession=0xc37a00)
356   //       at comm.db/diameter.comm.LocalServer.cc:275
357   //   #9  0x000000000048d288 in anna::diameter::comm::ServerSession::finalize (this=0xc37a00) at comm.db/diameter.comm.ServerSession.cc:510
358   //   #10 0x0000000000494e4f in anna::diameter::comm::ServerSessionReceiver::eventBreakLocalConnection (this=0xc119c0, clientSocket=@0xb0ea00)
359   // SOLUCION: no borrar aqui, marcar como "deprecated". Este estado no se necesita realmente puesto que nadie volvera a usar este recurso.
360   // Pero simplemente se podria usar para purgar mediante temporizacion (entonces sí se haría el erase)
361   serverSession->a_deprecated = true;
362   // WE WILL ERASE AT createServerSession
363   a_deliveryIterator = serverSession_begin();
364   lostConnection();
365 }
366
367
368 ServerSession* LocalServer::findServerSession(int socketId, anna::Exception::Mode::_v emode)
369 throw(anna::RuntimeException) {
370   serverSession_iterator ii = serverSession_find(socketId);
371
372   if(ii != serverSession_end())
373     return serverSession(ii);
374
375   if(emode != anna::Exception::Mode::Ignore) {
376     std::string msg("diameter::comm::LocalServer::findServerSession | SocketId: ");
377     msg += anna::functions::asString(socketId);
378     msg += " | ServerSession not found";
379     anna::RuntimeException ex(msg, ANNA_FILE_LOCATION);
380
381     if(emode == anna::Exception::Mode::Throw)
382       throw ex;
383
384     ex.trace();
385   }
386
387   return NULL;
388 }
389
390 ServerSession* LocalServer::findServerSession(const anna::comm::ClientSocket &clientSocket, anna::Exception::Mode::_v emode)
391 throw(anna::RuntimeException) {
392   return findServerSession(getServerSessionKey(clientSocket), emode);
393 }
394
395
396 int LocalServer::getOTARequests() const throw() {
397   int result = 0;
398
399   for(const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++)
400     result += serverSession(it)->getOTARequests();
401
402   return result;
403 }
404
405 void LocalServer::close() throw(anna::RuntimeException) {
406   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "close", ANNA_FILE_LOCATION));
407   // Close listener (permanently to avoid reopening when local connections are being deleted):
408   disable(true /* lock */);
409
410   for(serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++)
411     closeServerSession(serverSession(it));
412 }
413
414
415 void LocalServer::setMaxConnections(int maxConnections) throw(anna::RuntimeException) {
416   LOGMETHOD(anna::TraceMethod tttm("anna::diameter::comm::LocalServer", "setMaxConnections", ANNA_FILE_LOCATION));
417
418   // Negative & initial
419   if(maxConnections < 0) {
420     LOGDEBUG(anna::Logger::debug("Provided negative value means no limit accepting connections over server socket. Opening listen port (if closed)...", ANNA_FILE_LOCATION));
421     a_maxConnections = -1;
422     enable();
423     return;
424   }
425
426   // No changes
427   if(maxConnections == a_maxConnections) {
428     LOGDEBUG(anna::Logger::debug("Provided equal to current. Ignore operation", ANNA_FILE_LOCATION));
429     return;
430   }
431
432   // No margin
433   if(maxConnections < a_currentConnections) {
434     std::string msg = "There are more current connections (";
435     msg += anna::functions::entriesAsString(a_currentConnections);
436     msg += ") than provided maximum (";
437     msg += anna::functions::entriesAsString(maxConnections);
438     msg += "). Command rejected (you should release connections before logical limitation)";
439     throw anna::RuntimeException(msg, ANNA_FILE_LOCATION);
440   }
441
442   // Updating
443   if(maxConnections > a_currentConnections) {
444     LOGDEBUG(anna::Logger::debug("Increasing connection margin (new limit is greater than current connections). Opening listen port (if closed)...", ANNA_FILE_LOCATION));
445     enable();
446   } else { // maxConnections == a_currentConnections: listen port must be closed if it is opened
447     LOGDEBUG(
448
449       if(maxConnections == 0)
450       anna::Logger::debug("Provided zero value means disabling diameter server", ANNA_FILE_LOCATION);
451       anna::Logger::debug("Zeroing connections margin (new limit is equal to current connections). Closing listen port (if opened)...", ANNA_FILE_LOCATION);
452     );
453
454     disable();
455   }
456
457   // Trace
458   LOGDEBUG(
459     std::string msg("Updating max connections from ");
460     msg += (a_maxConnections == -1) ? "'no limit'" : anna::functions::asString(a_maxConnections);
461     msg += " to ";
462     msg += (maxConnections == -1) ? "'no limit'" : anna::functions::asString(maxConnections);
463     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
464   );
465   // Assignment
466   a_maxConnections = maxConnections;
467 }
468
469
470 bool LocalServer::send(const Message* message, int socketId) throw(anna::RuntimeException) {
471   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "send", ANNA_FILE_LOCATION));
472
473   if(!isAvailable()) {
474     LOGWARNING(
475       std::string msg = "The local server ";
476
477     if(a_description != "") {
478     msg += "'";
479     msg += a_description;
480     msg += "' ";
481   }
482   msg += "is currently unavailable (no server sessions to send the message)";
483   anna::Logger::warning(msg, ANNA_FILE_LOCATION);
484   );
485     return false;
486   }
487
488   if(socketId != -1) {  // socket id provided
489     // Send (it was a request because of key (socketId) != -1, we forward the answer):
490     try {
491       ServerSession * fixedServerSession = a_engine->findServerSession(socketId); // exception if not found
492       fixedServerSession->send(message);
493       return true;
494     } catch(anna::RuntimeException &ex) {
495       std::string msg = "Cannot deliver answer through a fixed server session (socket id ";
496       msg += anna::functions::asString(socketId);
497       msg += "). Perhaps it existed but not now. Ignore";
498       anna::Logger::error(msg, ANNA_FILE_LOCATION);
499       ex.trace();
500       return false;
501     }
502   }
503
504   // Socket is not provided: use readSocketId
505   socketId = (a_currentConnections > 1) ? readSocketId(message) : -1; // optimization
506
507   if(a_deliveryIterator == serverSession_end()) a_deliveryIterator = serverSession_begin();
508
509   a_lastUsedResource = (*a_deliveryIterator).second;
510
511   if(socketId != -1) {
512     a_lastUsedResource = findServerSession(socketId); // exception if not found
513   } else { // Round Robin delivery between client-sessions
514     if(getCurrentConnections() != 1) {  // optimize
515       // Next server-session:
516       a_deliveryIterator++;
517     }
518   }
519
520   // Send:
521   try {
522     const Response* response = a_lastUsedResource->send(message);
523     return true; // no matter if response is NULL (answers, i.e.) or not.
524   } catch(anna::RuntimeException &ex) {
525     ex.trace();
526   }
527
528   // Here, sent has failed:
529   // OAM
530   OamModule &oamModule = OamModule::instantiate();
531   std::string socket = anna::functions::socketLiteralAsString(getKey().first, getKey().second);
532   oamModule.activateAlarm(OamModule::Alarm::UnableToDeliverDiameterMessageToClientFromLocalServer__s__, socket.c_str());
533   oamModule.count(OamModule::Counter::UnableToDeliverToClient);
534   return false;
535 }
536
537
538 bool LocalServer::broadcast(const Message* message) throw(anna::RuntimeException) {
539   LOGMETHOD(anna::TraceMethod tttm("diameter::comm::LocalServer", "broadcast", ANNA_FILE_LOCATION));
540   const Response* response;
541   bool allok = true;
542
543   for(serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++) {
544     try {
545       response = serverSession(it)->send(message);
546     } catch(anna::RuntimeException &ex) {
547       ex.trace();
548       allok = false;
549     }
550   }
551
552   return allok;
553 }
554
555 void LocalServer::eventPeerShutdown(const ServerSession* serverSession) throw() {
556   LOGWARNING(
557     std::string msg(serverSession->asString());
558     msg += " | eventPeerShutdown";
559     anna::Logger::warning(msg, ANNA_FILE_LOCATION);
560   );
561 }
562
563 std::string LocalServer::asString() const throw() {
564   std::string result("diameter::comm::LocalServer { ");
565   result += "Description: ";
566   result += (a_description != "") ? a_description : "undefined";
567   result += " | Available (any server session bound): ";
568   result += a_available ? "yes" : "no";
569   result += " | Max Connections: ";
570   result += anna::functions::asString(a_maxConnections);
571   result += " | Current Connections: ";
572   result += anna::functions::asString(a_currentConnections);
573   // Current connections ??
574   result += " | Allowed inactivity time for server sessions: ";
575   result += a_allowedInactivityTime.asString();
576   result += " | Server socket: ";
577   result += a_serverSocket ? a_serverSocket->asString() : "closed";
578   result += anna::functions::asString(" | OTA requests: %d%s", getOTARequests(), idle() ? " (idle)" : "");
579   result += " | Last Incoming Activity Time: ";
580   result += a_lastIncomingActivityTime.asString();
581   result += " | Last Outgoing Activity Time: ";
582   result += a_lastOutgoingActivityTime.asString();
583 //   result += "\n";
584 //   result += a_statisticsAccumulator.asString();
585   // ServerSessions only in xml
586   return result += " }";
587 }
588
589
590 anna::xml::Node* LocalServer::asXML(anna::xml::Node* parent) const throw() {
591   anna::xml::Node* result = parent->createChild("diameter.LocalServer");
592   result->createAttribute("Description", (a_description != "") ? a_description : "undefined");
593   result->createAttribute("Available", a_available ? "yes" : "no");
594   result->createAttribute("MaxConnections", a_maxConnections);
595   result->createAttribute("CurrentConnections", a_currentConnections);
596   // Current connections ??
597   result->createAttribute("AllowedInactivityTimeForServerSessions", a_allowedInactivityTime.asString());
598
599   if(a_serverSocket)
600     a_serverSocket->asXML(result);
601   else
602     result->createAttribute("ServerSocket", "closed");
603
604   result->createAttribute("OTArequests", anna::functions::asString("%d%s", getOTARequests(), idle() ? " (idle)" : ""));
605   result->createAttribute("LastIncomingActivityTime", a_lastIncomingActivityTime.asString());
606   result->createAttribute("LastOutgoingActivityTime", a_lastOutgoingActivityTime.asString());
607   // Statistics
608   anna::xml::Node* stats = result->createChild("Statistics");
609   a_statisticsAccumulator.asXML(stats);
610   anna::xml::Node* serverSessions = result->createChild("ServerSessions"); // LocalServer.ServerSessions
611
612   for(const_serverSession_iterator it = serverSession_begin(); it != serverSession_end(); it++)
613     serverSession(it)->asXML(serverSessions);
614
615   return result;
616 }
617
618 //------------------------------------------------------------------------------
619 //------------------------------------ LocalServer::updateIncomingActivityTime()
620 //------------------------------------------------------------------------------
621 void LocalServer::updateIncomingActivityTime() throw() {
622   a_lastIncomingActivityTime = anna::functions::millisecond();
623   LOGDEBUG
624   (
625     std::string msg = "Updated INCOMING activity on local server (milliseconds unix): ";
626     msg += anna::functions::asString(a_lastIncomingActivityTime.getValue());
627     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
628   );
629 }
630
631
632 //------------------------------------------------------------------------------
633 //------------------------------------ LocalServer::updateOutgoingActivityTime()
634 //------------------------------------------------------------------------------
635 void LocalServer::updateOutgoingActivityTime(void) throw() {
636   a_lastOutgoingActivityTime = anna::functions::millisecond();
637   LOGDEBUG
638   (
639     std::string msg = "Updated OUTGOING activity on local server (milliseconds unix): ";
640     msg += anna::functions::asString(a_lastOutgoingActivityTime.getValue());
641     anna::Logger::debug(msg, ANNA_FILE_LOCATION);
642   );
643 }
644