Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .clang-tidy
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Checks: '
-fuchsia*,
-google-readability-todo,
-cppcoreguidelines-init-variables,
-cppcoreguidelines-avoid-do-while,
-cppcoreguidelines-owning-memory,
-cppcoreguidelines-pro-type-reinterpret-cast,
-llvm-namespace-comment,
Expand All @@ -15,6 +16,7 @@ Checks: '
-readability-avoid-return-with-void-value,
-readability-convert-member-functions-to-static,

-misc-use-anonymous-namespace,
-google-readability-braces-around-statements,
-google-readability-namespace-comments,
-hicpp-special-member-functions,
Expand All @@ -27,7 +29,7 @@ FormatStyle: 'none' # TODO: Replace with 'file' once we have a proper .clang-for
InheritParentConfig: true
CheckOptions:
misc-include-cleaner.MissingIncludes: 'false'
misc-include-cleaner.IgnoreHeaders: 'CppSockets/OSDetection.*'
misc-include-cleaner.IgnoreHeaders: 'CppSockets/OSDetection\.hpp;CppSockets/SocketInternals\.hpp'

bugprone-argument-comment.StrictMode: 1

Expand Down
5 changes: 5 additions & 0 deletions .clangd
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Diagnostics:
Includes:
IgnoreHeader:
- "CppSockets/OSDetection\\.hpp"
- "CppSockets/SocketInternals\\.hpp"
8 changes: 5 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
## Author Francois Michaut
##
## Started on Sun Aug 28 19:26:51 2022 Francois Michaut
## Last update Sat Oct 24 23:32:08 2026 Francois Michaut
## Last update Mon Oct 26 22:43:14 2026 Francois Michaut
##
## CMakeLists.txt : CMake to build the CppSockets library
##

cmake_minimum_required (VERSION 3.15)
cmake_minimum_required (VERSION 3.19)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED True)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
Expand All @@ -28,6 +28,7 @@ add_library(cppsockets
source/Tls/Socket.cpp

source/Address.cpp
source/ErrorUtils.cpp
source/IPv4.cpp
source/Socket.cpp
source/SocketInit.cpp
Expand All @@ -42,7 +43,7 @@ target_include_directories(cppsockets
)

if(WIN32)
target_compile_definitions(cppsockets PRIVATE CPPSOCKETS_DLL_EXPORTS=1)
target_compile_definitions(cppsockets PRIVATE CPPSOCKETS_DLL_EXPORTS=1 NOMINMAX)
endif()

target_compile_options(cppsockets PRIVATE
Expand All @@ -58,5 +59,6 @@ endif()

option(CPPSOCKETS_TESTS "TRUE to build the libcppsockets tests" FALSE)
if(CPPSOCKETS_TESTS)
include(CTest)
add_subdirectory(tests)
endif()
4 changes: 1 addition & 3 deletions include/CppSockets/Address.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
** Author Francois Michaut
**
** Started on Sun Feb 13 17:09:05 2022 Francois Michaut
** Last update Wed Jul 1 14:19:51 2026 Francois Michaut
** Last update Mon Oct 26 12:13:43 2026 Francois Michaut
**
** Address.hpp : Interface to represent network addresses
*/
Expand Down Expand Up @@ -36,9 +36,7 @@ namespace CppSockets {
[[nodiscard]] virtual auto get_addr() const -> const IAddress & = 0;
[[nodiscard]] virtual auto to_string() const -> const std::string & = 0;

static auto from_string(std::string endpoint) -> std::shared_ptr<CppSockets::IEndpoint>;
static auto from_string(std::string_view endpoint) -> std::shared_ptr<CppSockets::IEndpoint>;

protected:
[[nodiscard]] auto make_string() const -> std::string;
};
Expand Down
20 changes: 20 additions & 0 deletions include/CppSockets/ErrorUtils.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
** Project LibCppSockets, 2026
**
** Author Francois Michaut
**
** Started on Mon Oct 26 22:24:25 2026 Francois Michaut
** Last update Mon Oct 26 22:44:34 2026 Francois Michaut
**
** ErrorUtils.hpp : Portable system error utilities
*/

#pragma once

#include <string>

namespace CppSockets {
auto get_errno() -> int;
auto strerror(int err) -> std::string;
auto strerror() -> std::string;
}
15 changes: 11 additions & 4 deletions include/CppSockets/IPv4.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
** Author Francois Michaut
**
** Started on Sun Feb 13 17:05:02 2022 Francois Michaut
** Last update Wed Jul 1 14:19:39 2026 Francois Michaut
** Last update Mon Oct 26 14:26:38 2026 Francois Michaut
**
** IPv4.hpp : Class used to represent and manipulate IPv4 addresses
*/
Expand All @@ -13,18 +13,25 @@

#include "CppSockets/Address.hpp"

#include <string_view>

namespace CppSockets {
class IPv4 : public IAddress {
public:
explicit IPv4(std::uint32_t addr);
IPv4(const char *addr); // TODO add support for string. Maybe string_view ?
IPv4(std::string_view addr);

static auto from_host_order(std::uint32_t addr) -> IPv4;
static auto from_network_order(std::uint32_t addr) -> IPv4;

// returns address in network byte order
[[nodiscard]] auto get_address() const -> std::uint32_t override;
[[nodiscard]] auto get_family() const -> int override;
[[nodiscard]] auto to_string() const -> const std::string & override;

private:
std::uint32_t addr;
IPv4(std::uint32_t addr);

std::uint32_t addr; // always network byte order
std::string str;
};
using EndpointV4 = Endpoint<IPv4>;
Expand Down
2 changes: 1 addition & 1 deletion include/CppSockets/OSDetection.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
** Author Francois Michaut
**
** Started on Tue May 9 23:20:20 2023 Francois Michaut
** Last update Wed Jul 1 14:20:01 2026 Francois Michaut
** Last update Sun Oct 25 23:15:10 2026 Francois Michaut
**
** OSDetection.hpp : OS Detection macros
*/
Expand Down
61 changes: 61 additions & 0 deletions include/CppSockets/PollEvent.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
** Project LibCppSockets, 2022
**
** Author Francois Michaut
**
** Started on Mon Oct 26 09:37:12 2026 Francois Michaut
** Last update Mon Oct 26 09:48:55 2026 Francois Michaut
**
** PollEvent.hpp : Helper enum for Socket::poll()
*/

#pragma once

#include <cstdint>

namespace CppSockets {
class PollEvent {
public:
enum Value : std::uint8_t {
NONE = 0,
READ = 1,
WRITE = 2,
};

constexpr PollEvent() : m_value(Value::NONE) {}
constexpr PollEvent(Value value) : m_value(value) {}

constexpr auto operator|=(PollEvent other) -> PollEvent & {
m_value = static_cast<Value>(to_uint(m_value) | to_uint(other.m_value));
return *this;
}
constexpr auto operator&=(PollEvent other) -> PollEvent & {
m_value = static_cast<Value>(to_uint(m_value) & to_uint(other.m_value));
return *this;
}
[[nodiscard]] constexpr auto operator|(PollEvent other) const -> PollEvent {
other |= *this;
return other;
}
[[nodiscard]] constexpr auto operator&(PollEvent other) const -> PollEvent {
other &= *this;
return other;
}
[[nodiscard]] constexpr auto operator==(PollEvent other) const -> bool { return m_value == other.m_value; }
[[nodiscard]] constexpr auto operator!=(PollEvent other) const -> bool { return m_value != other.m_value; }

explicit constexpr operator bool() const { return m_value != Value::NONE; }

[[nodiscard]] constexpr auto has(PollEvent event) const -> bool {
return (to_uint(m_value) & to_uint(event.m_value)) != 0;
}
[[nodiscard]] constexpr auto value() const -> Value { return m_value; }

private:
static constexpr auto to_uint(Value value) -> std::uint8_t {
return static_cast<std::uint8_t>(value);
}

Value m_value;
};
}
31 changes: 19 additions & 12 deletions include/CppSockets/Socket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,32 +4,35 @@
** Author Francois Michaut
**
** Started on Sat Jan 15 01:17:42 2022 Francois Michaut
** Last update Sun Oct 25 11:38:13 2026 Francois Michaut
** Last update Mon Oct 26 20:22:18 2026 Francois Michaut
**
** Socket.hpp : Portable C++ socket class
*/

#pragma once

#include "CppSockets/Address.hpp"
#include "CppSockets/OSDetection.hpp"
#include "CppSockets/internal/SocketInit.hpp"
#include "CppSockets/PollEvent.hpp"

// TODO: move the RawSocketType in CppSockets namespace
#ifdef OS_WINDOWS
#define NOMINMAX
#include <winsock2.h>
using RawSocketType=SOCKET;
using socklen_t=int;
using SockOptType=char;
using PollfdType=WSAPOLLFD;
#else
#include <sys/socket.h>
using RawSocketType=int;
using SockOptType=void;
using PollfdType=struct pollfd;
#endif

#include <cstdint>
#include <memory>

#include "CppSockets/Address.hpp"
#include "CppSockets/internal/SocketInit.hpp"

namespace CppSockets {
class Socket : SocketInit {
Expand All @@ -47,9 +50,12 @@ namespace CppSockets {

virtual void close();

virtual auto read(std::size_t len = -1) -> std::string;
// TODO: Add support for writev/WSASend and sendfile/WSATransmitPackets

// read() with no lenght blocks once then returns all currently available data
auto read(std::size_t len = -1) -> std::string;
Comment thread
f-michaut marked this conversation as resolved.
Dismissed
virtual auto read(char *buff, std::size_t size) -> std::size_t;
virtual auto write(std::string_view buff) -> std::size_t;
auto write(std::string_view buff) -> std::size_t { return this->write(buff.data(), buff.size()); };
virtual auto write(const char *buff, std::size_t len) -> std::size_t;

auto set_reuseaddr(bool value) -> int;
Expand All @@ -62,7 +68,11 @@ namespace CppSockets {
auto bind(const IEndpoint &endpoint) -> int;
auto bind(const std::string &addr, uint16_t port) -> int;
auto listen(int backlog) -> int;
auto accept(void *addr_out = nullptr) -> std::unique_ptr<Socket>;

auto accept() -> std::unique_ptr<Socket>;
auto accept(sockaddr_storage &addr) -> std::unique_ptr<Socket>;

[[nodiscard]] auto poll(PollEvent events, int timeout_ms = 0) const -> PollEvent;

void set_blocking(bool val);

Expand All @@ -74,10 +84,6 @@ namespace CppSockets {

[[nodiscard]] auto connected() const -> bool { return m_is_connected; }

static auto get_errno() -> int;
static auto strerror(int err) -> std::string;
static auto strerror() -> std::string;

protected:
static void throw_errno_error(std::string message);
static void throw_errno_error(std::string message, int err);
Expand All @@ -91,7 +97,8 @@ namespace CppSockets {

void create_socket();

virtual auto acceptImpl(void *addr_out) -> Socket *;
[[nodiscard]] virtual auto has_more_data() const -> bool;
virtual auto acceptImpl(sockaddr_storage *addr_out) -> Socket *;
private:
int m_domain = 0;
int m_type = 0;
Expand Down
2 changes: 1 addition & 1 deletion include/CppSockets/Tls/Certificate.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
** Author Francois Michaut
**
** Started on Fri Aug 1 09:50:33 2025 Francois Michaut
** Last update Thu Jul 2 01:03:49 2026 Francois Michaut
** Last update Sun Oct 25 23:16:01 2026 Francois Michaut
**
** Certificate.hpp : Classes to create and manage Certificates
*/
Expand Down
2 changes: 2 additions & 0 deletions include/CppSockets/Tls/Context.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ namespace CppSockets {
~TlsContext();

void set_min_proto_version(int version);
void set_cipher_list(const char *cipher_list);
void set_ciphersuites(const char *ciphersuites);

void set_verify(int mode, TlsVerifyCallback callback = {});
void set_verify_depth(int depth);
Expand Down
30 changes: 19 additions & 11 deletions include/CppSockets/Tls/Socket.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
** Author Francois Michaut
**
** Started on Wed Sep 14 20:51:23 2022 Francois Michaut
** Last update Sun Oct 25 12:00:59 2026 Francois Michaut
** Last update Mon Oct 26 21:37:23 2026 Francois Michaut
**
** SecureSocket.hpp : TLS socket wrapper using openssl
*/
Expand Down Expand Up @@ -35,29 +35,36 @@ namespace CppSockets {
void close() override { this->close(false); };
bool close(bool force);

// read() with no length reads until the peer closes; use read(N) when reading from untrusted peers
auto read(std::size_t len = -1) -> std::string override;
// TODO: Add support for SSL_sendfile + SNI / ALPN
auto read(char *buff, std::size_t size) -> std::size_t override;
auto write(std::string_view buff) -> std::size_t override { return this->write(buff.data(), buff.size()); };
auto write(const char *buff, std::size_t len) -> std::size_t override;

void set_verify(int mode, TlsVerifyCallback verify_callback = nullptr);
void set_verify_depth(int depth);
void set_certificate(const std::string &cert_path, const std::string &pkey_path);
// Must be called before connect() for hostname verification to take
// effect (requires peer verification to be enabled).
void set_hostname(const std::string &hostname) { set_hostname(hostname.c_str()); }
void set_hostname(const char *hostname);

// TODO: Add connect overload that take a string hostname and port and call set_hostname automatically
auto connect(const IEndpoint &endpoint) -> int override;

auto accept(void *addr_out, TlsContext ctx) -> std::unique_ptr<TlsSocket>;
auto accept(void *addr_out = nullptr) -> std::unique_ptr<TlsSocket> { return accept(addr_out, m_ctx); }
auto accept(TlsContext ctx) -> std::unique_ptr<TlsSocket> { return accept(nullptr, std::move(ctx)); }
auto accept() -> std::unique_ptr<TlsSocket> { return accept(m_ctx); }
auto accept(TlsContext ctx) -> std::unique_ptr<TlsSocket>;
auto accept(sockaddr_storage &addr) -> std::unique_ptr<TlsSocket> { return accept(addr, m_ctx); }
auto accept(sockaddr_storage &addr, TlsContext ctx) -> std::unique_ptr<TlsSocket>;

[[nodiscard]] auto get_ssl_ctx() const -> TlsContext;
[[nodiscard]] auto get_ssl() const -> const SSL_ptr & { return m_ssl; }
[[nodiscard]] auto get_peer_cert() const -> const X509_ptr & { return m_peer_cert; }

[[nodiscard]] auto tls_strerror(int ret) -> std::string;
[[nodiscard]] auto tls_errno(int ret) -> int;
protected:
auto acceptImpl(void *addr_out) -> TlsSocket * override { return acceptImpl(addr_out, m_ctx); };
auto acceptImpl(void *addr_out, TlsContext ctx) -> TlsSocket *;
auto acceptImpl(sockaddr_storage *addr_out) -> TlsSocket * override { return acceptImpl(addr_out, m_ctx); };
auto acceptImpl(sockaddr_storage *addr_out, TlsContext ctx) -> TlsSocket *;

[[nodiscard]] auto has_more_data() const -> bool override;

void throw_tls_error(std::string message);
void throw_tls_error(std::string message, int ret);
Expand All @@ -67,6 +74,7 @@ namespace CppSockets {
X509_ptr m_peer_cert;

bool m_should_shutdown = false;
void check_for_error(std::string error_msg, int ret);
std::unique_ptr<TlsSocket> m_pending_accept; // partially handshaken accepted socket, for non-blocking sockets
auto handle_ssl_io_result(std::string error_msg, int ssl_ret, std::size_t nb) -> std::size_t;
};
}
Loading
Loading