|
reSIProcate/DialogUsageManager
9680
|
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 */
1.7.5.1