syndilights/open-lighting-architecture/ola-0.8.4/common/network/SocketTest.cpp

433 lines
13 KiB
C++

/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*
* SocketTest.cpp
* Test fixture for the Socket classes
* Copyright (C) 2005-2008 Simon Newton
*/
#include <cppunit/extensions/HelperMacros.h>
#include <stdint.h>
#include <string.h>
#include <string>
#include "ola/Closure.h"
#include "ola/network/NetworkUtils.h"
#include "ola/network/SelectServer.h"
#include "ola/network/Socket.h"
using std::string;
using ola::network::AcceptingSocket;
using ola::network::ConnectedSocket;
using ola::network::LoopbackSocket;
using ola::network::PipeSocket;
using ola::network::SelectServer;
using ola::network::TcpAcceptingSocket;
using ola::network::TcpSocket;
using ola::network::StringToAddress;
using ola::network::UdpSocket;
static const char test_cstring[] = "Foo";
// used to set a timeout which aborts the tests
static const int ABORT_TIMEOUT_IN_MS = 1000;
class SocketTest: public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(SocketTest);
CPPUNIT_TEST(testLoopbackSocket);
CPPUNIT_TEST(testPipeSocketClientClose);
CPPUNIT_TEST(testPipeSocketServerClose);
CPPUNIT_TEST(testTcpSocketClientClose);
CPPUNIT_TEST(testTcpSocketServerClose);
CPPUNIT_TEST(testUdpSocket);
CPPUNIT_TEST_SUITE_END();
public:
void setUp();
void tearDown();
void testLoopbackSocket();
void testPipeSocketClientClose();
void testPipeSocketServerClose();
void testTcpSocketClientClose();
void testTcpSocketServerClose();
void testUdpSocket();
// timing out indicates something went wrong
void Timeout() {
CPPUNIT_ASSERT(false);
m_timeout_closure = NULL;
}
// Socket data actions
void ReceiveAndClose(ConnectedSocket *socket);
void ReceiveAndTerminate(ConnectedSocket *socket);
void Receive(ConnectedSocket *socket);
void ReceiveAndSend(ConnectedSocket *socket);
void ReceiveSendAndClose(ConnectedSocket *socket);
void AcceptAndSend(TcpAcceptingSocket *socket);
void AcceptSendAndClose(TcpAcceptingSocket *socket);
void UdpReceiveAndTerminate(UdpSocket *socket);
void UdpReceiveAndSend(UdpSocket *socket);
// Socket close actions
void TerminateOnClose() {
m_ss->Terminate();
}
private:
SelectServer *m_ss;
AcceptingSocket *m_accepting_socket;
ola::SingleUseClosure<void> *m_timeout_closure;
};
CPPUNIT_TEST_SUITE_REGISTRATION(SocketTest);
/*
* Setup the select server
*/
void SocketTest::setUp() {
m_ss = new SelectServer();
m_timeout_closure = ola::NewSingleClosure(this, &SocketTest::Timeout);
CPPUNIT_ASSERT(m_ss->RegisterSingleTimeout(ABORT_TIMEOUT_IN_MS,
m_timeout_closure));
}
/*
* Cleanup the select server
*/
void SocketTest::tearDown() {
delete m_ss;
}
/*
* Test a loopback socket works correctly
*/
void SocketTest::testLoopbackSocket() {
LoopbackSocket socket;
CPPUNIT_ASSERT(socket.Init());
CPPUNIT_ASSERT(!socket.Init());
socket.SetOnData(ola::NewClosure(this, &SocketTest::ReceiveAndTerminate,
static_cast<ConnectedSocket*>(&socket)));
CPPUNIT_ASSERT(m_ss->AddSocket(&socket));
ssize_t bytes_sent = socket.Send(
reinterpret_cast<const uint8_t*>(test_cstring),
sizeof(test_cstring));
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), bytes_sent);
m_ss->Run();
m_ss->RemoveSocket(&socket);
}
/*
* Test a pipe socket works correctly.
* The client sends some data and expects the same data to be returned. The
* client then closes the connection.
*/
void SocketTest::testPipeSocketClientClose() {
PipeSocket socket;
CPPUNIT_ASSERT(socket.Init());
CPPUNIT_ASSERT(!socket.Init());
socket.SetOnData(
ola::NewClosure(this, &SocketTest::ReceiveAndClose,
static_cast<ConnectedSocket*>(&socket)));
CPPUNIT_ASSERT(m_ss->AddSocket(&socket));
PipeSocket *other_end = socket.OppositeEnd();
CPPUNIT_ASSERT(other_end);
other_end->SetOnData(
ola::NewClosure(this, &SocketTest::ReceiveAndSend,
static_cast<ConnectedSocket*>(other_end)));
other_end->SetOnClose(ola::NewSingleClosure(this,
&SocketTest::TerminateOnClose));
CPPUNIT_ASSERT(m_ss->AddSocket(other_end));
ssize_t bytes_sent = socket.Send(
reinterpret_cast<const uint8_t*>(test_cstring),
sizeof(test_cstring));
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), bytes_sent);
m_ss->Run();
m_ss->RemoveSocket(&socket);
m_ss->RemoveSocket(other_end);
delete other_end;
}
/*
* Test a pipe socket works correctly.
* The client sends some data. The server echos the data and closes the
* connection.
*/
void SocketTest::testPipeSocketServerClose() {
PipeSocket socket;
CPPUNIT_ASSERT(socket.Init());
CPPUNIT_ASSERT(!socket.Init());
socket.SetOnData(ola::NewClosure(
this, &SocketTest::Receive,
static_cast<ConnectedSocket*>(&socket)));
socket.SetOnClose(ola::NewSingleClosure(this, &SocketTest::TerminateOnClose));
CPPUNIT_ASSERT(m_ss->AddSocket(&socket));
PipeSocket *other_end = socket.OppositeEnd();
CPPUNIT_ASSERT(other_end);
other_end->SetOnData(ola::NewClosure(
this, &SocketTest::ReceiveSendAndClose,
static_cast<ConnectedSocket*>(other_end)));
CPPUNIT_ASSERT(m_ss->AddSocket(other_end));
ssize_t bytes_sent = socket.Send(
reinterpret_cast<const uint8_t*>(test_cstring),
sizeof(test_cstring));
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), bytes_sent);
m_ss->Run();
m_ss->RemoveSocket(&socket);
m_ss->RemoveSocket(other_end);
delete other_end;
}
/*
* Test TCP sockets work correctly.
* The client connects and the server sends some data. The client checks the
* data matches and then closes the connection.
*/
void SocketTest::testTcpSocketClientClose() {
string ip_address = "127.0.0.1";
uint16_t server_port = 9010;
TcpAcceptingSocket socket(ip_address, server_port);
CPPUNIT_ASSERT(socket.Listen());
CPPUNIT_ASSERT(!socket.Listen());
socket.SetOnData(ola::NewClosure(this, &SocketTest::AcceptAndSend, &socket));
CPPUNIT_ASSERT(m_ss->AddSocket(&socket));
TcpSocket *client_socket = TcpSocket::Connect(ip_address, server_port);
CPPUNIT_ASSERT(client_socket);
client_socket->SetOnData(ola::NewClosure(
this, &SocketTest::ReceiveAndClose,
static_cast<ConnectedSocket*>(client_socket)));
CPPUNIT_ASSERT(m_ss->AddSocket(client_socket));
m_ss->Run();
m_ss->RemoveSocket(&socket);
m_ss->RemoveSocket(client_socket);
delete client_socket;
}
/*
* Test TCP sockets work correctly.
* The client connects and the server then sends some data and closes the
* connection.
*/
void SocketTest::testTcpSocketServerClose() {
string ip_address = "127.0.0.1";
uint16_t server_port = 9010;
TcpAcceptingSocket socket(ip_address, server_port);
CPPUNIT_ASSERT(socket.Listen());
CPPUNIT_ASSERT(!socket.Listen());
socket.SetOnData(
ola::NewClosure(this, &SocketTest::AcceptSendAndClose, &socket));
CPPUNIT_ASSERT(m_ss->AddSocket(&socket));
// The client socket checks the response and terminates on close
TcpSocket *client_socket = TcpSocket::Connect(ip_address, server_port);
CPPUNIT_ASSERT(client_socket);
client_socket->SetOnData(ola::NewClosure(
this, &SocketTest::Receive,
static_cast<ConnectedSocket*>(client_socket)));
client_socket->SetOnClose(
ola::NewSingleClosure(this, &SocketTest::TerminateOnClose));
CPPUNIT_ASSERT(m_ss->AddSocket(client_socket));
m_ss->Run();
m_ss->RemoveSocket(&socket);
m_ss->RemoveSocket(client_socket);
delete client_socket;
}
/*
* Test UDP sockets work correctly.
* The client connects and the server sends some data. The client checks the
* data matches and then closes the connection.
*/
void SocketTest::testUdpSocket() {
string ip_address = "127.0.0.1";
uint16_t server_port = 9010;
UdpSocket socket;
CPPUNIT_ASSERT(socket.Init());
CPPUNIT_ASSERT(!socket.Init());
CPPUNIT_ASSERT(socket.Bind(server_port));
CPPUNIT_ASSERT(!socket.Bind(server_port));
socket.SetOnData(
ola::NewClosure(this, &SocketTest::UdpReceiveAndSend, &socket));
CPPUNIT_ASSERT(m_ss->AddSocket(&socket));
UdpSocket client_socket;
CPPUNIT_ASSERT(client_socket.Init());
CPPUNIT_ASSERT(!client_socket.Init());
client_socket.SetOnData(
ola::NewClosure(
this, &SocketTest::UdpReceiveAndTerminate,
static_cast<UdpSocket*>(&client_socket)));
CPPUNIT_ASSERT(m_ss->AddSocket(&client_socket));
ssize_t bytes_sent = client_socket.SendTo(
reinterpret_cast<const uint8_t*>(test_cstring),
sizeof(test_cstring),
ip_address,
server_port);
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), bytes_sent);
m_ss->Run();
m_ss->RemoveSocket(&socket);
m_ss->RemoveSocket(&client_socket);
}
/*
* Receive some data and close the socket
*/
void SocketTest::ReceiveAndClose(ConnectedSocket *socket) {
Receive(socket);
m_ss->RemoveSocket(socket);
socket->Close();
}
/*
* Receive some data and terminate
*/
void SocketTest::ReceiveAndTerminate(ConnectedSocket *socket) {
Receive(socket);
m_ss->Terminate();
}
/*
* Receive some data and check it's what we expected.
*/
void SocketTest::Receive(ConnectedSocket *socket) {
// try to read more than what we sent to test non-blocking
uint8_t buffer[sizeof(test_cstring) + 10];
unsigned int data_read;
CPPUNIT_ASSERT(!socket->Receive(buffer, sizeof(buffer), data_read));
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(sizeof(test_cstring)),
data_read);
CPPUNIT_ASSERT(!memcmp(test_cstring, buffer, data_read));
}
/*
* Receive some data and send it back
*/
void SocketTest::ReceiveAndSend(ConnectedSocket *socket) {
uint8_t buffer[sizeof(test_cstring) + 10];
unsigned int data_read;
socket->Receive(buffer, sizeof(buffer), data_read);
CPPUNIT_ASSERT_EQUAL(static_cast<unsigned int>(sizeof(test_cstring)),
data_read);
ssize_t bytes_sent = socket->Send(buffer, data_read);
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), bytes_sent);
}
/*
* Receive some data, send the same data and close
*/
void SocketTest::ReceiveSendAndClose(ConnectedSocket *socket) {
ReceiveAndSend(socket);
m_ss->RemoveSocket(socket);
socket->Close();
}
/*
* Accept a new connection and send some test data
*/
void SocketTest::AcceptAndSend(TcpAcceptingSocket *socket) {
ConnectedSocket *new_socket = socket->Accept();
CPPUNIT_ASSERT(new_socket);
ssize_t bytes_sent = new_socket->Send(
reinterpret_cast<const uint8_t*>(test_cstring),
sizeof(test_cstring));
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), bytes_sent);
new_socket->SetOnClose(ola::NewSingleClosure(this,
&SocketTest::TerminateOnClose));
m_ss->AddSocket(new_socket, true);
}
/*
* Accept a new connect, send some data and close
*/
void SocketTest::AcceptSendAndClose(TcpAcceptingSocket *socket) {
ConnectedSocket *new_socket = socket->Accept();
CPPUNIT_ASSERT(new_socket);
ssize_t bytes_sent = new_socket->Send(
reinterpret_cast<const uint8_t*>(test_cstring),
sizeof(test_cstring));
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), bytes_sent);
new_socket->Close();
delete new_socket;
}
/*
* Receive some data and check it.
*/
void SocketTest::UdpReceiveAndTerminate(UdpSocket *socket) {
struct in_addr expected_address;
CPPUNIT_ASSERT(StringToAddress("127.0.0.1", expected_address));
struct sockaddr_in src;
socklen_t src_size = sizeof(src);
uint8_t buffer[sizeof(test_cstring) + 10];
ssize_t data_read = sizeof(buffer);
socket->RecvFrom(buffer, &data_read, src, src_size);
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), data_read);
CPPUNIT_ASSERT(expected_address.s_addr == src.sin_addr.s_addr);
m_ss->Terminate();
}
/*
* Receive some data and echo it back.
*/
void SocketTest::UdpReceiveAndSend(UdpSocket *socket) {
struct in_addr expected_address;
CPPUNIT_ASSERT(StringToAddress("127.0.0.1", expected_address));
struct sockaddr_in src;
socklen_t src_size = sizeof(src);
uint8_t buffer[sizeof(test_cstring) + 10];
ssize_t data_read = sizeof(buffer);
socket->RecvFrom(buffer, &data_read, src, src_size);
CPPUNIT_ASSERT_EQUAL(static_cast<ssize_t>(sizeof(test_cstring)), data_read);
CPPUNIT_ASSERT(expected_address.s_addr == src.sin_addr.s_addr);
ssize_t data_sent = socket->SendTo(buffer, data_read, src);
CPPUNIT_ASSERT_EQUAL(data_read, data_sent);
}