--- /dev/null
+/tcp_messages.cc -diff merge=ours
+/tcp_messages.h -diff merge=ours
AM_CPPFLAGS += $(BOOST_INCLUDES) $(CRYPTO_CFLAGS) $(CRYPTO_INCLUDES)
AM_CXXFLAGS = $(KEA_CXXFLAGS)
-EXTRA_DIST = # tcp.dox
+EXTRA_DIST = tcp.dox
# Ensure that the message file is included in the distribution
EXTRA_DIST += tcp_messages.mes
libkea_tcp_la_CXXFLAGS = $(AM_CXXFLAGS)
libkea_tcp_la_CPPFLAGS = $(AM_CPPFLAGS)
libkea_tcp_la_LDFLAGS = $(AM_LDFLAGS)
-libkea_tcp_la_LDFLAGS += -no-undefined -version-info 52:0:0
+libkea_tcp_la_LDFLAGS += -no-undefined -version-info 1:0:0
libkea_tcp_la_LIBADD =
libkea_tcp_la_LIBADD += $(top_builddir)/src/lib/hooks/libkea-hooks.la
# Specify the headers for copying into the installation directory tree.
libkea_tcp_includedir = $(pkgincludedir)/tcp
libkea_tcp_include_HEADERS = \
- tcp_messages.h \
- tcp_connection.h \
- tcp_connection_pool.h \
- tcp_listener.h \
- tcp_log.h
+ tcp_connection_acceptor.h \
+ tcp_connection.h \
+ tcp_connection_pool.h \
+ tcp_listener.h \
+ tcp_log.h \
+ tcp_messages.h \
+ tcp_stream.h
This is a library of classes (in the isc::kea_tcp namespace) that provide
the ability to accept connections, listen for and respond to TCP messages.
+@section tcpMTConsiderations Multi-Threading Consideration for TCP Library
+
+This library is thread safe.
+
*/
#include <tcp/tcp_connection_pool.h>
#include <tcp/tcp_log.h>
#include <tcp/tcp_messages.h>
+#include <util/strutil.h>
#include <boost/make_shared.hpp>
#include <iomanip>
namespace isc {
namespace tcp {
-std::string
-TcpRequest::dumpAsHex(const uint8_t* data, size_t len) {
- std::stringstream output;
- for (unsigned int i = 0; i < len; i++) {
- if (i) {
- output << ":";
- }
-
- output << std::setfill('0') << std::setw(2) << std::hex
- << static_cast<unsigned short>(data[i]);
- }
-
- return (output.str());
-}
-
-void
+void
TcpResponse::consumeWireData(const size_t length) {
send_in_progress_ = true;
wire_data_.erase(wire_data_.begin(), wire_data_.begin() + length);
TcpConnection::doWrite(TcpResponsePtr response) {
try {
if (response->wireDataAvail()) {
- HERE("send:" << TcpRequest::dumpAsHex(response->getWireData(), response->getWireDataSize()));
+ HERE("send:" << isc::util::str::dumpAsHex(response->getWireData(), response->getWireDataSize()));
// Create instance of the callback. It is safe to pass the local instance
// of the callback, because the underlying std functions make copies
// as needed.
// Add data to the current request.
size_t bytes_used = request->postBuffer(static_cast<void*>(input_data.data()), length);
// Remove bytes used.
- bytes_left = length - bytes_used;
+ bytes_left = length - bytes_used;
input_data.erase(input_data.begin(), input_data.begin() + length);
}
request = createRequest();
if (bytes_left) {
// The input buffer spanned messages. Recurse to post the remainder to the
- // new request.
+ // new request.
request = postData(request, input_data);
// Restart the request timer.
HERE("spanning read, start request timer");
// No incomplete requests, start the idle timer.
HERE("no waiting requests, start idle timer");
setupIdleTimer();
- }
+ }
return (request);
}
return ("(unknown address)");
}
-void
+void
TcpConnection::setReadMax(const size_t read_max) {
if (!read_max) {
isc_throw(BadValue, "TcpConnection read_max must be > 0");
#if 1
#define HERE(a) std::cout << __FILE__ << ":" << __FUNCTION__ << ":" << __LINE__ << " " << a << std::endl << std::flush;
#else
-#define HERE(a)
+#define HERE(a)
#endif
/// @brief Defines a data structure for storing raw bytes of data on the wire.
typedef std::vector<uint8_t> WireData;
typedef boost::shared_ptr<WireData> WireDataPtr;
+/// @brief Base class for TCP messages.
+class TcpMessage {
+public:
+ /// @brief Constructor
+ TcpMessage(){
+ };
+
+ /// @brief Destructor
+ virtual ~TcpMessage(){
+ };
+
+ /// @brief Returns pointer to the first byte of the wire data.
+ /// @throw InvalidOperation if wire data is empty (i.e. getWireDataSize() == 0).
+ /// @return Constant raw pointer to the data.
+ const uint8_t* getWireData() const {
+ if (wire_data_.empty()) {
+ isc_throw(InvalidOperation, "TcpMessage::geWireData() - cannot access empty wire data");
+ }
+
+ return (wire_data_.data());
+ }
+
+ /// @brief Returns current size of the wire data.
+ size_t getWireDataSize() const {
+ return (wire_data_.size());
+ }
+
+protected:
+ /// @brief Buffer used for data in wire format data.
+ WireData wire_data_;
+};
+
/// @brief Abstract class used to receive an inbound message.
-class TcpRequest {
+class TcpRequest : public TcpMessage{
public:
/// @brief Constructor.
TcpRequest(){};
/// @brief Unpacks wire data once the message has been completely received.
virtual void unpack() = 0;
- /// @brief Returns pointer to the first byte of the wire data.
- const uint8_t* getWireData() const {
- return (wire_data_.data());
- }
-
- /// @brief Returns current size of the wire data.
- size_t getWireDataSize() const {
- return (wire_data_.size());
- }
-
- /// @brief Dumps a buffer of bytes as a string of hexadecimal digits
- ///
- /// @param data pointer to the data to dump
- /// @param length number of bytes to dump. Caller should ensure the length
- /// does not exceed the buffer.
- static std::string dumpAsHex(const uint8_t* data, size_t length);
-
private:
/// @brief Exception safe wrapper around logForamteRequest
/// the length of the output is unlimited.
/// @return Textual representation of the input buffer.
std::string logFormatRequestSafe(const size_t limit = 0) const;
-
-protected:
- /// @brief Buffer for the accumulated request data.
- WireData wire_data_;
};
/// @brief Defines a smart pointer to a TcpRequest.
typedef boost::shared_ptr<TcpRequest> TcpRequestPtr;
/// @brief Abstract class used to create and send an outbound response.
-class TcpResponse {
+class TcpResponse : public TcpMessage{
public:
/// @brief Constructor
TcpResponse()
return (!wire_data_.empty());
}
- /// @brief Returns pointer to the first byte of the wire data.
- const uint8_t* getWireData() const {
- return (wire_data_.data());
- }
-
- /// @brief Returns current size of the wire data.
- size_t getWireDataSize() const {
- return (wire_data_.size());
- }
-
/// @brief Prepares the wire data content for writing.
virtual void pack() = 0;
return(send_in_progress_);
}
-protected:
- /// @brief Buffer used for outbound data.
- WireData wire_data_;
-
private:
/// @brief Returns true once wire data consumption has begun.
bool send_in_progress_;
/// The input data is passed into the current request's postBuffer method.
/// If the request is still incomplete, we return it and wait for more
/// data to post. Otherwise, the request is complete and it is passed into
- /// @ref TcpConnection::requestReceived() to be processed. Upon return from
+ /// @ref TcpConnection::requestReceived() to be processed. Upon return from
/// that, a new request is created and returned to be used for the next
/// read cycle.
///
TcpRequestPtr postData(TcpRequestPtr request, WireData& input_data);
/// @brief Processes a request once it has been completely received.
- ///
+ ///
/// This function is called by @c postData() if the post results
/// in a completion (i.e. request's needData() returns false).
virtual void requestReceived(TcpRequestPtr request) = 0;
/// @brief Creates a new, empty request.
///
/// This function is called by @c postData(), following the completion
- /// of the current request, to create a new request for accepting the
+ /// of the current request, to create a new request for accepting the
/// next data read.
///
/// @return Pointer to the new request.
/// @brief Maximum bytes to write in a single socket write.
size_t write_max_;
- /// @brief Buffer for a single socket read.
+ /// @brief Buffer for a single socket read.
WireData input_buf_;
};
#include <config.h>
#include <tcp/tcp_stream.h>
+#include <util/strutil.h>
#include <iomanip>
#include <sstream>
size_t max = (limit && (limit < wire_data_.size()) ? limit : wire_data_.size());
output << "expected_size_: " << expected_size_ << ", current size: " << wire_data_.size()
<< ", data: "
- << dumpAsHex(wire_data_.data(), max);
+ << isc::util::str::dumpAsHex(wire_data_.data(), max);
} catch (const std::exception& ex) {
std::stringstream output;
output << "logFormatRequest error: " << ex.what();
return (impl_->scrub(original));
}
+std::string dumpAsHex(const uint8_t* data, size_t len) {
+ std::stringstream output;
+ for (unsigned int i = 0; i < len; i++) {
+ if (i) {
+ output << ":";
+ }
+
+ output << std::setfill('0') << std::setw(2) << std::hex
+ << static_cast<unsigned short>(data[i]);
+ }
+
+ return (output.str());
+}
+
} // namespace str
} // namespace util
} // namespace isc
#include <cctype>
#include <stdint.h>
#include <string>
+#include <iomanip>
#include <sstream>
#include <vector>
#include <exceptions/exceptions.h>
return (true);
}
+
+/// @brief Dumps a buffer of bytes as a string of hexadecimal digits
+///
+/// @param data pointer to the data to dump
+/// @param length number of bytes to dump. Caller should ensure the length
+/// does not exceed the buffer.
+std::string dumpAsHex(const uint8_t* data, size_t len);
+
} // namespace str
} // namespace util
} // namespace isc