src: Reorganizing source code in preparation to merge NRD code
Note that as of this commit, there are several changes in location of
compiled binaries in `build/` folder:
* `nfd` has been moved to `build/bin/nfd`
* `unit-tests` has been split into `unit-tests-core` and `unit-tests-daemon`
Change-Id: I2c830c117879edbaa5457d6423c13f0273285919
Refs: #1486
diff --git a/core/city-hash.cpp b/core/city-hash.cpp
new file mode 100644
index 0000000..e0bebb4
--- /dev/null
+++ b/core/city-hash.cpp
@@ -0,0 +1,628 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// This file provides CityHash64() and related functions.
+//
+// It's probably possible to create even faster hash functions by
+// writing a program that systematically explores some of the space of
+// possible hash functions, by using SIMD instructions, or by
+// compromising on hash quality.
+
+//#include "config.h"
+#include "city-hash.hpp"
+#include <algorithm>
+#include <string.h> // for memcpy and memset
+
+using namespace std;
+
+
+static uint64 UNALIGNED_LOAD64(const char *p) {
+ uint64 result;
+ memcpy(&result, p, sizeof(result));
+ return result;
+}
+
+static uint32 UNALIGNED_LOAD32(const char *p) {
+ uint32 result;
+ memcpy(&result, p, sizeof(result));
+ return result;
+}
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+#define bswap_32(x) _byteswap_ulong(x)
+#define bswap_64(x) _byteswap_uint64(x)
+
+#elif defined(__APPLE__)
+
+// Mac OS X / Darwin features
+#include <libkern/OSByteOrder.h>
+#define bswap_32(x) OSSwapInt32(x)
+#define bswap_64(x) OSSwapInt64(x)
+
+#elif defined(__NetBSD__)
+
+#include <sys/types.h>
+#include <machine/bswap.h>
+#if defined(__BSWAP_RENAME) && !defined(__bswap_32)
+#define bswap_32(x) bswap32(x)
+#define bswap_64(x) bswap64(x)
+#endif
+
+#else
+
+#include <byteswap.h>
+
+#endif
+
+#ifdef WORDS_BIGENDIAN
+#define uint32_in_expected_order(x) (bswap_32(x))
+#define uint64_in_expected_order(x) (bswap_64(x))
+#else
+#define uint32_in_expected_order(x) (x)
+#define uint64_in_expected_order(x) (x)
+#endif
+
+#if !defined(LIKELY)
+#if HAVE_BUILTIN_EXPECT
+#define LIKELY(x) (__builtin_expect(!!(x), 1))
+#else
+#define LIKELY(x) (x)
+#endif
+#endif
+
+static uint64 Fetch64(const char *p) {
+ return uint64_in_expected_order(UNALIGNED_LOAD64(p));
+}
+
+static uint32 Fetch32(const char *p) {
+ return uint32_in_expected_order(UNALIGNED_LOAD32(p));
+}
+
+// Some primes between 2^63 and 2^64 for various uses.
+static const uint64 k0 = 0xc3a5c85c97cb3127ULL;
+static const uint64 k1 = 0xb492b66fbe98f273ULL;
+static const uint64 k2 = 0x9ae16a3b2f90404fULL;
+
+// Magic numbers for 32-bit hashing. Copied from Murmur3.
+static const uint32_t c1 = 0xcc9e2d51;
+static const uint32_t c2 = 0x1b873593;
+
+// A 32-bit to 32-bit integer hash copied from Murmur3.
+static uint32 fmix(uint32 h)
+{
+ h ^= h >> 16;
+ h *= 0x85ebca6b;
+ h ^= h >> 13;
+ h *= 0xc2b2ae35;
+ h ^= h >> 16;
+ return h;
+}
+
+static uint32 Rotate32(uint32 val, int shift) {
+ // Avoid shifting by 32: doing so yields an undefined result.
+ return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
+}
+
+#undef PERMUTE3
+#define PERMUTE3(a, b, c) do { std::swap(a, b); std::swap(a, c); } while (0)
+
+static uint32 Mur(uint32 a, uint32 h) {
+ // Helper from Murmur3 for combining two 32-bit values.
+ a *= c1;
+ a = Rotate32(a, 17);
+ a *= c2;
+ h ^= a;
+ h = Rotate32(h, 19);
+ return h * 5 + 0xe6546b64;
+}
+
+static uint32 Hash32Len13to24(const char *s, size_t len) {
+ uint32 a = Fetch32(s - 4 + (len >> 1));
+ uint32 b = Fetch32(s + 4);
+ uint32 c = Fetch32(s + len - 8);
+ uint32 d = Fetch32(s + (len >> 1));
+ uint32 e = Fetch32(s);
+ uint32 f = Fetch32(s + len - 4);
+ uint32 h = len;
+
+ return fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h)))))));
+}
+
+static uint32 Hash32Len0to4(const char *s, size_t len) {
+ uint32 b = 0;
+ uint32 c = 9;
+ for (size_t i = 0; i < len; i++) {
+ signed char v = s[i];
+ b = b * c1 + v;
+ c ^= b;
+ }
+ return fmix(Mur(b, Mur(len, c)));
+}
+
+static uint32 Hash32Len5to12(const char *s, size_t len) {
+ uint32 a = len, b = len * 5, c = 9, d = b;
+ a += Fetch32(s);
+ b += Fetch32(s + len - 4);
+ c += Fetch32(s + ((len >> 1) & 4));
+ return fmix(Mur(c, Mur(b, Mur(a, d))));
+}
+
+uint32 CityHash32(const char *s, size_t len) {
+ if (len <= 24) {
+ return len <= 12 ?
+ (len <= 4 ? Hash32Len0to4(s, len) : Hash32Len5to12(s, len)) :
+ Hash32Len13to24(s, len);
+ }
+
+ // len > 24
+ uint32 h = len, g = c1 * len, f = g;
+ uint32 a0 = Rotate32(Fetch32(s + len - 4) * c1, 17) * c2;
+ uint32 a1 = Rotate32(Fetch32(s + len - 8) * c1, 17) * c2;
+ uint32 a2 = Rotate32(Fetch32(s + len - 16) * c1, 17) * c2;
+ uint32 a3 = Rotate32(Fetch32(s + len - 12) * c1, 17) * c2;
+ uint32 a4 = Rotate32(Fetch32(s + len - 20) * c1, 17) * c2;
+ h ^= a0;
+ h = Rotate32(h, 19);
+ h = h * 5 + 0xe6546b64;
+ h ^= a2;
+ h = Rotate32(h, 19);
+ h = h * 5 + 0xe6546b64;
+ g ^= a1;
+ g = Rotate32(g, 19);
+ g = g * 5 + 0xe6546b64;
+ g ^= a3;
+ g = Rotate32(g, 19);
+ g = g * 5 + 0xe6546b64;
+ f += a4;
+ f = Rotate32(f, 19);
+ f = f * 5 + 0xe6546b64;
+ size_t iters = (len - 1) / 20;
+ do {
+ uint32 a0 = Rotate32(Fetch32(s) * c1, 17) * c2;
+ uint32 a1 = Fetch32(s + 4);
+ uint32 a2 = Rotate32(Fetch32(s + 8) * c1, 17) * c2;
+ uint32 a3 = Rotate32(Fetch32(s + 12) * c1, 17) * c2;
+ uint32 a4 = Fetch32(s + 16);
+ h ^= a0;
+ h = Rotate32(h, 18);
+ h = h * 5 + 0xe6546b64;
+ f += a1;
+ f = Rotate32(f, 19);
+ f = f * c1;
+ g += a2;
+ g = Rotate32(g, 18);
+ g = g * 5 + 0xe6546b64;
+ h ^= a3 + a1;
+ h = Rotate32(h, 19);
+ h = h * 5 + 0xe6546b64;
+ g ^= a4;
+ g = bswap_32(g) * 5;
+ h += a4 * 5;
+ h = bswap_32(h);
+ f += a0;
+ PERMUTE3(f, h, g);
+ s += 20;
+ } while (--iters != 0);
+ g = Rotate32(g, 11) * c1;
+ g = Rotate32(g, 17) * c1;
+ f = Rotate32(f, 11) * c1;
+ f = Rotate32(f, 17) * c1;
+ h = Rotate32(h + g, 19);
+ h = h * 5 + 0xe6546b64;
+ h = Rotate32(h, 17) * c1;
+ h = Rotate32(h + f, 19);
+ h = h * 5 + 0xe6546b64;
+ h = Rotate32(h, 17) * c1;
+ return h;
+}
+
+// Bitwise right rotate. Normally this will compile to a single
+// instruction, especially if the shift is a manifest constant.
+static uint64 Rotate(uint64 val, int shift) {
+ // Avoid shifting by 64: doing so yields an undefined result.
+ return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
+}
+
+static uint64 ShiftMix(uint64 val) {
+ return val ^ (val >> 47);
+}
+
+static uint64 HashLen16(uint64 u, uint64 v) {
+ return Hash128to64(uint128(u, v));
+}
+
+static uint64 HashLen16(uint64 u, uint64 v, uint64 mul) {
+ // Murmur-inspired hashing.
+ uint64 a = (u ^ v) * mul;
+ a ^= (a >> 47);
+ uint64 b = (v ^ a) * mul;
+ b ^= (b >> 47);
+ b *= mul;
+ return b;
+}
+
+static uint64 HashLen0to16(const char *s, size_t len) {
+ if (len >= 8) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) + k2;
+ uint64 b = Fetch64(s + len - 8);
+ uint64 c = Rotate(b, 37) * mul + a;
+ uint64 d = (Rotate(a, 25) + b) * mul;
+ return HashLen16(c, d, mul);
+ }
+ if (len >= 4) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch32(s);
+ return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
+ }
+ if (len > 0) {
+ uint8 a = s[0];
+ uint8 b = s[len >> 1];
+ uint8 c = s[len - 1];
+ uint32 y = static_cast<uint32>(a) + (static_cast<uint32>(b) << 8);
+ uint32 z = len + (static_cast<uint32>(c) << 2);
+ return ShiftMix(y * k2 ^ z * k0) * k2;
+ }
+ return k2;
+}
+
+// This probably works well for 16-byte strings as well, but it may be overkill
+// in that case.
+static uint64 HashLen17to32(const char *s, size_t len) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) * k1;
+ uint64 b = Fetch64(s + 8);
+ uint64 c = Fetch64(s + len - 8) * mul;
+ uint64 d = Fetch64(s + len - 16) * k2;
+ return HashLen16(Rotate(a + b, 43) + Rotate(c, 30) + d,
+ a + Rotate(b + k2, 18) + c, mul);
+}
+
+// Return a 16-byte hash for 48 bytes. Quick and dirty.
+// Callers do best to use "random-looking" values for a and b.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(
+ uint64 w, uint64 x, uint64 y, uint64 z, uint64 a, uint64 b) {
+ a += w;
+ b = Rotate(b + a + z, 21);
+ uint64 c = a;
+ a += x;
+ a += y;
+ b += Rotate(a, 44);
+ return make_pair(a + z, b + c);
+}
+
+// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
+static pair<uint64, uint64> WeakHashLen32WithSeeds(
+ const char* s, uint64 a, uint64 b) {
+ return WeakHashLen32WithSeeds(Fetch64(s),
+ Fetch64(s + 8),
+ Fetch64(s + 16),
+ Fetch64(s + 24),
+ a,
+ b);
+}
+
+// Return an 8-byte hash for 33 to 64 bytes.
+static uint64 HashLen33to64(const char *s, size_t len) {
+ uint64 mul = k2 + len * 2;
+ uint64 a = Fetch64(s) * k2;
+ uint64 b = Fetch64(s + 8);
+ uint64 c = Fetch64(s + len - 24);
+ uint64 d = Fetch64(s + len - 32);
+ uint64 e = Fetch64(s + 16) * k2;
+ uint64 f = Fetch64(s + 24) * 9;
+ uint64 g = Fetch64(s + len - 8);
+ uint64 h = Fetch64(s + len - 16) * mul;
+ uint64 u = Rotate(a + g, 43) + (Rotate(b, 30) + c) * 9;
+ uint64 v = ((a + g) ^ d) + f + 1;
+ uint64 w = bswap_64((u + v) * mul) + h;
+ uint64 x = Rotate(e + f, 42) + c;
+ uint64 y = (bswap_64((v + w) * mul) + g) * mul;
+ uint64 z = e + f + c;
+ a = bswap_64((x + z) * mul + y) + b;
+ b = ShiftMix((z + a) * mul + d + h) * mul;
+ return b + x;
+}
+
+uint64 CityHash64(const char *s, size_t len) {
+ if (len <= 32) {
+ if (len <= 16) {
+ return HashLen0to16(s, len);
+ } else {
+ return HashLen17to32(s, len);
+ }
+ } else if (len <= 64) {
+ return HashLen33to64(s, len);
+ }
+
+ // For strings over 64 bytes we hash the end first, and then as we
+ // loop we keep 56 bytes of state: v, w, x, y, and z.
+ uint64 x = Fetch64(s + len - 40);
+ uint64 y = Fetch64(s + len - 16) + Fetch64(s + len - 56);
+ uint64 z = HashLen16(Fetch64(s + len - 48) + len, Fetch64(s + len - 24));
+ pair<uint64, uint64> v = WeakHashLen32WithSeeds(s + len - 64, len, z);
+ pair<uint64, uint64> w = WeakHashLen32WithSeeds(s + len - 32, y + k1, x);
+ x = x * k1 + Fetch64(s);
+
+ // Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
+ len = (len - 1) & ~static_cast<size_t>(63);
+ do {
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ len -= 64;
+ } while (len != 0);
+ return HashLen16(HashLen16(v.first, w.first) + ShiftMix(y) * k1 + z,
+ HashLen16(v.second, w.second) + x);
+}
+
+uint64 CityHash64WithSeed(const char *s, size_t len, uint64 seed) {
+ return CityHash64WithSeeds(s, len, k2, seed);
+}
+
+uint64 CityHash64WithSeeds(const char *s, size_t len,
+ uint64 seed0, uint64 seed1) {
+ return HashLen16(CityHash64(s, len) - seed0, seed1);
+}
+
+// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
+// of any length representable in signed long. Based on City and Murmur.
+static uint128 CityMurmur(const char *s, size_t len, uint128 seed) {
+ uint64 a = Uint128Low64(seed);
+ uint64 b = Uint128High64(seed);
+ uint64 c = 0;
+ uint64 d = 0;
+ signed long l = len - 16;
+ if (l <= 0) { // len <= 16
+ a = ShiftMix(a * k1) * k1;
+ c = b * k1 + HashLen0to16(s, len);
+ d = ShiftMix(a + (len >= 8 ? Fetch64(s) : c));
+ } else { // len > 16
+ c = HashLen16(Fetch64(s + len - 8) + k1, a);
+ d = HashLen16(b + len, c + Fetch64(s + len - 16));
+ a += d;
+ do {
+ a ^= ShiftMix(Fetch64(s) * k1) * k1;
+ a *= k1;
+ b ^= a;
+ c ^= ShiftMix(Fetch64(s + 8) * k1) * k1;
+ c *= k1;
+ d ^= c;
+ s += 16;
+ l -= 16;
+ } while (l > 0);
+ }
+ a = HashLen16(a, c);
+ b = HashLen16(d, b);
+ return uint128(a ^ b, HashLen16(b, a));
+}
+
+uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) {
+ if (len < 128) {
+ return CityMurmur(s, len, seed);
+ }
+
+ // We expect len >= 128 to be the common case. Keep 56 bytes of state:
+ // v, w, x, y, and z.
+ pair<uint64, uint64> v, w;
+ uint64 x = Uint128Low64(seed);
+ uint64 y = Uint128High64(seed);
+ uint64 z = len * k1;
+ v.first = Rotate(y ^ k1, 49) * k1 + Fetch64(s);
+ v.second = Rotate(v.first, 42) * k1 + Fetch64(s + 8);
+ w.first = Rotate(y + z, 35) * k1 + x;
+ w.second = Rotate(x + Fetch64(s + 88), 53) * k1;
+
+ // This is the same inner loop as CityHash64(), manually unrolled.
+ do {
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ x = Rotate(x + y + v.first + Fetch64(s + 8), 37) * k1;
+ y = Rotate(y + v.second + Fetch64(s + 48), 42) * k1;
+ x ^= w.second;
+ y += v.first + Fetch64(s + 40);
+ z = Rotate(z + w.first, 33) * k1;
+ v = WeakHashLen32WithSeeds(s, v.second * k1, x + w.first);
+ w = WeakHashLen32WithSeeds(s + 32, z + w.second, y + Fetch64(s + 16));
+ std::swap(z, x);
+ s += 64;
+ len -= 128;
+ } while (LIKELY(len >= 128));
+ x += Rotate(v.first + z, 49) * k0;
+ y = y * k0 + Rotate(w.second, 37);
+ z = z * k0 + Rotate(w.first, 27);
+ w.first *= 9;
+ v.first *= k0;
+ // If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
+ for (size_t tail_done = 0; tail_done < len; ) {
+ tail_done += 32;
+ y = Rotate(x + y, 42) * k0 + v.second;
+ w.first += Fetch64(s + len - tail_done + 16);
+ x = x * k0 + w.first;
+ z += w.second + Fetch64(s + len - tail_done);
+ w.second += v.first;
+ v = WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
+ v.first *= k0;
+ }
+ // At this point our 56 bytes of state should contain more than
+ // enough information for a strong 128-bit hash. We use two
+ // different 56-byte-to-8-byte hashes to get a 16-byte final result.
+ x = HashLen16(x, v.first);
+ y = HashLen16(y + z, w.first);
+ return uint128(HashLen16(x + v.second, w.second) + y,
+ HashLen16(x + w.second, y + v.second));
+}
+
+uint128 CityHash128(const char *s, size_t len) {
+ return len >= 16 ?
+ CityHash128WithSeed(s + 16, len - 16,
+ uint128(Fetch64(s), Fetch64(s + 8) + k0)) :
+ CityHash128WithSeed(s, len, uint128(k0, k1));
+}
+
+#ifdef __SSE4_2__
+#include <citycrc.h>
+#include <nmmintrin.h>
+
+// Requires len >= 240.
+static void CityHashCrc256Long(const char *s, size_t len,
+ uint32 seed, uint64 *result) {
+ uint64 a = Fetch64(s + 56) + k0;
+ uint64 b = Fetch64(s + 96) + k0;
+ uint64 c = result[0] = HashLen16(b, len);
+ uint64 d = result[1] = Fetch64(s + 120) * k0 + len;
+ uint64 e = Fetch64(s + 184) + seed;
+ uint64 f = 0;
+ uint64 g = 0;
+ uint64 h = c + d;
+ uint64 x = seed;
+ uint64 y = 0;
+ uint64 z = 0;
+
+ // 240 bytes of input per iter.
+ size_t iters = len / 240;
+ len -= iters * 240;
+ do {
+#undef CHUNK
+#define CHUNK(r) \
+ PERMUTE3(x, z, y); \
+ b += Fetch64(s); \
+ c += Fetch64(s + 8); \
+ d += Fetch64(s + 16); \
+ e += Fetch64(s + 24); \
+ f += Fetch64(s + 32); \
+ a += b; \
+ h += f; \
+ b += c; \
+ f += d; \
+ g += e; \
+ e += z; \
+ g += x; \
+ z = _mm_crc32_u64(z, b + g); \
+ y = _mm_crc32_u64(y, e + h); \
+ x = _mm_crc32_u64(x, f + a); \
+ e = Rotate(e, r); \
+ c += e; \
+ s += 40
+
+ CHUNK(0); PERMUTE3(a, h, c);
+ CHUNK(33); PERMUTE3(a, h, f);
+ CHUNK(0); PERMUTE3(b, h, f);
+ CHUNK(42); PERMUTE3(b, h, d);
+ CHUNK(0); PERMUTE3(b, h, e);
+ CHUNK(33); PERMUTE3(a, h, e);
+ } while (--iters > 0);
+
+ while (len >= 40) {
+ CHUNK(29);
+ e ^= Rotate(a, 20);
+ h += Rotate(b, 30);
+ g ^= Rotate(c, 40);
+ f += Rotate(d, 34);
+ PERMUTE3(c, h, g);
+ len -= 40;
+ }
+ if (len > 0) {
+ s = s + len - 40;
+ CHUNK(33);
+ e ^= Rotate(a, 43);
+ h += Rotate(b, 42);
+ g ^= Rotate(c, 41);
+ f += Rotate(d, 40);
+ }
+ result[0] ^= h;
+ result[1] ^= g;
+ g += h;
+ a = HashLen16(a, g + z);
+ x += y << 32;
+ b += x;
+ c = HashLen16(c, z) + h;
+ d = HashLen16(d, e + result[0]);
+ g += e;
+ h += HashLen16(x, f);
+ e = HashLen16(a, d) + g;
+ z = HashLen16(b, c) + a;
+ y = HashLen16(g, h) + c;
+ result[0] = e + z + y + x;
+ a = ShiftMix((a + y) * k0) * k0 + b;
+ result[1] += a + result[0];
+ a = ShiftMix(a * k0) * k0 + c;
+ result[2] = a + result[1];
+ a = ShiftMix((a + e) * k0) * k0;
+ result[3] = a + result[2];
+}
+
+// Requires len < 240.
+static void CityHashCrc256Short(const char *s, size_t len, uint64 *result) {
+ char buf[240];
+ memcpy(buf, s, len);
+ memset(buf + len, 0, 240 - len);
+ CityHashCrc256Long(buf, 240, ~static_cast<uint32>(len), result);
+}
+
+void CityHashCrc256(const char *s, size_t len, uint64 *result) {
+ if (LIKELY(len >= 240)) {
+ CityHashCrc256Long(s, len, 0, result);
+ } else {
+ CityHashCrc256Short(s, len, result);
+ }
+}
+
+uint128 CityHashCrc128WithSeed(const char *s, size_t len, uint128 seed) {
+ if (len <= 900) {
+ return CityHash128WithSeed(s, len, seed);
+ } else {
+ uint64 result[4];
+ CityHashCrc256(s, len, result);
+ uint64 u = Uint128High64(seed) + result[0];
+ uint64 v = Uint128Low64(seed) + result[1];
+ return uint128(HashLen16(u, v + result[2]),
+ HashLen16(Rotate(v, 32), u * k0 + result[3]));
+ }
+}
+
+uint128 CityHashCrc128(const char *s, size_t len) {
+ if (len <= 900) {
+ return CityHash128(s, len);
+ } else {
+ uint64 result[4];
+ CityHashCrc256(s, len, result);
+ return uint128(result[2], result[3]);
+ }
+}
+
+#endif
diff --git a/core/city-hash.hpp b/core/city-hash.hpp
new file mode 100644
index 0000000..54a90cb
--- /dev/null
+++ b/core/city-hash.hpp
@@ -0,0 +1,112 @@
+// Copyright (c) 2011 Google, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+//
+// CityHash, by Geoff Pike and Jyrki Alakuijala
+//
+// http://code.google.com/p/cityhash/
+//
+// This file provides a few functions for hashing strings. All of them are
+// high-quality functions in the sense that they pass standard tests such
+// as Austin Appleby's SMHasher. They are also fast.
+//
+// For 64-bit x86 code, on short strings, we don't know of anything faster than
+// CityHash64 that is of comparable quality. We believe our nearest competitor
+// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash
+// tables and most other hashing (excluding cryptography).
+//
+// For 64-bit x86 code, on long strings, the picture is more complicated.
+// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
+// CityHashCrc128 appears to be faster than all competitors of comparable
+// quality. CityHash128 is also good but not quite as fast. We believe our
+// nearest competitor is Bob Jenkins' Spooky. We don't have great data for
+// other 64-bit CPUs, but for long strings we know that Spooky is slightly
+// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
+// Note that CityHashCrc128 is declared in citycrc.h.
+//
+// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
+// is of comparable quality. We believe our nearest competitor is Murmur3A.
+// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
+//
+// Functions in the CityHash family are not suitable for cryptography.
+//
+// Please see CityHash's README file for more details on our performance
+// measurements and so on.
+//
+// WARNING: This code has been only lightly tested on big-endian platforms!
+// It is known to work well on little-endian platforms that have a small penalty
+// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
+// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;
+// bug reports are welcome.
+//
+// By the way, for some hash functions, given strings a and b, the hash
+// of a+b is easily derived from the hashes of a and b. This property
+// doesn't hold for any hash functions in this file.
+
+#ifndef CITY_HASH_HPP
+#define CITY_HASH_HPP
+
+#include <stdlib.h> // for size_t.
+#include <stdint.h>
+#include <utility>
+
+typedef uint8_t uint8;
+typedef uint32_t uint32;
+typedef uint64_t uint64;
+typedef std::pair<uint64, uint64> uint128;
+
+inline uint64 Uint128Low64(const uint128& x) { return x.first; }
+inline uint64 Uint128High64(const uint128& x) { return x.second; }
+
+// Hash function for a byte array.
+uint64 CityHash64(const char *buf, size_t len);
+
+// Hash function for a byte array. For convenience, a 64-bit seed is also
+// hashed into the result.
+uint64 CityHash64WithSeed(const char *buf, size_t len, uint64 seed);
+
+// Hash function for a byte array. For convenience, two seeds are also
+// hashed into the result.
+uint64 CityHash64WithSeeds(const char *buf, size_t len,
+ uint64 seed0, uint64 seed1);
+
+// Hash function for a byte array.
+uint128 CityHash128(const char *s, size_t len);
+
+// Hash function for a byte array. For convenience, a 128-bit seed is also
+// hashed into the result.
+uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed);
+
+// Hash function for a byte array. Most useful in 32-bit binaries.
+uint32 CityHash32(const char *buf, size_t len);
+
+// Hash 128 input bits down to 64 bits of output.
+// This is intended to be a reasonably good hash function.
+inline uint64 Hash128to64(const uint128& x) {
+ // Murmur-inspired hashing.
+ const uint64 kMul = 0x9ddfea08eb382d69ULL;
+ uint64 a = (Uint128Low64(x) ^ Uint128High64(x)) * kMul;
+ a ^= (a >> 47);
+ uint64 b = (Uint128High64(x) ^ a) * kMul;
+ b ^= (b >> 47);
+ b *= kMul;
+ return b;
+}
+
+#endif // CITY_HASH_H_
diff --git a/core/config-file.cpp b/core/config-file.cpp
new file mode 100644
index 0000000..436c480
--- /dev/null
+++ b/core/config-file.cpp
@@ -0,0 +1,125 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "config-file.hpp"
+#include "logger.hpp"
+
+#include <boost/property_tree/info_parser.hpp>
+#include <fstream>
+
+namespace nfd {
+
+NFD_LOG_INIT("ConfigFile");
+
+ConfigFile::ConfigFile()
+{
+}
+
+void
+ConfigFile::addSectionHandler(const std::string& sectionName,
+ ConfigSectionHandler subscriber)
+{
+ m_subscriptions[sectionName] = subscriber;
+}
+
+void
+ConfigFile::parse(const std::string& filename, bool isDryRun)
+{
+ std::ifstream inputFile;
+ inputFile.open(filename.c_str());
+ if (!inputFile.good() || !inputFile.is_open())
+ {
+ std::string msg = "Failed to read configuration file: ";
+ msg += filename;
+ throw Error(msg);
+ }
+ parse(inputFile, isDryRun, filename);
+ inputFile.close();
+}
+
+void
+ConfigFile::parse(const std::string& input, bool isDryRun, const std::string& filename)
+{
+ std::istringstream inputStream(input);
+ parse(inputStream, isDryRun, filename);
+}
+
+
+void
+ConfigFile::parse(std::istream& input, bool isDryRun, const std::string& filename)
+{
+ try
+ {
+ boost::property_tree::read_info(input, m_global);
+ }
+ catch (const boost::property_tree::info_parser_error& error)
+ {
+ std::stringstream msg;
+ msg << "Failed to parse configuration file";
+ msg << " " << filename;
+ msg << " " << error.message() << " line " << error.line();
+ throw Error(msg.str());
+ }
+
+ process(isDryRun, filename);
+}
+
+void
+ConfigFile::process(bool isDryRun, const std::string& filename)
+{
+ BOOST_ASSERT(!filename.empty());
+ // NFD_LOG_DEBUG("processing..." << ((isDryRun)?("dry run"):("")));
+
+ if (m_global.begin() == m_global.end())
+ {
+ std::string msg = "Error processing configuration file";
+ msg += ": ";
+ msg += filename;
+ msg += " no data";
+ throw Error(msg);
+ }
+
+ for (ConfigSection::const_iterator i = m_global.begin(); i != m_global.end(); ++i)
+ {
+ const std::string& sectionName = i->first;
+ const ConfigSection& section = i->second;
+
+ SubscriptionTable::iterator subscriberIt = m_subscriptions.find(sectionName);
+ if (subscriberIt != m_subscriptions.end())
+ {
+ ConfigSectionHandler subscriber = subscriberIt->second;
+ subscriber(section, isDryRun, filename);
+ }
+ else
+ {
+ std::string msg = "Error processing configuration file";
+ msg += " ";
+ msg += filename;
+ msg += " no module subscribed for section: " + sectionName;
+ throw Error(msg);
+ }
+ }
+}
+
+}
diff --git a/core/config-file.hpp b/core/config-file.hpp
new file mode 100644
index 0000000..f3128c4
--- /dev/null
+++ b/core/config-file.hpp
@@ -0,0 +1,107 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_CONFIG_FILE_HPP
+#define NFD_CORE_CONFIG_FILE_HPP
+
+#include "common.hpp"
+
+#include <boost/property_tree/ptree.hpp>
+
+namespace nfd {
+
+typedef boost::property_tree::ptree ConfigSection;
+
+/// \brief callback for config file sections
+typedef function<void(const ConfigSection&, bool, const std::string&)> ConfigSectionHandler;
+
+class ConfigFile : noncopyable
+{
+public:
+
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::runtime_error(what)
+ {
+
+ }
+ };
+
+ ConfigFile();
+
+ /// \brief setup notification of configuration file sections
+ void
+ addSectionHandler(const std::string& sectionName,
+ ConfigSectionHandler subscriber);
+
+
+ /**
+ * \param filename file to parse
+ * \param isDryRun true if performing a dry run of configuration, false otherwise
+ * \throws ConfigFile::Error if file not found
+ * \throws ConfigFile::Error if parse error
+ */
+ void
+ parse(const std::string& filename, bool isDryRun);
+
+ /**
+ * \param input configuration (as a string) to parse
+ * \param isDryRun true if performing a dry run of configuration, false otherwise
+ * \param filename optional convenience argument to provide more detailed error messages
+ * \throws ConfigFile::Error if file not found
+ * \throws ConfigFile::Error if parse error
+ */
+ void
+ parse(const std::string& input, bool isDryRun, const std::string& filename);
+
+ /**
+ * \param input stream to parse
+ * \param isDryRun true if performing a dry run of configuration, false otherwise
+ * \param filename optional convenience argument to provide more detailed error messages
+ * \throws ConfigFile::Error if parse error
+ */
+ void
+ parse(std::istream& input, bool isDryRun, const std::string& filename);
+
+private:
+
+ void
+ process(bool isDryRun, const std::string& filename);
+
+private:
+
+ typedef std::map<std::string, ConfigSectionHandler> SubscriptionTable;
+
+ SubscriptionTable m_subscriptions;
+
+ ConfigSection m_global;
+};
+
+} // namespace nfd
+
+
+#endif // NFD_CORE_CONFIG_FILE_HPP
diff --git a/core/ethernet.cpp b/core/ethernet.cpp
new file mode 100644
index 0000000..1aeaca6
--- /dev/null
+++ b/core/ethernet.cpp
@@ -0,0 +1,82 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "ethernet.hpp"
+
+#include <stdio.h>
+
+namespace nfd {
+namespace ethernet {
+
+std::string
+Address::toString(char sep) const
+{
+ char s[18]; // 12 digits + 5 separators + null terminator
+ ::snprintf(s, sizeof(s), "%02x%c%02x%c%02x%c%02x%c%02x%c%02x",
+ elems[0], sep, elems[1], sep, elems[2], sep,
+ elems[3], sep, elems[4], sep, elems[5]);
+ return std::string(s);
+}
+
+Address
+Address::fromString(const std::string& str)
+{
+ unsigned short temp[ADDR_LEN];
+ char sep[5][2]; // 5 * (1 separator char + 1 null terminator)
+ int n = 0; // num of chars read from the input string
+
+ // ISO C++98 does not support the 'hh' type modifier
+ /// \todo use SCNx8 (cinttypes) when we enable C++11
+ int ret = ::sscanf(str.c_str(), "%2hx%1[:-]%2hx%1[:-]%2hx%1[:-]%2hx%1[:-]%2hx%1[:-]%2hx%n",
+ &temp[0], &sep[0][0], &temp[1], &sep[1][0], &temp[2], &sep[2][0],
+ &temp[3], &sep[3][0], &temp[4], &sep[4][0], &temp[5], &n);
+
+ if (ret < 11 || static_cast<size_t>(n) != str.length())
+ return Address();
+
+ Address a;
+ for (size_t i = 0; i < ADDR_LEN; ++i)
+ {
+ // check that all separators are actually the same char (: or -)
+ if (i < 5 && sep[i][0] != sep[0][0])
+ return Address();
+
+ // check that each value fits into a uint8_t
+ if (temp[i] > 0xFF)
+ return Address();
+
+ a[i] = static_cast<uint8_t>(temp[i]);
+ }
+
+ return a;
+}
+
+std::ostream&
+operator<<(std::ostream& o, const Address& a)
+{
+ return o << a.toString();
+}
+
+} // namespace ethernet
+} // namespace nfd
diff --git a/core/ethernet.hpp b/core/ethernet.hpp
new file mode 100644
index 0000000..56888f6
--- /dev/null
+++ b/core/ethernet.hpp
@@ -0,0 +1,167 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_ETHERNET_HPP
+#define NFD_CORE_ETHERNET_HPP
+
+#include "common.hpp"
+
+#include <boost/array.hpp>
+
+#define ETHERTYPE_NDN 0x8624
+
+namespace nfd {
+namespace ethernet {
+
+const size_t ADDR_LEN = 6; ///< Octets in one Ethernet address
+const size_t TYPE_LEN = 2; ///< Octets in Ethertype field
+const size_t HDR_LEN = 14; ///< Total octets in Ethernet header (without 802.1Q tag)
+const size_t TAG_LEN = 4; ///< Octets in 802.1Q tag (TPID + priority + VLAN)
+const size_t MIN_DATA_LEN = 46; ///< Min octets in Ethernet payload (assuming no 802.1Q tag)
+const size_t MAX_DATA_LEN = 1500; ///< Max octets in Ethernet payload
+const size_t CRC_LEN = 4; ///< Octets in Ethernet frame check sequence
+
+
+class Address : public boost::array<uint8_t, ADDR_LEN>
+{
+public:
+ /// Constructs a null Ethernet address (00:00:00:00:00:00)
+ Address();
+
+ /// Constructs a new Ethernet address with the given octets
+ Address(uint8_t a1, uint8_t a2, uint8_t a3,
+ uint8_t a4, uint8_t a5, uint8_t a6);
+
+ /// Constructs a new Ethernet address with the given octets
+ explicit
+ Address(const uint8_t octets[ADDR_LEN]);
+
+ /// Copy constructor
+ Address(const Address& address);
+
+ /// True if this is a broadcast address (ff:ff:ff:ff:ff:ff)
+ bool
+ isBroadcast() const;
+
+ /// True if this is a multicast address
+ bool
+ isMulticast() const;
+
+ /// True if this is a null address (00:00:00:00:00:00)
+ bool
+ isNull() const;
+
+ /**
+ * @brief Converts the address to a human-readable string
+ *
+ * @param sep A character used to visually separate the octets,
+ * usually ':' (the default value) or '-'
+ */
+ std::string
+ toString(char sep = ':') const;
+
+ /**
+ * @brief Creates an Address from a string containing an Ethernet address
+ * in hexadecimal notation, with colons or hyphens as separators
+ *
+ * @param str The string to be parsed
+ * @return Always an instance of Address, which will be null
+ * if the parsing fails
+ */
+ static Address
+ fromString(const std::string& str);
+};
+
+/// Returns the Ethernet broadcast address (ff:ff:ff:ff:ff:ff)
+inline Address
+getBroadcastAddress()
+{
+ static Address bcast(0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF);
+ return bcast;
+}
+
+/// Returns the default Ethernet multicast address for NDN
+inline Address
+getDefaultMulticastAddress()
+{
+ static Address mcast(0x01, 0x00, 0x5E, 0x00, 0x17, 0xAA);
+ return mcast;
+}
+
+inline
+Address::Address()
+{
+ assign(0);
+}
+
+inline
+Address::Address(uint8_t a1, uint8_t a2, uint8_t a3, uint8_t a4, uint8_t a5, uint8_t a6)
+{
+ elems[0] = a1;
+ elems[1] = a2;
+ elems[2] = a3;
+ elems[3] = a4;
+ elems[4] = a5;
+ elems[5] = a6;
+}
+
+inline
+Address::Address(const uint8_t octets[])
+{
+ std::copy(octets, octets + size(), begin());
+}
+
+inline
+Address::Address(const Address& address)
+{
+ std::copy(address.begin(), address.end(), begin());
+}
+
+inline bool
+Address::isBroadcast() const
+{
+ return elems[0] == 0xFF && elems[1] == 0xFF && elems[2] == 0xFF &&
+ elems[3] == 0xFF && elems[4] == 0xFF && elems[5] == 0xFF;
+}
+
+inline bool
+Address::isMulticast() const
+{
+ return (elems[0] & 1) != 0;
+}
+
+inline bool
+Address::isNull() const
+{
+ return elems[0] == 0x0 && elems[1] == 0x0 && elems[2] == 0x0 &&
+ elems[3] == 0x0 && elems[4] == 0x0 && elems[5] == 0x0;
+}
+
+std::ostream&
+operator<<(std::ostream& o, const Address& a);
+
+} // namespace ethernet
+} // namespace nfd
+
+#endif // NFD_FACE_ETHERNET_HPP
diff --git a/core/event-emitter.hpp b/core/event-emitter.hpp
new file mode 100644
index 0000000..35925f9
--- /dev/null
+++ b/core/event-emitter.hpp
@@ -0,0 +1,343 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_EVENT_EMITTER_HPP
+#define NFD_CORE_EVENT_EMITTER_HPP
+
+#include "common.hpp"
+
+namespace nfd {
+
+struct empty {};
+
+/** \class EventEmitter
+ * \brief provides a lightweight event system
+ *
+ * To declare an event:
+ * EventEmitter<TArgs> m_eventName;
+ * To subscribe to an event:
+ * eventSource->m_eventName += eventHandler;
+ * Multiple functions can subscribe to the same event.
+ * To trigger an event:
+ * m_eventName(args);
+ * To clear event subscriptions:
+ * m_eventName.clear();
+ */
+
+// four arguments
+template<typename T1 = empty, typename T2 = empty,
+ typename T3 = empty, typename T4 = empty>
+class EventEmitter : noncopyable
+{
+public:
+ /// represents a handler that can subscribe to the event
+ typedef function<void(const T1&, const T2&,
+ const T3&, const T4&)> Handler;
+
+ /// adds an subscription
+ void
+ operator+=(Handler handler);
+
+ /// returns true if there is no subscription,
+ /// otherwise returns false
+ bool
+ isEmpty();
+
+ /// clears all subscriptions
+ void
+ clear();
+
+ /// triggers the event
+ void
+ operator()(const T1& a1, const T2& a2, const T3& a3, const T4& a4);
+
+private:
+ /// stores all subscribed handlers
+ std::vector<Handler> m_handlers;
+};
+
+// zero argument
+template<>
+class EventEmitter<empty, empty, empty, empty> : noncopyable
+{
+public:
+ typedef function<void()> Handler;
+
+ void
+ operator+=(Handler handler);
+
+ bool
+ isEmpty();
+
+ void
+ clear();
+
+ void
+ operator()();
+
+private:
+ std::vector<Handler> m_handlers;
+};
+
+
+// one argument
+template<typename T1>
+class EventEmitter<T1, empty, empty, empty> : noncopyable
+{
+public:
+ typedef function<void(const T1&)> Handler;
+
+ void
+ operator+=(Handler handler);
+
+ bool
+ isEmpty();
+
+ void
+ clear();
+
+ void
+ operator()(const T1& a1);
+
+private:
+ std::vector<Handler> m_handlers;
+};
+
+
+// two arguments
+template<typename T1, typename T2>
+class EventEmitter<T1, T2, empty, empty> : noncopyable
+{
+public:
+ typedef function<void(const T1&, const T2&)> Handler;
+
+ void
+ operator+=(Handler handler);
+
+ bool
+ isEmpty();
+
+ void
+ clear();
+
+ void
+ operator()(const T1& a1, const T2& a2);
+
+private:
+ std::vector<Handler> m_handlers;
+};
+
+
+// three arguments
+template<typename T1, typename T2, typename T3>
+class EventEmitter<T1, T2, T3, empty> : noncopyable
+{
+public:
+ typedef function<void(const T1&, const T2&, const T3&)> Handler;
+
+ void
+ operator+=(Handler handler);
+
+ bool
+ isEmpty();
+
+ void
+ clear();
+
+ void
+ operator()(const T1& a1, const T2& a2, const T3& a3);
+
+private:
+ std::vector<Handler> m_handlers;
+};
+
+
+// zero argument
+
+inline void
+EventEmitter<empty, empty, empty, empty>::operator+=(Handler handler)
+{
+ m_handlers.push_back(handler);
+}
+
+inline bool
+EventEmitter<empty, empty, empty, empty>::isEmpty()
+{
+ return m_handlers.empty();
+}
+
+inline void
+EventEmitter<empty, empty, empty, empty>::clear()
+{
+ return m_handlers.clear();
+}
+
+inline void
+EventEmitter<empty, empty, empty, empty>::operator()()
+{
+ std::vector<Handler>::iterator it;
+ for (it = m_handlers.begin(); it != m_handlers.end(); ++it) {
+ (*it)();
+ }
+}
+
+// one argument
+
+template<typename T1>
+inline void
+EventEmitter<T1, empty, empty, empty>::operator+=(Handler handler)
+{
+ m_handlers.push_back(handler);
+}
+
+template<typename T1>
+inline bool
+EventEmitter<T1, empty, empty, empty>::isEmpty()
+{
+ return m_handlers.empty();
+}
+
+template<typename T1>
+inline void
+EventEmitter<T1, empty, empty, empty>::clear()
+{
+ return m_handlers.clear();
+}
+
+template<typename T1>
+inline void
+EventEmitter<T1, empty, empty, empty>::operator()(const T1& a1)
+{
+ typename std::vector<Handler>::iterator it;
+ for (it = m_handlers.begin(); it != m_handlers.end(); ++it) {
+ (*it)(a1);
+ }
+}
+
+// two arguments
+
+template<typename T1, typename T2>
+inline void
+EventEmitter<T1, T2, empty, empty>::operator+=(Handler handler)
+{
+ m_handlers.push_back(handler);
+}
+
+template<typename T1, typename T2>
+inline bool
+EventEmitter<T1, T2, empty, empty>::isEmpty()
+{
+ return m_handlers.empty();
+}
+
+template<typename T1, typename T2>
+inline void
+EventEmitter<T1, T2, empty, empty>::clear()
+{
+ return m_handlers.clear();
+}
+
+template<typename T1, typename T2>
+inline void
+EventEmitter<T1, T2, empty, empty>::operator()
+ (const T1& a1, const T2& a2)
+{
+ typename std::vector<Handler>::iterator it;
+ for (it = m_handlers.begin(); it != m_handlers.end(); ++it) {
+ (*it)(a1, a2);
+ }
+}
+
+// three arguments
+
+template<typename T1, typename T2, typename T3>
+inline void
+EventEmitter<T1, T2, T3, empty>::operator+=(Handler handler)
+{
+ m_handlers.push_back(handler);
+}
+
+template<typename T1, typename T2, typename T3>
+inline bool
+EventEmitter<T1, T2, T3, empty>::isEmpty()
+{
+ return m_handlers.empty();
+}
+
+template<typename T1, typename T2, typename T3>
+inline void
+EventEmitter<T1, T2, T3, empty>::clear()
+{
+ return m_handlers.clear();
+}
+
+template<typename T1, typename T2, typename T3>
+inline void
+EventEmitter<T1, T2, T3, empty>::operator()
+ (const T1& a1, const T2& a2, const T3& a3)
+{
+ typename std::vector<Handler>::iterator it;
+ for (it = m_handlers.begin(); it != m_handlers.end(); ++it) {
+ (*it)(a1, a2, a3);
+ }
+}
+
+// four arguments
+
+template<typename T1, typename T2, typename T3, typename T4>
+inline void
+EventEmitter<T1, T2, T3, T4>::operator+=(Handler handler)
+{
+ m_handlers.push_back(handler);
+}
+
+template<typename T1, typename T2, typename T3, typename T4>
+inline bool
+EventEmitter<T1, T2, T3, T4>::isEmpty()
+{
+ return m_handlers.empty();
+}
+
+template<typename T1, typename T2, typename T3, typename T4>
+inline void
+EventEmitter<T1, T2, T3, T4>::clear()
+{
+ return m_handlers.clear();
+}
+
+template<typename T1, typename T2, typename T3, typename T4>
+inline void
+EventEmitter<T1, T2, T3, T4>::operator()
+ (const T1& a1, const T2& a2, const T3& a3, const T4& a4)
+{
+ typename std::vector<Handler>::iterator it;
+ for (it = m_handlers.begin(); it != m_handlers.end(); ++it) {
+ (*it)(a1, a2, a3, a4);
+ }
+}
+
+
+} // namespace nfd
+
+#endif // NFD_CORE_EVENT_EMITTER_HPP
diff --git a/core/face-uri.cpp b/core/face-uri.cpp
new file mode 100644
index 0000000..7eaaddd
--- /dev/null
+++ b/core/face-uri.cpp
@@ -0,0 +1,151 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "face-uri.hpp"
+#include "core/logger.hpp"
+
+#ifdef HAVE_LIBPCAP
+#include "ethernet.hpp"
+#endif // HAVE_LIBPCAP
+
+#include <boost/regex.hpp>
+
+NFD_LOG_INIT("FaceUri");
+
+namespace nfd {
+
+FaceUri::FaceUri(const std::string& uri)
+{
+ if (!parse(uri)) {
+ throw Error("Malformed URI: " + uri);
+ }
+}
+
+FaceUri::FaceUri(const char* uri)
+{
+ if (!parse(uri)) {
+ throw Error("Malformed URI: " + std::string(uri));
+ }
+}
+
+bool
+FaceUri::parse(const std::string& uri)
+{
+ m_scheme.clear();
+ m_host.clear();
+ m_isV6 = false;
+ m_port.clear();
+ m_path.clear();
+
+ static const boost::regex protocolExp("(\\w+\\d?)://([^/]*)(\\/[^?]*)?");
+ boost::smatch protocolMatch;
+ if (!boost::regex_match(uri, protocolMatch, protocolExp)) {
+ return false;
+ }
+ m_scheme = protocolMatch[1];
+ const std::string& authority = protocolMatch[2];
+ m_path = protocolMatch[3];
+
+ // pattern for IPv6 address enclosed in [ ], with optional port number
+ static const boost::regex v6Exp("^\\[([a-fA-F0-9:]+)\\](?:\\:(\\d+))?$");
+ // pattern for Ethernet address in standard hex-digits-and-colons notation
+ static const boost::regex etherExp("^((?:[a-fA-F0-9]{1,2}\\:){5}(?:[a-fA-F0-9]{1,2}))$");
+ // pattern for IPv4/hostname/fd/ifname, with optional port number
+ static const boost::regex v4HostExp("^([^:]+)(?:\\:(\\d+))?$");
+
+ if (authority.empty()) {
+ // UNIX, internal
+ }
+ else {
+ boost::smatch match;
+ m_isV6 = boost::regex_match(authority, match, v6Exp);
+ if (m_isV6 ||
+ boost::regex_match(authority, match, etherExp) ||
+ boost::regex_match(authority, match, v4HostExp)) {
+ m_host = match[1];
+ m_port = match[2];
+ }
+ else {
+ return false;
+ }
+ }
+
+ NFD_LOG_DEBUG("URI [" << uri << "] parsed into: " <<
+ m_scheme << ", " << m_host << ", " << m_port << ", " << m_path);
+ return true;
+}
+
+FaceUri::FaceUri(const boost::asio::ip::tcp::endpoint& endpoint)
+{
+ m_isV6 = endpoint.address().is_v6();
+ m_scheme = m_isV6 ? "tcp6" : "tcp4";
+ m_host = endpoint.address().to_string();
+ m_port = boost::lexical_cast<std::string>(endpoint.port());
+}
+
+FaceUri::FaceUri(const boost::asio::ip::udp::endpoint& endpoint)
+{
+ m_isV6 = endpoint.address().is_v6();
+ m_scheme = m_isV6 ? "udp6" : "udp4";
+ m_host = endpoint.address().to_string();
+ m_port = boost::lexical_cast<std::string>(endpoint.port());
+}
+
+#ifdef HAVE_UNIX_SOCKETS
+FaceUri::FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint)
+ : m_isV6(false)
+{
+ m_scheme = "unix";
+ m_path = endpoint.path();
+}
+#endif // HAVE_UNIX_SOCKETS
+
+FaceUri
+FaceUri::fromFd(int fd)
+{
+ FaceUri uri;
+ uri.m_scheme = "fd";
+ uri.m_host = boost::lexical_cast<std::string>(fd);
+ return uri;
+}
+
+#ifdef HAVE_LIBPCAP
+FaceUri::FaceUri(const ethernet::Address& address)
+ : m_isV6(false)
+{
+ m_scheme = "ether";
+ m_host = address.toString();
+}
+#endif // HAVE_LIBPCAP
+
+FaceUri
+FaceUri::fromDev(const std::string& ifname)
+{
+ FaceUri uri;
+ uri.m_scheme = "dev";
+ uri.m_host = ifname;
+ return uri;
+}
+
+} // namespace nfd
diff --git a/core/face-uri.hpp b/core/face-uri.hpp
new file mode 100644
index 0000000..487f8f8
--- /dev/null
+++ b/core/face-uri.hpp
@@ -0,0 +1,191 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_FACE_URI_H
+#define NFD_CORE_FACE_URI_H
+
+#include "common.hpp"
+
+namespace nfd {
+
+#ifdef HAVE_LIBPCAP
+namespace ethernet {
+class Address;
+} // namespace ethernet
+#endif // HAVE_LIBPCAP
+
+/** \brief represents the underlying protocol and address used by a Face
+ * \sa http://redmine.named-data.net/projects/nfd/wiki/FaceMgmt#FaceUri
+ */
+class FaceUri
+{
+public:
+ class Error : public std::invalid_argument
+ {
+ public:
+ explicit
+ Error(const std::string& what)
+ : std::invalid_argument(what)
+ {
+ }
+ };
+
+ FaceUri();
+
+ /** \brief construct by parsing
+ *
+ * \param uri scheme://host[:port]/path
+ * \throw FaceUri::Error if URI cannot be parsed
+ */
+ explicit
+ FaceUri(const std::string& uri);
+
+ // This overload is needed so that calls with string literal won't be
+ // resolved to boost::asio::local::stream_protocol::endpoint overload.
+ explicit
+ FaceUri(const char* uri);
+
+ /// exception-safe parsing
+ bool
+ parse(const std::string& uri);
+
+public: // scheme-specific construction
+ /// construct tcp4 or tcp6 canonical FaceUri
+ explicit
+ FaceUri(const boost::asio::ip::tcp::endpoint& endpoint);
+
+ /// construct udp4 or udp6 canonical FaceUri
+ explicit
+ FaceUri(const boost::asio::ip::udp::endpoint& endpoint);
+
+#ifdef HAVE_UNIX_SOCKETS
+ /// construct unix canonical FaceUri
+ explicit
+ FaceUri(const boost::asio::local::stream_protocol::endpoint& endpoint);
+#endif // HAVE_UNIX_SOCKETS
+
+ /// create fd FaceUri from file descriptor
+ static FaceUri
+ fromFd(int fd);
+
+#ifdef HAVE_LIBPCAP
+ /// construct ether canonical FaceUri
+ explicit
+ FaceUri(const ethernet::Address& address);
+#endif // HAVE_LIBPCAP
+
+ /// create dev FaceUri from network device name
+ static FaceUri
+ fromDev(const std::string& ifname);
+
+public: // getters
+ /// get scheme (protocol)
+ const std::string&
+ getScheme() const;
+
+ /// get host (domain)
+ const std::string&
+ getHost() const;
+
+ /// get port
+ const std::string&
+ getPort() const;
+
+ /// get path
+ const std::string&
+ getPath() const;
+
+ /// write as a string
+ std::string
+ toString() const;
+
+private:
+ std::string m_scheme;
+ std::string m_host;
+ /// whether to add [] around host when writing string
+ bool m_isV6;
+ std::string m_port;
+ std::string m_path;
+
+ friend std::ostream& operator<<(std::ostream& os, const FaceUri& uri);
+};
+
+inline
+FaceUri::FaceUri()
+ : m_isV6(false)
+{
+}
+
+inline const std::string&
+FaceUri::getScheme() const
+{
+ return m_scheme;
+}
+
+inline const std::string&
+FaceUri::getHost() const
+{
+ return m_host;
+}
+
+inline const std::string&
+FaceUri::getPort() const
+{
+ return m_port;
+}
+
+inline const std::string&
+FaceUri::getPath() const
+{
+ return m_path;
+}
+
+inline std::string
+FaceUri::toString() const
+{
+ std::ostringstream os;
+ os << *this;
+ return os.str();
+}
+
+inline std::ostream&
+operator<<(std::ostream& os, const FaceUri& uri)
+{
+ os << uri.m_scheme << "://";
+ if (uri.m_isV6) {
+ os << "[" << uri.m_host << "]";
+ }
+ else {
+ os << uri.m_host;
+ }
+ if (!uri.m_port.empty()) {
+ os << ":" << uri.m_port;
+ }
+ os << uri.m_path;
+ return os;
+}
+
+} // namespace nfd
+
+#endif // NFD_CORE_FACE_URI_H
diff --git a/core/global-io.cpp b/core/global-io.cpp
new file mode 100644
index 0000000..f8d8270
--- /dev/null
+++ b/core/global-io.cpp
@@ -0,0 +1,53 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "global-io.hpp"
+
+namespace nfd {
+
+namespace scheduler {
+// defined in scheduler.cpp
+void
+resetGlobalScheduler();
+} // namespace scheduler
+
+static shared_ptr<boost::asio::io_service> g_ioService;
+
+boost::asio::io_service&
+getGlobalIoService()
+{
+ if (!static_cast<bool>(g_ioService)) {
+ g_ioService = make_shared<boost::asio::io_service>();
+ }
+ return *g_ioService;
+}
+
+void
+resetGlobalIoService()
+{
+ scheduler::resetGlobalScheduler();
+ g_ioService.reset();
+}
+
+} // namespace nfd
diff --git a/core/global-io.hpp b/core/global-io.hpp
new file mode 100644
index 0000000..d5030ab
--- /dev/null
+++ b/core/global-io.hpp
@@ -0,0 +1,48 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_GLOBAL_IO_HPP
+#define NFD_CORE_GLOBAL_IO_HPP
+
+#include "common.hpp"
+
+namespace nfd {
+
+/** \return the global io_service instance
+ */
+boost::asio::io_service&
+getGlobalIoService();
+
+#ifdef WITH_TESTS
+/** \brief delete the global io_service instance
+ *
+ * It will be recreated at the next invocation of getGlobalIoService.
+ */
+void
+resetGlobalIoService();
+#endif
+
+} // namespace nfd
+
+#endif // NFD_CORE_GLOBAL_IO_HPP
diff --git a/core/logger-factory.cpp b/core/logger-factory.cpp
new file mode 100644
index 0000000..3a738eb
--- /dev/null
+++ b/core/logger-factory.cpp
@@ -0,0 +1,196 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "logger-factory.hpp"
+
+namespace nfd {
+
+LoggerFactory&
+LoggerFactory::getInstance()
+{
+ static LoggerFactory globalLoggerFactory;
+
+ return globalLoggerFactory;
+}
+
+LoggerFactory::LoggerFactory()
+ : m_defaultLevel(LOG_INFO)
+{
+ m_levelNames["NONE"] = LOG_NONE;
+ m_levelNames["ERROR"] = LOG_ERROR;
+ m_levelNames["WARN"] = LOG_WARN;
+ m_levelNames["INFO"] = LOG_INFO;
+ m_levelNames["DEBUG"] = LOG_DEBUG;
+ m_levelNames["TRACE"] = LOG_TRACE;
+ m_levelNames["ALL"] = LOG_ALL;
+}
+
+void
+LoggerFactory::setConfigFile(ConfigFile& config)
+{
+ config.addSectionHandler("log", bind(&LoggerFactory::onConfig, this, _1, _2, _3));
+}
+
+LogLevel
+LoggerFactory::parseLevel(const std::string& level)
+{
+ std::string upperLevel = level;
+ boost::to_upper(upperLevel);
+
+ // std::cerr << "parsing level: " << upperLevel << std::endl;;
+ // std::cerr << "# levels: " << m_levelNames.size() << std::endl;
+ // std::cerr << m_levelNames.begin()->first << std::endl;
+
+ LevelMap::const_iterator levelIt = m_levelNames.find(upperLevel);
+ if (levelIt != m_levelNames.end())
+ {
+ return levelIt->second;
+ }
+ try
+ {
+ uint32_t levelNo = boost::lexical_cast<uint32_t>(level);
+
+ if ((LOG_NONE <= levelNo && levelNo <= LOG_TRACE) ||
+ levelNo == LOG_ALL)
+ {
+ return static_cast<LogLevel>(levelNo);
+ }
+ }
+ catch (const boost::bad_lexical_cast& error)
+ {
+ }
+ throw LoggerFactory::Error("Unsupported logging level \"" +
+ level + "\"");
+}
+
+
+void
+LoggerFactory::onConfig(const ConfigSection& section,
+ bool isDryRun,
+ const std::string& filename)
+{
+// log
+// {
+// ; default_level specifies the logging level for modules
+// ; that are not explicitly named. All debugging levels
+// ; listed above the selected value are enabled.
+//
+// default_level INFO
+//
+// ; You may also override the default for specific modules:
+//
+// FibManager DEBUG
+// Forwarder WARN
+// }
+
+ // std::cerr << "loading logging configuration" << std::endl;
+ for (ConfigSection::const_iterator item = section.begin();
+ item != section.end();
+ ++item)
+ {
+ std::string levelString;
+ try
+ {
+ levelString = item->second.get_value<std::string>();
+ }
+ catch (const boost::property_tree::ptree_error& error)
+ {
+ }
+
+ if (levelString.empty())
+ {
+ throw LoggerFactory::Error("No logging level found for option \"" + item->first + "\"");
+ }
+
+ LogLevel level = parseLevel(levelString);
+
+ if (item->first == "default_level")
+ {
+ if (!isDryRun)
+ {
+ setDefaultLevel(level);
+ }
+ }
+ else
+ {
+ LoggerMap::iterator loggerIt = m_loggers.find(item->first);
+ if (loggerIt == m_loggers.end())
+ {
+ throw LoggerFactory::Error("Invalid module name \"" +
+ item->first + "\" in configuration file");
+ }
+
+ if (!isDryRun)
+ {
+ // std::cerr << "changing level for module " << item->first << " to " << level << std::endl;
+ loggerIt->second.setLogLevel(level);
+ }
+ }
+ }
+}
+
+void
+LoggerFactory::setDefaultLevel(LogLevel level)
+{
+ // std::cerr << "changing to default_level " << level << std::endl;
+
+ m_defaultLevel = level;
+ for (LoggerMap::iterator i = m_loggers.begin(); i != m_loggers.end(); ++i)
+ {
+ // std::cerr << "changing " << i->first << " to default " << m_defaultLevel << std::endl;
+ i->second.setLogLevel(m_defaultLevel);
+ }
+}
+
+Logger&
+LoggerFactory::create(const std::string& moduleName)
+{
+ return LoggerFactory::getInstance().createLogger(moduleName);
+}
+
+Logger&
+LoggerFactory::createLogger(const std::string& moduleName)
+{
+ // std::cerr << "creating logger for " << moduleName
+ // << " with level " << m_defaultLevel << std::endl;
+
+ std::pair<LoggerMap::iterator, bool> loggerIt =
+ m_loggers.insert(NameAndLogger(moduleName, Logger(moduleName, m_defaultLevel)));
+
+ return loggerIt.first->second;
+}
+
+std::list<std::string>
+LoggerFactory::getModules() const
+{
+ std::list<std::string> modules;
+ for (LoggerMap::const_iterator i = m_loggers.begin(); i != m_loggers.end(); ++i)
+ {
+ modules.push_back(i->first);
+ }
+
+ return modules;
+}
+
+} // namespace nfd
diff --git a/core/logger-factory.hpp b/core/logger-factory.hpp
new file mode 100644
index 0000000..b5aa31d
--- /dev/null
+++ b/core/logger-factory.hpp
@@ -0,0 +1,107 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_LOGGER_FACTORY_HPP
+#define NFD_CORE_LOGGER_FACTORY_HPP
+
+#include "common.hpp"
+#include "config-file.hpp"
+#include "logger.hpp"
+
+namespace nfd {
+
+class LoggerFactory : noncopyable
+{
+public:
+
+ class Error : public std::runtime_error
+ {
+ public:
+ explicit
+ Error(const std::string& error)
+ : std::runtime_error(error)
+ {
+ }
+ };
+
+ static LoggerFactory&
+ getInstance();
+
+ void
+ setConfigFile(ConfigFile& config);
+
+ void
+ onConfig(const ConfigSection& section, bool isDryRun, const std::string& filename);
+
+ std::list<std::string>
+ getModules() const;
+
+ static Logger&
+ create(const std::string& moduleName);
+
+
+PUBLIC_WITH_TESTS_ELSE_PRIVATE:
+
+ // these methods are used during unit-testing
+
+ LogLevel
+ getDefaultLevel() const;
+
+ void
+ setDefaultLevel(LogLevel level);
+
+private:
+
+ LoggerFactory();
+
+ Logger&
+ createLogger(const std::string& moduleName);
+
+ LogLevel
+ parseLevel(const std::string& level);
+
+private:
+
+ typedef std::map<std::string, LogLevel> LevelMap;
+ typedef std::pair<std::string, LogLevel> NameAndLevel;
+
+ LevelMap m_levelNames;
+
+ typedef std::map<std::string, Logger> LoggerMap;
+ typedef std::pair<std::string, Logger> NameAndLogger;
+
+ LoggerMap m_loggers;
+
+ LogLevel m_defaultLevel;
+};
+
+inline LogLevel
+LoggerFactory::getDefaultLevel() const
+{
+ return m_defaultLevel;
+}
+
+} // namespace nfd
+
+#endif // NFD_CORE_LOGGER_FACTORY_HPP
diff --git a/core/logger.hpp b/core/logger.hpp
new file mode 100644
index 0000000..907ce7e
--- /dev/null
+++ b/core/logger.hpp
@@ -0,0 +1,176 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_LOGGER_HPP
+#define NFD_CORE_LOGGER_HPP
+
+#include "common.hpp"
+#include <ndn-cpp-dev/util/time.hpp>
+
+/// \todo use when we enable C++11 (see todo in now())
+// #include <cinttypes>
+
+namespace nfd {
+
+enum LogLevel {
+ LOG_NONE = 0, // no messages
+ LOG_ERROR = 1, // serious error messages
+ LOG_WARN = 2, // warning messages
+ LOG_INFO = 3, // informational messages
+ LOG_DEBUG = 4, // debug messages
+ LOG_TRACE = 5, // trace messages (most verbose)
+ // LOG_FATAL is not a level and is logged unconditionally
+ LOG_ALL = 255 // all messages
+};
+
+class Logger
+{
+public:
+
+ Logger(const std::string& name, LogLevel level)
+ : m_moduleName(name)
+ , m_enabledLogLevel(level)
+ {
+ }
+
+ bool
+ isEnabled(LogLevel level) const
+ {
+ // std::cerr << m_moduleName <<
+ // " enabled = " << m_enabledLogLevel
+ // << " level = " << level << std::endl;
+ return (m_enabledLogLevel >= level);
+ }
+
+ void
+ setLogLevel(LogLevel level)
+ {
+ m_enabledLogLevel = level;
+ }
+
+ const std::string&
+ getName() const
+ {
+ return m_moduleName;
+ }
+
+ void
+ setName(const std::string& name)
+ {
+ m_moduleName = name;
+ }
+
+ /// \brief return a string representation of time since epoch: seconds.microseconds
+ static std::string
+ now()
+ {
+ using namespace ndn::time;
+
+ static const microseconds::rep ONE_SECOND = 1000000;
+ microseconds::rep microseconds_since_epoch =
+ duration_cast<microseconds>(system_clock::now().time_since_epoch()).count();
+
+ // 10 (whole seconds) + '.' + 6 (fraction) + 1 (\0)
+ char buffer[10 + 1 + 6 + 1];
+ ::snprintf(buffer, sizeof(buffer), "%lld.%06lld",
+ static_cast<long long int>(microseconds_since_epoch / ONE_SECOND),
+ static_cast<long long int>(microseconds_since_epoch % ONE_SECOND));
+
+ /// \todo use this version when we enable C++11 to avoid casting
+ // ::snprintf(buffer, sizeof(buffer), "%" PRIdLEAST64 ".%06" PRIdLEAST64,
+ // microseconds_since_epoch / ONE_SECOND,
+ // microseconds_since_epoch % ONE_SECOND);
+
+ return std::string(buffer);
+ }
+
+private:
+ std::string m_moduleName;
+ LogLevel m_enabledLogLevel;
+};
+
+inline std::ostream&
+operator<<(std::ostream& output, const Logger& logger)
+{
+ output << logger.getName();
+ return output;
+}
+
+} // namespace nfd
+
+#include "core/logger-factory.hpp"
+
+namespace nfd {
+
+#define NFD_LOG_INIT(name) \
+static nfd::Logger& g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG_INCLASS_DECLARE() \
+static nfd::Logger& g_logger
+
+#define NFD_LOG_INCLASS_DEFINE(cls, name) \
+nfd::Logger& cls::g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG_INCLASS_TEMPLATE_DEFINE(cls, name) \
+template<class T> \
+nfd::Logger& cls<T>::g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG_INCLASS_TEMPLATE_SPECIALIZATION_DEFINE(cls, specialization, name) \
+template<> \
+nfd::Logger& cls<specialization>::g_logger = nfd::LoggerFactory::create(name)
+
+#define NFD_LOG_INCLASS_2TEMPLATE_SPECIALIZATION_DEFINE(cls, s1, s2, name) \
+template<> \
+nfd::Logger& cls<s1, s2>::g_logger = nfd::LoggerFactory::create(name)
+
+
+#define NFD_LOG(level, expression) \
+do { \
+ if (g_logger.isEnabled(::nfd::LOG_##level)) \
+ std::clog << ::nfd::Logger::now() << " "#level": " \
+ << "[" << g_logger << "] " << expression << "\n"; \
+} while (false)
+
+#define NFD_LOG_TRACE(expression) NFD_LOG(TRACE, expression)
+#define NFD_LOG_DEBUG(expression) NFD_LOG(DEBUG, expression)
+#define NFD_LOG_INFO(expression) NFD_LOG(INFO, expression)
+#define NFD_LOG_ERROR(expression) NFD_LOG(ERROR, expression)
+
+// specialize WARN because the message is "WARNING" instead of "WARN"
+#define NFD_LOG_WARN(expression) \
+do { \
+ if (g_logger.isEnabled(::nfd::LOG_WARN)) \
+ std::clog << ::nfd::Logger::now() << " WARNING: " \
+ << "[" << g_logger << "] " << expression << "\n"; \
+} while (false)
+
+#define NFD_LOG_FATAL(expression) \
+do { \
+ std::clog << ::nfd::Logger::now() << " FATAL: " \
+ << "[" << g_logger << "] " << expression << "\n"; \
+} while (false)
+
+} //namespace nfd
+
+#endif
diff --git a/core/map-value-iterator.hpp b/core/map-value-iterator.hpp
new file mode 100644
index 0000000..1dfdd5c
--- /dev/null
+++ b/core/map-value-iterator.hpp
@@ -0,0 +1,87 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_MAP_VALUE_ITERATOR_H
+#define NFD_CORE_MAP_VALUE_ITERATOR_H
+
+#include "common.hpp"
+#include <boost/iterator/transform_iterator.hpp>
+
+namespace nfd {
+
+/** \class MapValueIterator
+ * \brief ForwardIterator to iterator over map values
+ */
+template<typename Map>
+class MapValueIterator
+ : public boost::transform_iterator<
+ function<const typename Map::mapped_type&(const typename Map::value_type&)>,
+ typename Map::const_iterator>
+{
+public:
+ explicit
+ MapValueIterator(typename Map::const_iterator it)
+ : boost::transform_iterator<
+ function<const typename Map::mapped_type&(const typename Map::value_type&)>,
+ typename Map::const_iterator>(it, &takeSecond)
+ {
+ }
+
+private:
+ static const typename Map::mapped_type&
+ takeSecond(const typename Map::value_type& pair)
+ {
+ return pair.second;
+ }
+};
+
+/** \class MapValueReverseIterator
+ * \brief ReverseIterator to iterator over map values
+ */
+template<typename Map>
+class MapValueReverseIterator
+ : public boost::transform_iterator<
+ function<const typename Map::mapped_type&(const typename Map::value_type&)>,
+ typename Map::const_reverse_iterator>
+{
+public:
+ explicit
+ MapValueReverseIterator(typename Map::const_reverse_iterator it)
+ : boost::transform_iterator<
+ function<const typename Map::mapped_type&(const typename Map::value_type&)>,
+ typename Map::const_reverse_iterator>(it, &takeSecond)
+ {
+ }
+
+private:
+ static const typename Map::mapped_type&
+ takeSecond(const typename Map::value_type& pair)
+ {
+ return pair.second;
+ }
+};
+
+} // namespace nfd
+
+#endif // NFD_CORE_MAP_VALUE_ITERATOR_H
diff --git a/core/network-interface.cpp b/core/network-interface.cpp
new file mode 100644
index 0000000..df47ac5
--- /dev/null
+++ b/core/network-interface.cpp
@@ -0,0 +1,139 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "network-interface.hpp"
+#include "core/logger.hpp"
+
+#include <boost/foreach.hpp>
+
+#include <arpa/inet.h> // for inet_ntop()
+#include <netinet/in.h> // for struct sockaddr_in{,6}
+#include <ifaddrs.h> // for getifaddrs()
+
+#if defined(__linux__)
+#include <net/if_arp.h> // for ARPHRD_* constants
+#include <netpacket/packet.h> // for struct sockaddr_ll
+#elif defined(__APPLE__) || defined(__FreeBSD__)
+#include <net/if_dl.h> // for struct sockaddr_dl
+#else
+#error Platform not supported
+#endif
+
+NFD_LOG_INIT("NetworkInterfaceInfo");
+
+namespace nfd {
+
+std::list< shared_ptr<NetworkInterfaceInfo> >
+listNetworkInterfaces()
+{
+ typedef std::map< std::string, shared_ptr<NetworkInterfaceInfo> > InterfacesMap;
+ InterfacesMap ifmap;
+
+ ifaddrs* ifa_list;
+ if (::getifaddrs(&ifa_list) < 0)
+ throw std::runtime_error("getifaddrs() failed");
+
+ for (ifaddrs* ifa = ifa_list; ifa != 0; ifa = ifa->ifa_next)
+ {
+ shared_ptr<NetworkInterfaceInfo> netif;
+ std::string ifname(ifa->ifa_name);
+ InterfacesMap::iterator i = ifmap.find(ifname);
+ if (i == ifmap.end())
+ {
+ netif = make_shared<NetworkInterfaceInfo>();
+ netif->name = ifname;
+ netif->flags = ifa->ifa_flags;
+ ifmap[ifname] = netif;
+ }
+ else
+ {
+ netif = i->second;
+ }
+
+ if (!ifa->ifa_addr)
+ continue;
+
+ switch (ifa->ifa_addr->sa_family)
+ {
+ case AF_INET: {
+ const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_addr);
+ char address[INET_ADDRSTRLEN];
+ if (::inet_ntop(AF_INET, &sin->sin_addr, address, sizeof(address)))
+ netif->ipv4Addresses.push_back(boost::asio::ip::address_v4::from_string(address));
+ else
+ NFD_LOG_WARN("inet_ntop() failed on " << ifname);
+ }
+ break;
+ case AF_INET6: {
+ const sockaddr_in6* sin6 = reinterpret_cast<sockaddr_in6*>(ifa->ifa_addr);
+ char address[INET6_ADDRSTRLEN];
+ if (::inet_ntop(AF_INET6, &sin6->sin6_addr, address, sizeof(address)))
+ netif->ipv6Addresses.push_back(boost::asio::ip::address_v6::from_string(address));
+ else
+ NFD_LOG_WARN("inet_ntop() failed on " << ifname);
+ }
+ break;
+#if defined(__linux__)
+ case AF_PACKET: {
+ const sockaddr_ll* sll = reinterpret_cast<sockaddr_ll*>(ifa->ifa_addr);
+ netif->index = sll->sll_ifindex;
+ if (sll->sll_hatype == ARPHRD_ETHER && sll->sll_halen == ethernet::ADDR_LEN)
+ netif->etherAddress = ethernet::Address(sll->sll_addr);
+ else if (sll->sll_hatype != ARPHRD_LOOPBACK)
+ NFD_LOG_WARN("Unrecognized hardware address on " << ifname);
+ }
+ break;
+#elif defined(__APPLE__) || defined(__FreeBSD__)
+ case AF_LINK: {
+ const sockaddr_dl* sdl = reinterpret_cast<sockaddr_dl*>(ifa->ifa_addr);
+ netif->index = sdl->sdl_index;
+ netif->etherAddress = ethernet::Address(reinterpret_cast<uint8_t*>(LLADDR(sdl)));
+ }
+ break;
+#endif
+ }
+
+ if (netif->isBroadcastCapable() && ifa->ifa_broadaddr != 0)
+ {
+ const sockaddr_in* sin = reinterpret_cast<sockaddr_in*>(ifa->ifa_broadaddr);
+
+ char address[INET_ADDRSTRLEN];
+ if (::inet_ntop(AF_INET, &sin->sin_addr, address, sizeof(address)))
+ netif->broadcastAddress = boost::asio::ip::address_v4::from_string(address);
+ else
+ NFD_LOG_WARN("inet_ntop() failed on " << ifname);
+ }
+ }
+
+ ::freeifaddrs(ifa_list);
+
+ std::list< shared_ptr<NetworkInterfaceInfo> > list;
+ BOOST_FOREACH(InterfacesMap::value_type elem, ifmap) {
+ list.push_back(elem.second);
+ }
+
+ return list;
+}
+
+} // namespace nfd
diff --git a/core/network-interface.hpp b/core/network-interface.hpp
new file mode 100644
index 0000000..08824fa
--- /dev/null
+++ b/core/network-interface.hpp
@@ -0,0 +1,90 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_NETWORK_INTERFACE_HPP
+#define NFD_CORE_NETWORK_INTERFACE_HPP
+
+#include "common.hpp"
+#include "ethernet.hpp"
+
+#include <net/if.h>
+
+namespace nfd {
+
+class NetworkInterfaceInfo
+{
+public:
+
+ int index;
+ std::string name;
+ ethernet::Address etherAddress;
+ std::vector<boost::asio::ip::address_v4> ipv4Addresses;
+ std::vector<boost::asio::ip::address_v6> ipv6Addresses;
+ boost::asio::ip::address_v4 broadcastAddress;
+ unsigned int flags;
+
+ bool
+ isLoopback() const;
+
+ bool
+ isMulticastCapable() const;
+
+ bool
+ isBroadcastCapable() const;
+
+ bool
+ isUp() const;
+
+};
+
+inline bool
+NetworkInterfaceInfo::isLoopback() const
+{
+ return (flags & IFF_LOOPBACK) != 0;
+}
+
+inline bool
+NetworkInterfaceInfo::isMulticastCapable() const
+{
+ return (flags & IFF_MULTICAST) != 0;
+}
+
+inline bool
+NetworkInterfaceInfo::isBroadcastCapable() const
+{
+ return (flags & IFF_BROADCAST) != 0;
+}
+
+inline bool
+NetworkInterfaceInfo::isUp() const
+{
+ return (flags & IFF_UP) != 0;
+}
+
+std::list< shared_ptr<NetworkInterfaceInfo> >
+listNetworkInterfaces();
+
+} // namespace nfd
+
+#endif // NFD_CORE_NETWORK_INTERFACE_HPP
diff --git a/core/resolver.hpp b/core/resolver.hpp
new file mode 100644
index 0000000..d4dc31c
--- /dev/null
+++ b/core/resolver.hpp
@@ -0,0 +1,214 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_RESOLVER_H
+#define NFD_CORE_RESOLVER_H
+
+#include "common.hpp"
+#include "core/global-io.hpp"
+#include "core/scheduler.hpp"
+
+namespace nfd {
+namespace resolver {
+
+typedef function<bool (const boost::asio::ip::address& address)> AddressSelector;
+
+struct AnyAddress {
+ bool
+ operator()(const boost::asio::ip::address& address)
+ {
+ return true;
+ }
+};
+
+struct Ipv4Address {
+ bool
+ operator()(const boost::asio::ip::address& address)
+ {
+ return address.is_v4();
+ }
+};
+
+struct Ipv6Address {
+ bool
+ operator()(const boost::asio::ip::address& address)
+ {
+ return address.is_v6();
+ }
+};
+
+} // namespace resolver
+
+template<class Protocol>
+class Resolver
+{
+public:
+ struct Error : public std::runtime_error
+ {
+ Error(const std::string& what) : std::runtime_error(what) {}
+ };
+
+ typedef function<void (const typename Protocol::endpoint& endpoint)> SuccessCallback;
+ typedef function<void (const std::string& reason)> ErrorCallback;
+
+ typedef boost::asio::ip::basic_resolver< Protocol > resolver;
+
+ /** \brief Asynchronously resolve host and port
+ *
+ * If an address selector predicate is specified, then each resolved IP address
+ * is checked against the predicate.
+ *
+ * Available address selector predicates:
+ *
+ * - resolver::AnyAddress()
+ * - resolver::Ipv4Address()
+ * - resolver::Ipv6Address()
+ */
+ static void
+ asyncResolve(const std::string& host, const std::string& port,
+ const SuccessCallback& onSuccess,
+ const ErrorCallback& onError,
+ const nfd::resolver::AddressSelector& addressSelector = nfd::resolver::AnyAddress(),
+ const time::seconds& timeout = time::seconds(4))
+ {
+ shared_ptr<Resolver> resolver =
+ shared_ptr<Resolver>(new Resolver(onSuccess, onError,
+ addressSelector));
+
+ resolver->asyncResolve(host, port, timeout, resolver);
+ // resolver will be destroyed when async operation finishes or global IO service stops
+ }
+
+ /** \brief Synchronously resolve host and port
+ *
+ * If an address selector predicate is specified, then each resolved IP address
+ * is checked against the predicate.
+ *
+ * Available address selector predicates:
+ *
+ * - resolver::AnyAddress()
+ * - resolver::Ipv4Address()
+ * - resolver::Ipv6Address()
+ */
+ static typename Protocol::endpoint
+ syncResolve(const std::string& host, const std::string& port,
+ const nfd::resolver::AddressSelector& addressSelector = nfd::resolver::AnyAddress())
+ {
+ Resolver resolver(SuccessCallback(), ErrorCallback(), addressSelector);
+
+ typename resolver::query query(host, port
+#if not defined(__FreeBSD__)
+ , resolver::query::all_matching
+#endif
+ );
+
+ typename resolver::iterator remoteEndpoint = resolver.m_resolver.resolve(query);
+ typename resolver::iterator end;
+ for (; remoteEndpoint != end; ++remoteEndpoint)
+ {
+ if (addressSelector(typename Protocol::endpoint(*remoteEndpoint).address()))
+ return *remoteEndpoint;
+ }
+ throw Error("No endpoint matching the specified address selector found");
+ }
+
+private:
+ Resolver(const SuccessCallback& onSuccess,
+ const ErrorCallback& onError,
+ const nfd::resolver::AddressSelector& addressSelector)
+ : m_resolver(getGlobalIoService())
+ , m_addressSelector(addressSelector)
+ , m_onSuccess(onSuccess)
+ , m_onError(onError)
+ {
+ }
+
+ void
+ asyncResolve(const std::string& host, const std::string& port,
+ const time::seconds& timeout,
+ const shared_ptr<Resolver>& self)
+ {
+ typename resolver::query query(host, port
+#if not defined(__FreeBSD__)
+ , resolver::query::all_matching
+#endif
+ );
+
+ m_resolver.async_resolve(query,
+ bind(&Resolver::onResolveSuccess, this, _1, _2, self));
+
+ m_resolveTimeout = scheduler::schedule(timeout,
+ bind(&Resolver::onResolveError, this,
+ "Timeout", self));
+ }
+
+ void
+ onResolveSuccess(const boost::system::error_code& error,
+ typename resolver::iterator remoteEndpoint,
+ const shared_ptr<Resolver>& self)
+ {
+ scheduler::cancel(m_resolveTimeout);
+
+ if (error)
+ {
+ if (error == boost::system::errc::operation_canceled)
+ return;
+
+ return m_onError("Remote endpoint hostname or port cannot be resolved: " +
+ error.category().message(error.value()));
+ }
+
+ typename resolver::iterator end;
+ for (; remoteEndpoint != end; ++remoteEndpoint)
+ {
+ if (m_addressSelector(typename Protocol::endpoint(*remoteEndpoint).address()))
+ return m_onSuccess(*remoteEndpoint);
+ }
+
+ m_onError("No endpoint matching the specified address selector found");
+ }
+
+ void
+ onResolveError(const std::string& errorInfo,
+ const shared_ptr<Resolver>& self)
+ {
+ m_resolver.cancel();
+ m_onError(errorInfo);
+ }
+
+private:
+ resolver m_resolver;
+ EventId m_resolveTimeout;
+
+ nfd::resolver::AddressSelector m_addressSelector;
+ SuccessCallback m_onSuccess;
+ ErrorCallback m_onError;
+};
+
+typedef Resolver<boost::asio::ip::tcp> TcpResolver;
+typedef Resolver<boost::asio::ip::udp> UdpResolver;
+
+} // namespace nfd
+
+#endif // NFD_CORE_RESOLVER_H
diff --git a/core/scheduler.cpp b/core/scheduler.cpp
new file mode 100644
index 0000000..fb09557
--- /dev/null
+++ b/core/scheduler.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#include "scheduler.hpp"
+#include "global-io.hpp"
+
+namespace nfd {
+namespace scheduler {
+
+static shared_ptr<Scheduler> g_scheduler;
+
+inline Scheduler&
+getGlobalScheduler()
+{
+ if (!static_cast<bool>(g_scheduler)) {
+ g_scheduler = make_shared<Scheduler>(boost::ref(getGlobalIoService()));
+ }
+ return *g_scheduler;
+}
+
+EventId
+schedule(const time::nanoseconds& after, const Scheduler::Event& event)
+{
+ return getGlobalScheduler().scheduleEvent(after, event);
+}
+
+void
+cancel(const EventId& eventId)
+{
+ getGlobalScheduler().cancelEvent(eventId);
+}
+
+void
+resetGlobalScheduler()
+{
+ g_scheduler.reset();
+}
+
+} // namespace scheduler
+} // namespace nfd
diff --git a/core/scheduler.hpp b/core/scheduler.hpp
new file mode 100644
index 0000000..f275c69
--- /dev/null
+++ b/core/scheduler.hpp
@@ -0,0 +1,57 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/**
+ * Copyright (c) 2014 Regents of the University of California,
+ * Arizona Board of Regents,
+ * Colorado State University,
+ * University Pierre & Marie Curie, Sorbonne University,
+ * Washington University in St. Louis,
+ * Beijing Institute of Technology
+ *
+ * This file is part of NFD (Named Data Networking Forwarding Daemon).
+ * See AUTHORS.md for complete list of NFD authors and contributors.
+ *
+ * NFD is free software: you can redistribute it and/or modify it under the terms
+ * of the GNU General Public License as published by the Free Software Foundation,
+ * either version 3 of the License, or (at your option) any later version.
+ *
+ * NFD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ * PURPOSE. See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * NFD, e.g., in COPYING.md file. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+#ifndef NFD_CORE_SCHEDULER_HPP
+#define NFD_CORE_SCHEDULER_HPP
+
+#include "common.hpp"
+#include <ndn-cpp-dev/util/scheduler.hpp>
+
+namespace nfd {
+namespace scheduler {
+
+using ndn::Scheduler;
+
+/** \class EventId
+ * \brief Opaque type (shared_ptr) representing ID of a scheduled event
+ */
+using ndn::EventId;
+
+/** \brief schedule an event
+ */
+EventId
+schedule(const time::nanoseconds& after, const Scheduler::Event& event);
+
+/** \brief cancel a scheduled event
+ */
+void
+cancel(const EventId& eventId);
+
+} // namespace scheduler
+
+using scheduler::EventId;
+
+} // namespace nfd
+
+#endif // NFD_CORE_SCHEDULER_HPP