reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
ClientPublication.cxx
Go to the documentation of this file.
1#include "rutil/ResipAssert.h"
2
9#include "rutil/Logger.hxx"
11
12#include <utility>
13
14#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
15
16using namespace resip;
17
23
25 DialogSet& dialogSet,
26 std::shared_ptr<SipMessage> req)
27 : NonDialogUsage(dum, dialogSet),
28 mPublished(false),
29 mWaitingForResponse(false),
30 mPendingPublish(false),
31 mPendingEnd(false),
32 mPublish(req),
33 mEventType(mPublish->header(h_Event).value()),
34 mTimerSeq(0),
35 mDocument(mPublish->releaseContents().release())
36{
37 DebugLog( << "ClientPublication::ClientPublication: " << mId);
38}
39
41{
42 DebugLog( << "ClientPublication::~ClientPublication: " << mId);
43 mDialogSet.mClientPublication = 0;
44 delete mDocument;
45}
46
47void
49{
50 end(false);
51}
52
53void
55{
56 if (immediate)
57 {
58 InfoLog(<< "End client publication immediately to " << mPublish->header(h_RequestLine).uri());
59 delete this;
60 return;
61 }
62 if (mWaitingForResponse)
63 {
64 InfoLog(<< "Waiting for response, pending End of client publication to " << mPublish->header(h_RequestLine).uri());
65 mPendingEnd = true;
66 return;
67 }
68 if (mPublished)
69 {
70 InfoLog(<< "End client publication to " << mPublish->header(h_RequestLine).uri());
71 mPublish->header(h_Expires).value() = 0;
72 mPublish->releaseContents();
73 send(mPublish);
74 }
75 else
76 {
77 InfoLog(<< "End client publication immediately (not published) to " << mPublish->header(h_RequestLine).uri());
78 delete this;
79 }
80}
81
83{
84public:
85 ClientPublicationEndCommand(const ClientPublicationHandle& clientPublicationHandle, bool immediate)
86 : mClientPublicationHandle(clientPublicationHandle), mImmediate(immediate)
87 {
88 }
89
90 void executeCommand() override
91 {
92 if(mClientPublicationHandle.isValid())
93 {
94 mClientPublicationHandle->end(mImmediate);
95 }
96 }
97
98 EncodeStream& encodeBrief(EncodeStream& strm) const override
99 {
100 return strm << "ClientPublicationEndCommand";
101 }
102private:
103 ClientPublicationHandle mClientPublicationHandle;
104 bool mImmediate;
105};
106
107void
109{
111}
112
113void
115{
117 resip_assert(handler);
118
119 if (msg.isRequest())
120 {
121 DebugLog( << "Dropping stray request to ClientPublication usage: " << msg);
122 }
123 else
124 {
125 const int code = msg.header(h_StatusLine).statusCode();
126 if (code < 200)
127 {
128 return;
129 }
130
131 resip_assert(code >= 200);
132 mWaitingForResponse = false;
133
134 if (code < 300)
135 {
136 mPublished = true;
137 if (mPublish->exists(h_Expires) && mPublish->header(h_Expires).value() == 0)
138 {
139 handler->onRemove(getHandle(), msg);
140 delete this;
141 return;
142 }
143 else if (msg.exists(h_SIPETag) && msg.exists(h_Expires))
144 {
145 mPublish->header(h_SIPIfMatch) = msg.header(h_SIPETag);
146 if(!mPendingPublish)
147 {
148 mPublish->releaseContents();
149 }
151 Helper::aBitSmallerThan(msg.header(h_Expires).value()),
153 ++mTimerSeq);
154 handler->onSuccess(getHandle(), msg);
155 }
156 else
157 {
158 // Any PUBLISH/200 must have an ETag. This should not happen. Not
159 // sure what the app can do in this case.
160 WarningLog (<< "PUBLISH/200 received with no ETag " << mPublish->header(h_From).uri());
161 handler->onFailure(getHandle(), msg);
162 delete this;
163 return;
164 }
165 }
166 else
167 {
168 if (code == 412)
169 {
170 InfoLog(<< "SIPIfMatch failed -- republish");
171 mPublish->remove(h_SIPIfMatch);
172 update(mDocument);
173 return;
174 }
175 else if (code == 423) // interval too short
176 {
177 if (msg.exists(h_MinExpires))
178 {
179 mPublish->header(h_Expires).value() = msg.header(h_MinExpires).value();
180 update(mDocument); // !dys! since contents not released until on success, no need to call update any more.
181 }
182 else
183 {
184 handler->onFailure(getHandle(), msg);
185 delete this;
186 return;
187 }
188 }
189 else if (code == 408 ||
190 (code == 503 && !msg.isFromWire()) ||
191 ((code == 404 ||
192 code == 413 ||
193 code == 480 ||
194 code == 486 ||
195 code == 500 ||
196 code == 503 ||
197 code == 600 ||
198 code == 603) &&
199 msg.exists(h_RetryAfter)))
200 {
201 int retryMinimum = 0;
202 if (msg.exists(h_RetryAfter))
203 {
204 retryMinimum = msg.header(h_RetryAfter).value();
205 }
206
207 // RFC 3261:20.33 Retry-After
208 int retry = handler->onRequestRetry(getHandle(), retryMinimum, msg);
209 if (retry < 0)
210 {
211 DebugLog(<< "Application requested failure on Retry-After");
212 handler->onFailure(getHandle(), msg);
213 delete this;
214 return;
215 }
216 else if (retry == 0 && retryMinimum == 0)
217 {
218 DebugLog(<< "Application requested immediate retry on Retry-After");
219 refresh();
220 return;
221 }
222 else
223 {
224 retry = resipMax(retry, retryMinimum);
225 DebugLog(<< "Application requested delayed retry on Retry-After: " << retry);
227 retry,
229 ++mTimerSeq);
230 return;
231 }
232 }
233 else
234 {
235 handler->onFailure(getHandle(), msg);
236 delete this;
237 return;
238 }
239 }
240
241 if (mPendingEnd)
242 {
243 mPendingEnd = false;
244 if (mPublished)
245 {
246 mPublish->header(h_Expires).value() = 0;
247 mPublish->releaseContents();
248 InfoLog(<< "Sending pending end PUBLISH: " << mPublish->brief());
249 send(mPublish);
250 }
251 else
252 {
253 InfoLog(<< "Pending end PUBLISH, but not published, so ending immediately: " << mPublish->brief());
254 delete this;
255 return;
256 }
257 }
258 else if (mPendingPublish)
259 {
260 InfoLog (<< "Sending pending PUBLISH: " << mPublish->brief());
261 send(mPublish);
262 }
263 }
264}
265
266void
268{
269 if (timer.seq() == mTimerSeq)
270 {
271 refresh();
272 }
273}
274
275void
276ClientPublication::refresh(unsigned int expiration)
277{
278 if (expiration != 0)
279 {
280 mPublish->header(h_Expires).value() = expiration;
281 }
282 send(mPublish);
283}
284
286{
287public:
288 ClientPublicationRefreshCommand(const ClientPublicationHandle& clientPublicationHandle, unsigned int expiration)
289 : mClientPublicationHandle(clientPublicationHandle),
290 mExpiration(expiration)
291 {
292 }
293
294 void executeCommand() override
295 {
296 if(mClientPublicationHandle.isValid())
297 {
298 mClientPublicationHandle->refresh(mExpiration);
299 }
300 }
301
302 EncodeStream& encodeBrief(EncodeStream& strm) const override
303 {
304 return strm << "ClientPublicationRefreshCommand";
305 }
306
307private:
308 ClientPublicationHandle mClientPublicationHandle;
309 unsigned int mExpiration;
310};
311
312void
313ClientPublication::refreshCommand(unsigned int expiration)
314{
316}
317
318void
320{
321 InfoLog (<< "Updating presence document: " << mPublish->header(h_To).uri());
322
323 if (mDocument != body)
324 {
325 delete mDocument;
326 if (body)
327 {
328 mDocument = body->clone();
329 }
330 else
331 {
332 mDocument = body;
333 }
334 }
335
336 mPublish->setContents(mDocument);
337 send(mPublish);
338}
339
341{
342public:
343 ClientPublicationUpdateCommand(const ClientPublicationHandle& clientPublicationHandle, const Contents* body)
344 : mClientPublicationHandle(clientPublicationHandle),
345 mBody(body ? body->clone() : nullptr)
346 {
347 }
348
349 void executeCommand() override
350 {
351 if(mClientPublicationHandle.isValid())
352 {
353 mClientPublicationHandle->update(mBody.get());
354 }
355 }
356
357 EncodeStream& encodeBrief(EncodeStream& strm) const override
358 {
359 return strm << "ClientPublicationUpdateCommand";
360 }
361
362private:
363 ClientPublicationHandle mClientPublicationHandle;
364 std::unique_ptr<Contents> mBody;
365};
366
367void
372
373void
374ClientPublication::send(std::shared_ptr<SipMessage> request)
375{
376 if (mWaitingForResponse)
377 {
378 mPendingPublish = true;
379 }
380 else
381 {
382 request->header(h_CSeq).sequence()++;
383 mDum.send(request);
384 mWaitingForResponse = true;
385 mPendingPublish = false;
386 }
387}
388
390ClientPublication::dump(EncodeStream& strm) const
391{
392 strm << "ClientPublication " << mId << " " << mPublish->header(h_From).uri();
393 return strm;
394}
395
396/* ====================================================================
397 * The Vovida Software License, Version 1.0
398 *
399 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
400 *
401 * Redistribution and use in source and binary forms, with or without
402 * modification, are permitted provided that the following conditions
403 * are met:
404 *
405 * 1. Redistributions of source code must retain the above copyright
406 * notice, this list of conditions and the following disclaimer.
407 *
408 * 2. Redistributions in binary form must reproduce the above copyright
409 * notice, this list of conditions and the following disclaimer in
410 * the documentation and/or other materials provided with the
411
412 * distribution.
413 *
414 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
415 * and "Vovida Open Communication Application Library (VOCAL)" must
416 * not be used to endorse or promote products derived from this
417 * software without prior written permission. For written
418 * permission, please contact vocal@vovida.org.
419 *
420 * 4. Products derived from this software may not be called "VOCAL", nor
421 * may "VOCAL" appear in their name, without prior written
422 * permission of Vovida Networks, Inc.
423 *
424 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
425 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
426 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
427 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
428 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
429 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
430 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
431 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
432 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
433 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
434 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
435 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
436 * DAMAGE.
437 *
438 * ====================================================================
439 *
440 * This software consists of voluntary contributions made by Vovida
441 * Networks, Inc. and many individuals on behalf of Vovida Networks,
442 * Inc. For more information on Vovida Networks, Inc., please see
443 * <http://www.vovida.org/>.
444 *
445 */
#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
ClientPublicationEndCommand(const ClientPublicationHandle &clientPublicationHandle, bool immediate)
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
ClientPublicationRefreshCommand(const ClientPublicationHandle &clientPublicationHandle, unsigned int expiration)
EncodeStream & encodeBrief(EncodeStream &strm) const override
output a brief description to stream
ClientPublicationUpdateCommand(const ClientPublicationHandle &clientPublicationHandle, const Contents *body)
BaseUsageHandle getBaseHandle() const
Definition BaseUsage.cxx:36
DialogUsageManager & mDum
Definition BaseUsage.hxx:43
virtual void onRemove(ClientPublicationHandle, const SipMessage &status)=0
virtual int onRequestRetry(ClientPublicationHandle, int retrySeconds, const SipMessage &status)=0
call on Retry-After failure.
virtual void onSuccess(ClientPublicationHandle, const SipMessage &status)=0
Called when the publication succeeds or each time it is successfully refreshed.
virtual void onFailure(ClientPublicationHandle, const SipMessage &status)=0
ClientPublication(DialogUsageManager &dum, DialogSet &dialogSet, std::shared_ptr< SipMessage > pub)
void updateCommand(const Contents *body)
Provide asynchronous method access by using command.
void refresh(unsigned int expiration=0)
void send(std::shared_ptr< SipMessage > request) override
virtual void endCommand(bool immediate=false)
Handle< ClientPublication > ClientPublicationHandle
void refreshCommand(unsigned int expiration=0)
EncodeStream & dump(EncodeStream &strm) const override
void update(const Contents *body)
void dispatch(const SipMessage &msg) override
ClientPublicationHandle getHandle()
Base class for all SIP body types.
Definition Contents.hxx:51
virtual Contents * clone() const =0
returns a copy of a Contents object
void send(std::shared_ptr< SipMessage > request)
ClientPublicationHandler * getClientPublicationHandler(const Data &eventType)
unsigned int seq() const
Handled::Id mId
Definition Handled.hxx:25
static T aBitSmallerThan(T secs)
Used by Registration, Publication and Subscription refreshes, to calculate the time at which a refres...
Definition Helper.hxx:53
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 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.
void post(Message *msg)
Posts a Message to this TransactionUser's fifo.
dcm! – add UnusedChecking(_enum) below;
StatusLineType h_StatusLine
Definition Headers.cxx:348
RequestLineType h_RequestLine
Definition Headers.cxx:347
const _Tp & resipMax(const _Tp &__a, const _Tp &__b)
Definition compat.hxx:194
#define EncodeStream