~ubuntu-branches/ubuntu/saucy/resiprocate/saucy-proposed

« back to all changes in this revision

Viewing changes to resip/dum/ClientPublication.cxx

  • Committer: Package Import Robot
  • Author(s): Daniel Pocock
  • Date: 2012-05-17 19:29:59 UTC
  • Revision ID: package-import@ubuntu.com-20120517192959-vv00m77isztdy64q
Tags: upstream-1.8.2
ImportĀ upstreamĀ versionĀ 1.8.2

Show diffs side-by-side

added added

removed removed

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