/[resiprocate]/main/resip/dum/InMemorySyncRegDb.cxx
ViewVC logotype

Contents of /main/resip/dum/InMemorySyncRegDb.cxx

Parent Directory Parent Directory | Revision Log Revision Log


Revision 10868 - (show annotations) (download)
Tue Jan 14 15:09:52 2014 UTC (5 years, 10 months ago) by sgodin
File MIME type: text/plain
File size: 12911 byte(s)
-make sure multiple RegSync Servers can be added and dispatched to
-fixes repro bug when starting both IPv4 and IPv6 regsync servers
1 #include "resip/dum/InMemorySyncRegDb.hxx"
2 #include "rutil/Timer.hxx"
3 #include "rutil/Logger.hxx"
4 #include "rutil/WinLeakCheck.hxx"
5
6 using namespace resip;
7
8 #define RESIPROCATE_SUBSYSTEM Subsystem::DUM
9
10 class RemoveIfRequired
11 {
12 protected:
13 UInt64 mNow;
14 unsigned int mRemoveLingerSecs;
15 public:
16 RemoveIfRequired(UInt64& now, unsigned int removeLingerSecs) :
17 mNow(now),
18 mRemoveLingerSecs(removeLingerSecs) {}
19 bool operator () (const ContactInstanceRecord& rec)
20 {
21 return mustRemove(rec);
22 }
23 bool mustRemove(const ContactInstanceRecord& rec)
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(). */
38 void
39 contactsRemoveIfRequired(ContactList& contacts, UInt64& now,
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
56 InMemorySyncRegDb::InMemorySyncRegDb(unsigned int removeLingerSecs) :
57 mRemoveLingerSecs(removeLingerSecs)
58 {
59 }
60
61 InMemorySyncRegDb::~InMemorySyncRegDb()
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
71 void
72 InMemorySyncRegDb::addHandler(InMemorySyncRegDbHandler* handler)
73 {
74 Lock lock(mHandlerMutex);
75 mHandlers.push_back(handler);
76 }
77
78 void
79 InMemorySyncRegDb::removeHandler(InMemorySyncRegDbHandler* handler)
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
92 void
93 InMemorySyncRegDb::invokeOnAorModified(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 (*it)->onAorModified(aor, contacts);
99 }
100 }
101
102 void
103 InMemorySyncRegDb::invokeOnInitialSyncAor(unsigned int connectionId, const resip::Uri& aor, const ContactList& contacts)
104 {
105 Lock lock(mHandlerMutex);
106 for(HandlerList::iterator it = mHandlers.begin(); it != mHandlers.end(); it++)
107 {
108 (*it)->onInitialSyncAor(connectionId, aor, contacts);
109 }
110 }
111
112 void
113 InMemorySyncRegDb::initialSync(unsigned int connectionId)
114 {
115 Lock g(mDatabaseMutex);
116 UInt64 now = Timer::getTimeSecs();
117 for(database_map_t::iterator it = mDatabase.begin(); it != mDatabase.end(); it++)
118 {
119 if(it->second)
120 {
121 ContactList& contacts = *(it->second);
122 if(mRemoveLingerSecs > 0)
123 {
124 contactsRemoveIfRequired(contacts, now, mRemoveLingerSecs);
125 }
126 invokeOnInitialSyncAor(connectionId, it->first, contacts);
127 }
128 }
129 }
130
131 void
132 InMemorySyncRegDb::addAor(const Uri& aor,
133 const ContactList& contacts)
134 {
135 Lock g(mDatabaseMutex);
136 database_map_t::iterator it = mDatabase.find(aor);
137 if(it != mDatabase.end())
138 {
139 if(it->second)
140 {
141 *(it->second) = contacts;
142 }
143 else
144 {
145 it->second = new ContactList(contacts);
146 }
147 }
148 else
149 {
150 mDatabase[aor] = new ContactList(contacts);
151 }
152 invokeOnAorModified(aor, contacts);
153 }
154
155 void
156 InMemorySyncRegDb::removeAor(const Uri& aor)
157 {
158 database_map_t::iterator i;
159
160 Lock g(mDatabaseMutex);
161 i = mDatabase.find(aor);
162 //DebugLog (<< "Removing registration bindings " << aor);
163 if (i != mDatabase.end())
164 {
165 if (i->second)
166 {
167 if(mRemoveLingerSecs > 0)
168 {
169 ContactList& contacts = *(i->second);
170 UInt64 now = Timer::getTimeSecs();
171 for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
172 {
173 // Don't delete record - set expires to 0
174 it->mRegExpires = 0;
175 it->mLastUpdated = now;
176 }
177 invokeOnAorModified(aor, contacts);
178 }
179 else
180 {
181 delete i->second;
182 // Setting this to 0 causes it to be removed when we unlock the AOR.
183 i->second = 0;
184 ContactList emptyList;
185 invokeOnAorModified(aor, emptyList);
186 }
187 }
188 }
189 }
190
191 void
192 InMemorySyncRegDb::getAors(InMemorySyncRegDb::UriList& container)
193 {
194 container.clear();
195 Lock g(mDatabaseMutex);
196 for( database_map_t::const_iterator it = mDatabase.begin();
197 it != mDatabase.end(); it++)
198 {
199 container.push_back(it->first);
200 }
201 }
202
203 bool
204 InMemorySyncRegDb::aorIsRegistered(const Uri& aor)
205 {
206 Lock g(mDatabaseMutex);
207 database_map_t::iterator i = mDatabase.find(aor);
208 if (i != mDatabase.end() && i->second == 0)
209 {
210 if(mRemoveLingerSecs > 0)
211 {
212 ContactList& contacts = *(i->second);
213 UInt64 now = Timer::getTimeSecs();
214 for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
215 {
216 if(it->mRegExpires > now)
217 {
218 return true;
219 }
220 }
221 }
222 else
223 {
224 return true;
225 }
226 }
227 return false;
228 }
229
230 void
231 InMemorySyncRegDb::lockRecord(const Uri& aor)
232 {
233 Lock g2(mLockedRecordsMutex);
234
235 DebugLog(<< "InMemorySyncRegDb::lockRecord: aor=" << aor << " threadid=" << ThreadIf::selfId());
236
237 {
238 Lock g1(mDatabaseMutex);
239 // This forces insertion if the record does not yet exist.
240 mDatabase[aor];
241 }
242
243 while (mLockedRecords.count(aor))
244 {
245 mRecordUnlocked.wait(mLockedRecordsMutex);
246 }
247
248 mLockedRecords.insert(aor);
249 }
250
251 void
252 InMemorySyncRegDb::unlockRecord(const Uri& aor)
253 {
254 Lock g2(mLockedRecordsMutex);
255
256 DebugLog(<< "InMemorySyncRegDb::unlockRecord: aor=" << aor << " threadid=" << ThreadIf::selfId());
257
258 {
259 Lock g1(mDatabaseMutex);
260 // If the pointer is null, we remove the record from the map.
261 database_map_t::iterator i = mDatabase.find(aor);
262
263 // The record must have been inserted when we locked it in the first place
264 assert (i != mDatabase.end());
265
266 if (i->second == 0)
267 {
268 mDatabase.erase(i);
269 }
270 }
271
272 mLockedRecords.erase(aor);
273 mRecordUnlocked.broadcast();
274 }
275
276 RegistrationPersistenceManager::update_status_t
277 InMemorySyncRegDb::updateContact(const resip::Uri& aor,
278 const ContactInstanceRecord& rec)
279 {
280 ContactList *contactList = 0;
281
282 {
283 Lock g(mDatabaseMutex);
284
285 database_map_t::iterator i;
286 i = mDatabase.find(aor);
287 if (i == mDatabase.end() || i->second == 0)
288 {
289 contactList = new ContactList();
290 mDatabase[aor] = contactList;
291 }
292 else
293 {
294 contactList = i->second;
295 }
296 }
297
298 assert(contactList);
299
300 ContactList::iterator j;
301
302 // See if the contact is already present. We use URI matching rules here.
303 for (j = contactList->begin(); j != contactList->end(); j++)
304 {
305 if (*j == rec)
306 {
307 update_status_t status = CONTACT_UPDATED;
308 if(mRemoveLingerSecs > 0 && j->mRegExpires == 0)
309 {
310 // If records linger, then check if updating a lingering record, if so
311 // modify status to CREATED so that ServerRegistration will properly generate
312 // an onAdd callback, instead of onRefresh.
313 // When contacts linger, their expires time is set to 0
314 status = CONTACT_CREATED;
315 }
316 *j=rec;
317 if(!rec.mSyncContact) invokeOnAorModified(aor, *contactList);
318 return status;
319 }
320 }
321
322 // This is a new contact, so we add it to the list.
323 contactList->push_back(rec);
324 if(!rec.mSyncContact) invokeOnAorModified(aor, *contactList);
325 return CONTACT_CREATED;
326 }
327
328 void
329 InMemorySyncRegDb::removeContact(const Uri& aor,
330 const ContactInstanceRecord& rec)
331 {
332 ContactList *contactList = 0;
333
334 {
335 Lock g(mDatabaseMutex);
336
337 database_map_t::iterator i;
338 i = mDatabase.find(aor);
339 if (i == mDatabase.end() || i->second == 0)
340 {
341 return;
342 }
343 contactList = i->second;
344 }
345
346 ContactList::iterator j;
347
348 // See if the contact is present. We use URI matching rules here.
349 for (j = contactList->begin(); j != contactList->end(); j++)
350 {
351 if (*j == rec)
352 {
353 if(mRemoveLingerSecs > 0)
354 {
355 j->mRegExpires = 0;
356 j->mLastUpdated = Timer::getTimeSecs();
357 if(!rec.mSyncContact) invokeOnAorModified(aor, *contactList);
358 }
359 else
360 {
361 contactList->erase(j);
362 if (contactList->empty())
363 {
364 removeAor(aor);
365 }
366 else
367 {
368 if(!rec.mSyncContact) invokeOnAorModified(aor, *contactList);
369 }
370 }
371 return;
372 }
373 }
374 }
375
376 void
377 InMemorySyncRegDb::getContacts(const Uri& aor, ContactList& container)
378 {
379 Lock g(mDatabaseMutex);
380 database_map_t::iterator i = mDatabase.find(aor);
381 if (i == mDatabase.end() || i->second == 0)
382 {
383 container.clear();
384 return;
385 }
386 if(mRemoveLingerSecs > 0)
387 {
388 ContactList& contacts = *(i->second);
389 UInt64 now = Timer::getTimeSecs();
390 contactsRemoveIfRequired(contacts, now, mRemoveLingerSecs);
391 container.clear();
392 for(ContactList::iterator it = contacts.begin(); it != contacts.end(); it++)
393 {
394 if(it->mRegExpires > now)
395 {
396 container.push_back(*it);
397 }
398 }
399 }
400 else
401 {
402 container = *(i->second);
403 }
404 }
405
406 void
407 InMemorySyncRegDb::getContactsFull(const Uri& aor, ContactList& container)
408 {
409 Lock g(mDatabaseMutex);
410 database_map_t::iterator i = mDatabase.find(aor);
411 if (i == mDatabase.end() || i->second == 0)
412 {
413 container.clear();
414 return;
415 }
416 ContactList& contacts = *(i->second);
417 if(mRemoveLingerSecs > 0)
418 {
419 UInt64 now = Timer::getTimeSecs();
420 contactsRemoveIfRequired(contacts, now, mRemoveLingerSecs);
421 }
422 container = contacts;
423 }
424
425
426 /* ====================================================================
427 * The Vovida Software License, Version 1.0
428 *
429 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
430 *
431 * Redistribution and use in source and binary forms, with or without
432 * modification, are permitted provided that the following conditions
433 * are met:
434 *
435 * 1. Redistributions of source code must retain the above copyright
436 * notice, this list of conditions and the following disclaimer.
437 *
438 * 2. Redistributions in binary form must reproduce the above copyright
439 * notice, this list of conditions and the following disclaimer in
440 * the documentation and/or other materials provided with the
441 * distribution.
442 *
443 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
444 * and "Vovida Open Communication Application Library (VOCAL)" must
445 * not be used to endorse or promote products derived from this
446 * software without prior written permission. For written
447 * permission, please contact vocal@vovida.org.
448 *
449 * 4. Products derived from this software may not be called "VOCAL", nor
450 * may "VOCAL" appear in their name, without prior written
451 * permission of Vovida Networks, Inc.
452 *
453 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
454 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
455 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
456 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
457 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
458 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
459 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
460 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
461 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
462 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
463 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
464 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
465 * DAMAGE.
466 *
467 * ====================================================================
468 *
469 * This software consists of voluntary contributions made by Vovida
470 * Networks, Inc. and many individuals on behalf of Vovida Networks,
471 * Inc. For more information on Vovida Networks, Inc., please see
472 * <http://www.vovida.org/>.
473 *
474 */

Properties

Name Value
svn:eol-style native
svn:mime-type text/plain

webmaster AT resiprocate DOT org
ViewVC Help
Powered by ViewVC 1.1.27