// Called from the pingInteral timeout.
static void pingCallback(void* vic)
{
    struct Context* ic = Identity_cast((struct Context*) vic);
    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
    ic->pingCount++;

    // scan for endpoints have not sent anything recently.
    for (uint32_t i = 0; i < ic->peerMap.count; i++) {
        struct IFCPeer* ep = ic->peerMap.values[i];
        if (now > ep->timeOfLastMessage + ic->pingAfterMilliseconds) {
            #ifdef Log_DEBUG
                  uint8_t key[56];
                  Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
            #endif
            if (ep->transient && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds) {
                Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] "
                                      "seconds, dropping connection",
                                      key, ic->forgetAfterMilliseconds / 1024);
                Allocator_free(ep->external->allocator);
            } else if (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds) {
                // Lets skip 87% of pings when they're really down.
                if (ic->pingCount % 8) {
                    continue;
                }
                ep->state = InterfaceController_PeerState_UNRESPONSIVE;
                uint32_t lag = ((now - ep->timeOfLastMessage) / 1024);
                Log_debug(ic->logger, "Pinging unresponsive peer [%s.k] lag [%u]", key, lag);
            } else {
                uint32_t lag = ((now - ep->timeOfLastMessage) / 1024);
                Log_debug(ic->logger, "Pinging lazy peer [%s] lag [%u]", key, lag);
            }

            struct SwitchPinger_Ping* ping =
                SwitchPinger_newPing(ep->switchLabel,
                                     String_CONST(""),
                                     ic->timeoutMilliseconds,
                                     onPingResponse,
                                     ic->switchPinger);

            ping->onResponseContext = ep;

            SwitchPinger_sendPing(ping);
        }
    }
}
// Called from the pingInteral timeout.
static void pingCallback(void* vic)
{
    struct Context* ic = Identity_cast((struct Context*) vic);
    uint64_t now = Time_currentTimeMilliseconds(ic->eventBase);
    ic->pingCount++;

    // scan for endpoints have not sent anything recently.
    for (uint32_t i = 0; i < ic->peerMap.count; i++) {
        struct IFCPeer* ep = ic->peerMap.values[i];

        // This is here because of a pathological state where the connection is in ESTABLISHED
        // state but the *direct peer* has somehow been dropped from the routing table.
        // TODO: understand the cause of this issue rather than checking for it once per second.
        struct Node* peerNode = RouterModule_getNode(ep->switchLabel, ic->routerModule);

        if (now > ep->timeOfLastMessage + ic->pingAfterMilliseconds || !peerNode) {
            #ifdef Log_DEBUG
                  uint8_t key[56];
                  Base32_encode(key, 56, CryptoAuth_getHerPublicKey(ep->cryptoAuthIf), 32);
            #endif

            if (ep->isIncomingConnection
                && now > ep->timeOfLastMessage + ic->forgetAfterMilliseconds)
            {
                Log_debug(ic->logger, "Unresponsive peer [%s.k] has not responded in [%u] "
                                      "seconds, dropping connection",
                                      key, ic->forgetAfterMilliseconds / 1024);
                Allocator_free(ep->external->allocator);
                return;
            }

            bool unresponsive = (now > ep->timeOfLastMessage + ic->unresponsiveAfterMilliseconds);
            uint32_t lag = ~0u;
            if (unresponsive) {
                // flush the peer from the table...
                RouterModule_brokenPath(ep->switchLabel, ic->routerModule);

                // Lets skip 87% of pings when they're really down.
                if (ic->pingCount % 8) {
                    continue;
                }

                ep->state = InterfaceController_PeerState_UNRESPONSIVE;
                lag = ((now - ep->timeOfLastMessage) / 1024);
            } else {
                lag = ((now - ep->timeOfLastMessage) / 1024);
            }

            struct SwitchPinger_Ping* ping =
                SwitchPinger_newPing(ep->switchLabel,
                                     String_CONST(""),
                                     ic->timeoutMilliseconds,
                                     onPingResponse,
                                     ic->allocator,
                                     ic->switchPinger);

            if (!ping) {
                Log_debug(ic->logger,
                          "Failed to ping %s peer [%s.k] lag [%u], out of ping slots.",
                          (unresponsive ? "unresponsive" : "lazy"), key, lag);
                return;
            }

            ping->onResponseContext = ep;

            SwitchPinger_sendPing(ping);

            Log_debug(ic->logger,
                      "Pinging %s peer [%s.k] lag [%u]",
                      (unresponsive ? "unresponsive" : "lazy"), key, lag);
        }
    }
}