Add build system, basic docs and crypto helpers module

Change-Id: I761cde5adac85596c5a3a53ec3e94a9a81fb5416
diff --git a/.jenkins.d/00-deps.sh b/.jenkins.d/00-deps.sh
new file mode 100755
index 0000000..d4d9c33
--- /dev/null
+++ b/.jenkins.d/00-deps.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+set -ex
+
+if has OSX $NODE_LABELS; then
+    FORMULAE=(boost openssl pkg-config)
+    if has OSX-10.13 $NODE_LABELS || has OSX-10.14 $NODE_LABELS; then
+        FORMULAE+=(python)
+    fi
+
+    if [[ -n $TRAVIS ]]; then
+        # Travis images come with a large number of pre-installed
+        # brew packages, don't waste time upgrading all of them
+        brew list --versions "${FORMULAE[@]}" || brew update
+        for FORMULA in "${FORMULAE[@]}"; do
+            brew list --versions "$FORMULA" || brew install "$FORMULA"
+        done
+        # Ensure /usr/local/opt/openssl exists
+        brew reinstall openssl
+    else
+        brew update
+        brew upgrade
+        brew install "${FORMULAE[@]}"
+        brew cleanup
+    fi
+
+elif has Ubuntu $NODE_LABELS; then
+    sudo apt-get -qq update
+    sudo apt-get -qy install g++ pkg-config python3-minimal \
+                             libboost-all-dev libssl-dev libsqlite3-dev
+
+    if [[ $JOB_NAME == *"code-coverage" ]]; then
+        sudo apt-get -qy install gcovr lcov
+    fi
+fi
diff --git a/.jenkins.d/01-ndn-cxx.sh b/.jenkins.d/01-ndn-cxx.sh
new file mode 100755
index 0000000..7bf1cfe
--- /dev/null
+++ b/.jenkins.d/01-ndn-cxx.sh
@@ -0,0 +1,59 @@
+#!/usr/bin/env bash
+set -ex
+
+pushd "$CACHE_DIR" >/dev/null
+
+INSTALLED_VERSION=
+if has OSX $NODE_LABELS; then
+    BOOST=$(brew ls --versions boost)
+    OLD_BOOST=$(cat boost.txt || :)
+    if [[ $OLD_BOOST != $BOOST ]]; then
+        echo "$BOOST" > boost.txt
+        INSTALLED_VERSION=NONE
+    fi
+fi
+
+if [[ -z $INSTALLED_VERSION ]]; then
+    INSTALLED_VERSION=$(git -C ndn-cxx rev-parse HEAD 2>/dev/null || echo NONE)
+fi
+
+sudo rm -rf ndn-cxx-latest
+git clone --depth 1 https://github.com/named-data/ndn-cxx.git ndn-cxx-latest
+LATEST_VERSION=$(git -C ndn-cxx-latest rev-parse HEAD 2>/dev/null || echo UNKNOWN)
+
+if [[ $INSTALLED_VERSION != $LATEST_VERSION ]]; then
+    sudo rm -rf ndn-cxx
+    mv ndn-cxx-latest ndn-cxx
+else
+    sudo rm -rf ndn-cxx-latest
+fi
+
+sudo rm -f /usr/local/bin/ndnsec*
+sudo rm -fr /usr/local/include/ndn-cxx
+sudo rm -f /usr/local/lib{,64}/libndn-cxx*
+sudo rm -f /usr/local/lib{,64}/pkgconfig/libndn-cxx.pc
+
+pushd ndn-cxx >/dev/null
+
+if has Linux $NODE_LABELS && [[ $CXX != clang* && -z $DISABLE_ASAN ]]; then
+    # https://stackoverflow.com/a/47022141
+    ASAN="--with-sanitizer=address"
+fi
+if has CentOS-8 $NODE_LABELS; then
+    # https://bugzilla.redhat.com/show_bug.cgi?id=1721553
+    PCH="--without-pch"
+fi
+
+./waf --color=yes configure --disable-static --enable-shared --without-osx-keychain $ASAN $PCH
+./waf --color=yes build -j$WAF_JOBS
+sudo_preserve_env PATH -- ./waf --color=yes install
+
+popd >/dev/null
+popd >/dev/null
+
+if has CentOS-8 $NODE_LABELS; then
+    sudo tee /etc/ld.so.conf.d/ndn.conf >/dev/null <<< /usr/local/lib64
+fi
+if has Linux $NODE_LABELS; then
+    sudo ldconfig
+fi
diff --git a/.jenkins.d/10-build.sh b/.jenkins.d/10-build.sh
new file mode 100755
index 0000000..20e6bd1
--- /dev/null
+++ b/.jenkins.d/10-build.sh
@@ -0,0 +1,41 @@
+#!/usr/bin/env bash
+set -ex
+
+git submodule sync
+git submodule update --init
+
+if [[ -z $DISABLE_ASAN ]]; then
+    ASAN="--with-sanitizer=address"
+fi
+if [[ $JOB_NAME == *"code-coverage" ]]; then
+    COVERAGE="--with-coverage"
+fi
+
+if [[ $JOB_NAME != *"code-coverage" && $JOB_NAME != *"limited-build" ]]; then
+    # Build in release mode with tests
+    ./waf --color=yes configure --with-tests
+    ./waf --color=yes build -j$WAF_JOBS
+
+    # Cleanup
+    ./waf --color=yes distclean
+
+    # Build in release mode without tests
+    ./waf --color=yes configure
+    ./waf --color=yes build -j$WAF_JOBS
+
+    # Cleanup
+    ./waf --color=yes distclean
+fi
+
+# Build in debug mode with tests
+./waf --color=yes configure --debug --with-tests $ASAN $COVERAGE
+./waf --color=yes build -j$WAF_JOBS
+
+# (tests will be run against the debug version)
+
+# Install
+sudo_preserve_env PATH -- ./waf --color=yes install
+
+if has Linux $NODE_LABELS; then
+    sudo ldconfig
+fi
diff --git a/.jenkins.d/20-tests.sh b/.jenkins.d/20-tests.sh
new file mode 100755
index 0000000..226c77d
--- /dev/null
+++ b/.jenkins.d/20-tests.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+set -ex
+
+# Prepare environment
+rm -rf ~/.ndn
+
+BOOST_VERSION=$(python3 -c "import sys; sys.path.append('build/c4che'); import _cache; print(_cache.BOOST_VERSION_NUMBER);")
+
+ut_log_args() {
+    if (( BOOST_VERSION >= 106200 )); then
+        echo --logger=HRF,test_suite,stdout:XML,all,build/xunit-${1:-report}.xml
+    else
+        if [[ -n $XUNIT ]]; then
+            echo --log_level=all $( (( BOOST_VERSION >= 106000 )) && echo -- ) \
+                 --log_format2=XML --log_sink2=build/xunit-${1:-report}.xml
+        else
+            echo --log_level=test_suite
+        fi
+    fi
+}
+
+# https://github.com/google/sanitizers/wiki/AddressSanitizerFlags
+ASAN_OPTIONS="color=always"
+ASAN_OPTIONS+=":check_initialization_order=1"
+ASAN_OPTIONS+=":detect_stack_use_after_return=1"
+ASAN_OPTIONS+=":strict_init_order=1"
+ASAN_OPTIONS+=":strict_string_checks=1"
+ASAN_OPTIONS+=":detect_invalid_pointer_pairs=2"
+ASAN_OPTIONS+=":strip_path_prefix=${PWD}/"
+export ASAN_OPTIONS
+
+export BOOST_TEST_BUILD_INFO=1
+export BOOST_TEST_COLOR_OUTPUT=1
+
+# Run unit tests
+./build/unit-tests $(ut_log_args)
diff --git a/.jenkins.d/30-coverage.sh b/.jenkins.d/30-coverage.sh
new file mode 100755
index 0000000..4cce87d
--- /dev/null
+++ b/.jenkins.d/30-coverage.sh
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+set -ex
+
+if [[ $JOB_NAME == *"code-coverage" ]]; then
+    gcovr --object-directory=build \
+          --output=build/coverage.xml \
+          --exclude="$PWD/tests" \
+          --root=. \
+          --xml
+
+    # Generate also a detailed HTML output, but using lcov (better results)
+    lcov --quiet \
+         --capture \
+         --directory . \
+         --no-external \
+         --rc lcov_branch_coverage=1 \
+         --output-file build/coverage-with-tests.info
+
+    lcov --quiet \
+         --remove build/coverage-with-tests.info "$PWD/tests/*" \
+         --rc lcov_branch_coverage=1 \
+         --output-file build/coverage.info
+
+    genhtml --branch-coverage \
+            --demangle-cpp \
+            --legend \
+            --output-directory build/coverage \
+            --title "ndncert unit tests" \
+            build/coverage.info
+fi
diff --git a/.jenkins.d/README.md b/.jenkins.d/README.md
new file mode 100644
index 0000000..e8dbf37
--- /dev/null
+++ b/.jenkins.d/README.md
@@ -0,0 +1,28 @@
+# CONTINUOUS INTEGRATION SCRIPTS
+
+## Environment Variables Used in Build Scripts
+
+- `NODE_LABELS`: space-separated list of platform properties. The included values are used by
+  the build scripts to select the proper behavior for different operating systems and versions.
+
+  The list should normally contain `[OS_TYPE]`, `[DISTRO_TYPE]`, and `[DISTRO_VERSION]`.
+
+  Example values:
+
+  - `[OS_TYPE]`: `Linux`, `OSX`
+  - `[DISTRO_TYPE]`: `Ubuntu`, `CentOS`
+  - `[DISTRO_VERSION]`: `Ubuntu-16.04`, `Ubuntu-18.04`, `CentOS-8`, `OSX-10.14`, `OSX-10.15`
+
+- `JOB_NAME`: optional variable that defines the type of build job. Depending on the job type,
+  the build scripts can perform different tasks.
+
+  Possible values:
+
+  - empty: default build task
+  - `code-coverage`: debug build with tests and code coverage analysis (Ubuntu Linux is assumed)
+  - `limited-build`: only a single debug build with tests
+
+- `CACHE_DIR`: directory containing cached files from previous builds, e.g., a compiled version
+  of ndn-cxx. If not set, `/tmp` is used.
+
+- `WAF_JOBS`: number of parallel build threads used by waf, defaults to 1.
diff --git a/.jenkins.d/util.sh b/.jenkins.d/util.sh
new file mode 100644
index 0000000..8077a74
--- /dev/null
+++ b/.jenkins.d/util.sh
@@ -0,0 +1,39 @@
+has() {
+    local saved_xtrace
+    [[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
+    set +x
+
+    local p=$1
+    shift
+    local i ret=1
+    for i in "$@"; do
+        if [[ "${i}" == "${p}" ]]; then
+            ret=0
+            break
+        fi
+    done
+
+    set ${saved_xtrace}
+    return ${ret}
+}
+export -f has
+
+sudo_preserve_env() {
+    local saved_xtrace
+    [[ $- == *x* ]] && saved_xtrace=-x || saved_xtrace=+x
+    set +x
+
+    local vars=()
+    while [[ $# -gt 0 ]]; do
+        local arg=$1
+        shift
+        case ${arg} in
+            --) break ;;
+            *)  vars+=("${arg}=${!arg}") ;;
+        esac
+    done
+
+    set ${saved_xtrace}
+    sudo env "${vars[@]}" "$@"
+}
+export -f sudo_preserve_env