示例#1
0
void
WebSocketTransport::doSend(Transport::Packet&& packet)
{
  NFD_LOG_FACE_TRACE(__func__);

  websocketpp::lib::error_code error;
  m_server.send(m_handle, packet.packet.wire(), packet.packet.size(),
                websocketpp::frame::opcode::binary, error);
  if (error)
    return processErrorCode(error);

  NFD_LOG_FACE_TRACE("Successfully sent: " << packet.packet.size() << " bytes");
}
示例#2
0
void
DatagramTransport<T, U>::receiveDatagram(const uint8_t* buffer, size_t nBytesReceived,
                                         const boost::system::error_code& error)
{
  if (error)
    return processErrorCode(error);

  NFD_LOG_FACE_TRACE("Received: " << nBytesReceived << " bytes from " << m_sender);

  bool isOk = false;
  Block element;
  std::tie(isOk, element) = Block::fromBuffer(buffer, nBytesReceived);
  if (!isOk) {
    NFD_LOG_FACE_WARN("Failed to parse incoming packet from " << m_sender);
    // This packet won't extend the face lifetime
    return;
  }
  if (element.size() != nBytesReceived) {
    NFD_LOG_FACE_WARN("Received datagram size and decoded element size don't match");
    // This packet won't extend the face lifetime
    return;
  }
  m_hasRecentlyReceived = true;

  Transport::Packet tp(std::move(element));
  tp.remoteEndpoint = makeEndpointId(m_sender);
  this->receive(std::move(tp));
}
示例#3
0
void
TcpTransport::reconnect()
{
  NFD_LOG_FACE_TRACE(__func__);

  if (getState() == TransportState::CLOSING ||
      getState() == TransportState::FAILED ||
      getState() == TransportState::CLOSED) {
    // transport is shutting down, don't attempt to reconnect
    return;
  }

  BOOST_ASSERT(getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT);
  BOOST_ASSERT(getState() == TransportState::DOWN);

  // recreate the socket
  m_socket = protocol::socket(m_socket.get_io_service());
  this->resetReceiveBuffer();
  this->resetSendQueue();

  m_reconnectEvent = scheduler::schedule(m_nextReconnectWait,
                                         [this] { handleReconnectTimeout(); });
  m_socket.async_connect(m_remoteEndpoint,
                         [this] (const boost::system::error_code& error) { handleReconnect(error); });
}
示例#4
0
void
WebSocketTransport::handlePong()
{
  NFD_LOG_FACE_TRACE(__func__);

  ++this->nInPongs;
}
示例#5
0
void
GenericLinkService::doReceivePacket(const Block& packet, const EndpointId& endpoint)
{
  try {
    lp::Packet pkt(packet);

    if (m_options.reliabilityOptions.isEnabled) {
      m_reliability.processIncomingPacket(pkt);
    }

    if (!pkt.has<lp::FragmentField>()) {
      NFD_LOG_FACE_TRACE("received IDLE packet: DROP");
      return;
    }

    if ((pkt.has<lp::FragIndexField>() || pkt.has<lp::FragCountField>()) &&
        !m_options.allowReassembly) {
      NFD_LOG_FACE_WARN("received fragment, but reassembly disabled: DROP");
      return;
    }

    bool isReassembled = false;
    Block netPkt;
    lp::Packet firstPkt;
    std::tie(isReassembled, netPkt, firstPkt) = m_reassembler.receiveFragment(endpoint, pkt);
    if (isReassembled) {
      this->decodeNetPacket(netPkt, firstPkt, endpoint);
    }
  }
  catch (const tlv::Error& e) {
    ++this->nInLpInvalid;
    NFD_LOG_FACE_WARN("packet parse error (" << e.what() << "): DROP");
  }
}
示例#6
0
void
DatagramTransport<T, U>::handleSend(const boost::system::error_code& error, size_t nBytesSent)
{
  if (error)
    return processErrorCode(error);

  NFD_LOG_FACE_TRACE("Successfully sent: " << nBytesSent << " bytes");
}
示例#7
0
void
DatagramTransport<T, U>::doSend(Transport::Packet&& packet)
{
  NFD_LOG_FACE_TRACE(__func__);

  m_socket.async_send(boost::asio::buffer(packet.packet),
                      // packet.packet is copied into the lambda to retain the underlying Buffer
                      [this, p = packet.packet] (auto&&... args) {
                        this->handleSend(std::forward<decltype(args)>(args)...);
                      });
}
示例#8
0
void
GenericLinkService::checkCongestionLevel(lp::Packet& pkt)
{
  ssize_t sendQueueLength = getTransport()->getSendQueueLength();
  // This operation requires that the transport supports retrieving current send queue length
  if (sendQueueLength < 0) {
    return;
  }

  // To avoid overflowing the queue, set the congestion threshold to at least half of the send
  // queue capacity.
  size_t congestionThreshold = m_options.defaultCongestionThreshold;
  if (getTransport()->getSendQueueCapacity() >= 0) {
    congestionThreshold = std::min(congestionThreshold,
                                   static_cast<size_t>(getTransport()->getSendQueueCapacity()) /
                                                       DEFAULT_CONGESTION_THRESHOLD_DIVISOR);
  }

  if (sendQueueLength > 0) {
    NFD_LOG_FACE_TRACE("txqlen=" << sendQueueLength << " threshold=" << congestionThreshold <<
                       " capacity=" << getTransport()->getSendQueueCapacity());
  }

  if (static_cast<size_t>(sendQueueLength) > congestionThreshold) { // Send queue is congested
    const auto now = time::steady_clock::now();
    if (now >= m_nextMarkTime || now >= m_lastMarkTime + m_options.baseCongestionMarkingInterval) {
      // Mark at most one initial packet per baseCongestionMarkingInterval
      if (m_nMarkedSinceInMarkingState == 0) {
        m_nextMarkTime = now;
      }

      // Time to mark packet
      pkt.set<lp::CongestionMarkField>(1);
      ++nCongestionMarked;
      NFD_LOG_FACE_DEBUG("LpPacket was marked as congested");

      ++m_nMarkedSinceInMarkingState;
      // Decrease the marking interval by the inverse of the square root of the number of packets
      // marked in this incident of congestion
      m_nextMarkTime += time::nanoseconds(static_cast<time::nanoseconds::rep>(
                                            m_options.baseCongestionMarkingInterval.count() /
                                            std::sqrt(m_nMarkedSinceInMarkingState)));
      m_lastMarkTime = now;
    }
  }
  else if (m_nextMarkTime != time::steady_clock::TimePoint::max()) {
    // Congestion incident has ended, so reset
    NFD_LOG_FACE_DEBUG("Send queue length dropped below congestion threshold");
    m_nextMarkTime = time::steady_clock::TimePoint::max();
    m_nMarkedSinceInMarkingState = 0;
  }
}
示例#9
0
void
WebSocketTransport::doClose()
{
  NFD_LOG_FACE_TRACE(__func__);

  m_pingEventId.cancel();

  // use the non-throwing variant and ignore errors, if any
  websocketpp::lib::error_code error;
  m_server.close(m_handle, websocketpp::close::status::normal, "closed by NFD", error);

  this->setState(TransportState::CLOSED);
}
示例#10
0
void
WebSocketTransport::sendPing()
{
  NFD_LOG_FACE_TRACE(__func__);

  ++this->nOutPings;

  websocketpp::lib::error_code error;
  m_server.ping(m_handle, "NFD-WebSocket", error);
  if (error)
    return processErrorCode(error);

  this->schedulePing();
}
示例#11
0
void
WebSocketTransport::receiveMessage(const std::string& msg)
{
  NFD_LOG_FACE_TRACE("Received: " << msg.size() << " bytes");

  bool isOk = false;
  Block element;
  std::tie(isOk, element) = Block::fromBuffer(reinterpret_cast<const uint8_t*>(msg.c_str()), msg.size());
  if (!isOk) {
    NFD_LOG_FACE_WARN("Failed to parse message payload");
    return;
  }

  this->receive(Transport::Packet(std::move(element)));
}
示例#12
0
bool
Transport::canChangePersistencyTo(ndn::nfd::FacePersistency newPersistency) const
{
  // not changing, or setting initial persistency in subclass constructor
  if (m_persistency == newPersistency || m_persistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
    return true;
  }

  if (newPersistency == ndn::nfd::FACE_PERSISTENCY_NONE) {
    NFD_LOG_FACE_TRACE("cannot change persistency to NONE");
    return false;
  }

  return this->canChangePersistencyToImpl(newPersistency);
}
示例#13
0
void
TcpTransport::handleReconnect(const boost::system::error_code& error)
{
  if (getState() == TransportState::CLOSING ||
      getState() == TransportState::FAILED ||
      getState() == TransportState::CLOSED ||
      error == boost::asio::error::operation_aborted) {
    // transport is shutting down, abort the reconnection attempt and ignore any errors
    return;
  }

  if (error) {
    NFD_LOG_FACE_TRACE("Reconnection attempt failed: " << error.message());
    return;
  }

  m_reconnectEvent.cancel();
  m_nextReconnectWait = s_initialReconnectWait;

  this->setLocalUri(FaceUri(m_socket.local_endpoint()));
  NFD_LOG_FACE_TRACE("TCP connection reestablished");
  this->setState(TransportState::UP);
  this->startReceive();
}
示例#14
0
void
WebSocketTransport::processErrorCode(const websocketpp::lib::error_code& error)
{
  NFD_LOG_FACE_TRACE(__func__);

  if (getState() == TransportState::CLOSING ||
      getState() == TransportState::FAILED ||
      getState() == TransportState::CLOSED)
    // transport is shutting down, ignore any errors
    return;

  NFD_LOG_FACE_WARN("Send or ping operation failed: " << error.message());

  this->setState(TransportState::FAILED);
  doClose();
}
示例#15
0
void
TcpTransport::handleError(const boost::system::error_code& error)
{
  if (this->getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
    NFD_LOG_FACE_TRACE("TCP socket error: " << error.message());
    this->setState(TransportState::DOWN);

    // cancel all outstanding operations
    boost::system::error_code error;
    m_socket.cancel(error);

    // do this asynchronously because there could be some callbacks still pending
    getGlobalIoService().post([this] { reconnect(); });
  }
  else {
    StreamTransport::handleError(error);
  }
}
示例#16
0
void
DatagramTransport<T, U>::doClose()
{
  NFD_LOG_FACE_TRACE(__func__);

  if (m_socket.is_open()) {
    // Cancel all outstanding operations and close the socket.
    // Use the non-throwing variants and ignore errors, if any.
    boost::system::error_code error;
    m_socket.cancel(error);
    m_socket.close(error);
  }

  // Ensure that the Transport stays alive at least until
  // all pending handlers are dispatched
  getGlobalIoService().post([this] {
    this->setState(TransportState::CLOSED);
  });
}
示例#17
0
void
Transport::send(const Block& packet, const EndpointId& endpoint)
{
  BOOST_ASSERT(packet.isValid());
  BOOST_ASSERT(this->getMtu() == MTU_UNLIMITED ||
               packet.size() <= static_cast<size_t>(this->getMtu()));

  TransportState state = this->getState();
  if (state != TransportState::UP && state != TransportState::DOWN) {
    NFD_LOG_FACE_TRACE("send ignored in " << state << " state");
    return;
  }

  if (state == TransportState::UP) {
    ++this->nOutPackets;
    this->nOutBytes += packet.size();
  }

  this->doSend(packet, endpoint);
}
示例#18
0
void
DatagramTransport<T, U>::processErrorCode(const boost::system::error_code& error)
{
  NFD_LOG_FACE_TRACE(__func__);

  if (getState() == TransportState::CLOSING ||
      getState() == TransportState::FAILED ||
      getState() == TransportState::CLOSED ||
      error == boost::asio::error::operation_aborted) {
    // transport is shutting down, ignore any errors
    return;
  }

  if (getPersistency() == ndn::nfd::FACE_PERSISTENCY_PERMANENT) {
    NFD_LOG_FACE_DEBUG("Permanent face ignores error: " << error.message());
    return;
  }

  NFD_LOG_FACE_ERROR("Send or receive operation failed: " << error.message());
  this->setState(TransportState::FAILED);
  doClose();
}
示例#19
0
std::tuple<bool, Block, lp::Packet>
LpReassembler::receiveFragment(Transport::EndpointId remoteEndpoint, const lp::Packet& packet)
{
  BOOST_ASSERT(packet.has<lp::FragmentField>());

  static auto FALSE_RETURN = std::make_tuple(false, Block(), lp::Packet());

  // read and check FragIndex and FragCount
  uint64_t fragIndex = 0;
  uint64_t fragCount = 1;
  if (packet.has<lp::FragIndexField>()) {
    fragIndex = packet.get<lp::FragIndexField>();
  }
  if (packet.has<lp::FragCountField>()) {
    fragCount = packet.get<lp::FragCountField>();
  }

  if (fragIndex >= fragCount) {
    NFD_LOG_FACE_WARN("reassembly error, FragIndex>=FragCount: DROP");
    return FALSE_RETURN;
  }

  if (fragCount > m_options.nMaxFragments) {
    NFD_LOG_FACE_WARN("reassembly error, FragCount over limit: DROP");
    return FALSE_RETURN;
  }

  // check for fast path
  if (fragIndex == 0 && fragCount == 1) {
    ndn::Buffer::const_iterator fragBegin, fragEnd;
    std::tie(fragBegin, fragEnd) = packet.get<lp::FragmentField>();
    Block netPkt(&*fragBegin, std::distance(fragBegin, fragEnd));
    return std::make_tuple(true, netPkt, packet);
  }

  // check Sequence and compute message identifier
  if (!packet.has<lp::SequenceField>()) {
    NFD_LOG_FACE_WARN("reassembly error, Sequence missing: DROP");
    return FALSE_RETURN;
  }
  lp::Sequence messageIdentifier = packet.get<lp::SequenceField>() - fragIndex;
  Key key = std::make_tuple(remoteEndpoint, messageIdentifier);

  // add to PartialPacket
  PartialPacket& pp = m_partialPackets[key];
  if (pp.fragCount == 0) { // new PartialPacket
    pp.fragCount = fragCount;
    pp.nReceivedFragments = 0;
    pp.fragments.resize(fragCount);
  }
  else {
    if (fragCount != pp.fragCount) {
      NFD_LOG_FACE_WARN("reassembly error, FragCount changed: DROP");
      return FALSE_RETURN;
    }
  }

  if (pp.fragments[fragIndex].has<lp::SequenceField>()) {
    NFD_LOG_FACE_TRACE("fragment already received: DROP");
    return FALSE_RETURN;
  }

  pp.fragments[fragIndex] = packet;
  ++pp.nReceivedFragments;

  // check complete condition
  if (pp.nReceivedFragments == pp.fragCount) {
    Block reassembled = doReassembly(key);
    lp::Packet firstFrag(std::move(pp.fragments[0]));
    m_partialPackets.erase(key);
    return std::make_tuple(true, reassembled, firstFrag);
  }

  // set drop timer
  pp.dropTimer = scheduler::schedule(m_options.reassemblyTimeout, [=] { timeoutPartialPacket(key); });

  return FALSE_RETURN;
}