apps/sbc/RegisterCache.h
01c4e1c7
 #ifndef _RegisterCache_h_
 #define _RegisterCache_h_
 
 #include "singleton.h"
 #include "hash_table.h"
6146fb5e
 #include "atomic_types.h"
01c4e1c7
 
872aabf2
 #include "AmSipMsg.h"
 #include "AmUriParser.h"
d386f9dc
 #include "AmAppTimer.h"
872aabf2
 
01c4e1c7
 #include <string>
 #include <map>
a1232627
 #include <memory>
01c4e1c7
 using std::string;
 using std::map;
a1232627
 using std::auto_ptr;
01c4e1c7
 
 #define REG_CACHE_TABLE_POWER   10
 #define REG_CACHE_TABLE_ENTRIES (1<<REG_CACHE_TABLE_POWER)
 
872aabf2
 #define DEFAULT_REG_EXPIRES 3600
 
a1232627
 /*
  * Register cache:
  * ---------------
  * Data model:
  *  - canonical AoR <--1-to-n--> contacts
  *  - alias         <--1-to-1--> contact
  */
 
01c4e1c7
 struct RegBinding
 {
872aabf2
   // Absolute timestamp representing
   // the expiration timer at the 
   // registrar side
   long int reg_expire;
01c4e1c7
 
   // unique-id used as contact user toward the registrar
   string alias;
872aabf2
 
   RegBinding()
     : reg_expire(0)
   {}
01c4e1c7
 };
 
c3b36a47
 // Contact-URI/Public-IP -> RegBinding
01c4e1c7
 typedef map<string,RegBinding*> AorEntry;
 
a1232627
 struct AliasEntry
d386f9dc
   : public DirectAppTimer
a1232627
 {
d386f9dc
   string aor;
a1232627
   string contact_uri;
d386f9dc
   string alias;
a1232627
 
   // saved state for NAT handling
   string         source_ip;
   unsigned short source_port;
eb80fbda
   string         trsp;
a1232627
 
   // sticky interface
   unsigned short local_if;
872aabf2
 
9331eadf
   // User-Agent
   string remote_ua;
 
872aabf2
   // Absolute timestamp representing
   // the expiration timer at the 
   // registered UA side
   long int ua_expire;
 
   AliasEntry()
     : source_port(0), local_if(0), ua_expire(0)
   {}
d386f9dc
 
   // from DirectAppTimer
   void fire();
a1232627
 };
 
 struct RegCacheStorageHandler 
 {
   virtual void onDelete(const string& aor, const string& uri, 
 			const string& alias) {}
 
   virtual void onUpdate(const string& canon_aor, const string& alias, 
 			long int expires, const AliasEntry& alias_update) {}
872aabf2
 
   virtual void onUpdate(const string& alias, long int ua_expires) {}
a1232627
 };
 
01c4e1c7
 /**
  * Hash-table bucket:
a1232627
  *   AoR -> AorEntry
01c4e1c7
  */
e7a5c623
 class AorBucket
01c4e1c7
   : public ht_map_bucket<string,AorEntry>
 {
 public:
e7a5c623
   AorBucket(unsigned long id)
01c4e1c7
   : ht_map_bucket<string,AorEntry>(id) 
   {}
 
   /**
    * Match and retrieve the cache entry associated with the AOR passed.
    * aor: canonicalized AOR
    */
   AorEntry* get(const string& aor);
 
   /* Maintenance stuff */
 
a1232627
   void gbc(RegCacheStorageHandler* h, long int now, list<string>& alias_list);
   void dump_elmt(const string& aor, const AorEntry* p_aor_entry) const;
01c4e1c7
 };
 
 /**
  * Hash-table bucket:
  *   Alias -> Contact-URI
  */
 class AliasBucket
   : public ht_map_bucket<string,AliasEntry>
 {
 public:
   AliasBucket(unsigned long int id)
   : ht_map_bucket<string,AliasEntry>(id)
   {}
 
   AliasEntry* getContact(const string& alias);
 
e7a5c623
   void dump_elmt(const string& alias, const AliasEntry* ae) const;
 };
 
 class ContactBucket
   : public ht_map_bucket<string,string>
 {
676c5f2c
   typedef ht_map_bucket<string,string> Bucket;
 
   bool insert(const string& k, string* v) {
     return Bucket::insert(k,v);
   }
 
   bool remove(const string& k) {
     return Bucket::remove(k);
   }
 
e7a5c623
 public:
   ContactBucket(unsigned long int id)
   : ht_map_bucket<string,string>(id)
   {}
 
   void insert(const string& contact_uri, const string& remote_ip,
 	      unsigned short remote_port, const string& alias);
 
   string getAlias(const string& contact_uri, const string& remote_ip,
 		  unsigned short remote_port);
 
   void remove(const string& contact_uri, const string& remote_ip,
 	      unsigned short remote_port);
 
   void dump_elmt(const string& key, const string* alias) const;
01c4e1c7
 };
 
872aabf2
 /** 
  * Registrar/Reg-Caching 
  * parsing/processing context 
  */
 struct RegisterCacheCtx
   : public AmObject
 {
   string              from_aor;
   bool               aor_parsed;
 
   vector<AmUriParser> contacts;
   bool         contacts_parsed;
 
   unsigned int requested_expires;
   bool            expires_parsed;
 
   unsigned int min_reg_expires;
   unsigned int max_ua_expires;
 
   RegisterCacheCtx()
     : aor_parsed(false),
       contacts_parsed(false),
       requested_expires(DEFAULT_REG_EXPIRES),
       expires_parsed(false),
       min_reg_expires(0),
       max_ua_expires(0)
   {}
 };
 
01c4e1c7
 class _RegisterCache
   : public AmThread
 {
e7a5c623
   hash_table<AorBucket> reg_cache_ht;
01c4e1c7
   hash_table<AliasBucket>        id_idx;
e7a5c623
   hash_table<ContactBucket>      contact_idx;
01c4e1c7
 
a1232627
   auto_ptr<RegCacheStorageHandler> storage_handler;
 
01c4e1c7
   unsigned int gbc_bucket_id;
 
   AmSharedVar<bool> running;
 
6146fb5e
   // stats
   atomic_int active_regs;
 
01c4e1c7
   void gbc(unsigned int bucket_id);
89568c1a
   void removeAlias(const string& alias, bool generate_event);
01c4e1c7
 
 protected:
   _RegisterCache();
   ~_RegisterCache();
 
   void dispose() { stop(); }
 
   /* AmThread interface */
   void run();
   void on_stop();
 
   /**
    * Returns the bucket associated with the passed contact-uri
    * aor: canonicalized AOR
    */
e7a5c623
   AorBucket* getAorBucket(const string& aor);
01c4e1c7
 
   /**
    * Returns the bucket associated with the alias given
    * alias: Contact-user
    */
   AliasBucket* getAliasBucket(const string& alias);
 
e7a5c623
   /**
    * Returns the bucket associated with the contact-URI given
    */
   ContactBucket* getContactBucket(const string& contact_uri,
 				  const string& remote_ip,
 				  unsigned short remote_port);
 
c5a996bc
   int parseAoR(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger);
   int parseContacts(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger);
   int parseExpires(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger);
872aabf2
 
d386f9dc
   void setAliasUATimer(AliasEntry* alias_e);
   void removeAliasUATimer(AliasEntry* alias_e);
 
01c4e1c7
 public:
   static string canonicalize_aor(const string& aor);
c3b36a47
   static string compute_alias_hash(const string& aor, const string& contact_uri,
 				   const string& public_ip);
01c4e1c7
 
a1232627
   void setStorageHandler(RegCacheStorageHandler* h) { storage_handler.reset(h); }
 
01c4e1c7
   /**
    * Match, retrieve the contact cache entry associated with the URI passed,
    * and return the alias found in the cache entry.
    *
    * Note: this function locks and unlocks the contact cache bucket.
    *
    * aor: canonical Address-of-Record
    * uri: Contact-URI
    */
872aabf2
   bool getAlias(const string& aor, const string& uri,
c3b36a47
 		const string& public_ip, RegBinding& out_binding);
01c4e1c7
 
   /**
    * Update contact cache entry and alias map entries.
    *
    * Note: this function locks and unlocks 
    *       the contact cache bucket and
    *       the alias map bucket.
    *
    * aor: canonical Address-of-Record
    * uri: Contact-URI
    * alias: 
    */
e7a5c623
   void update(const string& alias, long int reg_expires,
872aabf2
 	      const AliasEntry& alias_update);
 
e7a5c623
   void update(long int reg_expires, const AliasEntry& alias_update);
 
b4990d21
   bool updateAliasExpires(const string& alias, long int ua_expires);
01c4e1c7
 
   /**
    * Remove contact cache entry and alias map entries.
    *
    * Note: this function locks and unlocks 
    *       the contact cache bucket and
    *       the alias map bucket.
    *
    * aor: canonical Address-of-Record
    * uri: Contact-URI
    * alias:
    */
c3b36a47
   void remove(const string& aor, const string& uri,
 	      const string& alias);
01c4e1c7
 
872aabf2
   void remove(const string& aor);
01c4e1c7
 
   /**
    * Retrieve an alias map containing all entries related
    * to a particular AOR. This is needed to support REGISTER
    * with '*' contact.
    *
    * Note: this function locks and unlocks 
    *       the contact cache bucket.
    *
    * aor: canonical Address-of-Record
b4990d21
    * alias_map: alias -> contact
01c4e1c7
    */
872aabf2
   bool getAorAliasMap(const string& aor, map<string,string>& alias_map);
01c4e1c7
 
   /**
    * Retrieve the alias entry related to the given alias
    */
   bool findAliasEntry(const string& alias, AliasEntry& alias_entry);
872aabf2
 
   /**
e7a5c623
    * Retrieve the alias entry related to the given contact-URI, remote-IP & port
    */
   bool findAEByContact(const string& contact_uri, const string& remote_ip,
 		       unsigned short remote_port, AliasEntry& ae);
 
   /**
872aabf2
    * Throttle REGISTER requests
    *
    * Returns false if REGISTER should be forwarded:
    * - if registrar binding should be renewed.
    * - if source IP or port do not match the saved IP & port.
    * - if the request unregisters any contact.
    * - if request is not a REGISTER
    */
   bool throttleRegister(RegisterCacheCtx& ctx,
c5a996bc
 			const AmSipRequest& req,
46055a8b
                         msg_logger *logger = NULL);
872aabf2
 
   /**
fd786423
    * Save a single REGISTER contact into cache
872aabf2
    *
    * Returns false if failed:
    * - if request is not a REGISTER.
    * - more than one contact should be (un)registered.
fd786423
    *
    * If true has been returned, the request has already 
    * been replied with either an error or 200 (w/ contact).
    *
    * Note: this function also handles binding query.
    *       (REGISTER w/o contacts)
872aabf2
    */
   bool saveSingleContact(RegisterCacheCtx& ctx,
c5a996bc
 			const AmSipRequest& req,
46055a8b
                         msg_logger *logger = NULL);
6146fb5e
 
   /**
    * Statistics
    */
   unsigned int getActiveRegs() { return active_regs.get(); }
01c4e1c7
 };
 
 typedef singleton<_RegisterCache> RegisterCache;
 
 #endif