reSIProcate/DialogUsageManager  9694
ServerRegistration.cxx
Go to the documentation of this file.
00001 #include "resip/stack/ExtensionParameter.hxx"
00002 #include "resip/stack/InteropHelper.hxx"
00003 #include "resip/stack/SipMessage.hxx"
00004 #include "resip/stack/Helper.hxx"
00005 #include "resip/dum/DialogUsageManager.hxx"
00006 #include "resip/dum/MasterProfile.hxx"
00007 #include "resip/dum/ServerRegistration.hxx"
00008 #include "resip/dum/Dialog.hxx"
00009 #include "resip/dum/RegistrationHandler.hxx"
00010 #include "resip/dum/RegistrationPersistenceManager.hxx"
00011 #include "rutil/DnsUtil.hxx"
00012 #include "rutil/Logger.hxx"
00013 #include "rutil/Timer.hxx"
00014 #include "rutil/WinLeakCheck.hxx"
00015 
00016 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
00017 
00018 using namespace resip;
00019 
00020 ServerRegistrationHandle 
00021 ServerRegistration::getHandle()
00022 {
00023    return ServerRegistrationHandle(mDum, getBaseHandle().getId());
00024 }
00025 
00026 ServerRegistration::ServerRegistration(DialogUsageManager& dum,  DialogSet& dialogSet, const SipMessage& request)
00027    : NonDialogUsage(dum, dialogSet),
00028      mRequest(request),
00029       mDidOutbound(false),
00030       mAsyncState(asyncStateNone)
00031 {}
00032 
00033 ServerRegistration::~ServerRegistration()
00034 {
00035    mDialogSet.mServerRegistration = 0;
00036 }
00037 
00038 void 
00039 ServerRegistration::end()
00040 {
00041 }
00042 
00043 static Token outbound(Symbols::Outbound);
00044 void
00045 ServerRegistration::accept(SipMessage& ok)
00046 {
00047    ok.remove(h_Contacts);
00048 
00049    InfoLog( << "accepted a registration " << mAor );
00050 
00051    if (mDidOutbound)
00052    {
00053       ok.header(h_Requires).push_back(outbound);
00054       if(InteropHelper::getFlowTimerSeconds() > 0)
00055       {
00056          ok.header(h_FlowTimer).value() = InteropHelper::getFlowTimerSeconds();         
00057          mDum.getSipStack().enableFlowTimer(mRequest.getSource());
00058       }
00059    }
00060 
00061    if (!mDum.mServerRegistrationHandler->asyncProcessing())
00062    {
00063       // Add all registered contacts to the message.
00064       RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
00065 
00066       ContactList contacts;
00067       database->getContacts(mAor, contacts);
00068 
00069       //removes expired entries from the ok msg as well as calls the database to remove expired contacts.
00070       processFinalOkMsg(ok,contacts);
00071 
00072       database->unlockRecord(mAor);
00073 
00074       SharedPtr<SipMessage> msg(static_cast<SipMessage*>(ok.clone()));
00075       mDum.send(msg);
00076       delete(this);
00077    }
00078    else
00079    {
00080       if (mAsyncState == asyncStateQueryOnly)
00081       {
00082          if (!mAsyncLocalStore.get())
00083          {
00084             assert(0);
00085          }
00086          else
00087          {
00088             std::auto_ptr<ContactRecordTransactionLog> log;
00089             std::auto_ptr<ContactPtrList> contacts;
00090 
00091             mAsyncLocalStore->releaseLog(log,contacts);
00092 
00093             if (contacts.get())
00094             {
00095                asyncProcessFinalOkMsg(ok,*contacts);
00096             }
00097          }
00098 
00099          SharedPtr<SipMessage> msg(static_cast<SipMessage*>(ok.clone()));
00100          mDum.send(msg);
00101          delete(this);        
00102       }
00103       else
00104       {
00105          if (!mAsyncLocalStore.get())
00106          {
00107             assert(0);
00108             return;
00109          }
00110          //This register was accepted, but still need to apply the changes made by this register and then
00111          //receive a final contact list before sending the 200.
00112          mAsyncState = asyncStateAcceptedWaitingForFinalContactList;
00113 
00114          std::auto_ptr<ContactRecordTransactionLog> log;
00115          std::auto_ptr<ContactPtrList> modifiedContacts;
00116 
00117          mAsyncLocalStore->releaseLog(log,modifiedContacts);
00118 
00119          mAsyncOkMsg = SharedPtr<SipMessage>(static_cast<SipMessage*>(ok.clone()));
00120          mDum.mServerRegistrationHandler->asyncUpdateContacts(getHandle(),mAor,modifiedContacts,log);
00122          return;
00123       }
00124    }
00125 }
00126 
00127 void
00128 ServerRegistration::accept(int statusCode)
00129 {
00130    SipMessage success;
00131    mDum.makeResponse(success, mRequest, statusCode);
00132    // .bwc. Copy Path headers if present, indicate Path support
00133    // ?bwc? If path headers are present, but client indicates no path support, 
00134    // RFC 3327 says it is a matter of policy of whether to accept the 
00135    // registration or not. What should we do here? Is it worth it to make this 
00136    // configurable?
00137    if(!mRequest.empty(h_Paths))
00138    {
00139       success.header(h_Paths)=mRequest.header(h_Paths);
00140       success.header(h_Supporteds).push_back(Token(Symbols::Path));
00141    }
00142    accept(success);
00143 }
00144 
00145 void
00146 ServerRegistration::reject(int statusCode)
00147 {
00148    InfoLog( << "rejected a registration " << mAor << " with statusCode=" << statusCode );
00149 
00150    // First, we roll back the contact database to
00151    // the state it was before the registration request.
00152 
00153    // Async processing hasn't actually updated the database yet, so no need to roll back.
00154    if (mDum.mServerRegistrationHandler && !mDum.mServerRegistrationHandler->asyncProcessing())
00155    {
00156       // Rollback changes, since rejected
00157       RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
00158       database->removeAor(mAor);
00159       if (mOriginalContacts.get())
00160       {
00161          database->addAor(mAor, *mOriginalContacts);
00162       }
00163       database->unlockRecord(mAor);
00164    }
00165 
00166    SharedPtr<SipMessage> failure(new SipMessage);
00167    mDum.makeResponse(*failure, mRequest, statusCode);
00168    failure->remove(h_Contacts);
00169    mDum.send(failure);
00170    delete(this);
00171 }
00172 
00173 void 
00174 ServerRegistration::dispatch(const SipMessage& msg)
00175 {
00176    DebugLog( << "got a registration" );
00177    
00178    assert(msg.isRequest());
00179    ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler;
00180    RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
00181 
00182    if (!handler || (!handler->asyncProcessing() && !database))
00183    {
00184       // ?bwc? This is a server error; why are we sending a 4xx?
00185       // ?jmatthewsr? Possibly because of the note in section 21.5.2 about recognizing the method, but not supporting it?
00186        DebugLog( << "No handler or DB - sending 405" );
00187        
00188        SharedPtr<SipMessage> failure(new SipMessage);
00189        mDum.makeResponse(*failure, msg, 405);
00190        mDum.send(failure);
00191        delete(this);
00192        return;
00193     }
00194 
00195     mAor = msg.header(h_To).uri().getAorAsUri(msg.getSource().getType());
00196 
00197    // Checks to see whether this scheme is valid, and supported.
00198    if (!((mAor.scheme()=="sip" || mAor.scheme()=="sips")
00199          && mDum.getMasterProfile()->isSchemeSupported(mAor.scheme())))
00200    {
00201        DebugLog( << "Bad scheme in Aor" );
00202        
00203        SharedPtr<SipMessage> failure(new SipMessage);
00204        mDum.makeResponse(*failure, msg, 400);
00205        failure->header(h_StatusLine).reason() = "Bad/unsupported scheme in To: " + mAor.scheme();
00206        mDum.send(failure);
00207        delete(this);
00208        return;
00209    }
00210    
00211    if (handler->asyncProcessing())
00212    {
00213       mAsyncState = asyncStateWaitingForInitialContactList;
00214       handler->asyncGetContacts(getHandle(),mAor);
00216       return;
00217    }
00218 
00219    processRegistration(msg);
00220 }
00221 
00222 void
00223 ServerRegistration::processRegistration(const SipMessage& msg)
00224 {
00225    ServerRegistrationHandler* handler = mDum.mServerRegistrationHandler;
00226    RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
00227 
00228    enum {ADD, REMOVE, REFRESH} operation = REFRESH;
00229 
00230    UInt32 globalExpires=3600;
00231    UInt32 returnCode=0;
00232    handler->getGlobalExpires(msg,mDum.getMasterProfile(),globalExpires,returnCode);
00233 
00234    bool async = handler->asyncProcessing();
00235 
00236    if (returnCode >= 400)
00237    {
00238       SharedPtr<SipMessage> failure(new SipMessage);
00239       mDum.makeResponse(*failure, msg, returnCode);
00240       if (423 == returnCode)
00241       {
00242          failure->header(h_StatusLine).reason() = "Interval Too Brief";
00243          failure->header(h_MinExpires).value() = globalExpires;
00244       }
00245       mDum.send(failure);
00246       delete(this);
00247       return;
00248    }
00249 
00250    if (!async)
00251    {
00252       database->lockRecord(mAor);
00253 
00254       mOriginalContacts = resip::SharedPtr<ContactList>(new ContactList);
00255       database->getContacts(mAor, *mOriginalContacts);
00256    }
00257 
00258    // If no contacts are present in the request, this is simply a query.
00259    if (!msg.exists(h_Contacts))
00260    {
00261       if (async)
00262       {
00263          mAsyncState = asyncStateQueryOnly;
00264       }
00265       handler->onQuery(getHandle(), msg);
00267       return;
00268    }
00269 
00270    ParserContainer<NameAddr> contactList(msg.header(h_Contacts));
00271    ParserContainer<NameAddr>::iterator i(contactList.begin());
00272    ParserContainer<NameAddr>::iterator iEnd(contactList.end());
00273    UInt64 now=Timer::getTimeSecs();
00274    UInt32 expires=0;
00275 
00276    for (; i != iEnd; ++i)
00277    {
00278       if (!i->isWellFormed())
00279       {
00280          SharedPtr<SipMessage> failure(new SipMessage);
00281          mDum.makeResponse(*failure, msg, 400, "Malformed Contact");
00282          mDum.send(failure);
00283          if (!async)
00284          {
00285             database->unlockRecord(mAor);
00286          }
00287          delete(this);
00288          return;
00289       }
00290 
00291       expires = globalExpires;
00292       handler->getContactExpires(*i, mDum.getMasterProfile(), expires, returnCode);
00293 
00294       // Check for "Contact: *" style deregistration
00295       if (i->isAllContacts())
00296       {
00297          if (contactList.size() > 1 || expires != 0)
00298          {
00299             SharedPtr<SipMessage> failure(new SipMessage);
00300             mDum.makeResponse(*failure, msg, 400, "Invalid use of 'Contact: *'");
00301             mDum.send(failure);
00302             if (!async)
00303             {
00304                database->unlockRecord(mAor);
00305             }
00306             delete(this);
00307             return;
00308          }
00309 
00310          if (!async)
00311          {
00312             database->removeAor(mAor);
00313          }
00314          else
00315          {
00316             mAsyncLocalStore->removeAllContacts();
00317             mAsyncState = asyncStateWaitingForAcceptReject;
00318          }
00319 
00320          handler->onRemoveAll(getHandle(), msg);
00322          return;
00323       }
00324 
00325       ContactInstanceRecord rec;
00326       rec.mContact=*i;
00327       rec.mRegExpires=(UInt64)expires+now;
00328 
00329       if(i->exists(p_Instance))
00330       {
00331          rec.mInstance=i->param(p_Instance);
00332       }
00333 
00334       if(!msg.empty(h_Paths))
00335       {
00336          rec.mSipPath=msg.header(h_Paths);
00337       }
00338 
00339       rec.mLastUpdated=now;
00340       rec.mReceivedFrom=msg.getSource();
00341       rec.mPublicAddress=Helper::getClientPublicAddress(msg);
00342 
00343       bool hasFlow = tryFlow(rec,msg);
00344       
00345       if(!testFlowRequirements(rec, msg, hasFlow))
00346       {
00347          // We have rejected the request. Bail.
00348          if (!async)
00349          {
00350             database->unlockRecord(mAor);
00351          }
00352          delete(this);
00353          return;
00354       }
00355 
00356       // Add ContactInstanceRecord to List
00357       mRequestContacts.push_back(rec);
00358 
00359       // Check to see if this is a removal.
00360       if (expires == 0)
00361       {
00362          if (operation == REFRESH)
00363          {
00364             operation = REMOVE;
00365          }
00366 
00367          if (!async)
00368          {
00369             database->removeContact(mAor, rec);
00370          }
00371          else
00372          {
00373             mAsyncLocalStore->removeContact(rec);
00374          }
00375       }
00376       else // Otherwise, it's an addition or refresh.
00377       {
00378          RegistrationPersistenceManager::update_status_t status;
00379          InfoLog(<< "Adding " << mAor << " -> " << *i);
00380          DebugLog(<< "Contact has tuple " << rec.mReceivedFrom << " and detected public address " << rec.mPublicAddress);
00381 
00382          if (!async)
00383          {
00384             status = database->updateContact(mAor, rec);
00385          }
00386          else
00387          {
00388             status =  mAsyncLocalStore->updateContact(rec);
00389          }
00390 
00391          if (status == RegistrationPersistenceManager::CONTACT_CREATED)
00392          {
00393             operation = ADD;
00394          }
00395       }
00396    }
00397 
00398    // The way this works is:
00399    //
00400    //  - If no additions or removals are performed, this is a refresh
00401    //
00402    //  - If at least one contact is removed and none are added, this
00403    //    is a removal.
00404    //
00405    //  - If at least one contact is added, this is an addition, *even*
00406    //    *if* a contact was also removed.
00407 
00408    //for async processing, need to wait for accept()/reject().  If accepted, the modifications made here will be
00409    //sent to the user via asyncUpdateContacts().  The user then returns a final contact list, which is then processed
00410    //and sent back in the 200.
00411    if (async)
00412    {
00413       mAsyncState = asyncStateWaitingForAcceptReject;
00414    }
00415 
00416    switch (operation)
00417    {
00418       case REFRESH:
00419          handler->onRefresh(getHandle(), msg);
00421          return;
00422 
00423       case REMOVE:
00424          handler->onRemove(getHandle(), msg);
00426          return;
00427 
00428       case ADD:
00429          handler->onAdd(getHandle(), msg);
00431          return;
00432 
00433       default:
00434          assert(0);
00435    }
00436 }
00437 
00438 void
00439 ServerRegistration::dispatch(const DumTimeout& msg)
00440 {
00441 }
00442 
00443 EncodeStream&
00444 ServerRegistration::dump(EncodeStream& strm) const
00445 {
00446    strm << "ServerRegistration " << mAor;
00447    return strm;
00448 }
00449 
00450 bool 
00451 ServerRegistration::tryFlow(ContactInstanceRecord& rec,
00452                             const resip::SipMessage& msg)
00453 {
00454    // .bwc. ie. Can we assure that the connection the client is using on the
00455    // first hop can be re-used later?
00456    try
00457    {
00458       // Outbound logic
00459       if(InteropHelper::getOutboundSupported())
00460       {
00461          resip::NameAddr& contact(rec.mContact);
00462          if(contact.exists(p_Instance) && contact.exists(p_regid))
00463          {
00464             if(!msg.empty(h_Paths) && (msg.header(h_Paths).back().uri().exists(p_ob) ||
00465                                        InteropHelper::getAssumeFirstHopSupportsOutboundEnabled()))
00466             {
00467                rec.mRegId=contact.param(p_regid);
00468                // Edge-proxy is directly connected to the client, and ready to 
00469                // send traffic down the "connection" (TCP connection, or NAT 
00470                // pinhole, or what-have-you).
00471                mDidOutbound=true;
00472                return true;
00473             }
00474             else if(msg.header(h_Vias).size() == 1)
00475             {
00476                rec.mRegId=contact.param(p_regid);
00477                // We are directly connected to the client.
00478                // .bwc. In the outbound case, we should fail if the connection 
00479                // is gone. No recovery should be attempted by the server.
00480                rec.mUseFlowRouting = true;
00481                rec.mReceivedFrom.onlyUseExistingConnection=true;
00482                mDidOutbound=true;
00483                return true;
00484             }
00485          }
00486       }
00487 
00488       // Record-Route flow token hack, or client NAT detect hack; use with caution
00489       if(msg.header(h_Vias).size() == 1)  // client is directly connected to this server
00490       {
00491          if(InteropHelper::getRRTokenHackEnabled() || 
00492             flowTokenNeededForTls(rec) || 
00493             flowTokenNeededForSigcomp(rec) ||
00494             (InteropHelper::getClientNATDetectionMode() != InteropHelper::ClientNATDetectionDisabled &&
00495              Helper::isClientBehindNAT(msg, InteropHelper::getClientNATDetectionMode() == InteropHelper::ClientNATDetectionPrivateToPublicOnly)))
00496          {
00497                rec.mUseFlowRouting = true;
00498                rec.mReceivedFrom.onlyUseExistingConnection=false;
00499                return true;
00500          }
00501       }
00502    }
00503    catch(resip::ParseBuffer::Exception&)
00504    {}
00505    return false;
00506 }
00507 
00508 bool 
00509 ServerRegistration::testFlowRequirements(ContactInstanceRecord &rec,
00510                                           const resip::SipMessage& msg,
00511                                           bool hasFlow) const
00512 {
00513    const resip::NameAddr& contact(rec.mContact);
00514 
00515    if(contact.exists(p_Instance) && contact.exists(p_regid))
00516    {
00517       // Client has explicitly requested Outbound processing, which requires us 
00518       // to have a flow.
00519       if(!hasFlow)
00520       {
00521          SharedPtr<SipMessage> failure(new SipMessage);
00522          mDum.makeResponse(*failure, msg, 439);
00523          mDum.send(failure);
00524          return false;
00525       }
00526    }
00527 
00528    if(!hasFlow && flowTokenNeededForTls(rec))
00529    {
00530       SharedPtr<SipMessage> failure(new SipMessage);
00531       mDum.makeResponse(*failure, msg, 400, "Trying to use TLS with an IP-address in your Contact header won't work if you don't have a flow. Consider implementing outbound, or putting an FQDN in your contact header.");
00532       mDum.send(failure);
00533       return false;
00534    }
00535 
00536    if(!hasFlow && flowTokenNeededForSigcomp(rec))
00537    {
00538       SharedPtr<SipMessage> failure(new SipMessage);
00539       mDum.makeResponse(*failure, msg, 400, "Trying to use sigcomp on a connection-oriented protocol won't work if you don't have a flow. Consider implementing outbound, or using UDP/DTLS for this case.");
00540       mDum.send(failure);
00541       return false;
00542    }
00543 
00544    return true;
00545 }
00546 
00547 bool 
00548 ServerRegistration::flowTokenNeededForTls(const ContactInstanceRecord &rec) const
00549 {
00550    const resip::NameAddr& contact(rec.mContact);
00551    if(DnsUtil::isIpAddress(contact.uri().host()))
00552    {
00553       // IP address in host-part.
00554       if(contact.uri().scheme()=="sips")
00555       {
00556          // sips: and IP-address in contact. This will probably not work anyway.
00557          return true;
00558       }
00559 
00560       if(contact.uri().exists(p_transport))
00561       {
00562          TransportType type = Tuple::toTransport(contact.uri().param(p_transport));
00563          if(type==TLS || type == DTLS)
00564          {
00565             // secure transport and IP-address. Almost certainly won't work, but
00566             // we'll try anyway.
00567             return true;
00568          }
00569       }
00570    }
00571    return false;
00572 }
00573 
00574 bool 
00575 ServerRegistration::flowTokenNeededForSigcomp(const ContactInstanceRecord &rec) const
00576 {
00577    const resip::NameAddr& contact(rec.mContact);
00578 
00579    if(contact.uri().exists(p_sigcompId))
00580    {
00581       if(contact.uri().exists(p_transport))
00582       {
00583          TransportType type = Tuple::toTransport(contact.uri().param(p_transport));
00584          if(type == TLS || type == TCP)
00585          {
00586             // Client is using sigcomp on the first hop using a connection-
00587             // oriented transport. For this to work, that connection has to be
00588             // reused for all traffic.
00589             return true;
00590          }
00591       }
00592       else
00593       {
00594          // ?bwc? Client is using sigcomp, but we're not sure whether this is
00595          // over a connection-oriented transport or not.
00596          DebugLog(<< "Client is using sigcomp, but we're not sure whether this "
00597                      "is over a connection-oriented transport or not, because "
00598                      "the contact doesn't have a transport param in it. It is "
00599                      "possible this will work though, so we'll let it proceed."
00600                      );
00601       }
00602    }
00603    return false;
00604 }
00605 
00606 
00607 void
00608 ServerRegistration::asyncProcessFinalOkMsg(SipMessage &msg, ContactPtrList &contacts)
00609 {
00610    if (contacts.size() > 0)
00611    {
00612       ContactPtrList::iterator it(contacts.begin());
00613       ContactPtrList::iterator itEnd(contacts.end());
00614 
00615       std::auto_ptr<ContactPtrList> expired;
00616 
00617       UInt64 now=Timer::getTimeSecs();
00618 
00619       for (;it != itEnd;++it)
00620       {
00621          resip::SharedPtr<ContactInstanceRecord> rec(*it);
00622 
00623          if (!rec)
00624          {
00625             assert(0);
00626             continue;
00627          }
00628 
00629          if (rec->mRegExpires <= now)
00630          {
00631             if (!expired.get())
00632             {
00633                expired = std::auto_ptr<ContactPtrList>(new ContactPtrList());
00634             }
00635             expired->push_back(rec);
00636             continue;
00637          }
00638 
00639          rec->mContact.param(p_expires) = UInt32(rec->mRegExpires - now);
00640          msg.header(h_Contacts).push_back(rec->mContact);
00641       }
00642 
00643       if (expired.get() && expired->size() > 0)
00644       {
00645          mDum.mServerRegistrationHandler->asyncRemoveExpired(getHandle(),mAor,expired);
00647          return;
00648       }
00649    }
00650 }
00651 
00652 void
00653 ServerRegistration::processFinalOkMsg(SipMessage &msg, ContactList &contacts)
00654 {
00655    //build the 200Ok and remove any expired entries.
00656    //the non-asynchronous behavior is to call the database directly, the async behavior is to build a
00657    //list of all expired entries and send it to the handler.
00658    if (contacts.size() > 0)
00659    {
00660       ContactList::iterator it(contacts.begin());
00661       ContactList::iterator itEnd(contacts.end());
00662 
00663       RegistrationPersistenceManager *database = mDum.mRegistrationPersistenceManager;
00664       UInt64 now=Timer::getTimeSecs();
00665 
00666       for (;it != itEnd;++it)
00667       {
00668          if (it->mRegExpires <= now)
00669          {
00670             database->removeContact(mAor,*it);
00671             continue;
00672          }
00673          it->mContact.param(p_expires) = UInt32(it->mRegExpires - now);
00674          msg.header(h_Contacts).push_back(it->mContact);
00675       }
00676    }
00677 }
00678 
00679 bool
00680 ServerRegistration::asyncProvideContacts(std::auto_ptr<resip::ContactPtrList> contacts)
00681 {
00682    switch (mAsyncState)
00683    {
00684       case asyncStateWaitingForInitialContactList:
00685       {
00686          assert(mAsyncLocalStore.get() == 0);
00687          mAsyncLocalStore = resip::SharedPtr<AsyncLocalStore>(new AsyncLocalStore(contacts));
00688          mAsyncState = asyncStateProcessingRegistration;
00689          processRegistration(mRequest);
00690          break;
00691       }
00692       case asyncStateWaitingForAcceptReject:
00693       {
00694          assert(0); //need to call accept() or reject(), wait for asyncUpdateContacts(), then call this function.
00695          return false;
00696       }
00697       case asyncStateAcceptedWaitingForFinalContactList:
00698       {
00699          mAsyncState = asyncStateProvidedFinalContacts;
00700          asyncProcessFinalContacts(contacts);
00701          break;
00702       }
00703       default:
00704       {
00705          assert(0);
00706          return false;
00707       }
00708    }
00709 
00710    return true;
00711 }
00712 
00713 void
00714 ServerRegistration::asyncProcessFinalContacts(std::auto_ptr<resip::ContactPtrList> contacts)
00715 {
00716    if (contacts.get())
00717    {
00718       if (!mAsyncOkMsg.get())
00719       {
00720          assert(0);
00721       }
00722       else
00723       {
00724          asyncProcessFinalOkMsg(*mAsyncOkMsg,*contacts);
00725       }
00726    }
00727 
00728    mAsyncState = asyncStateNone;
00729    mDum.send(mAsyncOkMsg);
00730    mAsyncOkMsg.reset();
00731    delete(this);
00732 }
00733 
00734 void
00735 ServerRegistration::AsyncLocalStore::create(std::auto_ptr<ContactPtrList> originalContacts)
00736 {
00737    mModifiedContacts = originalContacts;
00738    mLog = std::auto_ptr<ContactRecordTransactionLog>(new ContactRecordTransactionLog());
00739 }
00740 
00741 void
00742 ServerRegistration::AsyncLocalStore::destroy(void)
00743 {
00744    mModifiedContacts.reset();
00745    mLog.reset();
00746 }
00747 
00748 RegistrationPersistenceManager::update_status_t
00749 ServerRegistration::AsyncLocalStore::updateContact(const ContactInstanceRecord &rec)
00750 {
00751    if (!mModifiedContacts.get() || !mLog.get())
00752    {
00753       assert(0);
00754       return RegistrationPersistenceManager::CONTACT_UPDATED;
00755    }
00756 
00757    ContactPtrList::iterator it(mModifiedContacts->begin());
00758    ContactPtrList::iterator itEnd(mModifiedContacts->end());
00759 
00760    resip::SharedPtr<ContactRecordTransaction> logEntry;
00761 
00762    // See if the contact is already present. We use URI matching rules here.
00763    for (; it != itEnd; ++it)
00764    {
00765       if ((*it) && **it == rec)
00766       {
00767          **it = rec;
00768 
00769          logEntry = resip::SharedPtr<ContactRecordTransaction>(new ContactRecordTransaction(ContactRecordTransaction::update,*it));
00770          mLog->push_back(logEntry);
00771 
00772          return RegistrationPersistenceManager::CONTACT_UPDATED;
00773       }
00774    }
00775 
00776    // This is a new contact, so we add it to the list.
00777    resip::SharedPtr<ContactInstanceRecord> newRec(new ContactInstanceRecord(rec));
00778 
00779    logEntry = resip::SharedPtr<ContactRecordTransaction>(new ContactRecordTransaction(ContactRecordTransaction::create,newRec));
00780    mLog->push_back(logEntry);
00781 
00782    mModifiedContacts->push_back(newRec);
00783 
00784    return RegistrationPersistenceManager::CONTACT_CREATED;
00785 }
00786 
00787 void
00788 ServerRegistration::AsyncLocalStore::removeContact(const ContactInstanceRecord &rec)
00789 {
00790    if (!mModifiedContacts.get() || !mLog.get())
00791    {
00792       assert(0);
00793       return;
00794    }
00795 
00796    ContactPtrList::iterator it(mModifiedContacts->begin());
00797    ContactPtrList::iterator itEnd(mModifiedContacts->end());
00798 
00799    // See if the contact is present. We use URI matching rules here.
00800    for (; it != itEnd; ++it)
00801    {
00802       if ((*it) && **it == rec)
00803       {
00804          resip::SharedPtr<ContactRecordTransaction>
00805          logEntry(resip::SharedPtr<ContactRecordTransaction>
00806                   (new ContactRecordTransaction(ContactRecordTransaction::remove,*it)));
00807 
00808          mLog->push_back(logEntry);
00809 
00810          mModifiedContacts->erase(it);
00811          return;
00812       }
00813    }
00814 }
00815 
00816 void
00817 ServerRegistration::AsyncLocalStore::removeAllContacts(void)
00818 {
00819    if (!mModifiedContacts.get() || !mLog.get())
00820    {
00821       return;
00822    }
00823 
00824    resip::SharedPtr<ContactInstanceRecord> recNull;
00825 
00826    resip::SharedPtr<ContactRecordTransaction>
00827    logEntry(resip::SharedPtr<ContactRecordTransaction>(new ContactRecordTransaction(ContactRecordTransaction::removeAll,recNull)));
00828 
00829    mLog->push_back(logEntry);
00830 
00831    mModifiedContacts->clear();
00832 }
00833 
00834 
00835 /* ====================================================================
00836  * The Vovida Software License, Version 1.0 
00837  * 
00838  * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
00839  * 
00840  * Redistribution and use in source and binary forms, with or without
00841  * modification, are permitted provided that the following conditions
00842  * are met:
00843  * 
00844  * 1. Redistributions of source code must retain the above copyright
00845  *    notice, this list of conditions and the following disclaimer.
00846  * 
00847  * 2. Redistributions in binary form must reproduce the above copyright
00848  *    notice, this list of conditions and the following disclaimer in
00849  *    the documentation and/or other materials provided with the
00850 
00851  *    distribution.
00852  * 
00853  * 3. The names "VOCAL", "Vovida Open Communication Application Library",
00854  *    and "Vovida Open Communication Application Library (VOCAL)" must
00855  *    not be used to endorse or promote products derived from this
00856  *    software without prior written permission. For written
00857  *    permission, please contact vocal@vovida.org.
00858  *
00859  * 4. Products derived from this software may not be called "VOCAL", nor
00860  *    may "VOCAL" appear in their name, without prior written
00861  *    permission of Vovida Networks, Inc.
00862  * 
00863  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
00864  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00865  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
00866  * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
00867  * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
00868  * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
00869  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00870  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00871  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
00872  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00873  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
00874  * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
00875  * DAMAGE.
00876  * 
00877  * ====================================================================
00878  * 
00879  * This software consists of voluntary contributions made by Vovida
00880  * Networks, Inc. and many individuals on behalf of Vovida Networks,
00881  * Inc.  For more information on Vovida Networks, Inc., please see
00882  * <http://www.vovida.org/>.
00883  *
00884  */