]>
Commit | Line | Data |
---|---|---|
886e2cf2 RG |
1 | #define BOOST_TEST_DYN_LINK |
2 | #define BOOST_TEST_NO_MAIN | |
3 | ||
4 | #include <boost/test/unit_test.hpp> | |
5 | ||
1ea747c0 | 6 | #include "dnsdist.hh" |
886e2cf2 | 7 | #include "iputils.hh" |
886e2cf2 | 8 | #include "dnswriter.hh" |
1ea747c0 | 9 | #include "dnsdist-cache.hh" |
886e2cf2 RG |
10 | |
11 | BOOST_AUTO_TEST_SUITE(dnsdistpacketcache_cc) | |
12 | ||
13 | BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) { | |
14 | const size_t maxEntries = 150000; | |
15 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
16 | BOOST_CHECK_EQUAL(PC.getSize(), 0); | |
17 | ||
18 | size_t counter=0; | |
19 | size_t skipped=0; | |
1ea747c0 | 20 | ComboAddress remote; |
886e2cf2 RG |
21 | try { |
22 | for(counter = 0; counter < 100000; ++counter) { | |
490dc586 | 23 | DNSName a=DNSName(std::to_string(counter))+DNSName(" hello"); |
886e2cf2 RG |
24 | BOOST_CHECK_EQUAL(DNSName(a.toString()), a); |
25 | ||
26 | vector<uint8_t> query; | |
27 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
28 | pwQ.getHeader()->rd = 1; | |
29 | ||
30 | vector<uint8_t> response; | |
31 | DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); | |
32 | pwR.getHeader()->rd = 1; | |
33 | pwR.getHeader()->ra = 1; | |
34 | pwR.getHeader()->qr = 1; | |
35 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
36 | pwR.startRecord(a, QType::A, 100, QClass::IN, DNSResourceRecord::ANSWER); | |
37 | pwR.xfr32BitInt(0x01020304); | |
38 | pwR.commit(); | |
39 | uint16_t responseLen = response.size(); | |
40 | ||
41 | char responseBuf[4096]; | |
42 | uint16_t responseBufSize = sizeof(responseBuf); | |
43 | uint32_t key = 0; | |
1ea747c0 RG |
44 | DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false); |
45 | bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key); | |
886e2cf2 RG |
46 | BOOST_CHECK_EQUAL(found, false); |
47 | ||
acb8f5d5 | 48 | PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none); |
886e2cf2 | 49 | |
1ea747c0 | 50 | found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true); |
886e2cf2 RG |
51 | if (found == true) { |
52 | BOOST_CHECK_EQUAL(responseBufSize, responseLen); | |
53 | int match = memcmp(responseBuf, response.data(), responseLen); | |
54 | BOOST_CHECK_EQUAL(match, 0); | |
55 | } | |
56 | else { | |
57 | skipped++; | |
58 | } | |
59 | } | |
60 | ||
61 | BOOST_CHECK_EQUAL(skipped, PC.getInsertCollisions()); | |
62 | BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped); | |
63 | ||
64 | size_t deleted=0; | |
65 | size_t delcounter=0; | |
66 | for(delcounter=0; delcounter < counter/1000; ++delcounter) { | |
490dc586 | 67 | DNSName a=DNSName(std::to_string(delcounter))+DNSName(" hello"); |
886e2cf2 RG |
68 | vector<uint8_t> query; |
69 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
70 | pwQ.getHeader()->rd = 1; | |
71 | char responseBuf[4096]; | |
72 | uint16_t responseBufSize = sizeof(responseBuf); | |
73 | uint32_t key = 0; | |
1ea747c0 RG |
74 | DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false); |
75 | bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key); | |
886e2cf2 | 76 | if (found == true) { |
4275aaba | 77 | PC.expungeByName(a); |
886e2cf2 RG |
78 | deleted++; |
79 | } | |
80 | } | |
81 | BOOST_CHECK_EQUAL(PC.getSize(), counter - skipped - deleted); | |
82 | ||
490dc586 | 83 | |
886e2cf2 RG |
84 | size_t matches=0; |
85 | vector<DNSResourceRecord> entry; | |
86 | size_t expected=counter-skipped-deleted; | |
87 | for(; delcounter < counter; ++delcounter) { | |
490dc586 | 88 | DNSName a(DNSName(std::to_string(delcounter))+DNSName(" hello")); |
886e2cf2 RG |
89 | vector<uint8_t> query; |
90 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
91 | pwQ.getHeader()->rd = 1; | |
92 | uint16_t len = query.size(); | |
93 | uint32_t key = 0; | |
94 | char response[4096]; | |
95 | uint16_t responseSize = sizeof(response); | |
1ea747c0 RG |
96 | DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), len, query.size(), false); |
97 | if(PC.get(dq, a.wirelength(), pwQ.getHeader()->id, response, &responseSize, &key)) { | |
490dc586 | 98 | matches++; |
886e2cf2 RG |
99 | } |
100 | } | |
101 | BOOST_CHECK_EQUAL(matches, expected); | |
490dc586 RG |
102 | |
103 | PC.expungeByName(DNSName(" hello"), QType::ANY, true); | |
104 | BOOST_CHECK_EQUAL(PC.getSize(), 0); | |
886e2cf2 RG |
105 | } |
106 | catch(PDNSException& e) { | |
107 | cerr<<"Had error: "<<e.reason<<endl; | |
108 | throw; | |
109 | } | |
110 | } | |
111 | ||
acb8f5d5 CH |
112 | BOOST_AUTO_TEST_CASE(test_PacketCacheServFailTTL) { |
113 | const size_t maxEntries = 150000; | |
114 | DNSDistPacketCache PC(maxEntries, 86400, 1); | |
115 | ||
116 | ComboAddress remote; | |
117 | try { | |
118 | DNSName a = DNSName("servfail"); | |
119 | BOOST_CHECK_EQUAL(DNSName(a.toString()), a); | |
120 | ||
121 | vector<uint8_t> query; | |
122 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
123 | pwQ.getHeader()->rd = 1; | |
124 | ||
125 | vector<uint8_t> response; | |
126 | DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); | |
127 | pwR.getHeader()->rd = 1; | |
128 | pwR.getHeader()->ra = 0; | |
129 | pwR.getHeader()->qr = 1; | |
130 | pwR.getHeader()->rcode = RCode::ServFail; | |
131 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
132 | pwR.commit(); | |
133 | uint16_t responseLen = response.size(); | |
134 | ||
135 | char responseBuf[4096]; | |
136 | uint16_t responseBufSize = sizeof(responseBuf); | |
137 | uint32_t key = 0; | |
138 | DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false); | |
139 | bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key); | |
140 | BOOST_CHECK_EQUAL(found, false); | |
141 | ||
142 | // Insert with failure-TTL of 0 (-> should not enter cache). | |
143 | PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(0)); | |
144 | found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true); | |
145 | BOOST_CHECK_EQUAL(found, false); | |
146 | ||
56459632 | 147 | // Insert with failure-TTL non-zero (-> should enter cache). |
acb8f5d5 CH |
148 | PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, RCode::ServFail, boost::optional<uint32_t>(300)); |
149 | found = PC.get(dq, a.wirelength(), pwR.getHeader()->id, responseBuf, &responseBufSize, &key, 0, true); | |
150 | BOOST_CHECK_EQUAL(found, true); | |
151 | } | |
152 | catch(PDNSException& e) { | |
153 | cerr<<"Had error: "<<e.reason<<endl; | |
154 | throw; | |
155 | } | |
156 | } | |
157 | ||
886e2cf2 RG |
158 | static DNSDistPacketCache PC(500000); |
159 | ||
af619119 | 160 | static void *threadMangler(void* off) |
886e2cf2 RG |
161 | { |
162 | try { | |
1ea747c0 | 163 | ComboAddress remote; |
af619119 | 164 | unsigned int offset=(unsigned int)(unsigned long)off; |
886e2cf2 RG |
165 | for(unsigned int counter=0; counter < 100000; ++counter) { |
166 | DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset)); | |
167 | vector<uint8_t> query; | |
168 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
169 | pwQ.getHeader()->rd = 1; | |
170 | ||
171 | vector<uint8_t> response; | |
172 | DNSPacketWriter pwR(response, a, QType::A, QClass::IN, 0); | |
173 | pwR.getHeader()->rd = 1; | |
174 | pwR.getHeader()->ra = 1; | |
175 | pwR.getHeader()->qr = 1; | |
176 | pwR.getHeader()->id = pwQ.getHeader()->id; | |
177 | pwR.startRecord(a, QType::A, 3600, QClass::IN, DNSResourceRecord::ANSWER); | |
178 | pwR.xfr32BitInt(0x01020304); | |
179 | pwR.commit(); | |
180 | uint16_t responseLen = response.size(); | |
181 | ||
182 | char responseBuf[4096]; | |
183 | uint16_t responseBufSize = sizeof(responseBuf); | |
184 | uint32_t key = 0; | |
1ea747c0 RG |
185 | DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false); |
186 | PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key); | |
886e2cf2 | 187 | |
acb8f5d5 | 188 | PC.insert(key, a, QType::A, QClass::IN, (const char*) response.data(), responseLen, false, 0, boost::none); |
886e2cf2 RG |
189 | } |
190 | } | |
191 | catch(PDNSException& e) { | |
192 | cerr<<"Had error: "<<e.reason<<endl; | |
193 | throw; | |
194 | } | |
195 | return 0; | |
196 | } | |
197 | ||
198 | AtomicCounter g_missing; | |
199 | ||
af619119 | 200 | static void *threadReader(void* off) |
886e2cf2 RG |
201 | { |
202 | try | |
203 | { | |
af619119 | 204 | unsigned int offset=(unsigned int)(unsigned long)off; |
886e2cf2 | 205 | vector<DNSResourceRecord> entry; |
1ea747c0 | 206 | ComboAddress remote; |
886e2cf2 RG |
207 | for(unsigned int counter=0; counter < 100000; ++counter) { |
208 | DNSName a=DNSName("hello ")+DNSName(std::to_string(counter+offset)); | |
209 | vector<uint8_t> query; | |
210 | DNSPacketWriter pwQ(query, a, QType::A, QClass::IN, 0); | |
211 | pwQ.getHeader()->rd = 1; | |
212 | ||
213 | char responseBuf[4096]; | |
214 | uint16_t responseBufSize = sizeof(responseBuf); | |
215 | uint32_t key = 0; | |
1ea747c0 RG |
216 | DNSQuestion dq(&a, QType::A, QClass::IN, &remote, &remote, (struct dnsheader*) query.data(), query.size(), query.size(), false); |
217 | bool found = PC.get(dq, a.wirelength(), 0, responseBuf, &responseBufSize, &key); | |
886e2cf2 RG |
218 | if (!found) { |
219 | g_missing++; | |
220 | } | |
221 | } | |
222 | } | |
223 | catch(PDNSException& e) { | |
224 | cerr<<"Had error in threadReader: "<<e.reason<<endl; | |
225 | throw; | |
226 | } | |
227 | return 0; | |
228 | } | |
229 | ||
230 | BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) { | |
231 | try { | |
232 | pthread_t tid[4]; | |
233 | for(int i=0; i < 4; ++i) | |
234 | pthread_create(&tid[i], 0, threadMangler, (void*)(i*1000000UL)); | |
235 | void* res; | |
236 | for(int i=0; i < 4 ; ++i) | |
237 | pthread_join(tid[i], &res); | |
238 | ||
239 | BOOST_CHECK_EQUAL(PC.getSize() + PC.getDeferredInserts() + PC.getInsertCollisions(), 400000); | |
240 | BOOST_CHECK_SMALL(1.0*PC.getInsertCollisions(), 10000.0); | |
241 | ||
242 | for(int i=0; i < 4; ++i) | |
243 | pthread_create(&tid[i], 0, threadReader, (void*)(i*1000000UL)); | |
244 | for(int i=0; i < 4 ; ++i) | |
245 | pthread_join(tid[i], &res); | |
246 | ||
247 | BOOST_CHECK((PC.getDeferredInserts() + PC.getDeferredLookups() + PC.getInsertCollisions()) >= g_missing); | |
248 | } | |
249 | catch(PDNSException& e) { | |
250 | cerr<<"Had error: "<<e.reason<<endl; | |
251 | throw; | |
252 | } | |
253 | ||
254 | } | |
255 | ||
256 | BOOST_AUTO_TEST_SUITE_END() |