reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ServerRegistration.cxx
Go to the documentation of this file.
11#include "rutil/DnsUtil.hxx"
12#include "rutil/Logger.hxx"
13#include "rutil/Timer.hxx"
16
17#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
18
19using namespace resip;
20
26
27ServerRegistration::ServerRegistration(DialogUsageManager& dum, DialogSet& dialogSet, const SipMessage& request)
28 : NonDialogUsage(dum, dialogSet),
29 mRequest(request),
30 mDidOutbound(false),
31 mAsyncState(asyncStateNone)
32{}
33
35{
36 mDialogSet.mServerRegistration = nullptr;
37}
38
39void
43
45void
47{
49 resip_assert(ok.header(h_StatusLine).statusCode() >= 200 && ok.header(h_StatusLine).statusCode() < 300);
50
51 ok.remove(h_Contacts);
52
53 InfoLog( << "accepted a registration " << mAor );
54
55 if (mDidOutbound)
56 {
57 ok.header(h_Requires).push_back(outbound);
59 {
60 ok.header(h_FlowTimer).value() = InteropHelper::getFlowTimerSeconds();
62 }
63 }
64
65 if (!mDum.mServerRegistrationHandler->asyncProcessing())
66 {
67 // Add all registered contacts to the message.
68 RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
69
70 ContactList contacts;
71 database->getContacts(mAor, contacts);
72
73 //removes expired entries from the ok msg as well as calls the database to remove expired contacts.
74 processFinalOkMsg(ok,contacts);
75
76 database->unlockRecord(mAor);
77
78 std::shared_ptr<SipMessage> msg(static_cast<SipMessage*>(ok.clone()));
79 mDum.send(msg);
80 delete(this);
81 }
82 else
83 {
84 if (mAsyncState == asyncStateQueryOnly)
85 {
86 if (!mAsyncLocalStore.get())
87 {
88 resip_assert(0);
89 }
90 else
91 {
92 std::unique_ptr<ContactRecordTransactionLog> log;
93 std::unique_ptr<ContactPtrList> contacts;
94
95 mAsyncLocalStore->releaseLog(log,contacts);
96
97 if (contacts)
98 {
99 asyncProcessFinalOkMsg(ok,*contacts);
100 }
101 }
102
103 std::shared_ptr<SipMessage> msg(static_cast<SipMessage*>(ok.clone()));
104 mDum.send(msg);
105 delete(this);
106 }
107 else
108 {
109 if (!mAsyncLocalStore)
110 {
111 resip_assert(0);
112 return;
113 }
114 //This register was accepted, but still need to apply the changes made by this register and then
115 //receive a final contact list before sending the 200.
116 mAsyncState = asyncStateAcceptedWaitingForFinalContactList;
117
118 std::unique_ptr<ContactRecordTransactionLog> log;
119 std::unique_ptr<ContactPtrList> modifiedContacts;
120
121 mAsyncLocalStore->releaseLog(log,modifiedContacts);
122
123 mAsyncOkMsg = std::shared_ptr<SipMessage>(static_cast<SipMessage*>(ok.clone()));
124 mDum.mServerRegistrationHandler->asyncUpdateContacts(getHandle(), mAor, std::move(modifiedContacts), std::move(log));
126 return;
127 }
128 }
129}
130
131void
133{
134 SipMessage success;
135 mDum.makeResponse(success, mRequest, statusCode);
136 // .bwc. Copy Path headers if present, indicate Path support
137 // ?bwc? If path headers are present, but client indicates no path support,
138 // RFC 3327 says it is a matter of policy of whether to accept the
139 // registration or not. What should we do here? Is it worth it to make this
140 // configurable?
141 if(!mRequest.empty(h_Paths))
142 {
143 success.header(h_Paths)=mRequest.header(h_Paths);
144 success.header(h_Supporteds).push_back(Token(Symbols::Path));
145 }
146 accept(success);
147}
148
149void
151{
152 resip_assert(failure.isResponse());
153 resip_assert(failure.header(h_StatusLine).statusCode() >= 300 && failure.header(h_StatusLine).statusCode() < 700);
154
155 failure.remove(h_Contacts);
156
157 InfoLog( << "rejected a registration " << mAor << " with statusCode=" << failure.header(h_StatusLine).statusCode() );
158
159 // First, we roll back the contact database to
160 // the state it was before the registration request.
161
162 // Async processing hasn't actually updated the database yet, so no need to roll back.
163 if (mDum.mServerRegistrationHandler && !mDum.mServerRegistrationHandler->asyncProcessing())
164 {
165 // Rollback changes, since rejected
166 RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
167 database->removeAor(mAor);
168 if (mOriginalContacts.get())
169 {
170 database->addAor(mAor, *mOriginalContacts);
171 }
172 database->unlockRecord(mAor);
173 }
174
175 mDum.send(std::shared_ptr<SipMessage>(static_cast<SipMessage*>(failure.clone())));
176 delete(this);
177}
178
179void
181{
182 SipMessage failure;
183 mDum.makeResponse(failure, mRequest, statusCode);
184 reject(failure);
185}
186
187void
189{
190 DebugLog( << "got a registration" );
191
192 resip_assert(msg.isRequest());
193 ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler;
194 RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
195
196 if (!handler || (!handler->asyncProcessing() && !database))
197 {
198 // ?bwc? This is a server error; why are we sending a 4xx?
199 // ?jmatthewsr? Possibly because of the note in section 21.5.2 about recognizing the method, but not supporting it?
200 DebugLog( << "No handler or DB - sending 405" );
201
202 auto failure = std::make_shared<SipMessage>();
203 mDum.makeResponse(*failure, msg, 405);
204 mDum.send(failure);
205 delete(this);
206 return;
207 }
208
209 mAor = msg.header(h_To).uri().getAorAsUri(msg.getSource().getType());
210
211 // Checks to see whether this scheme is valid, and supported.
212 if (!((mAor.scheme()=="sip" || mAor.scheme()=="sips")
213 && mDum.getMasterProfile()->isSchemeSupported(mAor.scheme())))
214 {
215 DebugLog( << "Bad scheme in Aor" );
216
217 auto failure = std::make_shared<SipMessage>();
218 mDum.makeResponse(*failure, msg, 400);
219 failure->header(h_StatusLine).reason() = "Bad/unsupported scheme in To: " + mAor.scheme();
220 mDum.send(failure);
221 delete(this);
222 return;
223 }
224
225 if (handler->asyncProcessing())
226 {
227 mAsyncState = asyncStateWaitingForInitialContactList;
228 handler->asyncGetContacts(getHandle(),mAor);
230 return;
231 }
232
233 processRegistration(msg);
234}
235
236void
237ServerRegistration::processRegistration(const SipMessage& msg)
238{
239 ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler;
240 RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
241
242 enum {ADD, REMOVE, REFRESH} operation = REFRESH;
243
244 uint32_t globalExpires=3600;
245 uint32_t returnCode=0;
246 handler->getGlobalExpires(msg,mDum.getMasterProfile(),globalExpires,returnCode);
247
248 bool async = handler->asyncProcessing();
249
250 if (returnCode >= 400)
251 {
252 auto failure = std::make_shared<SipMessage>();
253 mDum.makeResponse(*failure, msg, returnCode);
254 if (423 == returnCode)
255 {
256 failure->header(h_StatusLine).reason() = "Interval Too Brief";
257 failure->header(h_MinExpires).value() = globalExpires;
258 }
259 mDum.send(failure);
260 delete(this);
261 return;
262 }
263
264 if (!async)
265 {
266 database->lockRecord(mAor);
267
268 mOriginalContacts = std::make_shared<ContactList>();
269 database->getContacts(mAor, *mOriginalContacts);
270 }
271
272 // If no contacts are present in the request, this is simply a query.
273 if (!msg.exists(h_Contacts))
274 {
275 if (async)
276 {
277 mAsyncState = asyncStateQueryOnly;
278 }
279 handler->onQuery(getHandle(), msg);
281 return;
282 }
283
284 ParserContainer<NameAddr> contactList(msg.header(h_Contacts));
285 ParserContainer<NameAddr>::iterator i(contactList.begin());
286 ParserContainer<NameAddr>::iterator iEnd(contactList.end());
288 uint32_t expires=0;
289
290 for (; i != iEnd; ++i)
291 {
292 if (!i->isWellFormed())
293 {
294 auto failure = std::make_shared<SipMessage>();
295 mDum.makeResponse(*failure, msg, 400, "Malformed Contact");
296 mDum.send(failure);
297 if (!async)
298 {
299 database->unlockRecord(mAor);
300 }
301 delete(this);
302 return;
303 }
304
305 expires = globalExpires;
306 handler->getContactExpires(*i, mDum.getMasterProfile(), expires, returnCode);
307
308 // Check for "Contact: *" style deregistration
309 if (i->isAllContacts())
310 {
311 if (contactList.size() > 1 || expires != 0)
312 {
313 auto failure = std::make_shared<SipMessage>();
314 mDum.makeResponse(*failure, msg, 400, "Invalid use of 'Contact: *'");
315 mDum.send(failure);
316 if (!async)
317 {
318 database->unlockRecord(mAor);
319 }
320 delete(this);
321 return;
322 }
323
324 if (!async)
325 {
326 database->removeAor(mAor);
327 }
328 else
329 {
330 mAsyncLocalStore->removeAllContacts();
331 mAsyncState = asyncStateWaitingForAcceptReject;
332 }
333
334 handler->onRemoveAll(getHandle(), msg);
336 return;
337 }
338
340 rec.mContact=*i;
341 rec.mRegExpires=(uint64_t)expires+now;
342
343 if(i->exists(p_Instance))
344 {
345 rec.mInstance=i->param(p_Instance);
346 }
347 if (msg.exists(h_UserAgent))
348 {
349 rec.mUserAgent = msg.header(h_UserAgent).value();
350 }
351 if(!msg.empty(h_Paths))
352 {
353 rec.mSipPath=msg.header(h_Paths);
354 }
355
356 rec.mLastUpdated=now;
357 rec.mReceivedFrom=msg.getSource();
359
360 bool hasFlow = tryFlow(rec,msg);
361
362 if(!testFlowRequirements(rec, msg, hasFlow))
363 {
364 // We have rejected the request. Bail.
365 if (!async)
366 {
367 database->unlockRecord(mAor);
368 }
369 delete(this);
370 return;
371 }
372
373 // Add ContactInstanceRecord to List
374 mRequestContacts.push_back(rec);
375
376 // Check to see if this is a removal.
377 if (expires == 0)
378 {
379 if (operation == REFRESH)
380 {
381 operation = REMOVE;
382 }
383
384 if (!async)
385 {
386 database->removeContact(mAor, rec);
387 }
388 else
389 {
390 mAsyncLocalStore->removeContact(rec);
391 }
392 }
393 else // Otherwise, it's an addition or refresh.
394 {
396 InfoLog(<< "Adding " << mAor << " -> " << *i);
397 DebugLog(<< "Contact has tuple " << rec.mReceivedFrom << " and detected public address " << rec.mPublicAddress);
398
399 if (!async)
400 {
401 status = database->updateContact(mAor, rec);
402 }
403 else
404 {
405 status = mAsyncLocalStore->updateContact(rec);
406 }
407
409 {
410 operation = ADD;
411 }
412 }
413 }
414
415 // The way this works is:
416 //
417 // - If no additions or removals are performed, this is a refresh
418 //
419 // - If at least one contact is removed and none are added, this
420 // is a removal.
421 //
422 // - If at least one contact is added, this is an addition, *even*
423 // *if* a contact was also removed.
424
425 //for async processing, need to wait for accept()/reject(). If accepted, the modifications made here will be
426 //sent to the user via asyncUpdateContacts(). The user then returns a final contact list, which is then processed
427 //and sent back in the 200.
428 if (async)
429 {
430 mAsyncState = asyncStateWaitingForAcceptReject;
431 }
432
433 switch (operation)
434 {
435 case REFRESH:
436 handler->onRefresh(getHandle(), msg);
438 return;
439
440 case REMOVE:
441 handler->onRemove(getHandle(), msg);
443 return;
444
445 case ADD:
446 handler->onAdd(getHandle(), msg);
448 return;
449
450 default:
451 resip_assert(0);
452 }
453}
454
455void
459
461ServerRegistration::dump(EncodeStream& strm) const
462{
463 strm << "ServerRegistration " << mAor;
464 return strm;
465}
466
467bool
468ServerRegistration::tryFlow(ContactInstanceRecord& rec,
469 const resip::SipMessage& msg)
470{
471 // .bwc. ie. Can we assure that the connection the client is using on the
472 // first hop can be re-used later?
473 try
474 {
475 // Outbound logic
477 {
478 resip::NameAddr& contact(rec.mContact);
479 if(contact.exists(p_Instance) && contact.exists(p_regid))
480 {
481 if(!msg.empty(h_Paths) && (msg.header(h_Paths).back().uri().exists(p_ob) ||
483 {
484 rec.mRegId=contact.param(p_regid);
485 // Edge-proxy is directly connected to the client, and ready to
486 // send traffic down the "connection" (TCP connection, or NAT
487 // pinhole, or what-have-you).
488 mDidOutbound=true;
489 return true;
490 }
491 else if(msg.header(h_Vias).size() == 1)
492 {
493 rec.mRegId=contact.param(p_regid);
494 // We are directly connected to the client.
495 // .bwc. In the outbound case, we should fail if the connection
496 // is gone. No recovery should be attempted by the server.
497 rec.mUseFlowRouting = true;
499 mDidOutbound=true;
500 return true;
501 }
502 }
503 }
504
505 // Record-Route flow token hack, or client NAT detect hack; use with caution
506 if(msg.header(h_Vias).size() == 1) // client is directly connected to this server
507 {
509 flowTokenNeededForTls(rec) ||
510 flowTokenNeededForSigcomp(rec) ||
513 {
514 rec.mUseFlowRouting = true;
516 return true;
517 }
518 }
519
521 {
522 rec.mUseFlowRouting = true;
524 return true;
525 }
526 }
527 catch(resip::ParseBuffer::Exception&)
528 {}
529 return false;
530}
531
532bool
533ServerRegistration::testFlowRequirements(ContactInstanceRecord &rec,
534 const resip::SipMessage& msg,
535 bool hasFlow) const
536{
537 const resip::NameAddr& contact(rec.mContact);
538
539 if(!msg.empty(h_Supporteds) &&
540 msg.header(h_Supporteds).find(Token(Symbols::Outbound)) &&
541 contact.exists(p_Instance) &&
542 contact.exists(p_regid))
543 {
544 // Client has explicitly requested Outbound processing, which requires us
545 // to have a flow.
546 if(!hasFlow)
547 {
548 auto failure = std::make_shared<SipMessage>();
549 mDum.makeResponse(*failure, msg, 439);
550 mDum.send(failure);
551 return false;
552 }
553 }
554
555 if(!hasFlow && flowTokenNeededForTls(rec))
556 {
557 auto failure = std::make_shared<SipMessage>();
558 mDum.makeResponse(*failure, msg, 400, "Trying to use TLS with an IP-address in your Contact header won't work if you don't have a flow. Consider implementing outbound, or putting an FQDN in your contact header.");
559 mDum.send(failure);
560 return false;
561 }
562
563 if(!hasFlow && flowTokenNeededForSigcomp(rec))
564 {
565 auto failure = std::make_shared<SipMessage>();
566 mDum.makeResponse(*failure, msg, 400, "Trying to use sigcomp on a connection-oriented protocol won't work if you don't have a flow. Consider implementing outbound, or using UDP/DTLS for this case.");
567 mDum.send(failure);
568 return false;
569 }
570
571 return true;
572}
573
574bool
575ServerRegistration::flowTokenNeededForTls(const ContactInstanceRecord &rec) const
576{
577 const resip::NameAddr& contact(rec.mContact);
578 if(DnsUtil::isIpAddress(contact.uri().host()))
579 {
580 // IP address in host-part.
581 if(contact.uri().scheme()=="sips")
582 {
583 // sips: and IP-address in contact. This will probably not work anyway.
584 return true;
585 }
586
587 if(contact.uri().exists(p_transport))
588 {
589 TransportType type = Tuple::toTransport(contact.uri().param(p_transport));
590 if(isSecure(type))
591 {
592 // secure transport and IP-address. Almost certainly won't work, but
593 // we'll try anyway.
594 return true;
595 }
596 }
597 }
598 return false;
599}
600
601bool
602ServerRegistration::flowTokenNeededForSigcomp(const ContactInstanceRecord &rec) const
603{
604 const resip::NameAddr& contact(rec.mContact);
605
606 if(contact.uri().exists(p_sigcompId))
607 {
608 if(contact.uri().exists(p_transport))
609 {
610 TransportType type = Tuple::toTransport(contact.uri().param(p_transport));
611 if(type == TLS || type == TCP)
612 {
613 // Client is using sigcomp on the first hop using a connection-
614 // oriented transport. For this to work, that connection has to be
615 // reused for all traffic.
616 return true;
617 }
618 }
619 else
620 {
621 // ?bwc? Client is using sigcomp, but we're not sure whether this is
622 // over a connection-oriented transport or not.
623 DebugLog(<< "Client is using sigcomp, but we're not sure whether this "
624 "is over a connection-oriented transport or not, because "
625 "the contact doesn't have a transport param in it. It is "
626 "possible this will work though, so we'll let it proceed."
627 );
628 }
629 }
630 return false;
631}
632
633
634void
635ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &contacts)
636{
637 if (!contacts.empty())
638 {
639 std::unique_ptr<ContactPtrList> expired;
640
642
643 for (const auto& rec : contacts)
644 {
645 if (!rec)
646 {
647 resip_assert(0);
648 continue;
649 }
650
651 if (rec->mRegExpires <= now)
652 {
653 if (!expired)
654 {
655 expired = std::unique_ptr<ContactPtrList>(new ContactPtrList());
656 }
657 expired->push_back(rec);
658 continue;
659 }
660
661 rec->mContact.param(p_expires) = uint32_t(rec->mRegExpires - now);
662 msg.header(h_Contacts).push_back(rec->mContact);
663 }
664
665 if (expired.get() && !expired->empty())
666 {
667 mDum.mServerRegistrationHandler->asyncRemoveExpired(getHandle(), mAor, std::move(expired));
669 return;
670 }
671 }
672}
673
674void
675ServerRegistration::processFinalOkMsg(SipMessage &msg, ContactList &contacts)
676{
677 //build the 200Ok and remove any expired entries.
678 //the non-asynchronous behavior is to call the database directly, the async behavior is to build a
679 //list of all expired entries and send it to the handler.
680 if (!contacts.empty())
681 {
682 RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
684
685 for (auto& rec : contacts)
686 {
687 if (rec.mRegExpires <= now)
688 {
689 database->removeContact(mAor, rec);
690 continue;
691 }
692 rec.mContact.param(p_expires) = uint32_t(rec.mRegExpires - now);
693 msg.header(h_Contacts).push_back(rec.mContact);
694 }
695 }
696}
697
698bool
699ServerRegistration::asyncProvideContacts(std::unique_ptr<resip::ContactPtrList> contacts)
700{
701 switch (mAsyncState)
702 {
703 case asyncStateWaitingForInitialContactList:
704 {
705 resip_assert(mAsyncLocalStore.get() == 0);
706 mAsyncLocalStore = std::make_shared<AsyncLocalStore>(std::move(contacts));
707 mAsyncState = asyncStateProcessingRegistration;
708 processRegistration(mRequest);
709 break;
710 }
711 case asyncStateWaitingForAcceptReject:
712 {
713 resip_assert(0); //need to call accept() or reject(), wait for asyncUpdateContacts(), then call this function.
714 return false;
715 }
716 case asyncStateAcceptedWaitingForFinalContactList:
717 {
718 mAsyncState = asyncStateProvidedFinalContacts;
719 asyncProcessFinalContacts(std::move(contacts));
720 break;
721 }
722 default:
723 {
724 resip_assert(0);
725 return false;
726 }
727 }
728
729 return true;
730}
731
732void
733ServerRegistration::asyncProcessFinalContacts(std::unique_ptr<resip::ContactPtrList> contacts)
734{
735 if (contacts)
736 {
737 if (!mAsyncOkMsg)
738 {
739 resip_assert(0);
740 }
741 else
742 {
743 asyncProcessFinalOkMsg(*mAsyncOkMsg,*contacts);
744 }
745 }
746
747 mAsyncState = asyncStateNone;
748 mDum.send(mAsyncOkMsg);
749 mAsyncOkMsg.reset();
750 delete(this);
751}
752
753void
754ServerRegistration::AsyncLocalStore::create(std::unique_ptr<ContactPtrList> originalContacts)
755{
756 mModifiedContacts = std::move(originalContacts);
757 mLog = std::unique_ptr<ContactRecordTransactionLog>(new ContactRecordTransactionLog());
758}
759
760void
761ServerRegistration::AsyncLocalStore::destroy(void)
762{
763 mModifiedContacts.reset();
764 mLog.reset();
765}
766
768ServerRegistration::AsyncLocalStore::updateContact(const ContactInstanceRecord &rec)
769{
770 if (!mModifiedContacts || !mLog)
771 {
772 resip_assert(0);
774 }
775
776 // See if the contact is already present. We use URI matching rules here.
777 for (auto& modifiedContact : *mModifiedContacts)
778 {
779 if (modifiedContact && *modifiedContact == rec)
780 {
781 *modifiedContact = rec;
782
783 mLog->emplace_back(std::make_shared<ContactRecordTransaction>(ContactRecordTransaction::update, modifiedContact));
784
786 }
787 }
788
789 // This is a new contact, so we add it to the list.
790 auto newRec = std::make_shared<ContactInstanceRecord>(rec);
791
792 mLog->emplace_back(std::make_shared<ContactRecordTransaction>(ContactRecordTransaction::create, newRec));
793
794 mModifiedContacts->push_back(newRec);
795
797}
798
799void
800ServerRegistration::AsyncLocalStore::removeContact(const ContactInstanceRecord &rec)
801{
802 if (!mModifiedContacts || !mLog)
803 {
804 resip_assert(0);
805 return;
806 }
807
808 // See if the contact is present. We use URI matching rules here.
809 for (auto it = std::begin(*mModifiedContacts); it != std::end(*mModifiedContacts); ++it)
810 {
811 if ((*it) && **it == rec)
812 {
813 mLog->emplace_back(std::make_shared<ContactRecordTransaction>(ContactRecordTransaction::remove, *it));
814
815 mModifiedContacts->erase(it);
816 return;
817 }
818 }
819}
820
821void
822ServerRegistration::AsyncLocalStore::removeAllContacts()
823{
824 if (!mModifiedContacts || !mLog)
825 {
826 return;
827 }
828
829 mLog->emplace_back(std::make_shared<ContactRecordTransaction>(ContactRecordTransaction::removeAll, nullptr));
830
831 mModifiedContacts->clear();
832}
833
834
835/* ====================================================================
836 * The Vovida Software License, Version 1.0
837 *
838 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
839 *
840 * Redistribution and use in source and binary forms, with or without
841 * modification, are permitted provided that the following conditions
842 * are met:
843 *
844 * 1. Redistributions of source code must retain the above copyright
845 * notice, this list of conditions and the following disclaimer.
846 *
847 * 2. Redistributions in binary form must reproduce the above copyright
848 * notice, this list of conditions and the following disclaimer in
849 * the documentation and/or other materials provided with the
850
851 * distribution.
852 *
853 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
854 * and "Vovida Open Communication Application Library (VOCAL)" must
855 * not be used to endorse or promote products derived from this
856 * software without prior written permission. For written
857 * permission, please contact vocal@vovida.org.
858 *
859 * 4. Products derived from this software may not be called "VOCAL", nor
860 * may "VOCAL" appear in their name, without prior written
861 * permission of Vovida Networks, Inc.
862 *
863 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
864 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
865 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
866 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
867 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
868 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
869 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
870 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
871 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
872 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
873 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
874 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
875 * DAMAGE.
876 *
877 * ====================================================================
878 *
879 * This software consists of voluntary contributions made by Vovida
880 * Networks, Inc. and many individuals on behalf of Vovida Networks,
881 * Inc. For more information on Vovida Networks, Inc., please see
882 * <http://www.vovida.org/>.
883 *
884 */
bool expired(const ContactInstanceRecord &rec)
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define resip_assert(x)
This file needs to work for both C and C++ code.
static Token outbound(Symbols::Outbound)
BaseUsageHandle getBaseHandle() const
Definition BaseUsage.cxx:36
DialogUsageManager & mDum
Definition BaseUsage.hxx:43
A single contact record, bound to an Aor during registration.
void send(std::shared_ptr< SipMessage > request)
std::shared_ptr< MasterProfile > & getMasterProfile()
static bool isIpAddress(const Data &ipAddress)
Definition DnsUtil.cxx:453
static bool isClientBehindNAT(const SipMessage &request, bool privateToPublicOnly=true)
Looks at SIP headers and message source for a mismatch to make an assumption that the sender is behin...
Definition Helper.cxx:2357
static Tuple getClientPublicAddress(const SipMessage &request)
Look at Via headers, and find the first public IP address closest to the sending client.
Definition Helper.cxx:2400
static bool getRRTokenHackEnabled()
static unsigned int getFlowTimerSeconds()
static bool getAssumeFirstHopSupportsOutboundEnabled()
static bool getOutboundSupported()
static InteropHelper::ClientNATDetectionMode getClientNATDetectionMode()
static bool getAssumeFirstHopSupportsFlowTokensEnabled()
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
const Data & param(const ExtensionParameter &param) const
Const accessor for non-natively-supported parameter types.
An iterator class (bidirectional)
Container class for ParserCategory, used by SipMessage to represent multi-valued headers (Contact,...
Abstract interface of a datastore of all registered endpoints processed by DUM.
virtual void unlockRecord(const Uri &aor)=0
virtual void lockRecord(const Uri &aor)=0
virtual update_status_t updateContact(const Uri &aor, const ContactInstanceRecord &rec)=0
virtual void removeContact(const Uri &aor, const ContactInstanceRecord &rec)=0
virtual void removeAor(const Uri &aor)=0
virtual void addAor(const Uri &aor, const ContactList &contacts)=0
virtual void getContacts(const Uri &aor, ContactList &container)=0
const Uri & uri() const
virtual void asyncGetContacts(ServerRegistrationHandle, const Uri &aor)
Called when a REGISTER is first received to retrieve the current list.
virtual void onRefresh(ServerRegistrationHandle, const SipMessage &reg)=0
Called when registration is refreshed.
virtual void onRemoveAll(ServerRegistrationHandle, const SipMessage &reg)=0
Called when all the contacts are removed using "Contact: *".
virtual void asyncUpdateContacts(ServerRegistrationHandle, const Uri &aor, std::unique_ptr< ContactPtrList > modifiedContactList, std::unique_ptr< ContactRecordTransactionLog > transactionLog)
Notifies the handler to update the current contact list for the AOR to the specified list that has be...
virtual void onAdd(ServerRegistrationHandle, const SipMessage &reg)=0
Called when one or more contacts are added.
virtual void onQuery(ServerRegistrationHandle, const SipMessage &reg)=0
Called when a client queries for the list of current registrations.
virtual void getContactExpires(const NameAddr &contact, const std::shared_ptr< MasterProfile > &masterProfile, uint32_t &expires, uint32_t &returnCode)
When processing a REGISTER request, return the desired expires value by processing this contact's exp...
virtual void asyncRemoveExpired(ServerRegistrationHandle, const resip::Uri &aor, std::unique_ptr< resip::ContactPtrList > contacts)
Notifies the handler to remove the entries specified in the contacts parameter.
virtual void onRemove(ServerRegistrationHandle, const SipMessage &reg)=0
called when one or more specified contacts is removed
virtual void getGlobalExpires(const SipMessage &msg, const std::shared_ptr< MasterProfile > &masterProfile, uint32_t &expires, uint32_t &returnCode)
When processing a REGISTER request, return the desired expires value when processing the "Expires" he...
virtual bool asyncProcessing(void) const
If true, the registration processing will use the async* functions here and will not use the Registra...
ServerRegistrationHandle getHandle()
void reject(SipMessage &failure)
Reject a SIP registration with a specific response.
EncodeStream & dump(EncodeStream &strm) const override
void accept(SipMessage &ok)
Accept a SIP registration with a specific response.
bool asyncProvideContacts(std::unique_ptr< resip::ContactPtrList > contacts)
Used when useAsyncProcessing() is true.
void dispatch(const SipMessage &msg) override
Represents a SIP message.
bool isRequest() const
Returns true if message is a request, false otherwise.
bool empty(const HeaderBase &headerType) const
Returns true if the header field is present and non-empty, false otherwise.
const RequestLine & header(const RequestLineType &l) const
Returns the RequestLine. This is only valid for request messages.
bool isResponse() const
Returns true if message is a response, false otherwise.
bool exists(const HeaderBase &headerType) const
Returns true if the given header field is present, false otherwise.
const Tuple & getSource() const
Returns the source tuple that the message was received from only makes sense for messages received fr...
void remove(const HeaderBase &headerType)
Prevents a header field from being present when the message is prepared for sending to a transport.
virtual Message * clone() const
void enableFlowTimer(const resip::Tuple &flow)
static const char * Path
Definition Symbols.hxx:113
static const char * Outbound
Definition Symbols.hxx:114
static uint64_t getTimeSecs()
Returns the current clock time in seconds.
Definition Timer.hxx:78
Represents the "token" element in the RFC 3261 grammar.
Definition Token.hxx:18
bool onlyUseExistingConnection
Definition Tuple.hxx:192
TransportType getType() const
Definition Tuple.hxx:122
static TransportType toTransport(const Data &)
Converts a string representation of transport type, i.e.
Definition Tuple.cxx:921
Data & scheme()
Definition Uri.hxx:143
bool exists(const Param< Uri > &paramType) const
Definition Uri.cxx:1701
Uri getAorAsUri(TransportType transportTypeToRemoveDefaultPort=UNKNOWN_TRANSPORT) const
Definition Uri.cxx:1103
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
Definition Headers.cxx:348
std::deque< std::shared_ptr< ContactRecordTransaction > > ContactRecordTransactionLog
Contains a collection of database operations that were performed during REGISTER processing.
bool isSecure(TransportType type)
Returns true if passed in transport type is a secure transport protocol.
std::list< std::shared_ptr< ContactInstanceRecord > > ContactPtrList
Used to reduce copying ContactInstanceRecord objects when processing registration.
unsigned long long uint64_t
Definition Stun.hxx:39
unsigned int uint32_t
Definition Stun.hxx:34
TransportType
An enumeration of transport protocols.
Handle< ServerRegistration > ServerRegistrationHandle
Definition Handles.hxx:41
std::list< ContactInstanceRecord > ContactList
#define EncodeStream
unsigned int uint32_t
Definition stdint.h:85
unsigned __int64 uint64_t
Definition stdint.h:95