void
EdgeStrategy::onDataDenied
( const ndn::Data& data,
  const ndn::Interest& interest,
  ns3::Time& delay,
  const std::string& why )
{
    // if the denied data isn't leaving the network
    // then we just do the normal router stuff
    auto in_face = getFaceTable().get( data.getIncomingFaceId() );
    auto out_face = getFaceTable().get( interest.getIncomingFaceId() );
    bool coming_from_network = !in_face->isEdge();
    bool going_to_network = !out_face->isEdge();
    
    if( coming_from_network == going_to_network )
    {
        RouterStrategy::onDataDenied( data, interest, delay, why );
        return;
    }
    
    if( going_to_network )
    {
        BOOST_ASSERT( data.getCurrentNetwork()
                    == ndn::RouteTracker::INTERNET_NETWORK );
        RouterStrategy::onDataDenied( data, interest, delay, why );
        return;
    }
    
    // if the data is denied then we add the
    // tag used to retrieve it to the negative
    // cache; however we only want to do this
    // when the data is leaving the internet
    // and going into the client network
    // and the data's access level > 0
    BOOST_ASSERT( data.getCurrentNetwork()
                == ndn::RouteTracker::ENTRY_NETWORK );
    if( data.getAccessLevel() > 0 )
    {
        BOOST_ASSERT( interest.hasAuthTag() );
        tracers::edge->bloom_insert
        ( interest.getAuthTag(), s_edge_bloom_delay );
        delay += s_edge_bloom_delay;
        m_negative_cache.insert( interest.getAuthTag() );
    }

    // do whatever a normal router would do
    RouterStrategy::onDataDenied( data, interest, delay, why );
}
void
EdgeStrategy::onDataSatisfied
( const ndn::Data& data,
  const ndn::Interest& interest,
  ns3::Time& delay )
{
    // if the satisfied data isn't leaving the network
    // then we just do the normal router stuff
    auto in_face = getFaceTable().get( data.getIncomingFaceId() );
    auto out_face = getFaceTable().get( interest.getIncomingFaceId() );
    bool coming_from_network = !in_face->isEdge();
    bool going_to_network = !out_face->isEdge();
    
    if( coming_from_network == going_to_network )
    {
        RouterStrategy::onDataSatisfied( data, interest, delay );
        return;
    }
    
    if( going_to_network )
    {
        BOOST_ASSERT( data.getCurrentNetwork()
                    == ndn::RouteTracker::INTERNET_NETWORK );
        RouterStrategy::onDataSatisfied( data, interest, delay );
        return;
    }
    
    // if the data is satisfied then we add it to
    // the positive cache if it isn't marked with
    // the no recache flag and if its access level > 0
    BOOST_ASSERT( data.getCurrentNetwork()
                == ndn::RouteTracker::ENTRY_NETWORK );
    if( !data.getNoReCacheFlag()
      && data.getAccessLevel() > 0 )
    {
        BOOST_ASSERT( interest.hasAuthTag() );
        tracers::edge->bloom_insert
        ( interest.getAuthTag(), s_edge_bloom_delay );
        delay += s_edge_bloom_delay;
        m_positive_cache.insert( interest.getAuthTag() );
    }
    
    RouterStrategy::onDataSatisfied( data, interest, delay );
}
bool
EdgeStrategy::filterOutgoingInterest
( const nfd::Face& face,
  ndn::Interest& interest,
  ns3::Time& delay )
{
    auto in_face = getFaceTable().get( interest.getIncomingFaceId() );
    bool coming_from_network = !in_face->isEdge();
    bool going_to_network = !face.isEdge();
    
    // if the interest coming from and going to
    // the same network then we don't need to do
    // anything special
    if( coming_from_network == going_to_network )
    {
        return RouterStrategy::filterOutgoingInterest
               ( face, interest, delay );
    }
    
    // if the interest is leaving the network then just change
    // current network
    if( coming_from_network )
    {
        BOOST_ASSERT( interest.getCurrentNetwork()
                    == ndn::RouteTracker::INTERNET_NETWORK );
        tracers::edge->interest_left( interest );
        interest.setCurrentNetwork( ndn::RouteTracker::EXIT_NETWORK );
        return RouterStrategy::filterOutgoingInterest
               ( face, interest, delay );
    }
    
    // if the interest is entering the network then
    // we need to do some extra stuff
    BOOST_ASSERT( interest.getCurrentNetwork()
                == ndn::RouteTracker::ENTRY_NETWORK );
    tracers::edge->interest_entered( interest );
    interest.setCurrentNetwork( ndn::RouteTracker::INTERNET_NETWORK );
    
    // if the interest doesn't have an auth tag, or its auth level
    // is 0 then we don't do any authentication
    if( !interest.hasAuthTag()
      || interest.getAuthTag().getAccessLevel() == 0 )
    {
        return RouterStrategy::filterOutgoingInterest( face,
                                                        interest,
                                                        delay );
    }
    
    const ndn::AuthTag& auth = interest.getAuthTag();

    // if the auth tag provided by the interest is expired
    // then we can drop the interest
    if( auth.isExpired() )
    {
        tracers::edge->blocked_interest
        ( interest, tracers::BlockedExpired );
        onInterestDropped( interest, face, "Expired auth" );
        return false;
    }
    
    // if the interest and auth tag have different prefixes
    // then we drop the interest
    if( !auth.getPrefix().isPrefixOf( interest.getName() ) )
    {
        tracers::edge->blocked_interest
        ( interest, tracers::BlockedBadPrefix );
        onInterestDropped( interest, face, "Mismatched prefix" );
        return false;
    }
    
    // if the interest route hash doesn't match its auth tag
    // then we can drop it
    if( interest.getEntryRoute() != auth.getRouteHash() )
    {
        tracers::edge->blocked_interest
        ( interest, tracers::BlockedBadRoute );
        onInterestDropped( interest, face, "Bad route" );
        return false;
    }
    
    // if the interest auth is in the positive auth cache then
    // we set its auth validity probability
    tracers::edge->bloom_lookup( auth, s_edge_bloom_delay );
    delay += s_edge_bloom_delay;
    if( m_positive_cache.contains( auth ) )
    {
        double fpp = m_positive_cache.getEffectiveFPP();
        double prob = (double)1.0 - fpp;
        uint32_t iprob = prob*0xFFFFFFFF;
        interest.setAuthValidityProb( iprob );
        
    }
    else
    {
        // if it's in the negative cache then we validate
        // its signature manually
        tracers::edge->bloom_lookup( auth, s_edge_bloom_delay );
        delay += s_edge_bloom_delay;
        if( m_negative_cache.contains( auth ) )
        {
            // we simulate verification delay by incrementing
            // the processing delay
            tracers::edge->sigverif( auth, s_edge_signature_delay );
            delay += EdgeStrategy::s_edge_signature_delay;
            if( auth.getSignature().getValue().value_size() > 0
              && auth.getSignature().getValue().value()[0] != 0 )
            {
                // if signature is valid then set auth validity
                // and put auth into positive cache
                interest.setAuthValidityProb( 0xFFFFFFFF );
                tracers::edge->auth_cached
                ( auth, tracers::CachedPositiveMoved );
                m_positive_cache.insert( auth );
            }
            else
            {
                // otherwise we drop the interest
                onInterestDropped( interest, face, "negative cache, manual validation failed" );
                return false;
            }
        }
        else
        {
            // if the auth isn't in either cache then
            // we set validity probability to 0
            interest.setAuthValidityProb( 0 );
        }
    }
    
    return RouterStrategy::filterOutgoingInterest( face, interest,
                                                   delay );
}