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
45 changes: 44 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)

project(msocket LANGUAGES C CXX VERSION 2.0.3)
project(msocket LANGUAGES C CXX VERSION 2.1.0)

set(CMAKE_DISABLE_IN_SOURCE_BUILD ON)
set(CMAKE_DISABLE_SOURCE_CHANGES ON)
Expand Down Expand Up @@ -60,6 +60,7 @@ set(MSOCKET_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/include/msocket.h
${CMAKE_CURRENT_SOURCE_DIR}/include/msocket_error.h
${CMAKE_CURRENT_SOURCE_DIR}/include/msocket_server.h
${CMAKE_CURRENT_SOURCE_DIR}/include/msocket_tls.h
${CMAKE_CURRENT_SOURCE_DIR}/include/testsocket.h
${CMAKE_CURRENT_SOURCE_DIR}/include/testsocket_spy.h
)
Expand Down Expand Up @@ -90,6 +91,48 @@ target_include_directories(msocket
${CMAKE_CURRENT_SOURCE_DIR}/source
)

### TLS Support (Mbed TLS, optional)
option(MSOCKET_ENABLE_TLS "Enable TLS support using Mbed TLS" ON)

if(MSOCKET_ENABLE_TLS)
if(NOT TARGET mbedtls)
set(MBEDTLS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../mbedtls" CACHE PATH "Path to mbedtls repository")
if(EXISTS "${MBEDTLS_DIR}/CMakeLists.txt")
set(ENABLE_TESTING OFF CACHE BOOL "" FORCE)
set(ENABLE_PROGRAMS OFF CACHE BOOL "" FORCE)
add_subdirectory("${MBEDTLS_DIR}" "${CMAKE_BINARY_DIR}/mbedtls" EXCLUDE_FROM_ALL)
else()
find_package(MbedTLS QUIET)
endif()
endif()

if(TARGET mbedtls OR MbedTLS_FOUND)
set(MSOCKET_HAVE_TLS TRUE)
endif()

if(MSOCKET_HAVE_TLS)
target_compile_definitions(msocket PUBLIC MSOCKET_ENABLE_TLS)
target_sources(msocket PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/source/msocket_tls.c
${CMAKE_CURRENT_SOURCE_DIR}/source/msocket_tls_internal.h
)
list(APPEND MSOCKET_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/source/msocket_tls.c)
list(APPEND MSOCKET_HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/source/msocket_tls_internal.h)
if(TARGET mbedtls)
target_link_libraries(msocket PUBLIC mbedtls mbedx509 mbedcrypto)
else()
target_link_libraries(msocket PUBLIC ${MBEDTLS_LIBRARIES})
target_include_directories(msocket PUBLIC ${MBEDTLS_INCLUDE_DIRS})
endif()
endif()
endif()

get_directory_property(has_parent PARENT_DIRECTORY)
if(has_parent)
set(MSOCKET_HEADERS ${MSOCKET_HEADERS} PARENT_SCOPE)
set(MSOCKET_SOURCES ${MSOCKET_SOURCES} PARENT_SCOPE)
endif()

### Library: msocket_adapter (C++)
set(MSOCKET_ADAPTER_HEADERS
include/msocket_adapter.h
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ Online documentation and API reference: **[msocket.readthedocs.io](https://msock
It allows applications to register callbacks when lifecycle events occur on a socket (such as connection established, disconnected, or new data received). The `msocket` library manages the low-level details of the OS-level socket objects and background worker threads, functioning identically across Linux and Windows:

* **TCP Client and Server**: Stream communication supporting IPv4 and IPv6.
* **TLS Transport (Mbed TLS)**: Secure stream transport supporting TLS 1.2+ server and client, certificate validation, and mutual TLS (mTLS) authentication (optional).
* **UDP Client and Server**: Datagram communication with support for unicast and multicast.
* **UNIX Domain Sockets**: High-performance local inter-process communication on Linux and POSIX platforms.
* **Event-Driven Asynchronous I/O**: Integrated worker threads monitor socket activity and dispatch connect, disconnect, and data callbacks.
Expand All @@ -26,6 +27,7 @@ It allows applications to register callbacks when lifecycle events occur on a so
|-----------|--------|----------|-------------|
| `msocket` | `msocket.h` | Core | Client/peer event-driven socket handling TCP, UDP, and UNIX domains |
| `msocket_server` | `msocket_server.h` | Core | Server connection listener and client socket lifecycle manager |
| `msocket_tls` | `msocket_tls.h` | Core | TLS transport configuration, context management, and mTLS verification (optional) |
| `msocket_adapter` | `msocket_adapter.h` | C++ | RAII C++ wrapper classes (`Socket`, `TcpSocket`, `TestSocket`, `TcpServer`) and legacy adapter |
| `testsocket` | `testsocket.h` | Testing | In-memory mock socket engine for protocol testing without network access |
| `testsocket_spy` | `testsocket_spy.h` | Testing | Mock socket spy for recording sent data and verifying interactions in unit tests |
Expand All @@ -38,13 +40,18 @@ It allows applications to register callbacks when lifecycle events occur on a so

## Dependencies

### Required
* [cogu/adt](https://github.com/cogu/adt) (v0.3.7 or later)

When building standalone unit tests, clone `adt` and `msocket` side by side:
### Optional
* [Mbed TLS](https://github.com/Mbed-TLS/mbedtls) (v3.x or v2.x): Enables TLS stream transport and mutual TLS (mTLS) verification (`MSOCKET_ENABLE_TLS=ON`). When building standalone, `msocket` will automatically detect a sibling `../mbedtls` folder or look for a system-installed Mbed TLS via `find_package(MbedTLS)`. If Mbed TLS is not found or disabled, `msocket` builds cleanly with standard plain TCP, UDP, and UNIX socket support.

When building standalone unit tests, clone dependencies side by side:

```bash
cd ~/repo
git clone https://github.com/cogu/adt.git
git clone https://github.com/Mbed-TLS/mbedtls.git # optional, for TLS support
git clone https://github.com/cogu/msocket.git
cd msocket
```
Expand Down Expand Up @@ -133,9 +140,11 @@ cmake --build build
|---|---|---|---|
| `UNIT_TEST` | `-DUNIT_TEST=ON` | `OFF` | Enables building unit test executable (`msocket_unit`) |
| `BUILD_EXAMPLES` | `-DBUILD_EXAMPLES=ON` | `OFF` | Enables building example executables (`echo_server`, `echo_client`) |
| `MSOCKET_ENABLE_TLS` | `-DMSOCKET_ENABLE_TLS=ON` | `ON` | Enables TLS support via Mbed TLS (auto-disabled if Mbed TLS is not found) |
| `MSOCKET_SANITIZERS` | `-DMSOCKET_SANITIZERS="address,undefined"` | `""` | Enables compiler sanitizers (GCC / Clang) |
| `ENABLE_MSVC_ANALYZE` | `-DENABLE_MSVC_ANALYZE=ON` | `OFF` | Enables MSVC static code analysis (`/analyze`) |
| `ADT_DIR` | `-DADT_DIR="/path/to/adt"` | `../adt` | Path to `adt` repository |
| `MBEDTLS_DIR` | `-DMBEDTLS_DIR="/path/to/mbedtls"` | `../mbedtls` | Path to `mbedtls` repository (when building standalone) |

## License

Expand Down
6 changes: 6 additions & 0 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Todo List

## Handling of negative return code

In msocket, when stream data processing returns an error, its internal io_task thread breaks out of the loop and terminates immediately without calling msocket_common_on_disconnected().
Can we improve this design?
2 changes: 1 addition & 1 deletion docs/Doxyfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Doxyfile for Sphinx + Breathe integration
PROJECT_NAME = "msocket"
PROJECT_NUMBER = "2.0.3"
PROJECT_NUMBER = "2.1.0"
PROJECT_BRIEF = "Event-driven socket library for Linux and Windows"

# Input configuration
Expand Down
2 changes: 1 addition & 1 deletion docs/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
project = 'msocket'
copyright = '2026, Conny Gustafsson'
author = 'Conny Gustafsson'
release = '2.0.3'
release = '2.1.0'

# -- General configuration ---------------------------------------------------

Expand Down
18 changes: 18 additions & 0 deletions include/msocket.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ typedef uint8_t msocket_state_t;
struct msocket_tag;
struct msocket_server_tag;
struct msocket_os_tag;
struct msocket_tls_tag;
struct msocket_tls_config_tag;

/**
* Event handler callback table for stream and datagram socket events.
Expand Down Expand Up @@ -149,6 +151,7 @@ typedef struct msocket_tag {
uint32_t inactivity_call_ms;
struct msocket_server_tag *server;
struct msocket_os_tag *os;
struct msocket_tls_tag *tls;
} msocket_t;

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -356,6 +359,21 @@ msocket_endpoint_type_t msocket_parse_endpoint(const char *text, adt_str_t **add
#define tcp_rx_buf stream_rx_buf
#define tcp_info stream_info

/**
* Attaches a TLS context to an msocket.
*/
void msocket_set_tls(msocket_t *self, struct msocket_tls_tag *tls);

/**
* Retrieves the TLS context attached to an msocket.
*/
struct msocket_tls_tag *msocket_get_tls(const msocket_t *self);

/**
* Connects to a remote server using TLS over TCP.
*/
msocket_error_t msocket_connect_tls(msocket_t *self, const char *addr, uint16_t port, const struct msocket_tls_config_tag *tls_config);

#ifdef __cplusplus
}
#endif
Expand Down
3 changes: 3 additions & 0 deletions include/msocket_error.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ extern "C" {
#define MSOCKET_NOT_IMPLEMENTED_ERROR 4
#define MSOCKET_TIMEOUT_ERROR 5
#define MSOCKET_NOT_CONNECTED_ERROR 6
#define MSOCKET_TLS_ERROR 7
#define MSOCKET_TLS_HANDSHAKE_ERROR 8
#define MSOCKET_TLS_CERT_ERROR 9

typedef int8_t msocket_error_t;

Expand Down
13 changes: 13 additions & 0 deletions include/msocket_server.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ extern "C" {
// PUBLIC CONSTANTS AND DATA TYPES
//////////////////////////////////////////////////////////////////////////////
struct msocket_server_os_tag;
struct msocket_tls_server_tag;
struct msocket_tls_config_tag;

typedef struct msocket_server_tag {
msocket_t *accept_socket;
Expand All @@ -40,6 +42,7 @@ typedef struct msocket_server_tag {
msocket_handler_t handler_table;
void (*destructor)(void *arg);
struct msocket_server_os_tag *os;
struct msocket_tls_server_tag *tls_server;
} msocket_server_t;

//////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -121,6 +124,16 @@ void msocket_server_start(msocket_server_t *self, const char *udp_addr, uint16_t
*/
void msocket_server_unix_start(msocket_server_t *self, const char *socket_path);

/**
* Binds and starts a listening TCP server with TLS enabled.
*
* @param self Pointer to msocket_server_t instance.
* @param tcp_port TCP port to listen on.
* @param tls_config Pointer to TLS configuration.
* @return MSOCKET_NO_ERROR on success, or error code on failure.
*/
msocket_error_t msocket_server_start_tls(msocket_server_t *self, uint16_t tcp_port, const struct msocket_tls_config_tag *tls_config);

/**
* Disables the automatic background connection cleanup thread.
*
Expand Down
98 changes: 98 additions & 0 deletions include/msocket_tls.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
/*****************************************************************************
* \file msocket_tls.h
* \author Conny Gustafsson
* \date 2026-09-27
* \brief msocket TLS configuration and transport interface
*
* Copyright (c) 2026 Conny Gustafsson
* SPDX-License-Identifier: MIT
* See LICENSE in project root for full license terms.
******************************************************************************/

#ifndef MSOCKET_TLS_H
#define MSOCKET_TLS_H

#ifdef __cplusplus
extern "C" {
#endif

//////////////////////////////////////////////////////////////////////////////
// INCLUDES
//////////////////////////////////////////////////////////////////////////////
#include <stdint.h>
#include <stdbool.h>
#include "msocket_error.h"

//////////////////////////////////////////////////////////////////////////////
// PUBLIC CONSTANTS AND DATA TYPES
//////////////////////////////////////////////////////////////////////////////
struct msocket_tls_config_tag;
typedef struct msocket_tls_config_tag msocket_tls_config_t;

struct msocket_tls_tag;
typedef struct msocket_tls_tag msocket_tls_t;

struct msocket_tls_server_tag;
typedef struct msocket_tls_server_tag msocket_tls_server_t;

struct msocket_tls_client_tag;
typedef struct msocket_tls_client_tag msocket_tls_client_t;

struct msocket_tls_config_tag {
char *ca_cert_path;
char *server_cert_path;
char *server_key_path;
char *client_cert_path;
char *client_key_path;
bool require_client_cert;
};

//////////////////////////////////////////////////////////////////////////////
// PUBLIC FUNCTION PROTOTYPES
//////////////////////////////////////////////////////////////////////////////

/**
* Initializes a TLS configuration structure.
*/
void msocket_tls_config_create(msocket_tls_config_t *self);

/**
* Frees internal resources of a TLS configuration structure.
*/
void msocket_tls_config_destroy(msocket_tls_config_t *self);

/**
* Dynamically allocates and initializes a new TLS configuration structure.
*/
msocket_tls_config_t *msocket_tls_config_new(void);

/**
* Destroys and frees a TLS configuration structure.
*/
void msocket_tls_config_delete(msocket_tls_config_t *self);

/**
* Sets path to trusted CA certificate file (PEM format).
*/
msocket_error_t msocket_tls_config_set_ca_cert(msocket_tls_config_t *self, const char *ca_cert_path);

/**
* Sets server certificate and private key paths (PEM format).
*/
msocket_error_t msocket_tls_config_set_server_cert(msocket_tls_config_t *self, const char *cert_path, const char *key_path);

/**
* Sets client certificate and private key paths (PEM format, for mTLS).
*/
msocket_error_t msocket_tls_config_set_client_cert(msocket_tls_config_t *self, const char *cert_path, const char *key_path);

/**
* Enables or disables required client certificate verification (mTLS).
*/
void msocket_tls_config_set_require_client_cert(msocket_tls_config_t *self, bool require);

#ifdef __cplusplus
}
#endif

#endif /* MSOCKET_TLS_H */
Loading
Loading