Skip to content

Commit 2206f0b

Browse files
committed
Major refactor and cleanup of the codebase
1 parent eba71dd commit 2206f0b

File tree

9 files changed

+527
-593
lines changed

9 files changed

+527
-593
lines changed

Test/main.cpp

Lines changed: 78 additions & 147 deletions
Large diffs are not rendered by default.

include/WS_Lite.h

Lines changed: 75 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
#include <unordered_map>
66
#include <chrono>
77

8+
typedef struct x509_store_ctx_st X509_STORE_CTX;
9+
810
namespace SL {
911
namespace WS_LITE {
1012
template <typename T, typename Meaning>
@@ -49,6 +51,12 @@ namespace SL {
4951
PONG = 10,
5052
INVALID = 255
5153
};
54+
enum ExtentionOptions : unsigned char {
55+
NO_OPTIONS,
56+
DEFLATE,
57+
SERVER_NO_CONTEXT_TAKEOVER,
58+
CLIENT_NO_CONTEXT_TAKEOVER,
59+
};
5260
struct WSMessage {
5361
unsigned char *data;
5462
size_t len;
@@ -58,43 +66,25 @@ namespace SL {
5866
std::shared_ptr<unsigned char> Buffer;
5967
};
6068

61-
class WSListener;
62-
class WSClient;
63-
struct WSocketImpl;
64-
class WSocket {
65-
std::shared_ptr<WSocketImpl> WSocketImpl_;
69+
70+
class IWSocket: public std::enable_shared_from_this<IWSocket> {
6671
public:
67-
WSocket(const std::shared_ptr<WSocketImpl>& s) :WSocketImpl_(s) {}
68-
//WSocket() {}
69-
//can be used to compare two WSocket objects
70-
bool operator=(const WSocket& s) { return s.WSocketImpl_ == WSocketImpl_; }
71-
bool is_open();
72-
std::string get_address();
73-
unsigned short get_port();
74-
bool is_v4();
75-
bool is_v6();
76-
bool is_loopback();
77-
operator bool() const { return WSocketImpl_.operator bool(); }
78-
friend WSListener;
79-
friend WSClient;
72+
virtual ~IWSocket() {}
73+
virtual bool is_open() const = 0;
74+
virtual std::string get_address() const = 0;
75+
virtual unsigned short get_port() const = 0;
76+
virtual bool is_v4() const = 0;
77+
virtual bool is_v6() const = 0;
78+
virtual bool is_loopback() const = 0;
79+
virtual void send(WSMessage& msg, bool compressmessage) = 0;
80+
//send a close message and close the socket
81+
virtual void close(unsigned short code = 1000, const std::string& msg = "") = 0;
8082
};
81-
class WSContext;
8283
class WSListenerImpl;
8384
class WSListener {
8485
std::shared_ptr<WSListenerImpl> Impl_;
8586
public:
86-
//when a connection is fully established. If onconnect is called, then a matching onDisconnection is guaranteed
87-
void onConnection(const std::function<void(WSocket&, const std::unordered_map<std::string, std::string>&)>& handle);
88-
//when a message has been received
89-
void onMessage(const std::function<void(WSocket&, const WSMessage&)>& handle);
90-
//when a socket is closed down for ANY reason. If onconnect is called, then a matching onDisconnection is guaranteed
91-
void onDisconnection(const std::function<void(WSocket&, unsigned short, const std::string&)>& handle);
92-
//when a ping is received from a client
93-
void onPing(const std::function<void(WSocket&, const unsigned char *, size_t)>& handle);
94-
//when a pong is received from a client
95-
void onPong(const std::function<void(WSocket&, const unsigned char *, size_t)>& handle);
96-
//before onconnection is called, the conection is upgraded
97-
void onHttpUpgrade(const std::function<void(WSocket&)>& handle);
87+
WSListener(const std::shared_ptr<WSListenerImpl>& impl) : Impl_(impl) {}
9888
//the maximum payload size
9989
void set_MaxPayload(size_t bytes);
10090
//the maximum payload size
@@ -107,30 +97,32 @@ namespace SL {
10797
void set_WriteTimeout(std::chrono::seconds seconds);
10898
//get the current write timeout in seconds
10999
std::chrono::seconds get_WriteTimeout();
110-
//send a message to a specific client
111-
void send(const WSocket& s, WSMessage& msg, bool compressmessage);
112-
//send a close message and close the socket
113-
void close(const WSocket& s, unsigned short code = 1000, const std::string& msg = "");
114-
//start the process to listen for clients. This is non-blocking and will return immediatly
115-
void startlistening();
116-
friend WSContext;
117100
};
118-
class WSClientImpl;
119-
class WSClient {
120-
std::shared_ptr<WSClientImpl> Impl_;
101+
102+
class WSListener_Configuration {
103+
std::shared_ptr<WSListenerImpl> Impl_;
121104
public:
105+
WSListener_Configuration(const std::shared_ptr<WSListenerImpl>& impl) : Impl_(impl) {}
122106
//when a connection is fully established. If onconnect is called, then a matching onDisconnection is guaranteed
123-
void onConnection(const std::function<void(WSocket&, const std::unordered_map<std::string, std::string>&)>& handle);
107+
WSListener_Configuration onConnection(const std::function<void(const std::shared_ptr<IWSocket>&, const std::unordered_map<std::string, std::string>&)>& handle);
124108
//when a message has been received
125-
void onMessage(const std::function<void(WSocket&, const WSMessage&)>& handle);
109+
WSListener_Configuration onMessage(const std::function<void(const std::shared_ptr<IWSocket>&, const WSMessage&)>& handle);
126110
//when a socket is closed down for ANY reason. If onconnect is called, then a matching onDisconnection is guaranteed
127-
void onDisconnection(const std::function<void(WSocket&, unsigned short, const std::string&)>& handle);
111+
WSListener_Configuration onDisconnection(const std::function<void(const std::shared_ptr<IWSocket>&, unsigned short, const std::string&)>& handle);
128112
//when a ping is received from a client
129-
void onPing(const std::function<void(WSocket&, const unsigned char *, size_t)>& handle);
113+
WSListener_Configuration onPing(const std::function<void(const std::shared_ptr<IWSocket>&, const unsigned char *, size_t)>& handle);
130114
//when a pong is received from a client
131-
void onPong(const std::function<void(WSocket&, const unsigned char *, size_t)>& handle);
132-
//before onconnection is called, the conection is upgraded
133-
void onHttpUpgrade(const std::function<void(WSocket&)>& handle);
115+
WSListener_Configuration onPong(const std::function<void(const std::shared_ptr<IWSocket>&, const unsigned char *, size_t)>& handle);
116+
//start the process to listen for clients. This is non-blocking and will return immediatly
117+
WSListener listen();
118+
};
119+
120+
121+
class WSClientImpl;
122+
class WSClient {
123+
std::shared_ptr<WSClientImpl> Impl_;
124+
public:
125+
WSClient(const std::shared_ptr<WSClientImpl>& impl) : Impl_(impl) {}
134126
//the maximum payload size
135127
void set_MaxPayload(size_t bytes);
136128
//the maximum payload size
@@ -143,33 +135,55 @@ namespace SL {
143135
void set_WriteTimeout(std::chrono::seconds seconds);
144136
//get the current write timeout in seconds
145137
std::chrono::seconds get_WriteTimeout();
146-
//send a message to a specific client
147-
void send(const WSocket& s, WSMessage& msg, bool compressmessage);
148-
//send a close message and close the socket
149-
void close(const WSocket& s, unsigned short code = 1000, const std::string& msg = "");
150-
//connect to an endpoint. This is non-blocking and will return immediatly. If the library is unable to establish a connection, ondisconnection will be called.
151-
void connect(const std::string& host, PortNumber port, const std::string& endpoint = "/", const std::unordered_map<std::string, std::string>& extraheaders = {});
152-
friend WSContext;
138+
153139
};
154140
class WSContextImpl;
141+
class WSClient_Configuration {
142+
protected:
143+
std::shared_ptr<WSClientImpl> Impl_;
144+
public:
145+
WSClient_Configuration(const std::shared_ptr<WSClientImpl>& impl) :Impl_(impl) {}
146+
//when a connection is fully established. If onconnect is called, then a matching onDisconnection is guaranteed
147+
WSClient_Configuration onConnection(const std::function<void(const std::shared_ptr<IWSocket>&, const std::unordered_map<std::string, std::string>&)>& handle);
148+
//when a message has been received
149+
WSClient_Configuration onMessage(const std::function<void(const std::shared_ptr<IWSocket>&, const WSMessage&)>& handle);
150+
//when a socket is closed down for ANY reason. If onconnect is called, then a matching onDisconnection is guaranteed
151+
WSClient_Configuration onDisconnection(const std::function<void(const std::shared_ptr<IWSocket>&, unsigned short, const std::string&)>& handle);
152+
//when a ping is received from a client
153+
WSClient_Configuration onPing(const std::function<void(const std::shared_ptr<IWSocket>&, const unsigned char *, size_t)>& handle);
154+
//when a pong is received from a client
155+
WSClient_Configuration onPong(const std::function<void(const std::shared_ptr<IWSocket>&, const unsigned char *, size_t)>& handle);
156+
//connect to an endpoint. This is non-blocking and will return immediatly. If the library is unable to establish a connection, ondisconnection will be called.
157+
WSClient connect(const std::string& host, PortNumber port, const std::string& endpoint = "/", const std::unordered_map<std::string, std::string>& extraheaders = {});
158+
};
159+
160+
class WSSClient_Configuration: public WSClient_Configuration {
161+
public:
162+
WSSClient_Configuration(const std::shared_ptr<WSClientImpl>& impl) :WSClient_Configuration(impl) {}
163+
//set this if you want to verify the server's cert
164+
WSClient_Configuration onVerifyPeer(const std::function<bool(bool, X509_STORE_CTX*)>& handle);
165+
};
166+
155167
class WSContext {
156168
std::shared_ptr<WSContextImpl> Impl_;
157169
public:
158-
WSContext(ThreadCount threadcount);
170+
WSContext(const std::shared_ptr<WSContextImpl>& impl) :Impl_(impl) {}
159171

160-
WSListener CreateListener(PortNumber port);
161-
WSListener CreateTLSListener(
172+
WSListener_Configuration CreateListener(PortNumber port);
173+
WSListener_Configuration CreateTLSListener(
162174
PortNumber port,
163175
std::string Password,
164176
std::string Privatekey_File,
165177
std::string Publiccertificate_File,
166178
std::string dh_File);
167179

168-
WSClient CreateClient();
169-
WSClient CreateTLSClient();
170-
WSClient CreateTLSClient(std::string Publiccertificate_File);
180+
WSClient_Configuration CreateClient();
181+
WSSClient_Configuration CreateTLSClient();
182+
WSSClient_Configuration CreateTLSClient(std::string Publiccertificate_File);
171183

172184
};
185+
186+
WSContext CreateContext(ThreadCount threadcount);
173187
}
174188
}
175189

include/internal/DataStructures.h

Lines changed: 85 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -34,45 +34,6 @@ namespace SL {
3434
};
3535

3636

37-
struct SendQueueItem {
38-
WSMessage msg;
39-
bool compressmessage;
40-
};
41-
struct WSocketImpl
42-
{
43-
WSocketImpl(asio::io_service& s) :read_deadline(s), write_deadline(s), strand(s) {}
44-
~WSocketImpl() {
45-
canceltimers();
46-
if (ReceiveBuffer) {
47-
free(ReceiveBuffer);
48-
}
49-
}
50-
asio::basic_waitable_timer<std::chrono::steady_clock> read_deadline;
51-
asio::basic_waitable_timer<std::chrono::steady_clock> write_deadline;
52-
unsigned char* ReceiveBuffer = nullptr;
53-
size_t ReceiveBufferSize = 0;
54-
unsigned char ReceiveHeader[14];
55-
bool CompressionEnabled = false;
56-
57-
OpCode LastOpCode = OpCode::INVALID;
58-
std::shared_ptr<asio::ip::tcp::socket> Socket;
59-
std::shared_ptr<asio::ssl::stream<asio::ip::tcp::socket>> TLSSocket;
60-
asio::strand strand;
61-
std::deque<SendQueueItem> SendMessageQueue;
62-
63-
void canceltimers() {
64-
read_deadline.cancel();
65-
write_deadline.cancel();
66-
}
67-
};
68-
inline void set_Socket(std::shared_ptr<WSocketImpl>& ws, std::shared_ptr<asio::ssl::stream<asio::ip::tcp::socket>> s) {
69-
ws->TLSSocket = s;
70-
}
71-
inline void set_Socket(std::shared_ptr<WSocketImpl>& ws, std::shared_ptr<asio::ip::tcp::socket> s) {
72-
ws->Socket = s;
73-
}
74-
75-
7637
struct ThreadContext {
7738
std::unique_ptr<char[]> inflationBuffer;
7839
z_stream inflationStream = {};
@@ -113,25 +74,100 @@ namespace SL {
11374

11475
};
11576

116-
struct WSInternal {
77+
class WSInternal : std::enable_shared_from_this<WSInternal> {
78+
public:
11779
WSInternal(std::shared_ptr<WSContextImpl>& p) :WSContextImpl_(p), sslcontext(asio::ssl::context::tlsv11) {}
80+
virtual ~WSInternal() {}
11881
std::shared_ptr<WSContextImpl> WSContextImpl_;
11982
asio::ssl::context sslcontext;
12083
std::chrono::seconds ReadTimeout = std::chrono::seconds(30);
12184
std::chrono::seconds WriteTimeout = std::chrono::seconds(30);
12285
size_t MaxPayload = 1024 * 1024 * 20;//20 MB
12386
bool TLSEnabled = false;
12487

125-
std::function<void(WSocket&, const std::unordered_map<std::string, std::string>&)> onConnection;
126-
std::function<void(WSocket&, const WSMessage&)> onMessage;
127-
std::function<void(WSocket&, unsigned short, const std::string&)> onDisconnection;
128-
std::function<void(WSocket&, const unsigned char *, size_t)> onPing;
129-
std::function<void(WSocket&, const unsigned char *, size_t)> onPong;
130-
std::function<void(WSocket&)> onHttpUpgrade;
88+
std::function<void(const std::shared_ptr<IWSocket>&, const std::unordered_map<std::string, std::string>&)> onConnection;
89+
std::function<void(const std::shared_ptr<IWSocket>&, const WSMessage&)> onMessage;
90+
std::function<void(const std::shared_ptr<IWSocket>&, unsigned short, const std::string&)> onDisconnection;
91+
std::function<void(const std::shared_ptr<IWSocket>&, const unsigned char *, size_t)> onPing;
92+
std::function<void(const std::shared_ptr<IWSocket>&, const unsigned char *, size_t)> onPong;
93+
std::function<bool(bool, X509_STORE_CTX*)> onVerifyPeer;
13194

13295
};
13396

97+
struct SendQueueItem {
98+
WSMessage msg;
99+
bool compressmessage;
100+
};
134101

102+
template<class SOCKETTYPE, class PARENTTYPE>class WSocket : public IWSocket {
103+
104+
public:
105+
WSocket(std::shared_ptr<PARENTTYPE>& s, asio::ssl::context& sslcontext) :
106+
Parent(s),
107+
Socket(s->WSContextImpl_->io_service, sslcontext),
108+
read_deadline(s->WSContextImpl_->io_service),
109+
write_deadline(s->WSContextImpl_->io_service),
110+
strand(s->WSContextImpl_->io_service) {}
111+
WSocket(std::shared_ptr<PARENTTYPE>& s) :
112+
Parent(s),
113+
Socket(s->WSContextImpl_->io_service),
114+
read_deadline(s->WSContextImpl_->io_service),
115+
write_deadline(s->WSContextImpl_->io_service),
116+
strand(s->WSContextImpl_->io_service) {}
117+
virtual ~WSocket() {
118+
canceltimers();
119+
if (ReceiveBuffer) {
120+
free(ReceiveBuffer);
121+
}
122+
}
123+
virtual bool is_open() const {
124+
return true;
125+
}
126+
virtual std::string get_address() const {
127+
return SL::WS_LITE::get_address(Socket);
128+
}
129+
virtual unsigned short get_port() const {
130+
return SL::WS_LITE::get_port(Socket);
131+
}
132+
virtual bool is_v4() const {
133+
return SL::WS_LITE::is_v4(Socket);
134+
}
135+
virtual bool is_v6() const {
136+
return SL::WS_LITE::is_v6(Socket);
137+
}
138+
virtual bool is_loopback() const {
139+
return SL::WS_LITE::is_loopback(Socket);
140+
}
141+
virtual void send(WSMessage& msg, bool compressmessage) {
142+
auto self(std::static_pointer_cast<WSocket<SOCKETTYPE, PARENTTYPE>>( shared_from_this()));
143+
auto p(Parent.lock());
144+
sendImpl(p, self, msg, compressmessage);
145+
}
146+
//send a close message and close the socket
147+
virtual void close(unsigned short code, const std::string& msg) {
148+
auto self(std::static_pointer_cast<WSocket<SOCKETTYPE, PARENTTYPE>>(shared_from_this()));
149+
auto p(Parent.lock());
150+
closeImpl(p, self, code, msg);
151+
}
152+
153+
void canceltimers() {
154+
read_deadline.cancel();
155+
write_deadline.cancel();
156+
}
157+
asio::basic_waitable_timer<std::chrono::steady_clock> read_deadline;
158+
asio::basic_waitable_timer<std::chrono::steady_clock> write_deadline;
159+
unsigned char* ReceiveBuffer = nullptr;
160+
size_t ReceiveBufferSize = 0;
161+
unsigned char ReceiveHeader[14];
162+
bool CompressionEnabled = false;
163+
164+
OpCode LastOpCode = OpCode::INVALID;
165+
SOCKETTYPE Socket;
166+
std::weak_ptr<PARENTTYPE> Parent;
167+
168+
asio::strand strand;
169+
std::deque<SendQueueItem> SendMessageQueue;
170+
};
135171

136172
class WSClientImpl : public WSInternal {
137173
public:
@@ -156,7 +192,7 @@ namespace SL {
156192
ec.clear();
157193
}
158194
add_other_root_certs(sslcontext);
159-
}
195+
}
160196
WSClientImpl(std::shared_ptr<WSContextImpl>& p, bool dummyargtoenabletls) : WSClientImpl(p)
161197
{
162198
UNUSED(dummyargtoenabletls);
@@ -168,7 +204,7 @@ namespace SL {
168204
WSClientImpl(std::shared_ptr<WSContextImpl>& p) :WSInternal(p)
169205
{
170206
}
171-
~WSClientImpl() {}
207+
virtual ~WSClientImpl() {}
172208
};
173209

174210
class WSListenerImpl : public WSInternal {
@@ -225,7 +261,7 @@ namespace SL {
225261

226262
}
227263

228-
~WSListenerImpl() {
264+
virtual ~WSListenerImpl() {
229265
std::error_code ec;
230266
acceptor.close(ec);
231267
}

0 commit comments

Comments
 (0)