1 // ANNA - Anna is Not 'N' Anymore
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
5 // https://bitbucket.org/testillano/anna
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
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
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.
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.
33 // Authors: eduardo.ramos.testillano@gmail.com
34 // cisco.tierra@gmail.com
37 #ifndef anna_diameter_comm_Entity_hpp
38 #define anna_diameter_comm_Entity_hpp
45 #include <anna/config/defines.hpp>
47 #include <anna/core/RuntimeException.hpp>
48 #include <anna/core/util/Millisecond.hpp>
73 Generic diameter server list (N-servers entity)
77 std::vector<Server*> a_servers;
78 int a_maxServers; // -1 means "no limit to add servers"
79 std::string a_description;
81 std::vector<Server*>::iterator a_deliveryIterator;
82 Server *a_lastUsedResource;
88 bool a_available; // any of the servers must be bound
89 void availabilityLost() throw();
90 void availabilityRecovered() throw();
91 bool refreshAvailability() throw(); // return true if change
92 void assertReady() throw(anna::RuntimeException);
93 void initialize() throw();
94 void childIdle() const throw();
96 // Selected for remove
97 bool a_deprecated; // entity has been selected as deprecated (will be removed when idle)
100 std::string a_socketListLiteral; // ADDRESS:PORT space-separated list
101 std::string a_primarySocketLiteral; // ADDRESS:PORT for primary (used on standard entities)
102 std::string a_secondarySocketLiteral; // ADDRESS:PORT for primary (used on standard entities)
106 anna::Millisecond a_lastIncomingActivityTime; // last unix timestamp (in milliseconds) when message reception was managed over this entity
107 anna::Millisecond a_lastOutgoingActivityTime; // last unix timestamp (in milliseconds) when message sending was managed over this entity
108 void updateIncomingActivityTime() throw();
109 void updateOutgoingActivityTime() throw();
111 // Private close/destroy method
112 void close(bool destroy) throw(anna::RuntimeException);
119 * Default constructor. Entities should be create through diameter::comm::Engine
120 * @param maxServers Maximum number of servers managed by the entity. Default is 2 (standard/dual entity).
121 * The value -1, means no limit to add servers.
123 Entity(int maxServers = 2) : a_maxServers(maxServers) { initialize(); }
127 * Sets the maximum number of servers managed by the entity.
129 * @param maxServers Maximum number of servers managed by the entity.
131 void setMaxServers(int maxServers) throw() { a_maxServers = maxServers; }
134 * Gets the maximum number of servers managed by the entity.
136 * @return Maximum number of servers managed by the entity.
138 int getMaxServers() const throw() { return a_maxServers; }
142 * Sets the entity description.
144 * @param description Entity description. Empty by default.
146 void setDescription(const std::string &description) throw() { a_description = description; }
149 * Gets the entity description.
151 * @return Entity description.
153 const std::string & getDescription() const throw() { return a_description; }
157 * Sets the diameter::comm::Engine
158 * @param e Diameter::comm::Engine
160 void setEngine(Engine *e) throw() { a_engine = e; }
164 * Add a server to the entity and create all the servers configured at #setSocketsPerDiameterServer within that server.
166 * \param serverId Diameter server ip/port.
168 * @return Returns success on send operation over any server within the entity
170 void addServer(const socket_t & serverId) throw(anna::RuntimeException);
173 * Binds entity servers.
175 * @return Returns true if all client-session were successfully bound
177 bool bind() throw(anna::RuntimeException);
180 * Propagate auto recovery configuration to servers within entity
182 * @param autoRecovery Auto recovery indicator. True by default.
184 void raiseAutoRecovery(bool autoRecovery = true) throw(anna::RuntimeException);
187 Sets timeout for wait responses for any class code request for all entity servers
189 \param v Diameter request type.
190 \param millisecond Milliseconds for timeout
192 void setClassCodeTimeout(const ClassCode::_v v, const anna::Millisecond & millisecond) throw();
195 Sets entity category. Used by application in order to categorize or clasify.
197 @param category Entity category
199 void setCategory(int category) throw() { a_category = category; }
202 Gets entity category. Used by application in order to categorize or clasify.
204 @return Entity category
206 int getCategory() const throw() { return a_category; }
209 Gets the last used resource (server) during sending.
210 Broadcast doesn't updates this information.
212 Server *getLastUsedResource() const throw() { return (a_lastUsedResource); }
216 // SIMPLE BALANCE or STANDARD documentation version
218 // Sent a message to the entity. First uses primary server, secondary if fails and so on to the
219 // last defined resource (server) within entity. Another sending algorithm (non standard) could
220 // be enabled (balance boolean parameter): it consist in round-robin server selection without
221 // trying any one if fails (standard behaviour tries all servers from FIRST defined).
222 // Anyway, last used delivery resource could be known through #getLastUsedResource().
224 // When the message is a request, a timer will be set automatically to control the response time.
225 // If expires, the ResultCode Timeout will be finally notified on #Entity::eventResponse. This
226 // timeout value will be configured at #setClassCodeTimeout.
228 // \param message Message sent.
229 // \param balance False by default (standard beaviour), but useful to balance over servers within entity.
231 // @return Boolean about success in send operation. Standard behaviour (no balance) implies true result when any
232 // of the entity servers could send the message, and false when neither of the servers was available or fail to
233 // send the message. Broadcast try to send all over the resources in spite of any fail, and balanced sendings
234 // fails when next selected resource fail to send the message (and no alarm or error counter is generated in
235 // this case because it can't be understood/ensured as entity-sending fail.
238 // OJO: en el caso estandard, no se prueban todas las sessiones de un servidor si tiene mas de una, luego la alarma
239 // generada en caso de error, presupone que las sessiones no usadas, también darían error, lo cual no tiene porque
240 // ser cierto. En condiciones normales, los servidores tienen una session, con lo que lo anterior es cierto y el
241 // la practica es lo mas normal.
244 Sent a message to the entity. First uses primary server, secondary if fails and so on to the
245 last defined resource (server) within entity. Another sending algorithm (non standard) could
246 be enabled (balance boolean parameter): it consist in round-robin server selection to set the
247 first resource in a complete cycle (standard behaviour tries all servers from FIRST defined).
248 Anyway, last used delivery resource could be known through #getLastUsedResource().
250 When the message is a request, a timer will be set automatically to control the response time.
251 If expires, the ResultCode Timeout will be finally notified on #Entity::eventResponse. This
252 timeout value will be configured at #setClassCodeTimeout.
254 \param message Message sent.
255 \param balance False by default (standard beaviour), but useful to balance over servers within entity.
257 @return Boolean about success in send operation. Implies true result when any of the entity servers could
258 send the message, and false when neither of the servers was available or fail to send the message (an alarm
259 and error counter will be generated in this case). Broadcast try to send all over the resources in spite of
262 bool send(const Message *message, bool balance = false) throw(anna::RuntimeException);
263 bool send(const Message &message, bool balance = false) throw(anna::RuntimeException) { return send(&message, balance); }
267 Before sending a message over each entity server, socketId could be specified to select
268 which client session within such server will manage the message.
270 Default implementation has been focused on charging applications but any other kind of
271 application could re-implement this method and change the behaviour:
274 Charging involves two peers:
276 Charging Trigger Function (CTF): Makes decisions on how to charge the user for specific
277 services, issues requests to the server (OCF).
278 Online Charging Function (OCF): Performs actual charging based on received message type,
279 service logic and user profile information.
281 There are three main scenarios:
283 Immediate Event Charging (IEC): The CTF sends a one time request. This request contains
284 a predefined set of AVPs indicating which service has
285 been activated or how many units have been consumed
286 (this depends on application logic).
288 Event Charging with Unit Reservation (ECUR): The CTF issues a request which indicates the
289 desired unit count for reservation. On service
290 delivery, the CTF issues another request which
291 indicates how many units were actually consumed.
292 Units can be of any type, as they are application
295 Session Charging with Unit Reservation(SCUR): As above, however reservation can happen more than once.
297 In order to minimize race conditions within trasactions, default implementation will select the connection
298 fixed by an stickiness value (Session-Id will be used) for ECUR and SCUR models (Data, Voice and Content
299 traffic). IEC model, represented by SMS ans MMS traffic will use round-robin between sockets. The type
300 of traffic will be analyzed by mean Service-Context-Id AVP. If traffic type is not reconized, value of
301 '-1' will be returned doing round-robin socket selection within active server.
303 Diameter session-oriented load balancing enables to distribute Diameter signaling traffic across
304 multiple client sessions for the selected entity server. Application could re-implement different
305 load balancing policies, including support for session stickiness and business decisions, and
306 subscriber and service aware contextual load balancing strategies. By default, Session-Id avp
307 is used to select the resource. Session-Id is split into 4 sections: diameter identity, high
308 part, low part and optional part. Default implementation analizes 'low' part, returning its
309 value as reference for socket selection.
312 When server is configured as single client session (max client sessions equal to 1), entity will ignore
313 this method being more efficient, because former algorithms would not affect the session selection.
315 \param message Message which is being sent.
316 \param maxClientSessions Number of client-sessions on specific server prepared for send.
318 @return Socket-id used within range [0,maxClientSessions-1]. Value '-1' if round-robin is desired.
319 If socket-id is return out of range, send procedure will throw an exception.
321 virtual int readSocketId(const Message *message, int maxClientSessions) const throw();
325 Sent a message to all the entity servers.
326 It is used, i.e., in Disconnect-Peer-Request procedure over a certain entity.
328 \param message Message which is being sent.
330 @return Returns true (success) only when broadcast is success over all the entity servers. If any server fails,
331 then false is returned.
333 bool broadcast(const Message *message) throw(anna::RuntimeException);
334 bool broadcast(const Message &message) throw(anna::RuntimeException) { return broadcast(&message); }
338 Returns true when any of the entity servers is Bound. False when all not-bound.
340 bool isAvailable() const throw() { return a_available; }
343 Returns true when the entity has been selected as deprecated
345 bool isDeprecated() const throw() { return a_deprecated; }
348 Sets the entity deprecated state
350 void setDeprecated(bool deprecated = true) throw() { a_deprecated = deprecated; }
354 Gets the number of requests messages over-the-air.
356 @return OTA messages.
358 int getOTARequests() const throw();
361 Returns idle state (no pending answers).
365 bool idle() const throw() { return (getOTARequests() == 0); }
368 std::vector<Server*>::iterator begin() throw() { return a_servers.begin(); }
369 std::vector<Server*>::iterator end() throw() { return a_servers.end(); }
370 std::vector<Server*>::const_iterator begin() const throw() { return a_servers.begin(); }
371 std::vector<Server*>::const_iterator end() const throw() { return a_servers.end(); }
374 Close all the entity servers (close client-sessions within them). Depending on client-session configuration ('OnDisconnect' behaviour),
375 pending answers will be wait (graceful) or ignored (immediate-abrupt close).
376 Resources are not destroyed.
378 void close() throw(anna::RuntimeException) { close(false /* no destroy */); }
383 Number of currently configured servers
385 int getNumberOfServers() const throw() { return a_servers.size(); }
388 Number of maximum allowed servers
390 int getMaxServerss() const throw() { return a_maxServers; }
393 List of (address,port) pairs defining entity servers
395 socket_v getAddressPortList() const throw();
399 Deny resources for delivery restriction.
405 Allow resource for delivery permission.
406 Allow all its servers
411 Returns true when all its servers resources are hidden for application messages delivery
413 bool hidden() const throw();
416 Returns true when all its servers resources are shown for application messages delivery
418 bool shown() const throw();
422 Class string representation
423 \return String with relevant information for this instance.
425 std::string asString() const throw();
428 Class xml representation
429 \param parent Parent XML node on which hold this instance information.
430 \return XML document with relevant information for this instance.
432 anna::xml::Node* asXML(anna::xml::Node* parent) const throw();
437 Handler about event break connection from diameter server (server) over this entity.
438 When notified, ANNA.diameter.comm generates an diameter::comm::Entity::eventResponse for every request with pending answers.
439 Default implementation traces warning event
440 \param clientSession ClientSession from which shutdown has been received
442 virtual void eventPeerShutdown(const ClientSession* clientSession) throw();
445 Handler for diameter server (server) responses
447 \param response Answer container object for corresponding diameter request
449 virtual void eventResponse(const Response& response) throw(anna::RuntimeException) = 0;
452 Handler for diameter server (server) requests
454 \param clientSession ClientSession from which request has been received
455 \param request Diameter request message received
457 virtual void eventRequest(ClientSession* clientSession, const anna::DataBlock &request) throw(anna::RuntimeException) = 0;
458 //virtual void eventRequest(ClientSession* clientSession, const Message& request) throw(anna::RuntimeException) = 0;
461 Handler for diameter session responses out of context
463 \param clientSession ClientSession from which request has been received
464 \param response Answer data block object without context match
466 virtual void eventUnknownResponse(ClientSession *clientSession, const anna::DataBlock& response) throw(anna::RuntimeException) = 0;