reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ClientSubscription.cxx
Go to the documentation of this file.
1#include <queue>
2
4#include "rutil/Logger.hxx"
13
15
16using namespace resip;
17
18#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
19
20
22 : BaseSubscription(dum, dialog, request),
23 mOnNewSubscriptionCalled(mEventType == "refer"), // don't call onNewSubscription for Refer subscriptions
24 mEnded(false),
25 mNextRefreshSecs(0),
26 mLastSubSecs(Timer::getTimeSecs()), // Not exactly, but more forgiving
27 mSubscribed(false),
28 mRefreshing(false),
29 mHaveQueuedRefresh(false),
30 mQueuedRefreshInterval(-1),
31 mLargestNotifyCSeq(0)
32{
33 DebugLog (<< "ClientSubscription::ClientSubscription from " << request.brief() << ": " << this);
34 if(request.method() == SUBSCRIBE)
35 {
36 *mLastRequest = request;
37 }
38 else
39 {
40 // If a NOTIFY request is use to make this ClientSubscription, then create the implied SUBSCRIBE
41 // request as the mLastRequest
42 mDialog.makeRequest(*mLastRequest, SUBSCRIBE);
43 }
44}
45
47{
48 mDialog.mClientSubscriptions.remove(this);
49
50 while (!mQueuedNotifies.empty())
51 {
52 delete mQueuedNotifies.front();
53 mQueuedNotifies.pop_front();
54 }
55
56 clearDustbin();
57 DebugLog(<< "ClientSubscription::~ClientSubscription: " << this);
58}
59
65
66void
67ClientSubscription::dispatch(const SipMessage& msg)
68{
69 DebugLog (<< "ClientSubscription::dispatch " << msg.brief());
70
72 resip_assert(handler);
73
74 clearDustbin();
75
76 // asserts are checks the correctness of Dialog::dispatch
77 if (msg.isRequest() )
78 {
79 resip_assert( msg.header(h_RequestLine).getMethod() == NOTIFY );
80 mRefreshing = false;
81 mSubscribed = true; // If we got a NOTIFY then we are subscribed
82
83 // !dlb! 481 NOTIFY iff state is dead?
84
86 //mLastNotify = msg;
87
89 // when, for example, the UAS sends a 408 back and
90 // ClientSubscriptionHandler::onRequestRetry returns 0. A fix was
91 // attempted in revision 10128 but it created a more important
92 // regression. See
93 // http://list.resiprocate.org/archive/resiprocate-devel/thrd83.html#08362
94 // for more details.
95 if (!mOnNewSubscriptionCalled && !getAppDialogSet()->isReUsed())
96 {
97 mOnNewSubscriptionCalled = true;
98 InfoLog(<< "[ClientSubscription] " << mLastRequest->header(h_To));
99 handler->onNewSubscription(getHandle(), msg);
100 if (mEnded) return;
101 }
102
103 bool outOfOrder = mLargestNotifyCSeq > msg.header(h_CSeq).sequence();
104 if (!outOfOrder)
105 {
106 mLargestNotifyCSeq = msg.header(h_CSeq).sequence();
107 // If not out of order, then allow NOTIFY to do a target refresh - RFC6665
108 if (msg.exists(h_Contacts))
109 {
110 mDialog.mRemoteTarget = msg.header(h_Contacts).front();
111 }
112 }
113 else
114 {
115 DebugLog(<< "received out of order notify");
116 }
117
118 mQueuedNotifies.push_back(new QueuedNotify(msg, outOfOrder));
119 if (mQueuedNotifies.size() == 1)
120 {
121 DebugLog(<< "no queued notify");
122 processNextNotify();
123 return;
124 }
125 else
126 {
127 DebugLog(<< "Notify gets queued");
128 }
129 }
130 else
131 {
132 DebugLog(<< "processing client subscription response");
133 processResponse(msg);
134 }
135}
136
137void
138ClientSubscription::processResponse(const SipMessage& msg)
139{
141 resip_assert(handler);
142
143 mRefreshing = false;
144 int statusCode = msg.header(h_StatusLine).statusCode();
145
146 if (statusCode >= 200 && statusCode <300)
147 {
148 mSubscribed = true; // If we got a 200 response then we are subscribed
149 if (msg.exists(h_Expires))
150 {
151 // grab the expires from the 2xx in case there is not one on the NOTIFY .mjf.
152 uint32_t expires = msg.header(h_Expires).value();
153 uint32_t lastExpires = mLastRequest->header(h_Expires).value();
154 if (expires < lastExpires)
155 {
156 mLastRequest->header(h_Expires).value() = expires;
157 }
158 }
159
160 if(!mOnNewSubscriptionCalled)
161 {
162 mOnNewSubscriptionCalled = true;
163 handler->onNewSubscription(getHandle(), msg);
164 if (!mEnded)
165 {
166 // Timer for initial NOTIFY; since we don't know when the initial
167 // SUBSCRIBE is sent, we have to set the timer when the 200 comes in, if
168 // it beats the NOTIFY.
170 64 * Timer::T1,
172 ++mTimerSeq);
173 }
174 }
175 else if (!mEnded)
176 {
177 sendQueuedRefreshRequest();
178 }
179 }
180 else if (!mEnded &&
181 statusCode == 481 &&
182 msg.header(h_To).exists(p_tag) && // Only do this if we were re-subscribing
183 msg.exists(h_Expires) && msg.header(h_Expires).value() > 0)
184 {
185 InfoLog (<< "Received 481 to SUBSCRIBE, reSUBSCRIBEing (subscription server probably restarted) "
186 << mLastRequest->header(h_To));
187
188 reSubscribe(); // will delete "this"
189 return;
190 }
191 else if (!mEnded &&
192 (statusCode == 408 ||
193 (statusCode == 503 && !msg.isFromWire()) ||
194 ((statusCode == 413 ||
195 statusCode == 480 ||
196 statusCode == 486 ||
197 statusCode == 500 ||
198 statusCode == 503 ||
199 statusCode == 600 ||
200 statusCode == 603) &&
201 msg.exists(h_RetryAfter))))
202 {
203 int retry;
204 int retryAfter = 0;
205 if(msg.exists(h_RetryAfter))
206 {
207 retryAfter = msg.header(h_RetryAfter).value();
208 }
209
210 InfoLog (<< "Received " << statusCode << " to SUBSCRIBE "
211 << mLastRequest->header(h_To));
212 retry = handler->onRequestRetry(getHandle(), retryAfter, msg);
213
214 if (retry < 0)
215 {
216 DebugLog(<< "Application requested failure on Retry-After");
217 mEnded = true;
218 handler->onTerminated(getHandle(), &msg);
219 delete this;
220 return;
221 }
222 else if (retry == 0)
223 {
224 DebugLog(<< "Application requested immediate retry on Retry-After");
225
226 if (mOnNewSubscriptionCalled)
227 {
228 // If we already have a dialog, then just refresh again
230 }
231 else
232 {
233 reSubscribe(); // will delete "this"
234 return;
235 }
236 }
237 else
238 {
239 // leave the usage around until the timeout
240 // !dlb! would be nice to set the state to something dead, but not used
242 retry,
244 ++mTimerSeq);
245 // leave the usage around until the timeout
246 return;
247 }
248 }
249 else if (msg.header(h_StatusLine).statusCode() >= 300)
250 {
251 if (msg.header(h_StatusLine).statusCode() == 423
252 && msg.exists(h_MinExpires))
253 {
254 requestRefresh(msg.header(h_MinExpires).value());
255 }
256 else
257 {
258 mEnded = true;
259 handler->onTerminated(getHandle(), &msg);
260 delete this;
261 return;
262 }
263 }
264}
265
266void
267ClientSubscription::processNextNotify()
268{
272 //assert(!mQueuedNotifies.empty());
273 if (mQueuedNotifies.empty())
274 {
275 return;
276 }
277
278 QueuedNotify* qn = mQueuedNotifies.front();
280 resip_assert(handler);
281
282 unsigned long refreshInterval = 0;
283 bool setRefreshTimer=false;
284 if (!qn->outOfOrder())
285 {
286 uint32_t expires = 0;
287 //default to 3600 seconds so non-compliant endpoints don't result in leaked usages
288 if (qn->notify().exists(h_SubscriptionState) && qn->notify().header(h_SubscriptionState).exists(p_expires))
289 {
290 expires = qn->notify().header(h_SubscriptionState).param(p_expires);
291 }
292 else if (mLastRequest->exists(h_Expires))
293 {
294 expires = mLastRequest->header(h_Expires).value();
295 }
296 else
297 {
298 /* if we haven't gotten an expires value from:
299 1. the subscription state from this notify
300 2. the last request (may have came from the 2xx in response)
301 then use some reasonable value.
302 */
303 expires = 3600;
304 }
305
306 if (!mLastRequest->exists(h_Expires))
307 {
308 DebugLog(<< "No expires header in last request, set to " << expires);
309 mLastRequest->header(h_Expires).value() = expires;
310 }
311
312 if(!qn->notify().exists(h_SubscriptionState) ||
313 !isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Terminated))
314 {
315 // Don't do this stuff for a NOTIFY terminated.
317 refreshInterval = Helper::aBitSmallerThan((signed long)expires);
318
319 if (mNextRefreshSecs == 0 || now + refreshInterval < mNextRefreshSecs)
320 {
321 mNextRefreshSecs = now + refreshInterval;
322 setRefreshTimer = true;
323 }
324 }
325 }
326 //if no subscription state header, treat as an extension. Only allow for
327 //refer to handle non-compliant implementations
328 if (!qn->notify().exists(h_SubscriptionState))
329 {
330 if (qn->notify().exists(h_Event) && qn->notify().header(h_Event).value() == "refer")
331 {
332 SipFrag* frag = dynamic_cast<SipFrag*>(qn->notify().getContents());
333 if (frag)
334 {
335 if (frag->message().isResponse())
336 {
337 int code = frag->message().header(h_StatusLine).statusCode();
338 if (code < 200)
339 {
340 handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder());
341 }
342 else
343 {
344 acceptUpdate();
345 mEnded = true;
346 handler->onTerminated(getHandle(), &qn->notify());
347 delete this;
348 }
349 }
350 else
351 {
352 acceptUpdate();
353 mEnded = true;
354 handler->onTerminated(getHandle(), &qn->notify());
355 delete this;
356 }
357 }
358 else
359 {
360 acceptUpdate();
361 mEnded = true;
362 handler->onTerminated(getHandle(), &qn->notify());
363 delete this;
364 }
365 }
366 else
367 {
368 mDialog.makeResponse(*mLastResponse, qn->notify(), 400);
369 mLastResponse->header(h_StatusLine).reason() = "Missing Subscription-State header";
371 mEnded = true;
372 handler->onTerminated(getHandle(), &qn->notify());
373 delete this;
374 }
375 return;
376 }
377
378 if (!mEnded && isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Active))
379 {
380 if (setRefreshTimer)
381 {
382 scheduleRefresh(refreshInterval);
383 }
384
385 handler->onUpdateActive(getHandle(), qn->notify(), qn->outOfOrder());
386 }
387 else if (!mEnded && isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Pending))
388 {
389 if (setRefreshTimer)
390 {
391 scheduleRefresh(refreshInterval);
392 }
393
394 handler->onUpdatePending(getHandle(), qn->notify(), qn->outOfOrder());
395 }
396 else if (isEqualNoCase(qn->notify().header(h_SubscriptionState).value(), Symbols::Terminated))
397 {
398 if (mLastRequest->header(h_Expires).value() != 0 &&
399 isEqualNoCase(qn->notify().header(h_SubscriptionState).param(p_reason), "timeout"))
400 {
401 // Unexpected timeout of some sort. Look closer.
402 if(mNextRefreshSecs==0)
403 {
404 // No refresh scheduled; maybe we are trying to avoid a tight SUB/
405 // NOT loop here?
406 if(Helper::aBitSmallerThan((signed long)(Timer::getTimeSecs() - mLastSubSecs)) < 2)
407 {
408 acceptUpdate(200, "I just sent a refresh, what more do you want from me?");
409 }
410 else
411 {
412 acceptUpdate(200, "Why didn't I refresh here?");
413 }
414 }
415 else
416 {
417 acceptUpdate(200, "You terminated my subscription early! What gives?");
418 }
419 }
420 else
421 {
422 acceptUpdate();
423 }
424 mEnded = true;
425 handler->onTerminated(getHandle(), &qn->notify());
426 DebugLog (<< "[ClientSubscription] " << mLastRequest->header(h_To) << "[ClientSubscription] Terminated");
427 delete this;
428 return;
429 }
430 else if (!mEnded)
431 {
432 if (setRefreshTimer)
433 {
434 scheduleRefresh(refreshInterval);
435 }
436
437 handler->onUpdateExtension(getHandle(), qn->notify(), qn->outOfOrder());
438 }
439 else if (mEnded)
440 {
441 // We received a NOTIFY message when we thought the subscription was
442 // ended. This can happen, for example, when a previously sent NOTIFY gets
443 // resent while we (ClientSubscription) are trying to terminate the
444 // subscription. If we don't accept/reject this NOTIFY, it will stay into
445 // the mQueuedNotifies queue and we'll never terminate the subscription
446 // even if the server sends a NOTIFY/terminated. All received NOTIFY would
447 // get piled up on mQueuedNotifies and they will never get processed.
448 //
449 // Note that if that NOTIFY is in fact the terminated one, it will get
450 // caught by another if statement above and acted upon appropriately.
451 //
453 InfoLog(<< "[ClientSubscription] received NOTIFY when subscription was ended, rejecting it...");
454 rejectUpdate(481);
455 }
456}
457
458void
459ClientSubscription::dispatch(const DumTimeout& timer)
460{
461 if (timer.seq() == mTimerSeq)
462 {
463 if(timer.type() == DumTimeout::WaitForNotify)
464 {
466 if (mEnded)
467 {
468 InfoLog(<< "ClientSubscription: received NOTIFY timeout when trying to end, terminating...");
469 if (handler)
470 {
471 // NOTIFY terminated didn't come in
472 handler->onTerminated(getHandle(), 0);
473 }
474 delete this;
475 return;
476 }
477
478 if (handler)
479 {
480 // Initial NOTIFY never came in; let app decide what to do
481 handler->onNotifyNotReceived(getHandle());
482 }
483 }
484 else if (timer.type() == DumTimeout::SubscriptionRetry)
485 {
486 // Ensure someone hasn't called end() while we were waiting
487 if (!mEnded)
488 {
489 // this indicates that the ClientSubscription was created by a 408
490 if (mOnNewSubscriptionCalled)
491 {
492 InfoLog(<< "ClientSubscription: application retry refresh");
494 }
495 else
496 {
497 InfoLog(<< "ClientSubscription: application retry new request");
498 reSubscribe(); // will delete "this"
499 return;
500 }
501 }
502 }
503 else if(timer.type() == DumTimeout::Subscription)
504 {
506 }
507 }
508 else if(timer.seq() == 0 && timer.type() == DumTimeout::SendNextNotify)
509 {
510 DebugLog(<< "got DumTimeout::SendNextNotify");
511 processNextNotify();
512 }
513}
514
515void
517{
518 if (!mEnded)
519 {
520 if (mRefreshing)
521 {
522 DebugLog(<< "queue up refresh request");
523 mHaveQueuedRefresh = true;
524 mQueuedRefreshInterval = expires;
525 return;
526 }
527
528 mDialog.makeRequest(*mLastRequest, SUBSCRIBE);
530 //the map that stores the handlers, or part of the handler API
531 if(expires > 0)
532 {
533 mLastRequest->header(h_Expires).value() = expires;
534 }
535 mNextRefreshSecs = 0;
536 InfoLog (<< "Refresh subscription: " << mLastRequest->header(h_Contacts).front());
537 mRefreshing = true;
538 mLastSubSecs = Timer::getTimeSecs();
540 // Timer for reSUB NOTIFY.
542 64*Timer::T1,
544 ++mTimerSeq);
545 }
546}
547
549{
550public:
552 : mClientSubscriptionHandle(clientSubscriptionHandle),
553 mExpires(expires)
554 {
555
556 }
557
558 void executeCommand() override
559 {
560 if(mClientSubscriptionHandle.isValid())
561 {
562 mClientSubscriptionHandle->requestRefresh(mExpires);
563 }
564 }
565
566 EncodeStream& encodeBrief(EncodeStream& strm) const override
567 {
568 return strm << "ClientSubscriptionRefreshCommand";
569 }
570private:
571 ClientSubscriptionHandle mClientSubscriptionHandle;
572 uint32_t mExpires;
573};
574
575void
580
581void
583{
584 end(false /* immediate? */);
585}
586
587void
589{
590 if (!mEnded)
591 {
592 if(!immediate && mSubscribed)
593 {
594 InfoLog(<< "End subscription: " << mLastRequest->header(h_RequestLine).uri());
595 mDialog.makeRequest(*mLastRequest, SUBSCRIBE);
596 mLastRequest->header(h_Expires).value() = 0;
597 mEnded = true;
599 // Timer for NOTIFY terminated
601 64*Timer::T1,
603 ++mTimerSeq);
604 }
605 else
606 {
607 InfoLog(<< "End subscription immediately: " << mLastRequest->header(h_RequestLine).uri());
608 delete this;
609 return;
610 }
611 }
612 else
613 {
614 InfoLog(<< "End subscription called but already ended: " << mLastRequest->header(h_RequestLine).uri());
615 }
616}
617
619{
620public:
621 ClientSubscriptionEndCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, bool immediate)
622 :mClientSubscriptionHandle(clientSubscriptionHandle), mImmediate(immediate)
623 {
624
625 }
626
627 void executeCommand() override
628 {
629 if(mClientSubscriptionHandle.isValid())
630 {
631 mClientSubscriptionHandle->end(mImmediate);
632 }
633 }
634
635 EncodeStream& encodeBrief(EncodeStream& strm) const override
636 {
637 return strm << "ClientSubscriptionEndCommand";
638 }
639private:
640 ClientSubscriptionHandle mClientSubscriptionHandle;
641 bool mImmediate;
642};
643
644void
646{
648}
649
650void
651ClientSubscription::acceptUpdate(int statusCode, const char* reason)
652{
653 resip_assert(!mQueuedNotifies.empty());
654 if (mQueuedNotifies.empty())
655 {
656 InfoLog(<< "No queued notify to accept");
657 return;
658 }
659
660 QueuedNotify* qn = mQueuedNotifies.front();
661 mQueuedNotifies.pop_front();
662 mDustbin.push_back(qn);
663 mDialog.makeResponse(*mLastResponse, qn->notify(), statusCode);
664 if(reason)
665 {
666 mLastResponse->header(h_StatusLine).reason()=reason;
667 }
669}
670
672{
673public:
674 ClientSubscriptionAcceptUpdateCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, int statusCode, const char* reason)
675 : mClientSubscriptionHandle(clientSubscriptionHandle),
676 mStatusCode(statusCode),
677 mReason(reason ? Data(reason) : Data::Empty)
678 {
679
680 }
681
682 void executeCommand() override
683 {
684 if(mClientSubscriptionHandle.isValid())
685 {
686 mClientSubscriptionHandle->acceptUpdate(mStatusCode, mReason.c_str());
687 }
688 }
689
690 EncodeStream& encodeBrief(EncodeStream& strm) const override
691 {
692 return strm << "ClientSubscriptionAcceptUpdateCommand";
693 }
694private:
695 ClientSubscriptionHandle mClientSubscriptionHandle;
696 int mStatusCode;
697 Data mReason;
698};
699
700void
701ClientSubscription::acceptUpdateCommand(int statusCode, const char* reason)
702{
703 mDum.post(new ClientSubscriptionAcceptUpdateCommand(getHandle(), statusCode, reason));
704}
705
706void
708{
709 NameAddr target(mLastRequest->header(h_To));
710 target.remove(p_tag); // ensure To tag is removed
711 auto sub = mDum.makeSubscription(target, getUserProfile(), getEventType(), getAppDialogSet()->reuse());
712 mDum.send(sub);
713
714 delete this;
715}
716
717void
718ClientSubscription::send(std::shared_ptr<SipMessage> msg)
719{
721
722 if (!mEnded)
723 {
724 if (!mQueuedNotifies.empty() && msg->isResponse())
725 {
727 0,
729 0);
730 }
731 }
732
733}
734
735void
736ClientSubscription::rejectUpdate(int statusCode, const Data& reasonPhrase)
737{
739 resip_assert(handler);
740 resip_assert(!mQueuedNotifies.empty());
741 if (mQueuedNotifies.empty())
742 {
743 InfoLog(<< "No queued notify to reject");
744 return;
745 }
746
747 QueuedNotify* qn = mQueuedNotifies.front();
748 mQueuedNotifies.pop_front();
749 mDustbin.push_back(qn);
750
751 mDialog.makeResponse(*mLastResponse, qn->notify(), statusCode);
752 if (!reasonPhrase.empty())
753 {
754 mLastResponse->header(h_StatusLine).reason() = reasonPhrase;
755 }
756
759 {
762 break;
765 throw UsageUseException("Not a reasonable code to reject a NOTIFY with inside an established dialog.",
766 __FILE__, __LINE__);
767 break;
768 case Helper::DialogTermination: //?dcm? -- throw or destroy this?
770 // If we are already "ended" then we are likely here because we are rejecting an inbound
771 // NOTIFY with a 481 that crossed with our un-subscribe request (due to end()). In this case we don't
772 // want to call onTerminated or delete this - we wait for end() request to run it's course.
773 if (!mEnded)
774 {
775 mEnded = true;
776 handler->onTerminated(getHandle(), mLastResponse.get());
777 delete this;
778 }
779 break;
780 }
781}
782
784{
785public:
786 ClientSubscriptionRejectUpdateCommand(const ClientSubscriptionHandle& clientSubscriptionHandle, int statusCode, const Data& reasonPhrase)
787 : mClientSubscriptionHandle(clientSubscriptionHandle),
788 mStatusCode(statusCode),
789 mReasonPhrase(reasonPhrase)
790 {
791 }
792
793 void executeCommand() override
794 {
795 if(mClientSubscriptionHandle.isValid())
796 {
797 mClientSubscriptionHandle->rejectUpdate(mStatusCode, mReasonPhrase);
798 }
799 }
800
801 EncodeStream& encodeBrief(EncodeStream& strm) const override
802 {
803 return strm << "ClientSubscriptionRejectUpdateCommand";
804 }
805private:
806 ClientSubscriptionHandle mClientSubscriptionHandle;
807 int mStatusCode;
808 Data mReasonPhrase;
809};
810
811void
812ClientSubscription::rejectUpdateCommand(int statusCode, const Data& reasonPhrase)
813{
814 mDum.post(new ClientSubscriptionRejectUpdateCommand(getHandle(), statusCode, reasonPhrase));
815}
816
818ClientSubscription::dump(EncodeStream& strm) const
819{
820 strm << "ClientSubscription " << mLastRequest->header(h_From).uri();
821 return strm;
822}
823
824void
831
832void
840
841void
842ClientSubscription::sendQueuedRefreshRequest()
843{
844 resip_assert(!mRefreshing);
845
846 if (mHaveQueuedRefresh)
847 {
848 DebugLog(<< "send queued refresh request");
849 mHaveQueuedRefresh = false;
850 requestRefresh(mQueuedRefreshInterval);
851 }
852}
853
854void
855ClientSubscription::clearDustbin()
856{
857 for (Dustbin::iterator it = mDustbin.begin(); it != mDustbin.end(); ++it)
858 {
859 delete *it;
860 }
861
862 mDustbin.clear();
863
864}
865
866void
867ClientSubscription::scheduleRefresh(unsigned long refreshInterval)
868{
869 if(mNextRefreshSecs-mLastSubSecs < 2)
870 {
871 // Server is using an unreasonably short expiry; we sent a SUB
872 // very recently, and the server has told us to refresh almost
873 // immediately. By the time our refresh timer pops, less than two
874 // seconds will have elapsed since our last SUBSCRIBE. This is
875 // unacceptable. Just let the subscription end.
876 // It is also possible that our refresh SUB has crossed an update NOTIFY
877 // on the wire; in this case, the right thing to do is to wait until a
878 // NOTIFY for our refresh SUB comes in, which is exactly what this code
879 // ends up doing in this case.
880 // ?bwc? Make this minimum inter-SUBSCRIBE time configurable?
881 WarningLog(<< "Server is using an unacceptably short expiry. "
882 "Letting the subscription end so we don't get in a"
883 " tight SUB/NOT loop.");
884 mNextRefreshSecs=0;
885 }
886 else
887 {
888 mDum.addTimer(DumTimeout::Subscription, refreshInterval, getBaseHandle(), ++mTimerSeq);
889 InfoLog (<< "[ClientSubscription] reSUBSCRIBE in " << refreshInterval);
890 }
891}
892
893
894
895/* ====================================================================
896 * The Vovida Software License, Version 1.0
897 *
898 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
899 *
900 * Redistribution and use in source and binary forms, with or without
901 * modification, are permitted provided that the following conditions
902 * are met:
903 *
904 * 1. Redistributions of source code must retain the above copyright
905 * notice, this list of conditions and the following disclaimer.
906 *
907 * 2. Redistributions in binary form must reproduce the above copyright
908 * notice, this list of conditions and the following disclaimer in
909 * the documentation and/or other materials provided with the
910 * distribution.
911 *
912 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
913 * and "Vovida Open Communication Application Library (VOCAL)" must
914 * not be used to endorse or promote products derived from this
915 * software without prior written permission. For written
916 * permission, please contact vocal@vovida.org.
917 *
918 * 4. Products derived from this software may not be called "VOCAL", nor
919 * may "VOCAL" appear in their name, without prior written
920 * permission of Vovida Networks, Inc.
921 *
922 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
923 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
924 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
925 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
926 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
927 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
928 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
929 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
930 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
931 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
932 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
933 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
934 * DAMAGE.
935 *
936 * ====================================================================
937 *
938 * This software consists of voluntary contributions made by Vovida
939 * Networks, Inc. and many individuals on behalf of Vovida Networks,
940 * Inc. For more information on Vovida Networks, Inc., please see
941 * <http://www.vovida.org/>.
942 *
943 */
#define DebugLog(args_)
Definition Logger.hxx:128
#define InfoLog(args_)
Definition Logger.hxx:131
#define WarningLog(args_)
Definition Logger.hxx:134
#define resip_assert(x)
This file needs to work for both C and C++ code.
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
ClientSubscriptionAcceptUpdateCommand(const ClientSubscriptionHandle &clientSubscriptionHandle, int statusCode, const char *reason)
ClientSubscriptionEndCommand(const ClientSubscriptionHandle &clientSubscriptionHandle, bool immediate)
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
ClientSubscriptionRefreshCommand(const ClientSubscriptionHandle &clientSubscriptionHandle, uint32_t expires)
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
ClientSubscriptionRejectUpdateCommand(const ClientSubscriptionHandle &clientSubscriptionHandle, int statusCode, const Data &reasonPhrase)
dcm! – update contact in dialog if required
std::shared_ptr< SipMessage > mLastResponse
const Data & getEventType() const noexcept
const Data & getId() const noexcept
std::shared_ptr< SipMessage > mLastRequest
BaseUsageHandle getBaseHandle() const
Definition BaseUsage.cxx:36
DialogUsageManager & mDum
Definition BaseUsage.hxx:43
virtual void onUpdatePending(ClientSubscriptionHandle, const SipMessage &notify, bool outOfOrder)=0
virtual void onFlowTerminated(ClientSubscriptionHandle)
Called when a TCP or TLS flow to the server has terminated.
virtual void onUpdateExtension(ClientSubscriptionHandle, const SipMessage &notify, bool outOfOrder)=0
virtual void onNewSubscription(ClientSubscriptionHandle, const SipMessage &notify)=0
virtual void onReadyToSend(ClientSubscriptionHandle, SipMessage &msg)
called to allow app to adorn a message.
virtual void onUpdateActive(ClientSubscriptionHandle, const SipMessage &notify, bool outOfOrder)=0
virtual void onTerminated(ClientSubscriptionHandle, const SipMessage *msg)=0
virtual void onNotifyNotReceived(ClientSubscriptionHandle)
virtual int onRequestRetry(ClientSubscriptionHandle, int retrySeconds, const SipMessage &notify)=0
void acceptUpdate(int statusCode=200, const char *reason=nullptr)
void requestRefreshCommand(uint32_t expires=0)
virtual void onReadyToSend(SipMessage &msg) override
EncodeStream & dump(EncodeStream &strm) const override
void rejectUpdateCommand(int statusCode=400, const Data &reasonPhrase=Data::Empty)
Handle< ClientSubscription > ClientSubscriptionHandle
void acceptUpdateCommand(int statusCode=200, const char *reason=nullptr)
Provide asynchronous method access by using command.
void requestRefresh(uint32_t expires=0)
virtual void send(std::shared_ptr< SipMessage > msg) override
virtual void endCommand(bool immediate=false)
void rejectUpdate(int statusCode=400, const Data &reasonPhrase=Data::Empty)
ClientSubscription(DialogUsageManager &dum, Dialog &dialog, const SipMessage &request)
ClientSubscriptionHandle getHandle()
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
bool empty() const noexcept
Checks whether the Data is empty.
Definition Data.hxx:591
void send(std::shared_ptr< SipMessage > request)
ClientSubscriptionHandler * getClientSubscriptionHandler(const Data &eventType)
std::shared_ptr< SipMessage > makeSubscription(const NameAddr &target, const std::shared_ptr< UserProfile > &userProfile, const Data &eventType, AppDialogSet *=nullptr)
std::shared_ptr< UserProfile > getUserProfile() const
AppDialogSetHandle getAppDialogSet() const
virtual void send(std::shared_ptr< SipMessage > msg)
dcm! – kill typedef std::list<DialogId> DialogIdSet;
Definition Dialog.hxx:29
void makeRequest(SipMessage &request, MethodTypes method, bool incrementCSeq=true)
Definition Dialog.cxx:1033
void makeResponse(SipMessage &response, const SipMessage &request, int responseCode)
Definition Dialog.cxx:1108
Type type() const
unsigned int seq() const
static T aBitSmallerThan(T secs)
Used by Registration, Publication and Subscription refreshes, to calculate the time at which a refres...
Definition Helper.hxx:53
@ TransactionTermination
Definition Helper.hxx:614
@ ApplicationDependant
Definition Helper.hxx:615
static FailureMessageEffect determineFailureMessageEffect(const SipMessage &response, const std::set< int > *additionalTransactionTerminatingResponses=NULL)
Definition Helper.cxx:2151
virtual Brief brief() const
return a facet for brief encoding of message
Definition Message.cxx:16
Represents the "name-addr" and the "addr-spec" elements in the RFC 3261 grammar.
Definition NameAddr.hxx:19
void remove(const Param< NameAddr > &paramType)
Definition NameAddr.cxx:485
MethodTypes getMethod() const
SIP body type for holding SipFrag contents (MIME content-type message/sipfrag).
Definition SipFrag.hxx:22
SipMessage & message()
Definition SipFrag.cxx:82
Represents a SIP message.
bool isRequest() const
Returns true if message is a request, 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.
bool isFromWire() const
Check if SipMessage came off the wire.
resip::MethodTypes method() const
returns the method type of the message
static const char * Terminated
Definition Symbols.hxx:120
static const char * Pending
Definition Symbols.hxx:118
static const char * Active
Definition Symbols.hxx:119
This class is used to get the current system time.
Definition Timer.hxx:31
static unsigned long T1
Definition Timer.hxx:114
static uint64_t getTimeSecs()
Returns the current clock time in seconds.
Definition Timer.hxx:78
void post(Message *msg)
Posts a Message to this TransactionUser's fifo.
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
Definition Headers.cxx:348
bool isEqualNoCase(const Data &left, const Data &right)
Definition Data.hxx:1116
unsigned int uint32_t
Definition Stun.hxx:34
RequestLineType h_RequestLine
Definition Headers.cxx:347
#define EncodeStream
unsigned int uint32_t
Definition stdint.h:85
unsigned __int64 uint64_t
Definition stdint.h:95