Skip to content

Commit

Permalink
update
Browse files Browse the repository at this point in the history
  • Loading branch information
markaren committed May 16, 2024
1 parent 26e7883 commit 1ca1495
Show file tree
Hide file tree
Showing 7 changed files with 119 additions and 82 deletions.
8 changes: 8 additions & 0 deletions include/AvailablePortQuery.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@

#ifndef SIMPLE_SOCKET_AVAILABLEPORTQUERY_HPP
#define SIMPLE_SOCKET_AVAILABLEPORTQUERY_HPP


int getAvailablePort(int startPort, int endPort);

#endif//SIMPLE_SOCKET_AVAILABLEPORTQUERY_HPP
32 changes: 32 additions & 0 deletions src/AvailablePortQuery.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@

#include "AvailablePortQuery.hpp"

#include "SocketIncludes.hpp"


int getAvailablePort(int startPort, int endPort) {
int sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd == SOCKET_ERROR) {
return -1;
}

const int optval = 1;
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&optval), sizeof(optval));

sockaddr_in serv_addr{};
serv_addr.sin_family = AF_INET;
serv_addr.sin_addr.s_addr = INADDR_ANY;

for (int port = startPort; port <= endPort; ++port) {
serv_addr.sin_port = htons(port);
if (bind(sockfd, reinterpret_cast<sockaddr*>(&serv_addr), sizeof(serv_addr)) != SOCKET_ERROR) {
closeSocket(sockfd);

return port;
}
}

closeSocket(sockfd);

return -1; // No available port found
}
2 changes: 1 addition & 1 deletion src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

add_library(simple_socket TCPSocket.cpp UDPSocket.cpp WSASession.cpp)
add_library(simple_socket TCPSocket.cpp UDPSocket.cpp WSASession.cpp AvailablePortQuery.cpp)
target_compile_features(simple_socket PUBLIC "cxx_std_17")

if (WIN32)
Expand Down
40 changes: 40 additions & 0 deletions src/SocketIncludes.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

#ifndef SIMPLE_SOCKET_SOCKETINCLUDES_HPP
#define SIMPLE_SOCKET_SOCKETINCLUDES_HPP


#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
using SOCKET = int;
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR (-1)
#endif

#include <system_error>


inline void throwError(const std::string& msg) {

#ifdef _WIN32
throw std::system_error(WSAGetLastError(), std::system_category(), msg);
#else
throw std::system_error(errno, std::generic_category(), msg);
#endif
}

inline void closeSocket(SOCKET socket) {

#ifdef WIN32
closesocket(socket);
#else
close(socket);
#endif
}


#endif//SIMPLE_SOCKET_SOCKETINCLUDES_HPP
65 changes: 19 additions & 46 deletions src/TCPSocket.cpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,13 @@

#include "TCPSocket.hpp"

#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
using SOCKET = int;
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR (-1)
#endif

#include <iostream>

namespace {

void throwError(const std::string& msg) {
#ifdef _WIN32
throw std::system_error(WSAGetLastError(), std::system_category(), msg);
#else
throw std::system_error(errno, std::generic_category(), msg);
#endif
}
#include "SocketIncludes.hpp"

}// namespace

struct TCPSocket::Impl {

Impl(): sockfd(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) {

if (sockfd == INVALID_SOCKET) {
throwError("Failed to create socket");
}
Expand All @@ -38,23 +16,19 @@ struct TCPSocket::Impl {
setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char*>(&optval), sizeof(optval));
}

bool connect(const std::string& ip, int port) {
bool connect(const std::string& ip, int port) const {
sockaddr_in serv_addr{};
serv_addr.sin_family = AF_INET;
serv_addr.sin_port = htons(port);
if (inet_pton(AF_INET, ip.c_str(), &serv_addr.sin_addr) <= 0) {

return false;
}
if (::connect(sockfd, reinterpret_cast<sockaddr*>(&serv_addr), sizeof(serv_addr)) < 0) {

return false;
}

return true;
return ::connect(sockfd, reinterpret_cast<sockaddr*>(&serv_addr), sizeof(serv_addr)) >= 0;
}

void bind(int port) {
void bind(int port) const {

sockaddr_in serv_addr{};
serv_addr.sin_family = AF_INET;
Expand All @@ -67,15 +41,15 @@ struct TCPSocket::Impl {
}
}

void listen(int backlog) {
void listen(int backlog) const {

if (::listen(sockfd, backlog) < 0) {

throwError("Listen failed");
}
}

std::unique_ptr<Connection> accept() {
std::unique_ptr<Connection> accept() const {

sockaddr_in client_addr{};
socklen_t addrlen = sizeof(client_addr);
Expand All @@ -92,26 +66,27 @@ struct TCPSocket::Impl {
return conn;
}

bool read(unsigned char* buffer, size_t size, size_t* bytesRead) {
bool read(unsigned char* buffer, size_t size, size_t* bytesRead) const {

#ifdef _WIN32
auto read = recv(sockfd, reinterpret_cast<char*>(buffer), size, 0);
#else
auto read = ::read(sockfd, buffer, size);
const auto read = ::read(sockfd, buffer, size);
#endif
if (bytesRead) *bytesRead = read;

return (read != SOCKET_ERROR) && (read != 0);
}

bool readExact(unsigned char* buffer, size_t size) {
bool readExact(unsigned char* buffer, size_t size) const {

int totalBytesReceived = 0;
while (totalBytesReceived < size) {
const auto remainingBytes = size - totalBytesReceived;
#ifdef _WIN32
auto read = recv(sockfd, reinterpret_cast<char*>(buffer), size, 0);
auto read = recv(sockfd, reinterpret_cast<char*>(buffer + totalBytesReceived), remainingBytes, 0);
#else
auto read = ::read(sockfd, buffer, size);
auto read = ::read(sockfd, buffer + totalBytesReceived, remainingBytes);
#endif
if (read == SOCKET_ERROR || read == 0) {

Expand All @@ -120,15 +95,15 @@ struct TCPSocket::Impl {
totalBytesReceived += read;
}

return true;
return totalBytesReceived == size;
}

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

return send(sockfd, buffer.data(), buffer.size(), 0) != SOCKET_ERROR;
}

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

#ifdef _WIN32
return send(sockfd, reinterpret_cast<const char*>(buffer.data()), buffer.size(), 0) != SOCKET_ERROR;
Expand All @@ -148,11 +123,7 @@ struct TCPSocket::Impl {

if (!closed) {
closed = true;
#ifdef _WIN32
closesocket(sockfd);
#else
::close(sockfd);
#endif
closeSocket(sockfd);
}
}

Expand All @@ -164,6 +135,7 @@ struct TCPSocket::Impl {
private:
SOCKET sockfd;
bool closed{false};

};

TCPSocket::TCPSocket(): pimpl_(std::make_unique<Impl>()) {}
Expand Down Expand Up @@ -224,6 +196,7 @@ std::unique_ptr<Connection> TCPServer::accept() {
}

TCPServer::TCPServer(int port, int backlog) {

pimpl_->bind(port);
pimpl_->listen(backlog);
}
42 changes: 11 additions & 31 deletions src/UDPSocket.cpp
Original file line number Diff line number Diff line change
@@ -1,31 +1,16 @@

#include "UDPSocket.hpp"

#ifdef _WIN32
#include <WS2tcpip.h>
#include <winsock2.h>
#else
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#define SOCKET int
#define INVALID_SOCKET (SOCKET)(~0)
#define SOCKET_ERROR (-1)
#endif

#include <stdexcept>
#include <system_error>
#include "SocketIncludes.hpp"


struct UDPSocket::Impl {

explicit Impl(int port): sockfd(socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) {

if (sockfd == INVALID_SOCKET) {
#ifdef _WIN32
throw std::system_error(WSAGetLastError(), std::system_category(), "Failed to create socket");
#else
throw std::system_error(errno, std::generic_category(), "Failed to create socket");
#endif

throwError("Failed to create socket");
}

sockaddr_in local{};
Expand All @@ -34,26 +19,24 @@ struct UDPSocket::Impl {
local.sin_port = htons(port);

if (::bind(sockfd, (sockaddr*) &local, sizeof(local)) == SOCKET_ERROR) {
#if WIN32
throw std::system_error(WSAGetLastError(), std::system_category(), "Bind failed");
#else
throw std::system_error(errno, std::generic_category(), "Bind failed");
#endif

throwError("Bind failed");
}
}

bool sendTo(const std::string& address, uint16_t port, const std::string& data) {
bool sendTo(const std::string& address, uint16_t port, const std::string& data) const {
sockaddr_in to{};
to.sin_family = AF_INET;
to.sin_port = htons(port);
if (!inet_pton(AF_INET, address.c_str(), &to.sin_addr)) {

return false;
}

return sendto(sockfd, data.c_str(), data.size(), 0, (sockaddr*) &to, sizeof(to)) != SOCKET_ERROR;
}

int recvFrom(const std::string& address, uint16_t port, std::vector<unsigned char>& buffer) {
int recvFrom(const std::string& address, uint16_t port, std::vector<unsigned char>& buffer) const {

sockaddr_in from{};
from.sin_family = AF_INET;
Expand All @@ -74,13 +57,10 @@ struct UDPSocket::Impl {
void close() {
if (!closed) {
closed = true;
#ifdef _WIN32
closesocket(sockfd);
#else
::close(sockfd);
#endif
closeSocket(sockfd);
}
}

~Impl() {
close();
}
Expand Down
12 changes: 8 additions & 4 deletions tests/test_tcp.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@

#include "TCPSocket.hpp"
#include "WSASession.hpp"
#include "AvailablePortQuery.hpp"

#include <thread>
#include <vector>
Expand Down Expand Up @@ -37,10 +38,11 @@ namespace {

TEST_CASE("TCP read/write") {

int port = 8080;

WSASession session;

int port = getAvailablePort(8000, 9000);
REQUIRE(port != -1);

TCPServer server(port);
TCPClient client;

Expand Down Expand Up @@ -79,10 +81,12 @@ TEST_CASE("TCP read/write") {

TEST_CASE("TCP readexact/write") {

int port = 8080;

WSASession session;

int port = getAvailablePort(8000, 9000);
REQUIRE(port != -1);


TCPServer server(port);
TCPClient client;

Expand Down

0 comments on commit 1ca1495

Please sign in to comment.