1 #include "RegisterCache.h"
2 #include "sip/hash.h"
3 #include "sip/parse_uri.h"
4 
5 #include "AmBasicSipDialog.h"
6 #include "AmSipHeaders.h"
7 #include "AmUriParser.h"
8 #include "RegisterDialog.h"
9 #include "AmSession.h" //getNewId
10 #include "AmUtils.h"
11 #include "SBCEventLog.h"
12 
13 #include <utility>
14 using std::pair;
15 using std::make_pair;
16 
17 #define REG_CACHE_CYCLE 10L /* 10 seconds to expire all buckets */
18 
19  /* in us */
20 #define REG_CACHE_SINGLE_CYCLE \
21   ((REG_CACHE_CYCLE*1000000L)/REG_CACHE_TABLE_ENTRIES)
22 
hash_1str(const string & str)23 static unsigned int hash_1str(const string& str)
24 {
25   unsigned int h=0;
26   h = hashlittle(str.c_str(),str.length(),h);
27   return h & (REG_CACHE_TABLE_ENTRIES-1);
28 }
29 
hash_2str_1int(const string & str1,const string & str2,unsigned int i)30 static unsigned int hash_2str_1int(const string& str1, const string& str2,
31 				   unsigned int i)
32 {
33   unsigned int h=i;
34   h = hashlittle(str1.c_str(),str1.length(),h);
35   h = hashlittle(str2.c_str(),str2.length(),h);
36   return h & (REG_CACHE_TABLE_ENTRIES-1);
37 }
38 
unescape_sip(const string & str)39 static string unescape_sip(const string& str)
40 {
41   // TODO
42   return str;
43 }
44 
get(const string & aor)45 AorEntry* AorBucket::get(const string& aor)
46 {
47   value_map::iterator it = find(aor);
48   if(it == elmts.end())
49     return NULL;
50 
51   return it->second;
52 }
53 
dump_elmt(const string & aor,const AorEntry * p_aor_entry) const54 void AorBucket::dump_elmt(const string& aor,
55 			  const AorEntry* p_aor_entry) const
56 {
57   DBG("'%s' ->", aor.c_str());
58   if(!p_aor_entry) return;
59 
60   for(AorEntry::const_iterator it = p_aor_entry->begin();
61       it != p_aor_entry->end(); it++) {
62 
63     if(it->second) {
64       const RegBinding* b = it->second;
65       DBG("\t'%s' -> '%s'", it->first.c_str(),
66 	  b ? b->alias.c_str() : "NULL");
67     }
68   }
69 }
70 
gbc(RegCacheStorageHandler * h,long int now,list<string> & alias_list)71 void AorBucket::gbc(RegCacheStorageHandler* h, long int now,
72 		    list<string>& alias_list)
73 {
74   for(value_map::iterator it = elmts.begin(); it != elmts.end();) {
75 
76     AorEntry* aor_e = it->second;
77     if(aor_e) {
78 
79       for(AorEntry::iterator reg_it = aor_e->begin();
80 	  reg_it != aor_e->end();) {
81 
82 	RegBinding* binding = reg_it->second;
83 
84 	if(binding && (binding->reg_expire <= now)) {
85 
86 	  alias_list.push_back(binding->alias);
87 	  AorEntry::iterator del_it = reg_it++;
88 
89 	  DBG("delete binding: '%s' -> '%s' (%li <= %li)",
90 	      del_it->first.c_str(),binding->alias.c_str(),
91 	      binding->reg_expire,now);
92 
93 	  delete binding;
94 	  aor_e->erase(del_it);
95 	  continue;
96 	}
97 	reg_it++;
98       }
99     }
100     if(!aor_e || aor_e->empty()) {
101       DBG("delete empty AOR: '%s'", it->first.c_str());
102       value_map::iterator del_it = it++;
103       elmts.erase(del_it);
104       continue;
105     }
106     it++;
107   }
108 }
109 
getContact(const string & alias)110 AliasEntry* AliasBucket::getContact(const string& alias)
111 {
112   value_map::iterator it = find(alias);
113   if(it == elmts.end())
114     return NULL;
115 
116   return it->second;
117 }
118 
fire()119 void AliasEntry::fire()
120 {
121   AmArg ev;
122   ev["aor"]      = aor;
123   ev["to"]       = aor;
124   ev["contact"]  = contact_uri;
125   ev["source"]   = source_ip;
126   ev["src_port"] = source_port;
127   ev["from-ua"]  = remote_ua;
128 
129   DBG("Alias expired (UA/%li): '%s' -> '%s'\n",
130       (long)(AmAppTimer::instance()->unix_clock.get() - ua_expire),
131       alias.c_str(),aor.c_str());
132 
133   SBCEventLog::instance()->logEvent(alias,"ua-reg-expired",ev);
134 }
135 
dump_elmt(const string & alias,const AliasEntry * p_ae) const136 void AliasBucket::dump_elmt(const string& alias, const AliasEntry* p_ae) const
137 {
138   DBG("'%s' -> '%s'", alias.c_str(),
139       p_ae ? p_ae->contact_uri.c_str() : "NULL");
140 }
141 
getAlias(const string & contact_uri,const string & remote_ip,unsigned short remote_port)142 string ContactBucket::getAlias(const string& contact_uri,
143 			       const string& remote_ip,
144 			       unsigned short remote_port)
145 {
146   string key = contact_uri + "/" + remote_ip + ":" + int2str(remote_port);
147 
148   value_map::iterator it = find(key);
149   if(it == elmts.end())
150     return string();
151 
152   return *it->second;
153 }
154 
remove(const string & contact_uri,const string & remote_ip,unsigned short remote_port)155 void ContactBucket::remove(const string& contact_uri, const string& remote_ip,
156 			   unsigned short remote_port)
157 {
158   string k = contact_uri + "/" + remote_ip + ":" + int2str(remote_port);
159   elmts.erase(k);
160 }
161 
dump_elmt(const string & key,const string * alias) const162 void ContactBucket::dump_elmt(const string& key, const string* alias) const
163 {
164   DBG("'%s' -> %s", key.c_str(), alias? alias->c_str() : "NULL");
165 }
166 
167 struct RegCacheLogHandler
168   : RegCacheStorageHandler
169 {
onDeleteRegCacheLogHandler170   void onDelete(const string& aor, const string& uri, const string& alias) {
171     DBG("delete: aor='%s';uri='%s';alias='%s'",
172 	aor.c_str(),uri.c_str(),alias.c_str());
173   }
174 
onUpdateRegCacheLogHandler175   void onUpdate(const string& canon_aor, const string& alias,
176 		long int expires, const AliasEntry& alias_update) {
177     DBG("update: aor='%s';alias='%s';expires=%li",
178 	canon_aor.c_str(),alias.c_str(),expires);
179   }
180 
onUpdateRegCacheLogHandler181   void onUpdate(const string& alias, long int ua_expires) {
182     DBG("update: alias='%s';ua_expires=%li",
183 	alias.c_str(),ua_expires);
184   }
185 };
186 
187 
_RegisterCache()188 _RegisterCache::_RegisterCache()
189   : reg_cache_ht(REG_CACHE_TABLE_ENTRIES),
190     id_idx(REG_CACHE_TABLE_ENTRIES),
191     contact_idx(REG_CACHE_TABLE_ENTRIES)
192 {
193   // debug register cache WRITE operations
194   setStorageHandler(new RegCacheLogHandler());
195 }
196 
~_RegisterCache()197 _RegisterCache::~_RegisterCache()
198 {
199   DBG("##### REG CACHE DUMP #####");
200   reg_cache_ht.dump();
201   DBG("##### ID IDX DUMP #####");
202   id_idx.dump();
203   DBG("##### CONTACT IDX DUMP #####");
204   contact_idx.dump();
205   DBG("##### DUMP END #####");
206 }
207 
gbc(unsigned int bucket_id)208 void _RegisterCache::gbc(unsigned int bucket_id)
209 {
210   // if(!bucket_id) {
211   //   DBG("REG CACHE GBC CYCLE starting...");
212   // }
213 
214   struct timeval now;
215   gettimeofday(&now,NULL);
216 
217   AorBucket* bucket = reg_cache_ht.get_bucket(bucket_id);
218   bucket->lock();
219   list<string> alias_list;
220   bucket->gbc(storage_handler.get(),now.tv_sec,alias_list);
221   for(list<string>::iterator it = alias_list.begin();
222       it != alias_list.end(); it++){
223     removeAlias(*it,true);
224   }
225   bucket->unlock();
226 }
227 
on_stop()228 void _RegisterCache::on_stop()
229 {
230   running.set(false);
231 }
232 
run()233 void _RegisterCache::run()
234 {
235   struct timespec tick,rem;
236   tick.tv_sec  = (REG_CACHE_SINGLE_CYCLE/1000000L);
237   tick.tv_nsec = (REG_CACHE_SINGLE_CYCLE - (tick.tv_sec)*1000000L) * 1000L;
238 
239   running.set(true);
240 
241   gbc_bucket_id = 0;
242   while(running.get()) {
243     gbc(gbc_bucket_id);
244     gbc_bucket_id = (gbc_bucket_id+1);
245     gbc_bucket_id &= (REG_CACHE_TABLE_ENTRIES-1);
246     nanosleep(&tick,&rem);
247   }
248 }
249 
250 /**
251  * From RFC 3261 (Section 10.3, step 5):
252  *  "all URI parameters MUST be removed (including the user-param), and
253  *   any escaped characters MUST be converted to their unescaped form"
254  */
canonicalize_aor(const string & uri)255 string _RegisterCache::canonicalize_aor(const string& uri)
256 {
257   string canon_uri;
258   sip_uri parsed_uri;
259 
260   if(parse_uri(&parsed_uri,uri.c_str(),uri.length())) {
261     DBG("Malformed URI: '%s'",uri.c_str());
262     return "";
263   }
264 
265   switch(parsed_uri.scheme) {
266   case sip_uri::SIP:  canon_uri = "sip:"; break;
267   case sip_uri::SIPS: canon_uri = "sips:"; break;
268   default:
269     DBG("Unknown URI scheme in '%s'",uri.c_str());
270     return "";
271   }
272 
273   if(parsed_uri.user.len) {
274     canon_uri += unescape_sip(c2stlstr(parsed_uri.user)) + "@";
275   }
276 
277   canon_uri += unescape_sip(c2stlstr(parsed_uri.host));
278 
279   if(parsed_uri.port != 5060) {
280     canon_uri += ":" + unescape_sip(c2stlstr(parsed_uri.port_str));
281   }
282 
283   return canon_uri;
284 }
285 
286 string
compute_alias_hash(const string & aor,const string & contact_uri,const string & public_ip)287 _RegisterCache::compute_alias_hash(const string& aor, const string& contact_uri,
288 				   const string& public_ip)
289 {
290   unsigned int h1=0,h2=0;
291   h1 = hashlittle(aor.c_str(),aor.length(),h1);
292   h1 = hashlittle(contact_uri.c_str(),contact_uri.length(),h1);
293   h2 = hashlittle(public_ip.c_str(),public_ip.length(),h1);
294 
295   return int2hex(h1,true) + int2hex(h2,true);
296 }
297 
getAorBucket(const string & aor)298 AorBucket* _RegisterCache::getAorBucket(const string& aor)
299 {
300   return reg_cache_ht.get_bucket(hash_1str(aor));
301 }
302 
insert(const string & contact_uri,const string & remote_ip,unsigned short remote_port,const string & alias)303 void ContactBucket::insert(const string& contact_uri, const string& remote_ip,
304 			   unsigned short remote_port, const string& alias)
305 {
306   string k = contact_uri + "/" + remote_ip + ":" + int2str(remote_port);
307   insert(k,new string(alias));
308 }
309 
getAlias(const string & canon_aor,const string & uri,const string & public_ip,RegBinding & out_binding)310 bool _RegisterCache::getAlias(const string& canon_aor, const string& uri,
311 			      const string& public_ip, RegBinding& out_binding)
312 {
313   if(canon_aor.empty()) {
314     DBG("Canonical AOR is empty");
315     return false;
316   }
317 
318   bool alias_found = false;
319   AorBucket* bucket = getAorBucket(canon_aor);
320   bucket->lock();
321 
322   AorEntry* aor_e = bucket->get(canon_aor);
323   if(aor_e){
324     AorEntry::iterator binding_it = aor_e->find(uri + "/" + public_ip);
325     if((binding_it != aor_e->end()) && binding_it->second) {
326       alias_found = true;
327       out_binding = *binding_it->second;
328     }
329   }
330 
331   bucket->unlock();
332 
333   return alias_found;
334 }
335 
getAliasBucket(const string & alias)336 AliasBucket* _RegisterCache::getAliasBucket(const string& alias)
337 {
338   return id_idx.get_bucket(hash_1str(alias));
339 }
340 
getContactBucket(const string & contact_uri,const string & remote_ip,unsigned short remote_port)341 ContactBucket* _RegisterCache::getContactBucket(const string& contact_uri,
342 						const string& remote_ip,
343 						unsigned short remote_port)
344 {
345   unsigned int h = hash_2str_1int(contact_uri,remote_ip,remote_port);
346   return contact_idx.get_bucket(h);
347 }
348 
setAliasUATimer(AliasEntry * alias_e)349 void _RegisterCache::setAliasUATimer(AliasEntry* alias_e)
350 {
351   if(!alias_e->ua_expire)
352     return;
353 
354   AmAppTimer* app_timer = AmAppTimer::instance();
355   time_t timeout = alias_e->ua_expire - app_timer->unix_clock.get();
356   if(timeout > 0) {
357     app_timer->setTimer(alias_e,timeout);
358   }
359   else {
360     // already expired at the UA side, just fire the timer handler
361     alias_e->fire();
362   }
363 }
364 
removeAliasUATimer(AliasEntry * alias_e)365 void _RegisterCache::removeAliasUATimer(AliasEntry* alias_e)
366 {
367   AmAppTimer::instance()->removeTimer(alias_e);
368 }
369 
update(const string & alias,long int reg_expires,const AliasEntry & alias_update)370 void _RegisterCache::update(const string& alias, long int reg_expires,
371 			    const AliasEntry& alias_update)
372 {
373   string uri = alias_update.contact_uri;
374   string canon_aor = alias_update.aor;
375   string public_ip = alias_update.source_ip;
376   if(canon_aor.empty()) {
377     ERROR("Canonical AOR is empty: could not update register cache");
378     return;
379   }
380   if(uri.empty()) {
381     ERROR("Contact-URI is empty: could not update register cache");
382     return;
383   }
384   if(public_ip.empty()) {
385     ERROR("Source-IP is empty: could not update register cache");
386     return;
387   }
388 
389   AorBucket* bucket = getAorBucket(canon_aor);
390   AliasBucket* alias_bucket = getAliasBucket(alias);
391 
392   bucket->lock();
393   alias_bucket->lock();
394 
395   // Try to get the existing binding
396   RegBinding* binding = NULL;
397   AorEntry* aor_e = bucket->get(canon_aor);
398   if(!aor_e) {
399     // insert AorEntry if none
400     aor_e = new AorEntry();
401     bucket->insert(canon_aor,aor_e);
402     DBG("inserted new AOR '%s'",canon_aor.c_str());
403   }
404   else {
405     string idx = uri + "/" + public_ip;
406     AorEntry::iterator binding_it = aor_e->find(idx);
407     if(binding_it != aor_e->end()) {
408       binding = binding_it->second;
409     }
410   }
411 
412   if(!binding) {
413     // insert one if none exist
414     binding = new RegBinding();
415     binding->alias = alias;
416     aor_e->insert(AorEntry::value_type(uri + "/" + public_ip,binding));
417     DBG("inserted new binding: '%s' -> '%s'",
418 	uri.c_str(), alias.c_str());
419 
420     // inc stats
421     active_regs.inc();
422 
423     ContactBucket* ct_bucket = getContactBucket(uri,alias_update.source_ip,
424 						alias_update.source_port);
425     ct_bucket->lock();
426     ct_bucket->insert(uri,alias_update.source_ip,
427 		      alias_update.source_port,alias);
428     ct_bucket->unlock();
429   }
430   else {
431     DBG("updating existing binding: '%s' -> '%s'",
432 	uri.c_str(), binding->alias.c_str());
433     if(alias != binding->alias) {
434       ERROR("used alias ('%s') is different from stored one ('%s')",
435 	    alias.c_str(), binding->alias.c_str());
436     }
437   }
438   // and update binding
439   binding->reg_expire = reg_expires;
440 
441   AliasEntry* alias_e = alias_bucket->getContact(alias);
442   // if no alias map entry, insert a new one
443   if(!alias_e) {
444     DBG("inserting alias map entry: '%s' -> '%s'",
445 	alias.c_str(), uri.c_str());
446     alias_e = new AliasEntry(alias_update);
447     alias_bucket->insert(alias,alias_e);
448   }
449   else {
450     *alias_e = alias_update;
451   }
452 
453 #if 0 // disabled UA-timer
454   if(alias_e->ua_expire) {
455     setAliasUATimer(alias_e);
456   }
457 #endif
458 
459   if(storage_handler.get())
460     storage_handler->onUpdate(canon_aor,alias,reg_expires,*alias_e);
461 
462   alias_bucket->unlock();
463   bucket->unlock();
464 }
465 
update(long int reg_expires,const AliasEntry & alias_update)466 void _RegisterCache::update(long int reg_expires, const AliasEntry& alias_update)
467 {
468   string uri = alias_update.contact_uri;
469   string canon_aor = alias_update.aor;
470   string public_ip = alias_update.source_ip;
471   if(canon_aor.empty()) {
472     ERROR("Canonical AOR is empty: could not update register cache");
473     return;
474   }
475   if(uri.empty()) {
476     ERROR("Contact-URI is empty: could not update register cache");
477     return;
478   }
479   if(public_ip.empty()) {
480     ERROR("Source-IP is empty: could not update register cache");
481     return;
482   }
483 
484   string idx = uri + "/" + public_ip;
485   AorBucket* bucket = getAorBucket(canon_aor);
486   bucket->lock();
487 
488   // Try to get the existing binding
489   RegBinding* binding = NULL;
490   AorEntry* aor_e = bucket->get(canon_aor);
491   if(aor_e) {
492     // take the first, as we do not expect others to be here
493     AorEntry::iterator binding_it = aor_e->begin();
494 
495     if(binding_it != aor_e->end()) {
496 
497       binding = binding_it->second;
498       if(binding && (binding_it->first != idx)) {
499 
500 	// contact-uri and/or public IP has changed...
501 	string alias = binding->alias;
502 
503 	AliasEntry ae;
504 	if(findAliasEntry(alias,ae)) {
505 
506 	  // change contact index
507 	  ContactBucket* ct_bucket =
508 	    getContactBucket(ae.contact_uri,ae.source_ip,ae.source_port);
509 	  ct_bucket->lock();
510 	  ct_bucket->remove(ae.contact_uri,ae.source_ip,ae.source_port);
511 	  ct_bucket->unlock();
512 
513 	  ct_bucket = getContactBucket(uri,public_ip,alias_update.source_port);
514 	  ct_bucket->lock();
515 	  ct_bucket->insert(uri,public_ip,alias_update.source_port,alias);
516 	  ct_bucket->unlock();
517 	}
518 
519 	// relink binding with the new index
520       	aor_e->erase(binding_it);
521 	aor_e->insert(AorEntry::value_type(idx, binding));
522       }
523       else if(!binding) {
524 	// probably never happens, but who knows?
525 	aor_e->erase(binding_it);
526       }
527     }
528   }
529   else {
530     // insert AorEntry if none
531     aor_e = new AorEntry();
532     bucket->insert(canon_aor,aor_e);
533     DBG("inserted new AOR '%s'",canon_aor.c_str());
534   }
535 
536   if(!binding) {
537     // insert one if none exist
538     binding = new RegBinding();
539     binding->alias = _RegisterCache::
540       compute_alias_hash(canon_aor,uri,public_ip);
541 
542     // inc stats
543     active_regs.inc();
544 
545     string idx = uri + "/" + public_ip;
546     aor_e->insert(AorEntry::value_type(idx, binding));
547     DBG("inserted new binding: '%s' -> '%s'",
548 	idx.c_str(), binding->alias.c_str());
549 
550     ContactBucket* ct_bucket = getContactBucket(uri,alias_update.source_ip,
551 						alias_update.source_port);
552     ct_bucket->lock();
553     ct_bucket->insert(uri,alias_update.source_ip,
554 		      alias_update.source_port,binding->alias);
555     ct_bucket->unlock();
556   }
557   else {
558     DBG("updating existing binding: '%s' -> '%s'",
559 	uri.c_str(), binding->alias.c_str());
560   }
561   // and update binding
562   binding->reg_expire = reg_expires;
563 
564   AliasBucket* alias_bucket = getAliasBucket(binding->alias);
565   alias_bucket->lock();
566 
567   AliasEntry* alias_e = alias_bucket->getContact(binding->alias);
568   // if no alias map entry, insert a new one
569   if(!alias_e) {
570     DBG("inserting alias map entry: '%s' -> '%s'",
571 	binding->alias.c_str(), uri.c_str());
572     alias_e = new AliasEntry(alias_update);
573     alias_e->alias = binding->alias;
574     alias_bucket->insert(binding->alias,alias_e);
575   }
576   else {
577     *alias_e = alias_update;
578     alias_e->alias = binding->alias;
579   }
580 
581 #if 0 // disabled UA-timer
582   if(alias_e->ua_expire) {
583     setAliasUATimer(alias_e);
584   }
585 #endif
586 
587   if(storage_handler.get())
588     storage_handler->onUpdate(canon_aor,binding->alias,
589 			      reg_expires,*alias_e);
590 
591   alias_bucket->unlock();
592   bucket->unlock();
593 }
594 
updateAliasExpires(const string & alias,long int ua_expires)595 bool _RegisterCache::updateAliasExpires(const string& alias, long int ua_expires)
596 {
597   bool res = false;
598   AliasBucket* alias_bucket = getAliasBucket(alias);
599   alias_bucket->lock();
600 
601   AliasEntry* alias_e = alias_bucket->getContact(alias);
602   if(alias_e) {
603     alias_e->ua_expire = ua_expires;
604 #if 0 // disabled UA-timer
605     if(alias_e->ua_expire)
606       setAliasUATimer(alias_e);
607 #endif
608 
609     if(storage_handler.get()) {
610       storage_handler->onUpdate(alias,ua_expires);
611     }
612     res = true;
613   }
614 
615   alias_bucket->unlock();
616   return res;
617 }
618 
remove(const string & canon_aor,const string & uri,const string & alias)619 void _RegisterCache::remove(const string& canon_aor, const string& uri,
620 			    const string& alias)
621 {
622   if(canon_aor.empty()) {
623     DBG("Canonical AOR is empty");
624     return;
625   }
626 
627   AorBucket* bucket = getAorBucket(canon_aor);
628   bucket->lock();
629 
630   DBG("removing entries for aor = '%s', uri = '%s' and alias = '%s'",
631       canon_aor.c_str(), uri.c_str(), alias.c_str());
632 
633   AorEntry* aor_e = bucket->get(canon_aor);
634   if(aor_e) {
635     // remove all bindings for which the alias matches
636     for(AorEntry::iterator binding_it = aor_e->begin();
637 	binding_it != aor_e->end();) {
638 
639       RegBinding* binding = binding_it->second;
640       if(!binding || (binding->alias == alias)) {
641 
642 	delete binding;
643 	AorEntry::iterator del_it = binding_it++;
644 	aor_e->erase(del_it);
645 	continue;
646       }
647 
648       binding_it++;
649     }
650     if(aor_e->empty()) {
651       bucket->remove(canon_aor);
652     }
653   }
654 
655   removeAlias(alias,false);
656   bucket->unlock();
657 }
658 
remove(const string & aor)659 void _RegisterCache::remove(const string& aor)
660 {
661   if(aor.empty()) {
662     DBG("Canonical AOR is empty");
663     return;
664   }
665 
666   AorBucket* bucket = getAorBucket(aor);
667   bucket->lock();
668 
669   DBG("removing entries for aor = '%s'", aor.c_str());
670 
671   AorEntry* aor_e = bucket->get(aor);
672   if(aor_e) {
673     for(AorEntry::iterator binding_it = aor_e->begin();
674 	binding_it != aor_e->end(); binding_it++) {
675 
676       RegBinding* binding = binding_it->second;
677       if(binding) {
678 	removeAlias(binding->alias,false);
679 	delete binding;
680       }
681     }
682     bucket->remove(aor);
683   }
684 
685   bucket->unlock();
686 }
687 
removeAlias(const string & alias,bool generate_event)688 void _RegisterCache::removeAlias(const string& alias, bool generate_event)
689 {
690   AliasBucket* alias_bucket = getAliasBucket(alias);
691   alias_bucket->lock();
692 
693   AliasEntry* ae = alias_bucket->getContact(alias);
694   if(ae) {
695 #if 0 // disabled UA-timer
696     if(ae->ua_expire)
697       removeAliasUATimer(ae);
698 #endif
699 
700     if(generate_event) {
701       AmArg ev;
702       ev["aor"]      = ae->aor;
703       ev["to"]       = ae->aor;
704       ev["contact"]  = ae->contact_uri;
705       ev["source"]   = ae->source_ip;
706       ev["src_port"] = ae->source_port;
707       ev["from-ua"]  = ae->remote_ua;
708 
709       DBG("Alias expired @registrar (UA/%li): '%s' -> '%s'\n",
710 	  (long)(AmAppTimer::instance()->unix_clock.get() - ae->ua_expire),
711 	  ae->alias.c_str(),ae->aor.c_str());
712 
713       SBCEventLog::instance()->logEvent(ae->alias,"reg-expired",ev);
714     }
715 
716     ContactBucket* ct_bucket = getContactBucket(ae->contact_uri,
717 						ae->source_ip,
718 						ae->source_port);
719     ct_bucket->lock();
720     ct_bucket->remove(ae->contact_uri,ae->source_ip,ae->source_port);
721     ct_bucket->unlock();
722 
723     // dec stats
724     active_regs.dec();
725 
726     storage_handler->onDelete(ae->aor,
727 			      ae->contact_uri,
728 			      ae->alias);
729   }
730   alias_bucket->remove(alias);
731   alias_bucket->unlock();
732 }
733 
getAorAliasMap(const string & canon_aor,map<string,string> & alias_map)734 bool _RegisterCache::getAorAliasMap(const string& canon_aor,
735 				    map<string,string>& alias_map)
736 {
737   if(canon_aor.empty()) {
738     DBG("Canonical AOR is empty");
739     return false;
740   }
741 
742   AorBucket* bucket = getAorBucket(canon_aor);
743   bucket->lock();
744   AorEntry* aor_e = bucket->get(canon_aor);
745   if(aor_e) {
746     for(AorEntry::iterator it = aor_e->begin();
747 	it != aor_e->end(); ++it) {
748 
749       if(!it->second)
750 	continue;
751 
752       AliasEntry ae;
753       if(!findAliasEntry(it->second->alias,ae))
754 	continue;
755 
756       alias_map[ae.alias] = ae.contact_uri;
757     }
758   }
759   bucket->unlock();
760 
761   return true;
762 }
763 
findAliasEntry(const string & alias,AliasEntry & alias_entry)764 bool _RegisterCache::findAliasEntry(const string& alias, AliasEntry& alias_entry)
765 {
766   bool res = false;
767 
768   AliasBucket* bucket = getAliasBucket(alias);
769   bucket->lock();
770 
771   AliasEntry* a = bucket->getContact(alias);
772   if(a) {
773     alias_entry = *a;
774     res = true;
775   }
776 
777   bucket->unlock();
778   return res;
779 }
780 
findAEByContact(const string & contact_uri,const string & remote_ip,unsigned short remote_port,AliasEntry & ae)781 bool _RegisterCache::findAEByContact(const string& contact_uri,
782 				     const string& remote_ip,
783 				     unsigned short remote_port,
784 				     AliasEntry& ae)
785 {
786   bool res = false;
787 
788   ContactBucket* ct_bucket = getContactBucket(contact_uri,remote_ip,
789 					      remote_port);
790   ct_bucket->lock();
791   string alias = ct_bucket->getAlias(contact_uri,remote_ip,remote_port);
792   ct_bucket->unlock();
793 
794   if(alias.empty())
795     return false;
796 
797   res = findAliasEntry(alias,ae);
798 
799   return res;
800 }
801 
802 
parseAoR(RegisterCacheCtx & ctx,const AmSipRequest & req,msg_logger * logger)803 int _RegisterCache::parseAoR(RegisterCacheCtx& ctx,
804 			     const AmSipRequest& req,
805                              msg_logger *logger)
806 {
807   if(ctx.aor_parsed)
808     return 0;
809 
810   AmUriParser from_parser;
811   size_t end_from = 0;
812   if(!from_parser.parse_contact(req.from,0,end_from)) {
813     DBG("error parsing AoR: '%s'\n",req.from.c_str());
814     AmBasicSipDialog::reply_error(req,400,"Bad request - bad From HF", "", logger);
815     return -1;
816   }
817 
818   ctx.from_aor = RegisterCache::canonicalize_aor(from_parser.uri_str());
819   DBG("parsed AOR: '%s'",ctx.from_aor.c_str());
820 
821   if(ctx.from_aor.empty()) {
822     AmBasicSipDialog::reply_error(req,400,"Bad request - bad From HF", "", logger);
823     return -1;
824   }
825   ctx.aor_parsed = true;
826 
827   return 0;
828 }
829 
parseContacts(RegisterCacheCtx & ctx,const AmSipRequest & req,msg_logger * logger)830 int _RegisterCache::parseContacts(RegisterCacheCtx& ctx,
831 				  const AmSipRequest& req,
832                                   msg_logger *logger)
833 {
834   if(ctx.contacts_parsed)
835     return 0;
836 
837   if ((RegisterDialog::parseContacts(req.contact, ctx.contacts) < 0) ||
838       (ctx.contacts.size() == 0)) {
839     AmBasicSipDialog::reply_error(req, 400, "Bad Request",
840 				  "Warning: Malformed contact\r\n", logger);
841     return -1;
842   }
843   ctx.contacts_parsed = true;
844   return 0;
845 }
846 
parseExpires(RegisterCacheCtx & ctx,const AmSipRequest & req,msg_logger * logger)847 int _RegisterCache::parseExpires(RegisterCacheCtx& ctx,
848 				 const AmSipRequest& req,
849                                  msg_logger *logger)
850 {
851   if(ctx.expires_parsed)
852     return 0;
853 
854   // move Expires as separate header to contact parameter
855   string expires_str = getHeader(req.hdrs, "Expires");
856   if (!expires_str.empty() && str2i(expires_str, ctx.requested_expires)) {
857     AmBasicSipDialog::reply_error(req, 400, "Bad Request",
858 				  "Warning: Malformed expires\r\n", logger);
859     return true; // error reply sent
860   }
861   ctx.expires_parsed = true;
862   return 0;
863 }
864 
throttleRegister(RegisterCacheCtx & ctx,const AmSipRequest & req,msg_logger * logger)865 bool _RegisterCache::throttleRegister(RegisterCacheCtx& ctx,
866 				      const AmSipRequest& req,
867                                       msg_logger *logger)
868 {
869   if (req.method != SIP_METH_REGISTER) {
870     ERROR("unsupported method '%s'\n", req.method.c_str());
871     return false; // fwd
872   }
873 
874   if (req.contact.empty() || (req.contact == "*")) {
875     // binding query or unregister
876     DBG("req.contact.empty() || (req.contact == \"*\")\n");
877     return false; // fwd
878   }
879 
880   if ((parseAoR(ctx,req, logger) < 0) ||
881       (parseContacts(ctx,req, logger) < 0) ||
882       (parseExpires(ctx,req, logger) < 0)) {
883     DBG("could not parse AoR, Contact or Expires\n");
884     return true; // error reply sent
885   }
886 
887   unsigned int default_expires;
888   if(ctx.requested_expires && (ctx.requested_expires > ctx.max_ua_expires))
889     default_expires = ctx.max_ua_expires;
890   else
891     default_expires = ctx.requested_expires;
892 
893   vector<pair<string, long int> > alias_updates;
894   for(vector<AmUriParser>::iterator contact_it = ctx.contacts.begin();
895       contact_it != ctx.contacts.end(); contact_it++) {
896 
897     map<string, string>::iterator expires_it =
898       contact_it->params.find("expires");
899 
900     long int contact_expires=0;
901     if(expires_it == contact_it->params.end()) {
902       if(!default_expires){
903 	DBG("!default_expires");
904 	return false; // fwd
905       }
906 
907       contact_expires = default_expires;
908       contact_it->params["expires"] = long2str(contact_expires);
909     }
910     else {
911       if(!str2long(expires_it->second,contact_expires)) {
912 	AmBasicSipDialog::reply_error(req, 400, "Bad Request",
913 				      "Warning: Malformed expires\r\n", logger);
914 	return true; // error reply sent
915       }
916 
917       if(!contact_expires) {
918 	DBG("!contact_expires");
919 	return false; // fwd
920       }
921 
922       if(contact_expires && ctx.max_ua_expires &&
923 	 (contact_expires > (long int)ctx.max_ua_expires)) {
924 
925 	contact_expires = ctx.max_ua_expires;
926 	contact_it->params["expires"] = long2str(contact_expires);
927       }
928     }
929 
930     RegBinding reg_binding;
931     const string& uri = contact_it->uri_str();
932 
933     if(!getAlias(ctx.from_aor,uri,req.remote_ip,reg_binding) ||
934        !reg_binding.reg_expire) {
935       DBG("!getAlias(%s,%s,...) || !reg_binding.reg_expire",
936 	  ctx.from_aor.c_str(),uri.c_str());
937       return false; // fwd
938     }
939 
940     struct timeval now;
941     gettimeofday(&now,NULL);
942     contact_expires += now.tv_sec;
943 
944     if(contact_expires + 4 /* 4 seconds buffer */
945        >= reg_binding.reg_expire) {
946       DBG("%li + 4 >= %li",contact_expires,reg_binding.reg_expire);
947       return false; // fwd
948     }
949 
950     AliasEntry alias_entry;
951     if(!findAliasEntry(reg_binding.alias, alias_entry) ||
952        (alias_entry.source_ip != req.remote_ip) ||
953        (alias_entry.source_port != req.remote_port)) {
954       DBG("no alias entry or IP/port mismatch");
955       return false; // fwd
956     }
957 
958     alias_updates.push_back(make_pair(reg_binding.alias,
959 						       contact_expires));
960   }
961 
962   // reply 200 w/ contacts
963   vector<AmUriParser>::iterator it = ctx.contacts.begin();
964   vector<pair<string, long int> >::iterator alias_update_it =
965     alias_updates.begin();
966 
967   string contact_hdr = SIP_HDR_COLSP(SIP_HDR_CONTACT) + it->print();
968   assert(alias_update_it != alias_updates.end());
969   if(!updateAliasExpires(alias_update_it->first,
970 			 alias_update_it->second)) {
971     // alias not found ???
972     return false; // fwd
973   }
974   it++;
975   alias_update_it++;
976 
977   for(;it != ctx.contacts.end(); it++, alias_update_it++) {
978 
979     contact_hdr += ", " + it->print();
980 
981     assert(alias_update_it != alias_updates.end());
982     if(!updateAliasExpires(alias_update_it->first,
983 			   alias_update_it->second)) {
984       // alias not found ???
985       return false; // fwd
986     }
987   }
988   contact_hdr += CRLF;
989 
990   // send 200 reply
991   AmBasicSipDialog::reply_error(req, 200, "OK", contact_hdr, logger);
992   return true;
993 }
994 
saveSingleContact(RegisterCacheCtx & ctx,const AmSipRequest & req,msg_logger * logger)995 bool _RegisterCache::saveSingleContact(RegisterCacheCtx& ctx,
996 				       const AmSipRequest& req,
997                                        msg_logger *logger)
998 {
999   if (req.method != SIP_METH_REGISTER) {
1000     ERROR("unsupported method '%s'\n", req.method.c_str());
1001     return false;
1002   }
1003 
1004   if(parseAoR(ctx,req, logger) < 0) {
1005     return true;
1006   }
1007 
1008   if (req.contact.empty()) {
1009     string contact_hdr;
1010     map<string,string> alias_map;
1011     if(getAorAliasMap(ctx.from_aor, alias_map) &&
1012        !alias_map.empty()) {
1013 
1014       struct timeval now;
1015       gettimeofday(&now,NULL);
1016 
1017       AliasEntry alias_entry;
1018       if(findAliasEntry(alias_map.begin()->first,alias_entry) &&
1019 	 (now.tv_sec < alias_entry.ua_expire)) {
1020 
1021 	unsigned int exp = alias_entry.ua_expire - now.tv_sec;
1022 	contact_hdr = SIP_HDR_COLSP(SIP_HDR_CONTACT)
1023 	  + alias_entry.contact_uri + ";expires="
1024 	  + int2str(exp) + CRLF;
1025       }
1026     }
1027 
1028     AmBasicSipDialog::reply_error(req, 200, "OK", contact_hdr);
1029     return true;
1030   }
1031 
1032   unsigned int contact_expires=0;
1033   AmUriParser* contact=NULL;
1034   if (req.contact == "*") {
1035     // unregister everything
1036 
1037     if(parseExpires(ctx,req, logger) < 0) {
1038       return true;
1039     }
1040 
1041     if(ctx.requested_expires != 0) {
1042       AmBasicSipDialog::reply_error(req, 400, "Bad Request",
1043 				    "Warning: Expires not equal 0\r\n");
1044       return true;
1045     }
1046   }
1047   else if ((parseContacts(ctx,req, logger) < 0) ||
1048 	   (parseExpires(ctx,req, logger) < 0)) {
1049     return true; // error reply sent
1050   }
1051   else if (ctx.contacts.size() != 1) {
1052     AmBasicSipDialog::reply_error(req, 403, "Forbidden",
1053 				  "Warning: only one contact allowed\r\n", logger);
1054     return true; // error reply sent
1055   }
1056   else {
1057 
1058     contact = &ctx.contacts[0];
1059     if(contact->params.find("expires") != contact->params.end()) {
1060       DBG("contact->params[\"expires\"] = '%s'",
1061 	  contact->params["expires"].c_str());
1062       if(str2i(contact->params["expires"],contact_expires)) {
1063 	AmBasicSipDialog::reply_error(req, 400, "Bad Request",
1064 				      "Warning: Malformed expires\r\n", logger);
1065 	return true; // error reply sent
1066       }
1067       DBG("contact_expires = %u",contact_expires);
1068     }
1069     else {
1070       contact_expires = ctx.requested_expires;
1071     }
1072   }
1073 
1074   if(!contact_expires) {
1075     // unregister AoR
1076     remove(ctx.from_aor);
1077     AmBasicSipDialog::reply_error(req, 200, "OK", "", logger);
1078     return true;
1079   }
1080   assert(contact);
1081 
1082   // throttle contact_expires
1083   unsigned int reg_expires = contact_expires;
1084   if(reg_expires && (reg_expires < ctx.min_reg_expires))
1085     reg_expires = ctx.min_reg_expires;
1086 
1087   unsigned int ua_expires = contact_expires;
1088   if(ua_expires && ctx.max_ua_expires &&
1089      (ua_expires > ctx.max_ua_expires))
1090     ua_expires = ctx.max_ua_expires;
1091 
1092   struct timeval now;
1093   gettimeofday(&now,NULL);
1094 
1095   reg_expires += now.tv_sec;
1096 
1097   AliasEntry alias_update;
1098   alias_update.aor = ctx.from_aor;
1099   alias_update.contact_uri = contact->uri_str();
1100   alias_update.source_ip = req.remote_ip;
1101   alias_update.source_port = req.remote_port;
1102   alias_update.remote_ua = getHeader(req.hdrs,"User-Agent");
1103   alias_update.trsp = req.trsp;
1104   alias_update.local_if = req.local_if;
1105   alias_update.ua_expire = ua_expires + now.tv_sec;
1106 
1107   update(reg_expires,alias_update);
1108 
1109   contact->params["expires"] = int2str(ua_expires);
1110   string contact_hdr = SIP_HDR_COLSP(SIP_HDR_CONTACT)
1111     + contact->print() + CRLF;
1112 
1113   AmBasicSipDialog::reply_error(req, 200, "OK", contact_hdr);
1114   return true;
1115 }
1116