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