reSIProcate
SIP stack, Dialog Usage Manager and related libraries
Loading...
Searching...
No Matches
RRCache.cxx
Go to the documentation of this file.
1#if defined(HAVE_CONFIG_H)
2#include "config.h"
3#endif
4
5#include "AresCompat.hxx"
6
7#ifndef WIN32
8#include <sys/types.h>
9#include <sys/socket.h>
10#include <arpa/inet.h>
11#ifndef __CYGWIN__
12# include <netinet/in.h>
13# include <arpa/nameser.h>
14# include <resolv.h>
15#endif
16#include <netdb.h>
17#include <netinet/in.h>
18#else
19#include <Winsock2.h>
20#include <svcguid.h>
21#ifdef USE_IPV6
22#include <ws2tcpip.h>
23#endif
24#endif
25
26#include <set>
27#include <vector>
28#include <list>
29#include <map>
30#include "rutil/ResipAssert.h"
32#include "rutil/Data.hxx"
33#include "rutil/Timer.hxx"
34#include "rutil/Logger.hxx"
35#include "rutil/dns/AresDns.hxx"
45#include "rutil/dns/RRCache.hxx"
47
48//#define VERBOSE_DNS_STACK_LOGS 1
49
50using namespace resip;
51using namespace std;
52
53#define RESIPROCATE_SUBSYSTEM resip::Subsystem::DNS
54
56 : mHead(),
57 mLruHead(LruListType::makeList(&mHead)),
58 mUserDefinedTTL(DEFAULT_USER_DEFINED_TTL),
59 mSize(DEFAULT_SIZE)
60{
61 mFactoryMap[T_CNAME] = &mCnameRecordFactory;
62 mFactoryMap[T_NAPTR] = &mNaptrRecordFacotry;
63 mFactoryMap[T_SRV] = &mSrvRecordFactory;
64#ifdef USE_IPV6
65 mFactoryMap[T_AAAA] = &mAAAARecordFactory;
66#endif
67 mFactoryMap[T_A] = &mHostRecordFactory;
68}
69
71{
72 cleanup();
73}
74
75void
77{
78 //FactoryMap::iterator it = mFactoryMap.find(T_A);
79 RRList* key = new RRList(record, 3600);
80 RRSet::iterator lb = mRRSet.lower_bound(key);
81 if (lb != mRRSet.end() &&
82 !(mRRSet.key_comp()(key, *lb)))
83 {
84#ifdef VERBOSE_DNS_STACK_LOGS
85 StackLog(<< "Updating cache from hostfile: target=" << record.name() << ", host=" << record.host());
86#endif
87 (*lb)->update(record, 3600);
88 touch(*lb);
89 }
90 else
91 {
92#ifdef VERBOSE_DNS_STACK_LOGS
93 StackLog(<< "Adding to cache from hostfile: target=" << record.name() << ", host=" << record.host());
94#endif
95 RRList* val = new RRList(record, 3600);
96 mRRSet.insert(val);
97 mLruHead->push_back(val);
98 purge();
99 }
100 delete key;
101}
102
103void
105 const int rrType,
106 Itr begin,
107 Itr end)
108{
109 Data domain = (*begin).domain();
110 FactoryMap::iterator it = mFactoryMap.find(rrType);
111 if (it != mFactoryMap.end()) // If we don't understand rrType - ignore it
112 {
113 RRList* key = new RRList(domain, rrType);
114 RRSet::iterator lb = mRRSet.lower_bound(key);
115 if (lb != mRRSet.end() &&
116 !(mRRSet.key_comp()(key, *lb)))
117 {
118 (*lb)->update(it->second, begin, end, mUserDefinedTTL);
119 if ((*lb)->numRecords() == 0)
120 {
121 // *lb might be a RRList with no records if parsing failed - remove from cache
122 (*lb)->remove();
123 delete *lb;
124 mRRSet.erase(lb);
125#ifdef VERBOSE_DNS_STACK_LOGS
126 StackLog(<< "Update cache failed to parse, removed entry: target=" << target << ", type=" << AresDns::dnsRRTypeToString(rrType) << ", totalCachedEntries=" << mRRSet.size());
127#endif
128 }
129 else
130 {
131#ifdef VERBOSE_DNS_STACK_LOGS
132 StackLog(<< "Updated cache: target=" << target << ", type=" << AresDns::dnsRRTypeToString(rrType));
133#endif
134 // update good - touch entry
135 touch(*lb);
136 }
137 }
138 else
139 {
140 RRList* val = new RRList(it->second, domain, rrType, begin, end, mUserDefinedTTL);
141 if (val->numRecords() == 0)
142 {
143#ifdef VERBOSE_DNS_STACK_LOGS
144 StackLog(<< "Update cache failed to parse for new entry: target=" << target << ", type=" << AresDns::dnsRRTypeToString(rrType));
145#endif
146 // val might be a RRList with no records if parsing failed - don't cache
147 delete val;
148 }
149 else
150 {
151 mRRSet.insert(val);
152 mLruHead->push_back(val);
153 purge();
154#ifdef VERBOSE_DNS_STACK_LOGS
155 StackLog(<< "Updated cache with new entry: target=" << target << ", type=" << AresDns::dnsRRTypeToString(rrType) << ", totalCachedEntries=" << mRRSet.size());
156#endif
157 }
158 }
159 delete key;
160 }
161}
162
163void
165 const int rrType,
166 const int status,
167 RROverlay overlay)
168{
169 int ttl = getTTL(overlay);
170
171 if (ttl < 0)
172 {
173 return;
174 }
175
176 if (ttl < mUserDefinedTTL)
177 {
178 ttl = mUserDefinedTTL;
179 }
180
181 RRList* val = new RRList(target, rrType, ttl, status);
182 RRSet::iterator it = mRRSet.find(val);
183 if (it != mRRSet.end())
184 {
185 (*it)->remove();
186 delete *it;
187 mRRSet.erase(it);
188 }
189 mRRSet.insert(val);
190 mLruHead->push_back(val);
191 purge();
192
193#ifdef VERBOSE_DNS_STACK_LOGS
194 StackLog(<< "Updated cache ttl: target=" << target << ", type=" << AresDns::dnsRRTypeToString(rrType) << ", status=" << status << ", ttl=" << ttl << ", totalCachedEntries=" << mRRSet.size());
195#endif
196}
197
198bool
199RRCache::lookup(const Data& target,
200 const int type,
201 const int protocol,
202 Result& records,
203 int& status)
204{
205 records.clear();
206 status = 0;
207 RRList* key = new RRList(target, type);
208 RRSet::iterator it = mRRSet.find(key);
209 delete key;
210 if (it == mRRSet.end())
211 {
212#ifdef VERBOSE_DNS_STACK_LOGS
213 StackLog(<< "Cache lookup failed for: target=" << target << ", type=" << AresDns::dnsRRTypeToString(type) << ", protocol=" << protocol << ", totalCachedEntries=" << mRRSet.size());
214#endif
215 return false;
216 }
217 else
218 {
219 if (Timer::getTimeSecs() >= (*it)->absoluteExpiry())
220 {
221#ifdef VERBOSE_DNS_STACK_LOGS
222 StackLog(<< "Cache lookup found expired entry for: target=" << target << ", type=" << AresDns::dnsRRTypeToString(type) << ", protocol=" << protocol << ", totalCachedEntries=" << mRRSet.size());
223#endif
224 (*it)->remove();
225 delete *it;
226 mRRSet.erase(it);
227 return false;
228 }
229 else
230 {
231#ifdef VERBOSE_DNS_STACK_LOGS
232 StackLog(<< "Cache lookup success for: target=" << target << ", type=" << AresDns::dnsRRTypeToString(type) << ", protocol=" << protocol << ", totalCachedEntries=" << mRRSet.size());
233#endif
234 records = (*it)->records(protocol);
235 status = (*it)->status();
236 touch(*it);
237 return true;
238 }
239 }
240}
241
242void
244{
245 cleanup();
246}
247
248void
249RRCache::touch(RRList* node)
250{
251 node->remove();
252 mLruHead->push_back(node);
253}
254
255void
256RRCache::cleanup()
257{
258 for (std::set<RRList*, CompareT>::iterator it = mRRSet.begin(); it != mRRSet.end(); it++)
259 {
260 (*it)->remove();
261 delete *it;
262 }
263 mRRSet.clear();
264#ifdef VERBOSE_DNS_STACK_LOGS
265 StackLog(<< "Cache emptied, totalCachedEntries=" << mRRSet.size());
266#endif
267}
268
269int
270RRCache::getTTL(const RROverlay& overlay)
271{
272 // overlay is a soa answer.
273 if (overlay.type() != T_SOA) return -1;
274 char* name = 0;
275 long len = 0;
276 int status = ares_expand_name(overlay.data(), overlay.msg(), overlay.msgLength(), &name, &len);
277 if (status == ARES_SUCCESS)
278 {
279 const unsigned char* pPos = overlay.data() + len;
280 free(name);
281 name = 0;
282 status = ares_expand_name(pPos, overlay.msg(), overlay.msgLength(), &name, &len);
283 if (status == ARES_SUCCESS)
284 {
285 free(name);
286 pPos += len;
287 // serial, refresh, retry and expire, then minimum
288 if (pPos + 16 + 4 > overlay.data() + overlay.dataLength())
289 {
290 return -1;
291 }
292 pPos += 16; // skip four 32 bit entities.
293 return DNS__32BIT(pPos);
294 }
295 }
296 return -1;
297}
298
299void
300RRCache::purge()
301{
302 if (mRRSet.size() < mSize) return;
303 RRList* lst = *(mLruHead->begin());
304 RRSet::iterator it = mRRSet.find(lst);
305 if (it != mRRSet.end()) // safety check incase code forgets to remove from LRU list when removing from mRRset
306 {
307#ifdef VERBOSE_DNS_STACK_LOGS
308 StackLog(<< "Cache full purging LRU record, target=" << lst->key() << ", type=" << AresDns::dnsRRTypeToString(lst->rrType()) << ", status=" << lst->status() << ", totalCachedEntries=" << mRRSet.size() << ", maxSize=" << mSize);
309#endif
310
311 lst->remove();
312 delete* it;
313 mRRSet.erase(it);
314 }
315}
316
317void
319{
320 Data dnsCacheDump;
321 getCacheDump(dnsCacheDump);
322 WarningLog(<< endl << dnsCacheDump);
323}
324
325void
327{
329 DataStream strm(dnsCacheDump);
330 strm << "DNSCACHE: TotalEntries=" << mRRSet.size();
331 for (std::set<RRList*, CompareT>::iterator it = mRRSet.begin(); it != mRRSet.end(); )
332 {
333 if (now >= (*it)->absoluteExpiry())
334 {
335 (*it)->remove();
336 delete *it;
337 mRRSet.erase(it++);
338 }
339 else
340 {
341 strm << endl;
342 (*it)->encodeRRList(strm);
343 ++it;
344 }
345 }
346 strm.flush();
347}
348
349/* ====================================================================
350 * The Vovida Software License, Version 1.0
351 *
352 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved.
353 * Copyright (c) 2010 SIP Spectrum, Inc. All rights reserved.
354 *
355 * Redistribution and use in source and binary forms, with or without
356 * modification, are permitted provided that the following conditions
357 * are met:
358 *
359 * 1. Redistributions of source code must retain the above copyright
360 * notice, this list of conditions and the following disclaimer.
361 *
362 * 2. Redistributions in binary form must reproduce the above copyright
363 * notice, this list of conditions and the following disclaimer in
364 * the documentation and/or other materials provided with the
365 * distribution.
366 *
367 * 3. The names "VOCAL", "Vovida Open Communication Application Library",
368 * and "Vovida Open Communication Application Library (VOCAL)" must
369 * not be used to endorse or promote products derived from this
370 * software without prior written permission. For written
371 * permission, please contact vocal@vovida.org.
372 *
373 * 4. Products derived from this software may not be called "VOCAL", nor
374 * may "VOCAL" appear in their name, without prior written
375 * permission of Vovida Networks, Inc.
376 *
377 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
378 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
379 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
380 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA
381 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
382 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
383 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
384 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
385 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
386 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
387 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
388 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
389 * DAMAGE.
390 *
391 * ====================================================================
392 *
393 * This software consists of voluntary contributions made by Vovida
394 * Networks, Inc. and many individuals on behalf of Vovida Networks,
395 * Inc. For more information on Vovida Networks, Inc., please see
396 * <http://www.vovida.org/>.
397 *
398 */
#define StackLog(args_)
Definition Logger.hxx:125
#define WarningLog(args_)
Definition Logger.hxx:134
#define ARES_SUCCESS
Definition ares.h:79
#define DNS__32BIT(p)
Definition ares.h:46
int ares_expand_name(const unsigned char *encoded, const unsigned char *abuf, int alen, char **s, long *enclen)
#define T_CNAME
#define T_SOA
static const char * dnsRRTypeToString(int rrtype)
Definition AresDns.cxx:1060
An iostream that operates on an existing Data.
An alternative to std::string, encapsulates an arbitrary buffer of bytes.
Definition Data.hxx:90
virtual const Data & name() const
void updateCacheFromHostFile(const DnsHostRecord &)
Definition RRCache.cxx:76
bool lookup(const Data &target, const int type, const int proto, Result &records, int &status)
Definition RRCache.cxx:199
std::vector< RROverlay >::const_iterator Itr
Definition RRCache.hxx:27
void cacheTTL(const Data &target, const int rrType, const int status, RROverlay overlay)
Definition RRCache.cxx:164
void updateCache(const Data &target, const int rrType, Itr begin, Itr end)
Definition RRCache.cxx:104
void getCacheDump(Data &dnsCacheDump)
Definition RRCache.cxx:326
RRList::Records Result
Definition RRCache.hxx:26
void logCache()
Definition RRCache.cxx:318
void clearCache()
Definition RRCache.cxx:243
int rrType() const
Definition RRList.hxx:53
const Data & key() const
Definition RRList.hxx:51
int status() const
Definition RRList.hxx:52
size_t numRecords()
Definition RRList.hxx:49
int type() const
Definition RROverlay.hxx:44
int msgLength() const
Definition RROverlay.hxx:40
int dataLength() const
Definition RROverlay.hxx:41
const unsigned char * msg() const
Definition RROverlay.hxx:39
const unsigned char * data() const
Definition RROverlay.hxx:38
static uint64_t getTimeSecs()
Returns the current clock time in seconds.
Definition Timer.hxx:78
#define T_NAPTR
Definition compat.hxx:140
#define T_A
Definition compat.hxx:152
#define T_AAAA
Definition compat.hxx:148
#define T_SRV
Definition compat.hxx:144
dcm! – add UnusedChecking(_enum) below;
unsigned long long uint64_t
Definition Stun.hxx:39