transport: make error messages more informative
Change-Id: I188e1bef8ceceb6acab800e0db92f2c80abc64e5
diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml
index 267e3f4..ab194b9 100644
--- a/.github/workflows/docker.yml
+++ b/.github/workflows/docker.yml
@@ -2,7 +2,7 @@
on:
push:
tags:
- - 'ndn-cxx-*'
+ - 'ndn-cxx-[0-9]+*'
schedule:
# twice a month
- cron: '20 4 5,20 * *'
diff --git a/ndn-cxx/face.cpp b/ndn-cxx/face.cpp
index bc590f0..3a6304a 100644
--- a/ndn-cxx/face.cpp
+++ b/ndn-cxx/face.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2023 Regents of the University of California.
+ * Copyright (c) 2013-2024 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -118,11 +118,11 @@
NDN_THROW(ConfigFile::Error("Unsupported transport protocol \"" + protocol + "\""));
}
}
- catch (const Transport::Error&) {
- NDN_THROW_NESTED(ConfigFile::Error("Failed to create transport"));
+ catch (const Transport::Error& e) {
+ NDN_THROW_NESTED(ConfigFile::Error("Failed to create transport: "s + e.what()));
}
- catch (const FaceUri::Error&) {
- NDN_THROW_NESTED(ConfigFile::Error("Failed to create transport"));
+ catch (const FaceUri::Error& e) {
+ NDN_THROW_NESTED(ConfigFile::Error("Failed to create transport: "s + e.what()));
}
}
diff --git a/ndn-cxx/transport/detail/stream-transport-impl.hpp b/ndn-cxx/transport/detail/stream-transport-impl.hpp
index ff10539..0c65a5e 100644
--- a/ndn-cxx/transport/detail/stream-transport-impl.hpp
+++ b/ndn-cxx/transport/detail/stream-transport-impl.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2023 Regents of the University of California.
+ * Copyright (c) 2013-2024 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -26,24 +26,26 @@
#include <boost/asio/steady_timer.hpp>
#include <boost/asio/write.hpp>
+#include <boost/lexical_cast.hpp>
#include <list>
#include <queue>
namespace ndn::detail {
-/** \brief Implementation detail of a Boost.Asio-based stream-oriented transport.
- * \tparam BaseTransport a subclass of Transport
- * \tparam Protocol a Boost.Asio stream-oriented protocol, e.g. boost::asio::ip::tcp
- * or boost::asio::local::stream_protocol
+/**
+ * \brief Implementation detail of a Boost.Asio-based stream-oriented transport.
+ * \tparam BaseTransport a subclass of Transport
+ * \tparam Protocol a Boost.Asio stream-oriented protocol, e.g., `boost::asio::ip::tcp`
+ * or `boost::asio::local::stream_protocol`
*/
template<typename BaseTransport, typename Protocol>
class StreamTransportImpl : public std::enable_shared_from_this<StreamTransportImpl<BaseTransport, Protocol>>
{
-public:
- using Impl = StreamTransportImpl<BaseTransport, Protocol>;
+protected:
using TransmissionQueue = std::queue<Block, std::list<Block>>;
+public:
StreamTransportImpl(BaseTransport& transport, boost::asio::io_context& ioCtx)
: m_transport(transport)
, m_socket(ioCtx)
@@ -57,18 +59,25 @@
if (m_transport.getState() == Transport::State::CONNECTING) {
return;
}
+
+ m_endpoint = endpoint;
m_transport.setState(Transport::State::CONNECTING);
// Wait at most 4 seconds to connect
/// @todo Decide whether this number should be configurable
m_connectTimer.expires_after(std::chrono::seconds(4));
- m_connectTimer.async_wait([self = this->shared_from_this()] (const auto& error) {
- self->connectTimeoutHandler(error);
+ m_connectTimer.async_wait([self = this->shared_from_this()] (const auto& ec) {
+ if (ec) // e.g., cancelled timer
+ return;
+
+ self->m_transport.close();
+ NDN_THROW(Transport::Error(boost::system::errc::make_error_code(boost::system::errc::timed_out),
+ "could not connect to NDN forwarder at " +
+ boost::lexical_cast<std::string>(self->m_endpoint)));
});
- m_socket.open();
- m_socket.async_connect(endpoint, [self = this->shared_from_this()] (const auto& error) {
- self->connectHandler(error);
+ m_socket.async_connect(m_endpoint, [self = this->shared_from_this()] (const auto& ec) {
+ self->connectHandler(ec);
});
}
@@ -125,8 +134,13 @@
m_connectTimer.cancel();
if (error) {
+ if (error == boost::asio::error::operation_aborted) {
+ // async_connect was explicitly cancelled (e.g., socket close)
+ return;
+ }
m_transport.close();
- NDN_THROW(Transport::Error(error, "error while connecting to the forwarder"));
+ NDN_THROW(Transport::Error(error, "could not connect to NDN forwarder at " +
+ boost::lexical_cast<std::string>(m_endpoint)));
}
m_transport.setState(Transport::State::PAUSED);
@@ -138,16 +152,6 @@
}
void
- connectTimeoutHandler(const boost::system::error_code& error)
- {
- if (error) // e.g., cancelled timer
- return;
-
- m_transport.close();
- NDN_THROW(Transport::Error(error, "error while connecting to the forwarder"));
- }
-
- void
asyncWrite()
{
BOOST_ASSERT(!m_transmissionQueue.empty());
@@ -155,12 +159,12 @@
// capture a copy of the shared_ptr to "this" to prevent deallocation
[this, self = this->shared_from_this()] (const auto& error, size_t) {
if (error) {
- if (error == boost::system::errc::operation_canceled) {
- // async receive has been explicitly cancelled (e.g., socket close)
+ if (error == boost::asio::error::operation_aborted) {
+ // async_write was explicitly cancelled (e.g., socket close)
return;
}
m_transport.close();
- NDN_THROW(Transport::Error(error, "error while writing data to socket"));
+ NDN_THROW(Transport::Error(error, "socket write error"));
}
if (m_transport.getState() == Transport::State::CLOSED) {
@@ -184,12 +188,12 @@
// capture a copy of the shared_ptr to "this" to prevent deallocation
[this, self = this->shared_from_this()] (const auto& error, size_t nBytesRecvd) {
if (error) {
- if (error == boost::system::errc::operation_canceled) {
- // async receive has been explicitly cancelled (e.g., socket close)
+ if (error == boost::asio::error::operation_aborted) {
+ // async_receive was explicitly cancelled (e.g., socket close)
return;
}
m_transport.close();
- NDN_THROW(Transport::Error(error, "error while receiving data from socket"));
+ NDN_THROW(Transport::Error(error, "socket read error"));
}
m_inputBufferSize += nBytesRecvd;
@@ -199,7 +203,7 @@
bool hasProcessedSome = processAllReceived(m_inputBuffer, offset, m_inputBufferSize);
if (!hasProcessedSome && m_inputBufferSize == MAX_NDN_PACKET_SIZE && offset == 0) {
m_transport.close();
- NDN_THROW(Transport::Error("input buffer full, but a valid TLV cannot be decoded"));
+ NDN_THROW(Transport::Error("receive buffer full, but a valid TLV cannot be decoded"));
}
if (offset > 0) {
@@ -232,12 +236,12 @@
protected:
BaseTransport& m_transport;
-
+ typename Protocol::endpoint m_endpoint;
typename Protocol::socket m_socket;
- uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
- size_t m_inputBufferSize = 0;
- TransmissionQueue m_transmissionQueue;
boost::asio::steady_timer m_connectTimer;
+ TransmissionQueue m_transmissionQueue;
+ size_t m_inputBufferSize = 0;
+ uint8_t m_inputBuffer[MAX_NDN_PACKET_SIZE];
};
} // namespace ndn::detail
diff --git a/ndn-cxx/transport/detail/stream-transport-with-resolver-impl.hpp b/ndn-cxx/transport/detail/stream-transport-with-resolver-impl.hpp
index dec886a..b342425 100644
--- a/ndn-cxx/transport/detail/stream-transport-with-resolver-impl.hpp
+++ b/ndn-cxx/transport/detail/stream-transport-with-resolver-impl.hpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2023 Regents of the University of California.
+ * Copyright (c) 2013-2024 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -26,8 +26,9 @@
namespace ndn::detail {
-/** \brief Implementation detail of a Boost.Asio-based stream-oriented transport
- * with resolver support.
+/**
+ * \brief Implementation detail of a Boost.Asio-based stream-oriented transport
+ * with resolver support.
*/
template<typename BaseTransport, typename Protocol>
class StreamTransportWithResolverImpl : public StreamTransportImpl<BaseTransport, Protocol>
@@ -44,38 +45,47 @@
if (this->m_transport.getState() == Transport::State::CONNECTING) {
return;
}
+
this->m_transport.setState(Transport::State::CONNECTING);
+ auto hostAndPort = std::string(host) + ':' + std::string(port);
// Wait at most 4 seconds to connect
/// @todo Decide whether this number should be configurable
this->m_connectTimer.expires_after(std::chrono::seconds(4));
- this->m_connectTimer.async_wait([self = this->shared_from_base()] (const auto& ec) {
- self->connectTimeoutHandler(ec);
+ this->m_connectTimer.async_wait([self = this->shared_from_base(), hostAndPort] (const auto& ec) {
+ if (ec) // e.g., cancelled timer
+ return;
+
+ self->m_transport.close();
+ NDN_THROW(Transport::Error(boost::system::errc::make_error_code(boost::system::errc::timed_out),
+ "could not connect to NDN forwarder at " + hostAndPort));
});
auto resolver = make_shared<typename Protocol::resolver>(this->m_socket.get_executor());
- resolver->async_resolve(host, port, [self = this->shared_from_base(), resolver] (auto&&... args) {
- self->resolveHandler(std::forward<decltype(args)>(args)..., resolver);
- });
+ resolver->async_resolve(host, port,
+ [self = this->shared_from_base(), hostAndPort, resolver] (auto&&... args) {
+ self->resolveHandler(hostAndPort, std::forward<decltype(args)>(args)...);
+ });
}
protected:
void
- resolveHandler(const boost::system::error_code& error,
- const typename Protocol::resolver::results_type& endpoints,
- const shared_ptr<typename Protocol::resolver>&)
+ resolveHandler(const std::string& hostAndPort,
+ const boost::system::error_code& error,
+ const typename Protocol::resolver::results_type& endpoints)
{
if (error) {
- if (error == boost::system::errc::operation_canceled)
+ if (error == boost::asio::error::operation_aborted)
return;
this->m_transport.close();
- NDN_THROW(Transport::Error(error, "unable to resolve host or port"));
+ NDN_THROW(Transport::Error(error, "could not resolve " + hostAndPort));
}
BOOST_ASSERT(!endpoints.empty()); // guaranteed by Asio if the resolve operation is successful
- this->m_socket.async_connect(*endpoints.begin(), [self = this->shared_from_base()] (const auto& ec) {
+ this->m_endpoint = *endpoints.begin();
+ this->m_socket.async_connect(this->m_endpoint, [self = this->shared_from_base()] (const auto& ec) {
self->connectHandler(ec);
});
}
diff --git a/ndn-cxx/transport/transport.cpp b/ndn-cxx/transport/transport.cpp
index 1b7c774..11a3246 100644
--- a/ndn-cxx/transport/transport.cpp
+++ b/ndn-cxx/transport/transport.cpp
@@ -1,6 +1,6 @@
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
/*
- * Copyright (c) 2013-2023 Regents of the University of California.
+ * Copyright (c) 2013-2024 Regents of the University of California.
*
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
*
@@ -23,8 +23,8 @@
namespace ndn {
-Transport::Error::Error(const boost::system::error_code& code, const std::string& msg)
- : std::runtime_error(msg + (code.value() ? " (" + code.message() + ")" : ""))
+Transport::Error::Error(const boost::system::error_code& ec, const std::string& msg)
+ : std::runtime_error(msg + (ec ? " (" + ec.message() + ")" : ""))
{
}