Skip to content

Commit ceec18b

Browse files
committed
Adding TLS sockets for Linux
1 parent a72f287 commit ceec18b

File tree

9 files changed

+394
-46
lines changed

9 files changed

+394
-46
lines changed

CMakeLists.txt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
## Author Francois Michaut
55
##
66
## Started on Sun Aug 28 19:26:51 2022 Francois Michaut
7-
## Last update Thu Sep 15 14:08:03 2022 Francois Michaut
7+
## Last update Tue May 9 11:51:16 2023 Francois Michaut
88
##
99
## CMakeLists.txt : CMake to build the CppSockets library
1010
##
@@ -26,17 +26,19 @@ add_library(cppsockets
2626
source/IPv4.cpp
2727
source/Socket.cpp
2828
source/TlsSocket.cpp
29-
)
29+
)
30+
31+
target_link_libraries(cppsockets ssl)
3032

3133
add_custom_target(test
32-
COMMAND ${CMAKE_COMMAND}
34+
COMMAND ${CMAKE_COMMAND} --log-level=WARNING
3335
-B "${CMAKE_CURRENT_BINARY_DIR}/tests"
3436
-S "${CMAKE_CURRENT_SOURCE_DIR}/tests"
3537
-G ${CMAKE_GENERATOR}
3638
COMMAND ${CMAKE_COMMAND} -E cmake_echo_color
3739
--switch=$(COLOR) --cyan "Building tests..."
3840
COMMAND ${CMAKE_COMMAND}
39-
--build "${CMAKE_CURRENT_BINARY_DIR}/tests"
41+
--build "${CMAKE_CURRENT_BINARY_DIR}/tests" -- --quiet
4042
COMMAND ${CMAKE_MAKE_PROGRAM}
4143
-C "${CMAKE_CURRENT_BINARY_DIR}/tests" test
4244
)

include/CppSockets/Address.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
** Author Francois Michaut
55
**
66
** Started on Sun Feb 13 17:09:05 2022 Francois Michaut
7-
** Last update Mon Aug 29 20:46:03 2022 Francois Michaut
7+
** Last update Thu Feb 9 08:55:11 2023 Francois Michaut
88
**
99
** Address.hpp : Interface to represent network addresses
1010
*/
@@ -14,6 +14,7 @@
1414
#include <string>
1515
#include <type_traits>
1616

17+
// TODO: support IPv6 (uint32 for address will not support IPv6)
1718
namespace CppSockets {
1819
class IAddress {
1920
public:

include/CppSockets/IPv4.hpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
** Author Francois Michaut
55
**
66
** Started on Sun Feb 13 17:05:02 2022 Francois Michaut
7-
** Last update Wed Sep 14 22:28:32 2022 Francois Michaut
7+
** Last update Thu Feb 9 08:55:24 2023 Francois Michaut
88
**
99
** IPv4.hpp : Class used to represent and manipulate IPv4 addresses
1010
*/
@@ -32,4 +32,5 @@ namespace CppSockets {
3232
std::uint32_t addr;
3333
std::string str;
3434
};
35+
using EndpointV4 = Endpoint<IPv4>;
3536
}

include/CppSockets/Socket.hpp

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
** Author Francois Michaut
55
**
66
** Started on Sat Jan 15 01:17:42 2022 Francois Michaut
7-
** Last update Wed Sep 14 22:18:29 2022 Francois Michaut
7+
** Last update Tue Feb 7 22:31:12 2023 Francois Michaut
88
**
99
** Socket.hpp : Portable C++ socket class
1010
*/
@@ -26,11 +26,15 @@ using RawSocketType=int;
2626
#include "CppSockets/Address.hpp"
2727

2828
namespace CppSockets {
29+
static void init(bool init_ssl = true, bool init_wsa = true);
30+
static void deinit(bool deinit_ssl = true, bool deinit_wsa = true);
31+
2932
class Socket {
3033
public:
3134
Socket(int domain, int type, int protocol);
3235
~Socket();
3336

37+
// TODO Maybe enable copy with dup(2) ?
3438
Socket(const Socket &other) = delete;
3539
Socket(Socket &&other) noexcept;
3640
Socket &operator=(const Socket &other) = delete;
@@ -57,7 +61,7 @@ namespace CppSockets {
5761

5862
[[nodiscard]]
5963
RawSocketType get_fd() const; // TODO check if windows SOCKET can be
60-
// converted to int
64+
// converted to int
6165
[[nodiscard]]
6266
int get_type() const;
6367
[[nodiscard]]
@@ -67,16 +71,17 @@ namespace CppSockets {
6771

6872
[[nodiscard]]
6973
bool connected() const;
70-
private:
71-
Socket(int domain, int type, int protocol, int sockfd);
7274

73-
static void init();
74-
75-
static int getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen);
75+
public:
7676
static int get_errno();
7777
static char *strerror(int err);
7878
static char *strerror();
7979

80+
private:
81+
Socket(int domain, int type, int protocol, int sockfd);
82+
83+
static int getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen);
84+
8085
int domain;
8186
int type;
8287
int protocol;

include/CppSockets/TlsSocket.hpp

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
** Project LibCppSockets, 2022
3+
**
4+
** Author Francois Michaut
5+
**
6+
** Started on Wed Sep 14 20:51:23 2022 Francois Michaut
7+
** Last update Mon May 8 19:57:05 2023 Francois Michaut
8+
**
9+
** SecureSocket.hpp : TLS socket wrapper using openssl
10+
*/
11+
12+
#pragma once
13+
14+
#ifdef _WIN32
15+
// TODO Currently disabling TlsSocket for windows
16+
#else
17+
18+
#include "CppSockets/IPv4.hpp"
19+
#include <CppSockets/Socket.hpp>
20+
21+
#include <functional>
22+
23+
// TODO: find a better way do to this
24+
using SSL = struct ssl_st;
25+
using SSL_METHOD = struct ssl_method_st;
26+
using SSL_CTX = struct ssl_ctx_st;
27+
using X509 = struct x509_st;
28+
using RSA = struct rsa_st;
29+
using EVP_PKEY = struct evp_pkey_st;
30+
using EVP_MD = struct evp_md_st;
31+
using EVP_MD_CTX = struct evp_md_ctx_st;
32+
33+
namespace CppSockets {
34+
using SSL_CTX_ptr=std::unique_ptr<SSL_CTX, std::function<void(SSL_CTX *)>>;
35+
using SSL_ptr=std::unique_ptr<SSL, std::function<void(SSL *)>>;
36+
using X509_ptr=std::unique_ptr<X509, std::function<void(X509 *)>>;
37+
using RSA_ptr=std::unique_ptr<RSA, std::function<void(RSA *)>>;
38+
using EVP_PKEY_ptr=std::unique_ptr<EVP_PKEY, std::function<void(EVP_PKEY *)>>;
39+
using EVP_MD_ptr=std::unique_ptr<EVP_MD, std::function<void(EVP_MD *)>>;
40+
using EVP_MD_CTX_ptr=std::unique_ptr<EVP_MD_CTX, std::function<void(EVP_MD_CTX *)>>;
41+
42+
// TODO add more TLS-related functions
43+
class TlsSocket : public Socket {
44+
public:
45+
explicit TlsSocket(Socket &&other);
46+
TlsSocket(int domain, int type, int protocol);
47+
~TlsSocket();
48+
49+
TlsSocket(const TlsSocket &other) = delete;
50+
TlsSocket(TlsSocket &&other) noexcept;
51+
TlsSocket &operator=(const TlsSocket &other) = delete;
52+
TlsSocket &operator=(TlsSocket &&other) noexcept;
53+
54+
std::string read(std::size_t len = -1);
55+
std::size_t read(char *buff, std::size_t size);
56+
std::size_t write(const std::string &buff);
57+
std::size_t write(const char *buff, std::size_t len);
58+
59+
int connect(const IEndpoint &endpoint);
60+
61+
std::shared_ptr<TlsSocket> accept(void *addr_out);
62+
63+
[[nodiscard]]
64+
const SSL_CTX_ptr &get_ssl_ctx() const;
65+
[[nodiscard]]
66+
const SSL_ptr &get_ssl() const;
67+
[[nodiscard]]
68+
const X509_ptr &get_client_cert() const;
69+
70+
[[nodiscard]]
71+
const std::string tls_strerror(int ret);
72+
private:
73+
SSL_CTX_ptr ctx;
74+
SSL_ptr ssl;
75+
X509_ptr peer_cert;
76+
bool do_shutdown = true;
77+
};
78+
79+
inline std::size_t TlsSocket::write(const std::string &buff) {
80+
return write(buff.data(), buff.size());
81+
}
82+
83+
inline const SSL_CTX_ptr &TlsSocket::get_ssl_ctx() const {
84+
return ctx;
85+
}
86+
87+
inline const SSL_ptr &TlsSocket::get_ssl() const {
88+
return ssl;
89+
}
90+
91+
inline const X509_ptr &TlsSocket::get_client_cert() const {
92+
return peer_cert;
93+
}
94+
}
95+
#endif

source/Socket.cpp

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
** Author Francois Michaut
55
**
66
** Started on Sat Jan 15 01:27:40 2022 Francois Michaut
7-
** Last update Wed Sep 14 22:19:18 2022 Francois Michaut
7+
** Last update Sun Feb 19 11:01:09 2023 Francois Michaut
88
**
99
** Socket.cpp : Protable C++ socket class implementation
1010
*/
@@ -27,43 +27,26 @@ static constexpr int SOCKET_ERROR = -1;
2727

2828
static constexpr int BUFF_SIZE = 4096;
2929

30-
// TODO add exceptions on error retunrs
31-
// TODO throw custom exceptions on invalid status (eg: socket already connected)
30+
#include <array>
31+
3232
#include "CppSockets/IPv4.hpp"
3333
#include "CppSockets/Socket.hpp"
3434

35+
// TODO add exceptions on error retunrs
36+
// TODO throw custom exceptions on invalid status (eg: socket already connected)
3537
namespace CppSockets {
36-
void Socket::init() {
37-
#ifdef _WIN32
38-
static bool init_done = false;
39-
WSADATA wsa_data;
40-
41-
if (!init_done) {
42-
// TODO need to call WSACleanup too
43-
if (WSAStartup(MAKEWORD(2, 2), &wsa_data) != 0) {
44-
throw std::runtime_error(std::string("WASStartup Failed : ") + std::strerror(errno));
45-
}
46-
init_done = true;
47-
}
48-
#endif
49-
}
50-
5138
Socket::Socket(int domain, int type, int protocol, int sockfd) :
5239
domain(domain), type(type), protocol(protocol), sockfd(sockfd)
53-
{
54-
init();
55-
}
40+
{}
5641

5742
Socket::Socket(int domain, int type, int protocol) :
58-
domain(domain), type(type), protocol(protocol)
43+
domain(domain), type(type), protocol(protocol), sockfd(::socket(domain, type, protocol))
5944
{
60-
init();
61-
sockfd = ::socket(domain, type, protocol);
6245
if (sockfd == INVALID_SOCKET)
6346
throw std::runtime_error(std::string("Failed to create socket : ") + std::strerror(errno));
6447
}
6548

66-
Socket::Socket(Socket &&other) noexcept { // NOLINT
49+
Socket::Socket(Socket &&other) noexcept { // NOLINT(cppcoreguidelines-pro-type-member-init, hicpp-member-init)
6750
*this = std::move(other);
6851
}
6952

@@ -111,7 +94,7 @@ namespace CppSockets {
11194

11295
std::string Socket::read(std::size_t len) {
11396
std::array<char, BUFF_SIZE> buff = {0};
114-
std::string res;
97+
std::string res; // TODO use a stringstream
11598
std::size_t total = 0;
11699
std::size_t nb = 1;
117100

@@ -165,6 +148,11 @@ namespace CppSockets {
165148
return this->bind(inet_addr(addr.c_str()), port);
166149
}
167150

151+
int Socket::bind(const IEndpoint &endpoint) {
152+
// TODO: this only works for IPv4. Need to switch getFamily() to handle IPv6 / AF_UNIX ...
153+
return this->bind(endpoint.getAddr().getAddress(), endpoint.getPort());
154+
}
155+
168156
int Socket::bind(std::uint32_t s_addr, int port) {
169157
struct sockaddr_in addr = {};
170158
int ret = 0;
@@ -219,7 +207,7 @@ namespace CppSockets {
219207
socklen_t len = sizeof(int);
220208

221209
if (addr_out != nullptr) {
222-
// TODO
210+
// TODO figure it out
223211
}
224212
if (fd == INVALID_SOCKET) {
225213
return nullptr;
@@ -236,9 +224,9 @@ namespace CppSockets {
236224

237225
if (ret >= 0) {
238226
if (val) {
239-
ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); //NOLINT
227+
ret = fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); // NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg, hicpp-signed-bitwise)
240228
} else {
241-
ret = fcntl(sockfd, F_SETFL, (flags | O_NONBLOCK) ^ O_NONBLOCK); //NOLINT
229+
ret = fcntl(sockfd, F_SETFL, (flags | O_NONBLOCK) ^ O_NONBLOCK); // NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg, hicpp-signed-bitwise)
242230
}
243231
}
244232
if (ret < 0) {

0 commit comments

Comments
 (0)