1 #ifndef _RegisterCache_h_
2 #define _RegisterCache_h_
3 
4 #include "singleton.h"
5 #include "hash_table.h"
6 #include "atomic_types.h"
7 
8 #include "AmSipMsg.h"
9 #include "AmUriParser.h"
10 #include "AmAppTimer.h"
11 
12 #include <string>
13 #include <map>
14 #include <memory>
15 using std::string;
16 using std::map;
17 using std::unique_ptr;
18 
19 #define REG_CACHE_TABLE_POWER   10
20 #define REG_CACHE_TABLE_ENTRIES (1<<REG_CACHE_TABLE_POWER)
21 
22 #define DEFAULT_REG_EXPIRES 3600
23 
24 /*
25  * Register cache:
26  * ---------------
27  * Data model:
28  *  - canonical AoR <--1-to-n--> contacts
29  *  - alias         <--1-to-1--> contact
30  */
31 
32 struct RegBinding
33 {
34   // Absolute timestamp representing
35   // the expiration timer at the
36   // registrar side
37   long int reg_expire;
38 
39   // unique-id used as contact user toward the registrar
40   string alias;
41 
RegBindingRegBinding42   RegBinding()
43     : reg_expire(0)
44   {}
45 };
46 
47 // Contact-URI/Public-IP -> RegBinding
48 typedef map<string,RegBinding*> AorEntry;
49 
50 struct AliasEntry
51   : public DirectAppTimer
52 {
53   string aor;
54   string contact_uri;
55   string alias;
56 
57   // saved state for NAT handling
58   string         source_ip;
59   unsigned short source_port;
60   string         trsp;
61 
62   // sticky interface
63   unsigned short local_if;
64 
65   // User-Agent
66   string remote_ua;
67 
68   // Absolute timestamp representing
69   // the expiration timer at the
70   // registered UA side
71   long int ua_expire;
72 
AliasEntryAliasEntry73   AliasEntry()
74     : source_port(0), local_if(0), ua_expire(0)
75   {}
76 
77   // from DirectAppTimer
78   void fire();
79 };
80 
81 struct RegCacheStorageHandler
82 {
onDeleteRegCacheStorageHandler83   virtual void onDelete(const string& aor, const string& uri,
84 			const string& alias) {}
85 
onUpdateRegCacheStorageHandler86   virtual void onUpdate(const string& canon_aor, const string& alias,
87 			long int expires, const AliasEntry& alias_update) {}
88 
onUpdateRegCacheStorageHandler89   virtual void onUpdate(const string& alias, long int ua_expires) {}
90 };
91 
92 /**
93  * Hash-table bucket:
94  *   AoR -> AorEntry
95  */
96 class AorBucket
97   : public ht_map_bucket<string,AorEntry>
98 {
99 public:
AorBucket(unsigned long id)100   AorBucket(unsigned long id)
101   : ht_map_bucket<string,AorEntry>(id)
102   {}
103 
104   /**
105    * Match and retrieve the cache entry associated with the AOR passed.
106    * aor: canonicalized AOR
107    */
108   AorEntry* get(const string& aor);
109 
110   /* Maintenance stuff */
111 
112   void gbc(RegCacheStorageHandler* h, long int now, list<string>& alias_list);
113   void dump_elmt(const string& aor, const AorEntry* p_aor_entry) const;
114 };
115 
116 /**
117  * Hash-table bucket:
118  *   Alias -> Contact-URI
119  */
120 class AliasBucket
121   : public ht_map_bucket<string,AliasEntry>
122 {
123 public:
AliasBucket(unsigned long int id)124   AliasBucket(unsigned long int id)
125   : ht_map_bucket<string,AliasEntry>(id)
126   {}
127 
128   AliasEntry* getContact(const string& alias);
129 
130   void dump_elmt(const string& alias, const AliasEntry* ae) const;
131 };
132 
133 class ContactBucket
134   : public ht_map_bucket<string,string>
135 {
136   typedef ht_map_bucket<string,string> Bucket;
137 
insert(const string & k,string * v)138   bool insert(const string& k, string* v) {
139     return Bucket::insert(k,v);
140   }
141 
remove(const string & k)142   bool remove(const string& k) {
143     return Bucket::remove(k);
144   }
145 
146 public:
ContactBucket(unsigned long int id)147   ContactBucket(unsigned long int id)
148   : ht_map_bucket<string,string>(id)
149   {}
150 
151   void insert(const string& contact_uri, const string& remote_ip,
152 	      unsigned short remote_port, const string& alias);
153 
154   string getAlias(const string& contact_uri, const string& remote_ip,
155 		  unsigned short remote_port);
156 
157   void remove(const string& contact_uri, const string& remote_ip,
158 	      unsigned short remote_port);
159 
160   void dump_elmt(const string& key, const string* alias) const;
161 };
162 
163 /**
164  * Registrar/Reg-Caching
165  * parsing/processing context
166  */
167 struct RegisterCacheCtx
168   : public AmObject
169 {
170   string              from_aor;
171   bool               aor_parsed;
172 
173   vector<AmUriParser> contacts;
174   bool         contacts_parsed;
175 
176   unsigned int requested_expires;
177   bool            expires_parsed;
178 
179   unsigned int min_reg_expires;
180   unsigned int max_ua_expires;
181 
RegisterCacheCtxRegisterCacheCtx182   RegisterCacheCtx()
183     : aor_parsed(false),
184       contacts_parsed(false),
185       requested_expires(DEFAULT_REG_EXPIRES),
186       expires_parsed(false),
187       min_reg_expires(0),
188       max_ua_expires(0)
189   {}
190 };
191 
192 class _RegisterCache
193   : public AmThread
194 {
195   hash_table<AorBucket> reg_cache_ht;
196   hash_table<AliasBucket>        id_idx;
197   hash_table<ContactBucket>      contact_idx;
198 
199   unique_ptr<RegCacheStorageHandler> storage_handler;
200 
201   unsigned int gbc_bucket_id;
202 
203   AmSharedVar<bool> running;
204 
205   // stats
206   atomic_int active_regs;
207 
208   void gbc(unsigned int bucket_id);
209   void removeAlias(const string& alias, bool generate_event);
210 
211 protected:
212   _RegisterCache();
213   ~_RegisterCache();
214 
dispose()215   void dispose() { stop(); }
216 
217   /* AmThread interface */
218   void run();
219   void on_stop();
220 
221   /**
222    * Returns the bucket associated with the passed contact-uri
223    * aor: canonicalized AOR
224    */
225   AorBucket* getAorBucket(const string& aor);
226 
227   /**
228    * Returns the bucket associated with the alias given
229    * alias: Contact-user
230    */
231   AliasBucket* getAliasBucket(const string& alias);
232 
233   /**
234    * Returns the bucket associated with the contact-URI given
235    */
236   ContactBucket* getContactBucket(const string& contact_uri,
237 				  const string& remote_ip,
238 				  unsigned short remote_port);
239 
240   int parseAoR(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger);
241   int parseContacts(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger);
242   int parseExpires(RegisterCacheCtx& ctx, const AmSipRequest& req, msg_logger *logger);
243 
244   void setAliasUATimer(AliasEntry* alias_e);
245   void removeAliasUATimer(AliasEntry* alias_e);
246 
247 public:
248   static string canonicalize_aor(const string& aor);
249   static string compute_alias_hash(const string& aor, const string& contact_uri,
250 				   const string& public_ip);
251 
setStorageHandler(RegCacheStorageHandler * h)252   void setStorageHandler(RegCacheStorageHandler* h) { storage_handler.reset(h); }
253 
254   /**
255    * Match, retrieve the contact cache entry associated with the URI passed,
256    * and return the alias found in the cache entry.
257    *
258    * Note: this function locks and unlocks the contact cache bucket.
259    *
260    * aor: canonical Address-of-Record
261    * uri: Contact-URI
262    */
263   bool getAlias(const string& aor, const string& uri,
264 		const string& public_ip, RegBinding& out_binding);
265 
266   /**
267    * Update contact cache entry and alias map entries.
268    *
269    * Note: this function locks and unlocks
270    *       the contact cache bucket and
271    *       the alias map bucket.
272    *
273    * aor: canonical Address-of-Record
274    * uri: Contact-URI
275    * alias:
276    */
277   void update(const string& alias, long int reg_expires,
278 	      const AliasEntry& alias_update);
279 
280   void update(long int reg_expires, const AliasEntry& alias_update);
281 
282   bool updateAliasExpires(const string& alias, long int ua_expires);
283 
284   /**
285    * Remove contact cache entry and alias map entries.
286    *
287    * Note: this function locks and unlocks
288    *       the contact cache bucket and
289    *       the alias map bucket.
290    *
291    * aor: canonical Address-of-Record
292    * uri: Contact-URI
293    * alias:
294    */
295   void remove(const string& aor, const string& uri,
296 	      const string& alias);
297 
298   void remove(const string& aor);
299 
300   /**
301    * Retrieve an alias map containing all entries related
302    * to a particular AOR. This is needed to support REGISTER
303    * with '*' contact.
304    *
305    * Note: this function locks and unlocks
306    *       the contact cache bucket.
307    *
308    * aor: canonical Address-of-Record
309    * alias_map: alias -> contact
310    */
311   bool getAorAliasMap(const string& aor, map<string,string>& alias_map);
312 
313   /**
314    * Retrieve the alias entry related to the given alias
315    */
316   bool findAliasEntry(const string& alias, AliasEntry& alias_entry);
317 
318   /**
319    * Retrieve the alias entry related to the given contact-URI, remote-IP & port
320    */
321   bool findAEByContact(const string& contact_uri, const string& remote_ip,
322 		       unsigned short remote_port, AliasEntry& ae);
323 
324   /**
325    * Throttle REGISTER requests
326    *
327    * Returns false if REGISTER should be forwarded:
328    * - if registrar binding should be renewed.
329    * - if source IP or port do not match the saved IP & port.
330    * - if the request unregisters any contact.
331    * - if request is not a REGISTER
332    */
333   bool throttleRegister(RegisterCacheCtx& ctx,
334 			const AmSipRequest& req,
335                         msg_logger *logger = NULL);
336 
337   /**
338    * Save a single REGISTER contact into cache
339    *
340    * Returns false if failed:
341    * - if request is not a REGISTER.
342    * - more than one contact should be (un)registered.
343    *
344    * If true has been returned, the request has already
345    * been replied with either an error or 200 (w/ contact).
346    *
347    * Note: this function also handles binding query.
348    *       (REGISTER w/o contacts)
349    */
350   bool saveSingleContact(RegisterCacheCtx& ctx,
351 			const AmSipRequest& req,
352                         msg_logger *logger = NULL);
353 
354   /**
355    * Statistics
356    */
getActiveRegs()357   unsigned int getActiveRegs() { return active_regs.get(); }
358 };
359 
360 typedef singleton<_RegisterCache> RegisterCache;
361 
362 #endif
363