reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
InMemorySyncRegDb.cxx
Go to the documentation of this file.
2#include "rutil/Timer.hxx"
3#include "rutil/Logger.hxx"
5
6using namespace resip;
7
8#define RESIPROCATE_SUBSYSTEM Subsystem::DUM
9
11{
12protected:
14 unsigned int mRemoveLingerSecs;
15public:
16 RemoveIfRequired(uint64_t& now, unsigned int removeLingerSecs) :
17 mNow(now),
18 mRemoveLingerSecs(removeLingerSecs) {}
20 {
21 return mustRemove(rec);
22 }
24 {
25 if((rec.mRegExpires <= mNow) && ((mNow - rec.mLastUpdated) > mRemoveLingerSecs))
26 {
27 DebugLog(<< "ContactInstanceRecord removed after linger: " << rec.mContact);
28 return true;
29 }
30 return false;
31 }
32};
33
34/* Solaris with libCstd seems to choke on the use of an
35 object (such as RemoveIfRequired) as a predicate for remove_if.
36 Therefore, this wrapper function implements a workaround,
37 iterating the list explicitly and using erase(). */
38void
40 unsigned int removeLingerSecs)
41{
42 RemoveIfRequired rei(now, removeLingerSecs);
43#ifdef __SUNPRO_CC
44 for(ContactList::iterator i = contacts.begin(); i != contacts.end(); )
45 {
46 if(rei.mustRemove(*i))
47 i = contacts.erase(i);
48 else
49 ++i;
50 }
51#else
52 contacts.remove_if(rei);
53#endif
54}
55
56InMemorySyncRegDb::InMemorySyncRegDb(unsigned int removeLingerSecs) :
57 mRemoveLingerSecs(removeLingerSecs)
58{
59}
60
62{
63 for( database_map_t::const_iterator it = mDatabase.begin();
64 it != mDatabase.end(); it++)
65 {
66 delete it->second;
67 }
68 mDatabase.clear();
69}
70
71void
73{
74 Lock lock(mHandlerMutex);
75 mHandlers.push_back(handler);
76}
77
78void
80{
81 Lock lock(mHandlerMutex);
82 for(HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
83 {
84 if(*it == handler)
85 {
86 mHandlers.erase(it);
87 break;
88 }
89 }
90}
91
92void
93InMemorySyncRegDb::invokeOnAorModified(bool sync, const resip::Uri& aor, const ContactList& contacts)
94{
95 Lock lock(mHandlerMutex);
96 for(HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
97 {
98 // If handler mode is all, then send notification, otherwise handler mode is sync and we check the passed
99 // in sync flag
100 if (sync || (*it)->getMode() == InMemorySyncRegDbHandler::AllChanges)
101 {
102 (*it)->onAorModified(aor, contacts);
103 }
104 }
105}
106
107void
108InMemorySyncRegDb::invokeOnInitialSyncAor(unsigned int connectionId, const resip::Uri& aor, const ContactList& contacts)
109{
110 Lock lock(mHandlerMutex);
111 for (HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
112 {
113 if ((*it)->getMode() == InMemorySyncRegDbHandler::SyncServer)
114 {
115 (*it)->onInitialSyncAor(connectionId, aor, contacts);
116 }
117 }
118}
119
120void
121InMemorySyncRegDb::initialSync(unsigned int connectionId)
122{
125 for(database_map_t::iterator it = mDatabase.begin(); it != mDatabase.end(); it++)
126 {
127 if(it->second)
128 {
129 ContactList& contacts = *(it->second);
130 if(mRemoveLingerSecs > 0)
131 {
133 }
134 invokeOnInitialSyncAor(connectionId, it->first, contacts);
135 }
136 }
137}
138
139void
141 const ContactList& contacts)
142{
144 database_map_t::iterator it = mDatabase.find(aor);
145 if(it != mDatabase.end())
146 {
147 if(it->second)
148 {
149 *(it->second) = contacts;
150 }
151 else
152 {
153 it->second = new ContactList(contacts);
154 }
155 }
156 else
157 {
158 mDatabase[aor] = new ContactList(contacts);
159 }
160 invokeOnAorModified(true /* sync? */, aor, contacts);
161}
162
163void
165{
166 database_map_t::iterator i;
167
169 i = mDatabase.find(aor);
170 //DebugLog (<< "Removing registration bindings " << aor);
171 if (i != mDatabase.end())
172 {
173 if (i->second)
174 {
175 if(mRemoveLingerSecs > 0)
176 {
177 ContactList& contacts = *(i->second);
179 for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
180 {
181 // Don't delete record - set expires to 0
182 it->mRegExpires = 0;
183 it->mLastUpdated = now;
184 }
185 invokeOnAorModified(true /* sync? */, aor, contacts);
186 }
187 else
188 {
189 delete i->second;
190 // Setting this to 0 causes it to be removed when we unlock the AOR.
191 i->second = 0;
192 ContactList emptyList;
193 invokeOnAorModified(true /* sync? */, aor, emptyList);
194 }
195 }
196 }
197}
198
199void
201{
202 container.clear();
204 for( database_map_t::const_iterator it = mDatabase.begin();
205 it != mDatabase.end(); it++)
206 {
207 container.push_back(it->first);
208 }
209}
210
211bool
213{
214 return aorIsRegistered(aor, 0);
215}
216
217bool
219{
220 bool registered = false;
221
223 database_map_t::iterator i = mDatabase.find(aor);
224 if (i != mDatabase.end() && i->second != 0)
225 {
226 if (mRemoveLingerSecs > 0 || maxExpires)
227 {
228 ContactList& contacts = *(i->second);
230 for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
231 {
232 if(it->mRegExpires > now)
233 {
234 registered = true;
235 if (maxExpires)
236 {
237 *maxExpires = resipMax(*maxExpires, it->mRegExpires);
238 }
239 else
240 {
241 break; // Not looking for maxExpires - so we can quit iterating now
242 }
243 }
244 }
245 }
246 else
247 {
248 registered = true;
249 }
250 }
251 return registered;
252}
253
254void
256{
258 DebugLog(<< "InMemorySyncRegDb::lockRecord: aor=" << aor << " threadid=" << ThreadIf::selfId());
259
260 {
262 // This forces insertion if the record does not yet exist.
263 mDatabase[aor];
264 }
265
266 while (mLockedRecords.find(aor) != mLockedRecords.end())
267 {
268 mRecordUnlocked.wait(g2);
269 }
270
271 mLockedRecords.insert(aor);
272}
273
274void
276{
278 DebugLog(<< "InMemorySyncRegDb::unlockRecord: aor=" << aor << " threadid=" << ThreadIf::selfId());
279
280 {
282 // If the pointer is null, we remove the record from the map.
283 database_map_t::iterator i = mDatabase.find(aor);
284
285 // The record must have been inserted when we locked it in the first place
286 resip_assert (i != mDatabase.end());
287
288 if (i->second == 0)
289 {
290 mDatabase.erase(i);
291 }
292 }
293
294 mLockedRecords.erase(aor);
295 mRecordUnlocked.notify_all();
296}
297
300 const ContactInstanceRecord& rec)
301{
302 ContactList *contactList = 0;
303
304 {
306
307 database_map_t::iterator i;
308 i = mDatabase.find(aor);
309 if (i == mDatabase.end() || i->second == 0)
310 {
311 contactList = new ContactList();
312 mDatabase[aor] = contactList;
313 }
314 else
315 {
316 contactList = i->second;
317 }
318 }
319
320 resip_assert(contactList);
321
322 ContactList::iterator j;
323
324 // See if the contact is already present. We use URI matching rules here.
325 for (j = contactList->begin(); j != contactList->end(); j++)
326 {
327 if (*j == rec)
328 {
330 if(mRemoveLingerSecs > 0 && j->mRegExpires == 0)
331 {
332 // If records linger, then check if updating a lingering record, if so
333 // modify status to CREATED so that ServerRegistration will properly generate
334 // an onAdd callback, instead of onRefresh.
335 // When contacts linger, their expires time is set to 0
336 status = CONTACT_CREATED;
337 }
338 *j=rec;
339 // Only pass sync as true if this update didn't just come from an inbound sync operation
340 invokeOnAorModified(!rec.mSyncContact /* sync? */, aor, *contactList);
341 return status;
342 }
343 }
344
345 // This is a new contact, so we add it to the list.
346 contactList->push_back(rec);
347 // Only pass sync as true if this update didn't just come from an inbound sync operation
348 invokeOnAorModified(!rec.mSyncContact /* sync? */, aor, *contactList);
349 return CONTACT_CREATED;
350}
351
352void
354 const ContactInstanceRecord& rec)
355{
356 ContactList *contactList = 0;
357
358 {
360
361 database_map_t::iterator i;
362 i = mDatabase.find(aor);
363 if (i == mDatabase.end() || i->second == 0)
364 {
365 return;
366 }
367 contactList = i->second;
368 }
369
370 ContactList::iterator j;
371
372 // See if the contact is present. We use URI matching rules here.
373 for (j = contactList->begin(); j != contactList->end(); j++)
374 {
375 if (*j == rec)
376 {
377 if(mRemoveLingerSecs > 0)
378 {
379 j->mRegExpires = 0;
380 j->mLastUpdated = Timer::getTimeSecs();
381 // Only pass sync as true if this update didn't just come from an inbound sync operation
382 invokeOnAorModified(!rec.mSyncContact /* sync? */, aor, *contactList);
383 }
384 else
385 {
386 contactList->erase(j);
387 if (contactList->empty())
388 {
389 removeAor(aor);
390 }
391 else
392 {
393 // Only pass sync as true if this update didn't just come from an inbound sync operation
394 invokeOnAorModified(!rec.mSyncContact /* sync? */, aor, *contactList);
395 }
396 }
397 return;
398 }
399 }
400}
401
402void
404{
406 database_map_t::iterator i = mDatabase.find(aor);
407 if (i == mDatabase.end() || i->second == 0)
408 {
409 container.clear();
410 return;
411 }
412 if(mRemoveLingerSecs > 0)
413 {
414 ContactList& contacts = *(i->second);
417 container.clear();
418 for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
419 {
420 if(it->mRegExpires > now)
421 {
422 container.push_back(*it);
423 }
424 }
425 }
426 else
427 {
428 container = *(i->second);
429 }
430}
431
432void
434{
436 database_map_t::iterator i = mDatabase.find(aor);
437 if (i == mDatabase.end() || i->second == 0)
438 {
439 container.clear();
440 return;
441 }
442 ContactList& contacts = *(i->second);
443 if(mRemoveLingerSecs > 0)
444 {
447 }
448 container = contacts;
449}
450
451
452/* ====================================================================
453 * The Vovida Software License, Version 1.0
454 *
455 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
456 *
457 * Redistribution and use in source and binary forms, with or without
458 * modification, are permitted provided that the following conditions
459 * are met:
460 *
461 * 1. Redistributions of source code must retain the above copyright
462 * notice, this list of conditions and the following disclaimer.
463 *
464 * 2. Redistributions in binary form must reproduce the above copyright
465 * notice, this list of conditions and the following disclaimer in
466 * the documentation and/or other materials provided with the
467 * distribution.
468 *
469 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
470 * and "Vovida Open Communication Application Library (VOCAL)" must
471 * not be used to endorse or promote products derived from this
472 * software without prior written permission. For written
473 * permission, please contact vocal@vovida.org.
474 *
475 * 4. Products derived from this software may not be called "VOCAL", nor
476 * may "VOCAL" appear in their name, without prior written
477 * permission of Vovida Networks, Inc.
478 *
479 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
480 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
481 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
482 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
483 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
484 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
485 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
486 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
487 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
488 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
489 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
490 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
491 * DAMAGE.
492 *
493 * ====================================================================
494 *
495 * This software consists of voluntary contributions made by Vovida
496 * Networks, Inc. and many individuals on behalf of Vovida Networks,
497 * Inc. For more information on Vovida Networks, Inc., please see
498 * <http://www.vovida.org/>.
499 *
500 */
void contactsRemoveIfRequired(ContactList &contacts, uint64_t &now, unsigned int removeLingerSecs)
#define DebugLog(args_)
Definition Logger.hxx:128
#define resip_assert(x)
This file needs to work for both C and C++ code.
RemoveIfRequired(uint64_t &now, unsigned int removeLingerSecs)
bool operator()(const ContactInstanceRecord &rec)
unsigned int mRemoveLingerSecs
bool mustRemove(const ContactInstanceRecord &rec)
A single contact record, bound to an Aor during registration.
virtual void removeContact(const Uri &aor, const ContactInstanceRecord &rec)
virtual void removeAor(const Uri &aor)
virtual update_status_t updateContact(const resip::Uri &aor, const ContactInstanceRecord &rec)
virtual void addHandler(InMemorySyncRegDbHandler *handler)
virtual void unlockRecord(const Uri &aor)
virtual bool aorIsRegistered(const Uri &aor)
virtual void getContactsFull(const Uri &aor, ContactList &container)
void invokeOnInitialSyncAor(unsigned int connectionId, const resip::Uri &aor, const ContactList &contacts)
InMemorySyncRegDb(unsigned int removeLingerSecs=0)
virtual void initialSync(unsigned int connectionId)
virtual void addAor(const Uri &aor, const ContactList &contacts)
virtual void getAors(UriList &container)
return all the AOR in the DB
virtual void getContacts(const Uri &aor, ContactList &container)
virtual void lockRecord(const Uri &aor)
void invokeOnAorModified(bool sync, const resip::Uri &aor, const ContactList &contacts)
virtual void removeHandler(InMemorySyncRegDbHandler *handler)
static Id selfId()
Definition ThreadIf.cxx:124
static uint64_t getTimeSecs()
Returns the current clock time in seconds.
Definition Timer.hxx:78
Represents the "SIP-URI" and "SIPS-URI" elements in the RFC 3261 grammar.
Definition Uri.hxx:22
dcm! – add UnusedChecking(_enum) below;
std::unique_lock< Mutex > Lock
A convenience class to lock a Lockable (such as a Mutex) on object creation, and unlock on destructio...
Definition Lock.hxx:28
unsigned long long uint64_t
Definition Stun.hxx:39
const _Tp & resipMax(const _Tp &__a, const _Tp &__b)
Definition compat.hxx:194
std::list< ContactInstanceRecord > ContactList
unsigned __int64 uint64_t
Definition stdint.h:95