Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
markaren committed Sep 19, 2024
1 parent f8ffcd0 commit 09ade56
Show file tree
Hide file tree
Showing 10 changed files with 119 additions and 96 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# SimpleSocket

A simple cross-platform Socket (TCP/UDP/WebSockets) implementation for C++ (no external dependencies)
A simple cross-platform Socket (TCP, UDP, Web and Unix Domain Sockets) implementation for C++ (no external dependencies)
for education and hobby usage.

> NOT for use in production.
Expand Down
57 changes: 57 additions & 0 deletions include/simple_socket/Socket.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@

#ifndef SIMPLE_SOCKET_SOCKET_HPP
#define SIMPLE_SOCKET_SOCKET_HPP

#include <memory>
#include <string>
#include <vector>

namespace simple_socket {

class SocketConnection {
public:
virtual int read(std::vector<unsigned char>& buffer) = 0;

virtual int read(unsigned char* buffer, size_t size) = 0;

virtual bool readExact(std::vector<unsigned char>& buffer) = 0;

virtual bool readExact(unsigned char* buffer, size_t size) = 0;

virtual bool write(const std::string& message) = 0;

virtual bool write(const std::vector<unsigned char>& data) = 0;

virtual void close() = 0;

virtual ~SocketConnection() = default;
};

class Socket: public SocketConnection {
public:
Socket();

int read(std::vector<unsigned char>& buffer) override;

int read(unsigned char* buffer, size_t size) override;

bool readExact(std::vector<unsigned char>& buffer) override;

bool readExact(unsigned char* buffer, size_t size) override;

bool write(const std::string& message) override;

bool write(const std::vector<unsigned char>& data) override;

void close() override;

~Socket() override;

protected:
struct Impl;
std::unique_ptr<Impl> pimpl_;
};

}// namespace simple_socket

#endif//SIMPLE_SOCKET_SOCKET_HPP
68 changes: 4 additions & 64 deletions include/simple_socket/TCPSocket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,80 +2,20 @@
#ifndef SIMPLE_SOCKET_TCPSOCKET_HPP
#define SIMPLE_SOCKET_TCPSOCKET_HPP

#include <memory>
#include <string>
#include <vector>

// This Socket interface is not production grade
#include "simple_socket/Socket.hpp"

namespace simple_socket {

class TCPConnection {
public:
virtual int read(std::vector<unsigned char>& buffer) = 0;

virtual int read(unsigned char* buffer, size_t size) = 0;

virtual bool readExact(std::vector<unsigned char>& buffer) = 0;

virtual bool readExact(unsigned char* buffer, size_t size) = 0;

virtual bool write(const std::string& message) = 0;

virtual bool write(const std::vector<unsigned char>& data) = 0;

virtual void close() = 0;

virtual ~TCPConnection() = default;
};

class TCPSocket: public TCPConnection {
public:
TCPSocket();

int read(std::vector<unsigned char>& buffer) override;

int read(unsigned char* buffer, size_t size) override;

bool readExact(std::vector<unsigned char>& buffer) override;

bool readExact(unsigned char* buffer, size_t size) override;

bool write(const std::string& message) override;

bool write(const std::vector<unsigned char>& data) override;

void close() override;

~TCPSocket() override;

protected:
struct Impl;
std::unique_ptr<Impl> pimpl_;
};

class TCPClient: public TCPSocket {
class TCPClient: public Socket {
public:
bool connect(const std::string& ip, int port);
};

class TCPServer: public TCPSocket {
class TCPServer: public Socket {
public:
explicit TCPServer(int port, int backlog = 1);

std::unique_ptr<TCPConnection> accept();
};

class UnixDomainClient: public TCPSocket {
public:
bool connect(const std::string& domain);
};

class UnixDomainServer: public TCPSocket {
public:
explicit UnixDomainServer(const std::string& domain, int backlog = 1);

std::unique_ptr<TCPConnection> accept();
std::unique_ptr<SocketConnection> accept();
};

}// namespace simple_socket
Expand Down
23 changes: 23 additions & 0 deletions include/simple_socket/UnixDomainSocket.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@

#ifndef SIMPLE_SOCKET_UNIXDOMAINSOCKET_HPP
#define SIMPLE_SOCKET_UNIXDOMAINSOCKET_HPP

#include "simple_socket/Socket.hpp"

namespace simple_socket {

class UnixDomainClient: public Socket {
public:
bool connect(const std::string& domain);
};

class UnixDomainServer: public Socket {
public:
explicit UnixDomainServer(const std::string& domain, int backlog = 1);

std::unique_ptr<SocketConnection> accept();
};

}// namespace simple_socket

#endif//SIMPLE_SOCKET_UNIXDOMAINSOCKET_HPP
4 changes: 3 additions & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ set(publicHeaderDir "${PROJECT_SOURCE_DIR}/include")

set(publicHeaders
"simple_socket/port_query.hpp"
"simple_socket/Socket.hpp"
"simple_socket/TCPSocket.hpp"
"simple_socket/UDPSocket.hpp"
"simple_socket/UnixDomainSocket.hpp"
"simple_socket/WebSocket.hpp"
)

Expand All @@ -20,7 +22,7 @@ set(privateHeaders

set(sources
"simple_socket/port_query.cpp"
"simple_socket/TCPSocket.cpp"
"simple_socket/Socket.cpp"
"simple_socket/UDPSocket.cpp"
"simple_socket/WebSocket.cpp"
)
Expand Down
34 changes: 18 additions & 16 deletions src/simple_socket/TCPSocket.cpp → src/simple_socket/Socket.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@

#include "simple_socket/Socket.hpp"
#include "simple_socket/TCPSocket.hpp"
#include "simple_socket/UnixDomainSocket.hpp"

#include "simple_socket/common.hpp"

namespace simple_socket {

struct TCPSocket::Impl {
struct Socket::Impl {

Impl(): sockfd_(INVALID_SOCKET) {

Expand Down Expand Up @@ -94,7 +96,7 @@ namespace simple_socket {
}
}

[[nodiscard]] std::unique_ptr<TCPConnection> acceptTCP() const {
[[nodiscard]] std::unique_ptr<SocketConnection> acceptTCP() const {

sockaddr_in client_addr{};
socklen_t addrlen = sizeof(client_addr);
Expand All @@ -105,13 +107,13 @@ namespace simple_socket {
throwSocketError("Accept failed");
}

auto conn = std::make_unique<TCPSocket>();
auto conn = std::make_unique<Socket>();
conn->pimpl_->assign(new_sock);

return conn;
}

[[nodiscard]] std::unique_ptr<TCPConnection> acceptUnix() const {
[[nodiscard]] std::unique_ptr<SocketConnection> acceptUnix() const {

SOCKET new_sock = ::accept(sockfd_, nullptr, nullptr);

Expand All @@ -120,7 +122,7 @@ namespace simple_socket {
throwSocketError("Accept failed");
}

auto conn = std::make_unique<TCPSocket>();
auto conn = std::make_unique<Socket>();
conn->pimpl_->assign(new_sock);

return conn;
Expand Down Expand Up @@ -198,52 +200,52 @@ namespace simple_socket {
}
};

TCPSocket::TCPSocket(): pimpl_(std::make_unique<Impl>()) {}
Socket::Socket(): pimpl_(std::make_unique<Impl>()) {}

int TCPSocket::read(std::vector<unsigned char>& buffer) {
int Socket::read(std::vector<unsigned char>& buffer) {

size_t bytesRead = 0;
const auto success = pimpl_->read(buffer.data(), buffer.size(), &bytesRead);

return success ? static_cast<int>(bytesRead) : -1;
}

int TCPSocket::read(unsigned char* buffer, size_t size) {
int Socket::read(unsigned char* buffer, size_t size) {

size_t bytesRead = 0;
const auto success = pimpl_->read(buffer, size, &bytesRead);

return success ? static_cast<int>(bytesRead) : -1;
}

bool TCPSocket::readExact(std::vector<unsigned char>& buffer) {
bool Socket::readExact(std::vector<unsigned char>& buffer) {

return pimpl_->readExact(buffer.data(), buffer.size());
}

bool TCPSocket::readExact(unsigned char* buffer, size_t size) {
bool Socket::readExact(unsigned char* buffer, size_t size) {

return pimpl_->readExact(buffer, size);
}

bool TCPSocket::write(const std::string& buffer) {
bool Socket::write(const std::string& buffer) {

if (buffer.empty()) return false;

return pimpl_->write(buffer);
}

bool TCPSocket::write(const std::vector<unsigned char>& buffer) {
bool Socket::write(const std::vector<unsigned char>& buffer) {

return pimpl_->write(buffer);
}

void TCPSocket::close() {
void Socket::close() {

pimpl_->close();
}

TCPSocket::~TCPSocket() = default;
Socket::~Socket() = default;


bool TCPClient::connect(const std::string& ip, int port) {
Expand All @@ -258,7 +260,7 @@ namespace simple_socket {
pimpl_->listen(backlog);
}

std::unique_ptr<TCPConnection> TCPServer::accept() {
std::unique_ptr<SocketConnection> TCPServer::accept() {

return pimpl_->acceptTCP();
}
Expand All @@ -269,7 +271,7 @@ namespace simple_socket {
return pimpl_->connect(domain);
}

std::unique_ptr<TCPConnection> UnixDomainServer::accept() {
std::unique_ptr<SocketConnection> UnixDomainServer::accept() {

return pimpl_->acceptUnix();
}
Expand Down
4 changes: 2 additions & 2 deletions src/simple_socket/WebSocket.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ namespace {
class WebSocketConnectionImpl: public WebSocketConnection {

public:
WebSocketConnectionImpl(WebSocket* socket, std::unique_ptr<TCPConnection> conn)
WebSocketConnectionImpl(WebSocket* socket, std::unique_ptr<SocketConnection> conn)
: socket(socket), conn(std::move(conn)) {

handshake();
Expand Down Expand Up @@ -182,7 +182,7 @@ class WebSocketConnectionImpl: public WebSocketConnection {

std::atomic_bool closed{false};
WebSocket* socket;
std::unique_ptr<TCPConnection> conn;
std::unique_ptr<SocketConnection> conn;
std::thread thread;
};

Expand Down
10 changes: 5 additions & 5 deletions tests/integration/run_tcp_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@

using namespace simple_socket;

void socketHandler(std::unique_ptr<TCPConnection> conn) {
void socketHandler(std::unique_ptr<SocketConnection> conn) {

std::vector<unsigned char> buffer(1024);
auto n = conn->read(buffer);
const auto n = conn->read(buffer);

std::string msg(buffer.begin(), buffer.begin() + static_cast<int>(n));
std::string msg{buffer.begin(), buffer.begin() + n};
std::cout << "Received from client: " << msg << std::endl;
conn->write("Hello " + msg + "!");
}
Expand All @@ -24,10 +24,10 @@ int main() {
std::atomic_bool stop = false;
std::thread t([&] {
while (!stop) {
std::unique_ptr<TCPConnection> conn;
std::unique_ptr<SocketConnection> conn;
try {
conn = server.accept();
} catch (const std::exception& e) {
} catch (const std::exception&) {
continue;
}

Expand Down
6 changes: 3 additions & 3 deletions tests/test_tcp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace {
return "Hello " + msg + "!";
}

void socketHandler(std::unique_ptr<TCPConnection> conn) {
void socketHandler(std::unique_ptr<SocketConnection> conn) {

std::vector<unsigned char> buffer(1024);
const auto bytesRead = conn->read(buffer);
Expand All @@ -46,7 +46,7 @@ TEST_CASE("TCP read/write") {
TCPClient client;

std::thread serverThread([&server] {
std::unique_ptr<TCPConnection> conn;
std::unique_ptr<SocketConnection> conn;
REQUIRE_NOTHROW(conn = server.accept());
socketHandler(std::move(conn));
});
Expand Down Expand Up @@ -87,7 +87,7 @@ TEST_CASE("TCP readexact/write") {
TCPClient client;

std::thread serverThread([&server] {
std::unique_ptr<TCPConnection> conn;
std::unique_ptr<SocketConnection> conn;
REQUIRE_NOTHROW(conn = server.accept());
socketHandler(std::move(conn));
});
Expand Down
Loading

0 comments on commit 09ade56

Please sign in to comment.