123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515 |
- #include <string>
- #include <arpa/inet.h>
- #include <netinet/in.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <algorithm>
- #include <cstdlib>
- #include <cstddef>
- #include <vector>
- #include <gtest/gtest.h>
- #include <boost/bind.hpp>
- #include <boost/shared_ptr.hpp>
- #include <dns/buffer.h>
- #include <asio.hpp>
- #include <asiolink/asiolink_utilities.h>
- #include <asiolink/io_service.h>
- #include <asiolink/tcp_endpoint.h>
- #include <asiolink/tcp_socket.h>
- using namespace asio;
- using namespace asio::ip;
- using namespace isc::asiolink;
- using namespace isc::dns;
- using namespace std;
- namespace {
- const char SERVER_ADDRESS[] = "127.0.0.1";
- const unsigned short SERVER_PORT = 5303;
- const char OUTBOUND_DATA[] = "Data sent from client to server";
- const char INBOUND_DATA[] = "Returned data from server to client";
- }
- class TCPCallback {
- public:
-
- enum Operation {
- ACCEPT = 0,
- OPEN = 1,
- READ = 2,
- WRITE = 3,
- NONE = 4
- };
-
- enum {
- MIN_SIZE = (64 * 1024 + 2)
- };
- struct PrivateData {
- PrivateData() :
- error_code_(), length_(0), cumulative_(0), expected_(0), offset_(0),
- name_(""), queued_(NONE), called_(NONE)
- {}
- asio::error_code error_code_;
- size_t length_;
- size_t cumulative_;
- size_t expected_;
- size_t offset_;
- std::string name_;
- Operation queued_;
- Operation called_;
- uint8_t data_[MIN_SIZE];
- };
-
-
-
-
-
-
-
-
-
-
-
-
- TCPCallback(std::string which) : ptr_(new PrivateData())
- {
- ptr_->name_ = which;
- }
-
-
-
- virtual ~TCPCallback()
- {}
-
-
-
-
-
-
-
- void operator()(asio::error_code ec = asio::error_code(),
- size_t length = 0)
- {
- setCode(ec.value());
- ptr_->called_ = ptr_->queued_;
- ptr_->length_ = length;
- }
-
- int getCode() {
- return (ptr_->error_code_.value());
- }
-
-
-
- void setCode(int code) {
- ptr_->error_code_ = asio::error_code(code, asio::error_code().category());
- }
-
- size_t& length() {
- return (ptr_->length_);
- }
-
- size_t& cumulative() {
- return (ptr_->cumulative_);
- }
-
- size_t& expected() {
- return (ptr_->expected_);
- }
-
- size_t& offset() {
- return (ptr_->offset_);
- }
-
- uint8_t* data() {
- return (ptr_->data_);
- }
-
- Operation& queued() {
- return (ptr_->queued_);
- }
-
- Operation& called() {
- return (ptr_->called_);
- }
-
- std::string& name() {
- return (ptr_->name_);
- }
- private:
- boost::shared_ptr<PrivateData> ptr_;
- };
- void
- serverRead(tcp::socket& socket, TCPCallback& server_cb) {
-
-
-
-
-
-
- server_cb.cumulative() = 0;
- bool complete = false;
- while (!complete) {
-
- server_cb.length() = socket.receive(
- asio::buffer(server_cb.data() + server_cb.cumulative(),
- TCPCallback::MIN_SIZE - server_cb.cumulative()));
- server_cb.cumulative() += server_cb.length();
-
-
- if (server_cb.cumulative() >= 2) {
- server_cb.expected() = readUint16(server_cb.data());
- if ((server_cb.expected() + 2) == server_cb.cumulative()) {
-
-
-
-
- complete = true;
- }
- }
- }
- }
- TEST(TCPSocket, processReceivedData) {
- const uint16_t PACKET_SIZE = 16382;
- IOService service;
- TCPSocket<TCPCallback> test(service);
- uint8_t inbuff[PACKET_SIZE + 2];
- OutputBufferPtr outbuff(new OutputBuffer(16));
-
- size_t expected;
- size_t offset;
- size_t cumulative;
-
- for (size_t i = 0; i < sizeof(inbuff); ++i) {
- inbuff[i] = i % 256;
- }
-
- writeUint16(PACKET_SIZE, inbuff);
- cumulative = 0;
- offset = 0;
- expected = 0;
- outbuff->clear();
- bool complete = test.processReceivedData(inbuff, 1, cumulative, offset,
- expected, outbuff);
- EXPECT_FALSE(complete);
- EXPECT_EQ(1, cumulative);
- EXPECT_EQ(1, offset);
- EXPECT_EQ(0, expected);
- EXPECT_EQ(0, outbuff->getLength());
-
- complete = test.processReceivedData(inbuff, 1, cumulative, offset, expected,
- outbuff);
- EXPECT_FALSE(complete);
- EXPECT_EQ(2, cumulative);
- EXPECT_EQ(0, offset);
- EXPECT_EQ(PACKET_SIZE, expected);
- EXPECT_EQ(0, outbuff->getLength());
-
-
-
- complete = test.processReceivedData(inbuff + cumulative, 2, cumulative,
- offset, expected, outbuff);
- EXPECT_FALSE(complete);
- EXPECT_EQ(4, cumulative);
- EXPECT_EQ(0, offset);
- EXPECT_EQ(PACKET_SIZE, expected);
- EXPECT_EQ(2, outbuff->getLength());
- const uint8_t* dataptr = static_cast<const uint8_t*>(outbuff->getData());
- EXPECT_TRUE(equal(inbuff + 2, inbuff + cumulative, dataptr));
-
-
- complete = test.processReceivedData(inbuff + cumulative,
- PACKET_SIZE + 2 - cumulative,
- cumulative, offset, expected, outbuff);
- EXPECT_TRUE(complete);
- EXPECT_EQ(PACKET_SIZE + 2, cumulative);
- EXPECT_EQ(0, offset);
- EXPECT_EQ(PACKET_SIZE, expected);
- EXPECT_EQ(PACKET_SIZE, outbuff->getLength());
- dataptr = static_cast<const uint8_t*>(outbuff->getData());
- EXPECT_TRUE(equal(inbuff + 2, inbuff + cumulative, dataptr));
- }
- TEST(TCPSocket, SequenceTest) {
-
- IOService service;
-
- TCPSocket<TCPCallback> client(service);
- TCPCallback client_cb("Client");
- TCPEndpoint client_remote_endpoint;
- OutputBufferPtr client_buffer(new OutputBuffer(128));
-
-
- IOAddress server_address(SERVER_ADDRESS);
-
- TCPCallback server_cb("Server");
- TCPEndpoint server_endpoint(server_address, SERVER_PORT);
-
- TCPEndpoint server_remote_endpoint;
- tcp::socket server_socket(service.get_io_service());
-
-
-
-
-
- server_cb.queued() = TCPCallback::ACCEPT;
- server_cb.called() = TCPCallback::NONE;
- server_cb.setCode(42);
- tcp::acceptor acceptor(service.get_io_service(),
- tcp::endpoint(tcp::v4(), SERVER_PORT));
- acceptor.set_option(tcp::acceptor::reuse_address(true));
- acceptor.async_accept(server_socket, server_cb);
-
- client_cb.queued() = TCPCallback::OPEN;
- client_cb.called() = TCPCallback::NONE;
- client_cb.setCode(43);
- EXPECT_FALSE(client.isOpenSynchronous());
- client.open(&server_endpoint, client_cb);
-
- service.run_one();
- service.run_one();
- EXPECT_EQ(TCPCallback::ACCEPT, server_cb.called());
- EXPECT_EQ(0, server_cb.getCode());
- EXPECT_EQ(TCPCallback::OPEN, client_cb.called());
- EXPECT_EQ(0, client_cb.getCode());
-
-
-
- client_cb.called() = TCPCallback::NONE;
- client_cb.queued() = TCPCallback::WRITE;
- client_cb.setCode(143);
- client_cb.length() = 0;
- client.asyncSend(OUTBOUND_DATA, sizeof(OUTBOUND_DATA), &server_endpoint, client_cb);
-
-
- service.run_one();
-
- serverRead(server_socket, server_cb);
-
- EXPECT_EQ(TCPCallback::WRITE, client_cb.called());
- EXPECT_EQ(0, client_cb.getCode());
- EXPECT_EQ(sizeof(OUTBOUND_DATA) + 2, client_cb.length());
-
- EXPECT_EQ(sizeof(OUTBOUND_DATA) + 2, server_cb.cumulative());
- EXPECT_TRUE(equal(OUTBOUND_DATA,
- (OUTBOUND_DATA + (sizeof(OUTBOUND_DATA) - 1)),
- (server_cb.data() + 2)));
-
-
-
-
-
- server_cb.called() = TCPCallback::NONE;
- server_cb.queued() = TCPCallback::WRITE;
- server_cb.length() = 0;
- server_cb.cumulative() = 0;
- writeUint16(sizeof(INBOUND_DATA), server_cb.data());
- copy(INBOUND_DATA, (INBOUND_DATA + sizeof(INBOUND_DATA) - 1),
- (server_cb.data() + 2));
- server_socket.async_send(asio::buffer(server_cb.data(),
- (sizeof(INBOUND_DATA) + 2)),
- server_cb);
-
- client_cb.called() = TCPCallback::NONE;
- client_cb.queued() = TCPCallback::READ;
- client_cb.length() = 0;
- client_cb.cumulative() = 0;
- client_cb.expected() = 0;
- client_cb.offset() = 0;
- client.asyncReceive(client_cb.data(), TCPCallback::MIN_SIZE,
- client_cb.offset(), &client_remote_endpoint,
- client_cb);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- bool server_complete = false;
- bool client_complete = false;
- while (!server_complete || !client_complete) {
- service.run_one();
-
- if (!server_complete) {
- if (server_cb.called() == server_cb.queued()) {
-
-
-
- EXPECT_EQ(0, server_cb.getCode());
- EXPECT_EQ((sizeof(INBOUND_DATA) + 2), server_cb.length());
- server_complete = true;
- continue;
- }
- }
- if (!client_complete) {
-
- EXPECT_EQ(TCPCallback::READ, client_cb.called());
- EXPECT_EQ(0, client_cb.getCode());
-
-
- client_complete = client.processReceivedData(client_cb.data(),
- client_cb.length(),
- client_cb.cumulative(),
- client_cb.offset(),
- client_cb.expected(),
- client_buffer);
-
- if (! client_complete) {
- client_cb.called() = TCPCallback::NONE;
- client_cb.queued() = TCPCallback::READ;
- client_cb.length() = 0;
- client.asyncReceive(client_cb.data(), TCPCallback::MIN_SIZE ,
- client_cb.offset(), &client_remote_endpoint,
- client_cb);
- }
- }
- }
-
-
-
- EXPECT_EQ(TCPCallback::READ, client_cb.called());
- EXPECT_EQ(0, client_cb.getCode());
- EXPECT_EQ(sizeof(INBOUND_DATA) + 2, client_cb.cumulative());
- EXPECT_EQ(sizeof(INBOUND_DATA), client_buffer->getLength());
-
- EXPECT_EQ(TCPCallback::WRITE, server_cb.called());
- EXPECT_EQ(0, server_cb.getCode());
- EXPECT_EQ(sizeof(INBOUND_DATA) + 2, server_cb.length());
-
- const uint8_t* received = static_cast<const uint8_t*>(client_buffer->getData());
- EXPECT_TRUE(equal(INBOUND_DATA, (INBOUND_DATA + (sizeof(INBOUND_DATA) - 1)),
- received));
-
- EXPECT_NO_THROW(client.close());
- EXPECT_NO_THROW(server_socket.close());
- }
|