| 174 | } |
| 175 | |
| 176 | bool |
| 177 | IP::Sample(double rate, uint32_t seed, unsigned ipv4_cidr, unsigned ipv6_cidr) |
| 178 | { |
| 179 | CAssert(rate >= 0.0 && rate <= 1.0); // For detecting bugs in a Cript, 0.0 and 1.0 are valid though |
| 180 | |
| 181 | if (_sampler == 0) { |
| 182 | // This only works until 2038 |
| 183 | uint32_t now = (Time::Local::Now().Epoch() / NORMALIZED_TIME_QUANTUM) * NORMALIZED_TIME_QUANTUM; |
| 184 | |
| 185 | if (is_ip4()) { |
| 186 | auto addr = this->_addr._ip4.network_order(); |
| 187 | in_addr_t ip = addr & htonl(UINT32_MAX << (32 - ipv4_cidr)); |
| 188 | |
| 189 | _sampler = (ip >> 16) ^ (ip & 0x00ff); // Fold them to 16 bits, mixing net and host |
| 190 | |
| 191 | } else if (is_ip6()) { |
| 192 | unsigned int v6_zero_bytes = (128 - ipv6_cidr) / 8; |
| 193 | int v6_mask = 0xff >> ((128 - ipv6_cidr) % 8); |
| 194 | auto addr = this->_addr._ip6.network_order(); |
| 195 | |
| 196 | if (v6_zero_bytes > 0) { |
| 197 | memset(&addr.s6_addr[16 - v6_zero_bytes], 0, v6_zero_bytes); |
| 198 | } |
| 199 | if (v6_mask != 0xff) { |
| 200 | addr.s6_addr[16 - v6_zero_bytes] &= v6_mask; |
| 201 | } |
| 202 | |
| 203 | _sampler = *reinterpret_cast<uint16_t const *>(addr.s6_addr) ^ |
| 204 | *reinterpret_cast<uint16_t const *>(addr.s6_addr + sizeof(uint16_t)) ^ |
| 205 | *reinterpret_cast<uint16_t const *>(addr.s6_addr + 2 * sizeof(uint16_t)) ^ |
| 206 | *reinterpret_cast<uint16_t const *>(addr.s6_addr + 3 * sizeof(uint16_t)); |
| 207 | } else { |
| 208 | // Clearly this shouldn't happen, but lets not assert |
| 209 | } |
| 210 | |
| 211 | _sampler ^= (now >> 16) ^ (now & 0x00ff); // Fold in the hourly normalized timestamp |
| 212 | if (seed) { |
| 213 | _sampler ^= (seed >> 16) ^ (seed & 0x00ff); // Fold in the seed as well |
| 214 | } |
| 215 | } |
| 216 | |
| 217 | // To avoid picking sequential folded IPs bucketize them with a modulo of the sampler (just in case) |
| 218 | return (_sampler % static_cast<uint16_t>(rate * UINT16_MAX)) == _sampler; |
| 219 | } |
| 220 | |
| 221 | Client::Connection & |
| 222 | Client::Connection::_get(cripts::Context *context) |
nothing calls this directly
no test coverage detected