reSIProcate/DialogUsageManager  9680
ClientPublication.cxx
Go to the documentation of this file.
00001 #include <cassert>
00002 
00003 #include "resip/stack/Helper.hxx"
00004 #include "resip/stack/SipMessage.hxx"
00005 #include "resip/dum/ClientPublication.hxx"
00006 #include "resip/dum/Dialog.hxx"
00007 #include "resip/dum/DialogUsageManager.hxx"
00008 #include "resip/dum/DumTimeout.hxx"
00009 #include "rutil/Logger.hxx"
00010 #include "resip/dum/PublicationHandler.hxx"
00011 
00012 
00013 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
00014 
00015 using namespace resip;
00016 
00017 ClientPublicationHandle 
00018 ClientPublication::getHandle()
00019 {
00020    return ClientPublicationHandle(mDum, getBaseHandle().getId());
00021 }
00022 
00023 ClientPublication::ClientPublication(DialogUsageManager& dum,
00024                                      DialogSet& dialogSet,
00025                                      SharedPtr<SipMessage> req)
00026    : NonDialogUsage(dum, dialogSet),
00027      mWaitingForResponse(false),
00028      mPendingPublish(false),
00029      mPublish(req),
00030      mEventType(req->header(h_Event).value()),
00031      mTimerSeq(0),
00032      mDocument(mPublish->releaseContents().release())
00033 {
00034    DebugLog( << "ClientPublication::ClientPublication: " << mId);   
00035 }
00036 
00037 ClientPublication::~ClientPublication()
00038 {
00039    DebugLog( << "ClientPublication::~ClientPublication: " << mId);   
00040    mDialogSet.mClientPublication = 0;
00041    delete mDocument;
00042 }
00043 
00044 void
00045 ClientPublication::end()
00046 {
00047    end(false);
00048 }
00049 
00050 void
00051 ClientPublication::end(bool immediate)
00052 {
00053    InfoLog (<< "End client publication to " << mPublish->header(h_RequestLine).uri());
00054    if(!immediate)
00055    {
00056       mPublish->header(h_Expires).value() = 0;
00057       send(mPublish);
00058    }
00059    else
00060    {
00061       delete this;
00062    }
00063 }
00064 
00065 class ClientPublicationEndCommand : public DumCommandAdapter
00066 {
00067 public:
00068    ClientPublicationEndCommand(ClientPublication& clientPublication, bool immediate)
00069       : mClientPublication(clientPublication), mImmediate(immediate)
00070    {
00071 
00072    }
00073 
00074    virtual void executeCommand()
00075    {
00076       mClientPublication.end(mImmediate);
00077    }
00078 
00079    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00080    {
00081       return strm << "ClientPublicationEndCommand";
00082    }
00083 private:
00084    ClientPublication& mClientPublication;
00085    bool mImmediate;
00086 };
00087 
00088 void
00089 ClientPublication::endCommand(bool immediate)
00090 {
00091    mDum.post(new ClientPublicationEndCommand(*this, immediate));
00092 }
00093 
00094 void 
00095 ClientPublication::dispatch(const SipMessage& msg)
00096 {
00097    ClientPublicationHandler* handler = mDum.getClientPublicationHandler(mEventType);
00098    assert(handler);   
00099 
00100    if (msg.isRequest())
00101    {
00102       DebugLog( << "Dropping stray request to ClientPublication usage: " << msg);
00103    }
00104    else
00105    {
00106       const int code = msg.header(h_StatusLine).statusCode();
00107       if (code < 200)
00108       {
00109          return;
00110       }
00111 
00112       assert(code >= 200);
00113       mWaitingForResponse = false;
00114 
00115       if (code < 300)
00116       {
00117          if (mPublish->exists(h_Expires) && mPublish->header(h_Expires).value() == 0)
00118          {
00119             handler->onRemove(getHandle(), msg);
00120             delete this;
00121             return;
00122          }
00123          else if (msg.exists(h_SIPETag) && msg.exists(h_Expires))
00124          {
00125             mPublish->header(h_SIPIfMatch) = msg.header(h_SIPETag);
00126             if(!mPendingPublish)
00127             {
00128                mPublish->releaseContents();           
00129             }
00130             mDum.addTimer(DumTimeout::Publication, 
00131                           Helper::aBitSmallerThan(msg.header(h_Expires).value()), 
00132                           getBaseHandle(),
00133                           ++mTimerSeq);
00134             handler->onSuccess(getHandle(), msg);
00135          }
00136          else
00137          {
00138             // Any PUBLISH/200 must have an ETag. This should not happen. Not
00139             // sure what the app can do in this case. 
00140             WarningLog (<< "PUBLISH/200 received with no ETag " << mPublish->header(h_From).uri());
00141             handler->onFailure(getHandle(), msg);
00142             delete this;
00143             return;
00144          }
00145       }
00146       else
00147       {
00148          if (code == 412)
00149          {
00150             InfoLog(<< "SIPIfMatch failed -- republish");
00151             mPublish->remove(h_SIPIfMatch);
00152             update(mDocument);
00153             return;
00154          }         
00155          else if (code == 423) // interval too short
00156          {
00157             if (msg.exists(h_MinExpires))
00158             {
00159                mPublish->header(h_Expires).value() = msg.header(h_MinExpires).value();
00160                update(mDocument); // !dys! since contents not released until on success, no need to call update any more.
00161             }
00162             else
00163             {
00164                handler->onFailure(getHandle(), msg);
00165                delete this;
00166                return;
00167             }
00168          }
00169          else if (code == 408 ||
00170                   (code == 503 && msg.getReceivedTransport() == 0) ||
00171                   ((code == 404 ||
00172                     code == 413 ||
00173                     code == 480 ||
00174                     code == 486 ||
00175                     code == 500 ||
00176                     code == 503 ||
00177                     code == 600 ||
00178                     code == 603) &&
00179                    msg.exists(h_RetryAfter)))
00180          {
00181             int retryMinimum = 0;
00182             if (msg.exists(h_RetryAfter))
00183             {
00184                retryMinimum = msg.header(h_RetryAfter).value();
00185             }
00186 
00187             // RFC 3261:20.33 Retry-After
00188             int retry = handler->onRequestRetry(getHandle(), retryMinimum, msg);
00189             if (retry < 0)
00190             {
00191                DebugLog(<< "Application requested failure on Retry-After");
00192                handler->onFailure(getHandle(), msg);
00193                delete this;
00194                return;
00195             }
00196             else if (retry == 0 && retryMinimum == 0)
00197             {
00198                DebugLog(<< "Application requested immediate retry on Retry-After");
00199                refresh();
00200                return;
00201             }
00202             else
00203             {
00204                retry = resipMax(retry, retryMinimum);
00205                DebugLog(<< "Application requested delayed retry on Retry-After: " << retry);
00206                mDum.addTimer(DumTimeout::Publication, 
00207                              retry, 
00208                              getBaseHandle(),
00209                              ++mTimerSeq);       
00210                return;
00211                
00212             }
00213          }
00214          else
00215          {
00216             handler->onFailure(getHandle(), msg);
00217             delete this;
00218             return;
00219          }
00220 
00221       }
00222 
00223       if (mPendingPublish)
00224       {
00225          InfoLog (<< "Sending pending PUBLISH: " << mPublish->brief());
00226          send(mPublish);
00227       }
00228    }
00229 }
00230 
00231 void 
00232 ClientPublication::dispatch(const DumTimeout& timer)
00233 {
00234     if (timer.seq() == mTimerSeq)
00235     {
00236        refresh();
00237     }
00238 }
00239 
00240 void
00241 ClientPublication::refresh(unsigned int expiration)
00242 {
00243    if (expiration == 0 && mPublish->exists(h_Expires))
00244    {
00245       expiration = mPublish->header(h_Expires).value();
00246    }
00247    send(mPublish);
00248 }
00249 
00250 class ClientPublicationRefreshCommand : public DumCommandAdapter
00251 {
00252 public:
00253    ClientPublicationRefreshCommand(ClientPublication& clientPublication, unsigned int expiration)
00254       : mClientPublication(clientPublication),
00255         mExpiration(expiration)
00256    {
00257 
00258    }
00259 
00260    virtual void executeCommand()
00261    {
00262       mClientPublication.refresh(mExpiration);
00263    }
00264 
00265    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00266    {
00267       return strm << "ClientPublicationRefreshCommand";
00268    }
00269 
00270 private:
00271    ClientPublication& mClientPublication;
00272    unsigned int mExpiration;
00273 };
00274 
00275 void
00276 ClientPublication::refreshCommand(unsigned int expiration)
00277 {
00278    mDum.post(new ClientPublicationRefreshCommand(*this, expiration));
00279 }
00280 
00281 void
00282 ClientPublication::update(const Contents* body)
00283 {
00284    InfoLog (<< "Updating presence document: " << mPublish->header(h_To).uri());
00285 
00286    if (mDocument != body)
00287    {
00288       delete mDocument;
00289       if (body)
00290       {
00291          mDocument = body->clone();
00292       }
00293       else
00294       {
00295          mDocument = body;
00296       }
00297    }
00298 
00299    mPublish->setContents(mDocument);
00300    send(mPublish);
00301 }
00302 
00303 class ClientPublicationUpdateCommand : public DumCommandAdapter
00304 {
00305 public:
00306    ClientPublicationUpdateCommand(ClientPublication& clientPublication, const Contents* body)
00307       : mClientPublication(clientPublication),
00308       mBody(body?body->clone():0)
00309    {
00310 
00311    }
00312 
00313    virtual void executeCommand()
00314    {
00315       mClientPublication.update(mBody.get());
00316    }
00317 
00318    virtual EncodeStream& encodeBrief(EncodeStream& strm) const
00319    {
00320       return strm << "ClientPublicationUpdateCommand";
00321    }
00322 
00323 private:
00324    ClientPublication& mClientPublication;
00325    std::auto_ptr<Contents> mBody;
00326 };
00327 
00328 void
00329 ClientPublication::updateCommand(const Contents* body)
00330 {
00331    mDum.post(new ClientPublicationUpdateCommand(*this, body));
00332 }
00333 
00334 void 
00335 ClientPublication::send(SharedPtr<SipMessage> request)
00336 {
00337    if (mWaitingForResponse)
00338    {
00339       mPendingPublish = true;
00340    }
00341    else
00342    {
00343       request->header(h_CSeq).sequence()++;
00344       mDum.send(request);
00345       mWaitingForResponse = true;
00346       mPendingPublish = false;
00347    }
00348 }
00349 
00350 EncodeStream& 
00351 ClientPublication::dump(EncodeStream& strm) const
00352 {
00353    strm << "ClientPublication " << mId << " " << mPublish->header(h_From).uri();
00354    return strm;
00355 }
00356 
00357 /* ====================================================================
00358  * The Vovida Software License, Version 1.0 
00359  * 
00360  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00361  * 
00362  * Redistribution and use in source and binary forms, with or without
00363  * modification, are permitted provided that the following conditions
00364  * are met:
00365  * 
00366  * 1. Redistributions of source code must retain the above copyright
00367  *    notice, this list of conditions and the following disclaimer.
00368  * 
00369  * 2. Redistributions in binary form must reproduce the above copyright
00370  *    notice, this list of conditions and the following disclaimer in
00371  *    the documentation and/or other materials provided with the
00372 
00373  *    distribution.
00374  * 
00375  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00376  *    and "Vovida Open Communication Application Library (VOCAL)" must
00377  *    not be used to endorse or promote products derived from this
00378  *    software without prior written permission. For written
00379  *    permission, please contact vocal@vovida.org.
00380  *
00381  * 4. Products derived from this software may not be called "VOCAL", nor
00382  *    may "VOCAL" appear in their name, without prior written
00383  *    permission of Vovida Networks, Inc.
00384  * 
00385  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00386  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00387  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00388  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00389  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00390  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00391  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00392  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00393  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00394  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00395  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00396  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00397  * DAMAGE.
00398  * 
00399  * ====================================================================
00400  * 
00401  * This software consists of voluntary contributions made by Vovida
00402  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00403  * Inc.  For more information on Vovida Networks, Inc., please see
00404  * <http://www.vovida.org/>.
00405  *
00406  */