Skip to content

Commit 93e673d

Browse files
committed
Merge branch 'master' of github.com:machinezone/IXWebSocket
2 parents 92beef8 + 755d98d commit 93e673d

13 files changed

+96
-18
lines changed

.github/workflows/unittest_windows_gcc.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ jobs:
1111
steps:
1212
- uses: actions/checkout@v1
1313
- uses: seanmiddleditch/gha-setup-ninja@master
14-
- uses: egor-tensin/setup-mingw@v2.2.0
14+
- uses: bsergean/setup-mingw@d79ce405bac9edef3a1726ef00554a56f0bafe66
1515
- run: |
1616
mkdir build
1717
cd build

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ ws/.srl
88
ixhttpd
99
makefile
1010
a.out
11+
.idea/
12+
cmake-build-debug/

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
## Hello world
22

3+
(note from the main developer, sadly I don't have too much time to devote to this library anymore, maybe it's time to pass the maintenance to someone else more motivated ?)
4+
35
IXWebSocket is a C++ library for WebSocket client and server development. It has minimal dependencies (no boost), is very simple to use and support everything you'll likely need for websocket dev (SSL, deflate compression, compiles on most platforms, etc...). HTTP client and server code is also available, but it hasn't received as much testing.
46

57
It is been used on big mobile video game titles sending and receiving tons of messages since 2017 (iOS and Android). It was tested on macOS, iOS, Linux, Android, Windows and FreeBSD. Two important design goals are simplicity and correctness.

docs/usage.md

+11
Original file line numberDiff line numberDiff line change
@@ -445,6 +445,17 @@ server.wait();
445445

446446
```
447447
448+
### Heartbeat
449+
450+
You can configure an optional heartbeat / keep-alive for the WebSocket server. The heartbeat interval can be adjusted or disabled when constructing the `WebSocketServer`. Setting the interval to `-1` disables the heartbeat feature; this is the default setting. The parameter you set will be applied to every `WebSocket` object that the server creates.
451+
452+
To enable a 45 second heartbeat on a `WebSocketServer`:
453+
454+
```cpp
455+
int pingIntervalSeconds = 45;
456+
ix::WebSocketServer server(port, host, backlog, maxConnections, handshakeTimeoutSecs, addressFamily, pingIntervalSeconds);
457+
```
458+
448459
## HTTP client API
449460

450461
```cpp

ixwebsocket/IXHttp.cpp

+12-8
Original file line numberDiff line numberDiff line change
@@ -133,16 +133,20 @@ namespace ix
133133
if (headers.find("Content-Length") != headers.end())
134134
{
135135
int contentLength = 0;
136-
try
137136
{
138-
contentLength = std::stoi(headers["Content-Length"]);
137+
const char* p = headers["Content-Length"].c_str();
138+
char* p_end{};
139+
errno = 0;
140+
long val = std::strtol(p, &p_end, 10);
141+
if (p_end == p // invalid argument
142+
|| errno == ERANGE // out of range
143+
|| val < std::numeric_limits<int>::min()
144+
|| val > std::numeric_limits<int>::max()) {
145+
return std::make_tuple(
146+
false, "Error parsing HTTP Header 'Content-Length'", httpRequest);
147+
}
148+
contentLength = val;
139149
}
140-
catch (const std::exception&)
141-
{
142-
return std::make_tuple(
143-
false, "Error parsing HTTP Header 'Content-Length'", httpRequest);
144-
}
145-
146150
if (contentLength < 0)
147151
{
148152
return std::make_tuple(

ixwebsocket/IXSelectInterruptPipe.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,12 @@ namespace ix
3434

3535
SelectInterruptPipe::~SelectInterruptPipe()
3636
{
37-
::close(_fildes[kPipeReadIndex]);
38-
::close(_fildes[kPipeWriteIndex]);
37+
if (-1 != _fildes[kPipeReadIndex]) {
38+
::close(_fildes[kPipeReadIndex]);
39+
}
40+
if (-1 != _fildes[kPipeWriteIndex]) {
41+
::close(_fildes[kPipeWriteIndex]);
42+
}
3943
_fildes[kPipeReadIndex] = -1;
4044
_fildes[kPipeWriteIndex] = -1;
4145
}

ixwebsocket/IXSocketMbedTLS.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,11 @@ namespace ix
352352
return res;
353353
}
354354

355+
if (res == 0)
356+
{
357+
errno = ECONNRESET;
358+
}
359+
355360
if (res == MBEDTLS_ERR_SSL_WANT_READ || res == MBEDTLS_ERR_SSL_WANT_WRITE)
356361
{
357362
errno = EWOULDBLOCK;

ixwebsocket/IXSocketOpenSSL.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
#ifdef _WIN32
2828
// For manipulating the certificate store
29+
#include <windows.h>
2930
#include <wincrypt.h>
3031
#endif
3132

@@ -293,10 +294,16 @@ namespace ix
293294
*/
294295
bool SocketOpenSSL::checkHost(const std::string& host, const char* pattern)
295296
{
297+
#if OPENSSL_VERSION_NUMBER >= 0x10100000L
298+
return true;
299+
#else
300+
296301
#ifdef _WIN32
297302
return PathMatchSpecA(host.c_str(), pattern);
298303
#else
299304
return fnmatch(pattern, host.c_str(), 0) != FNM_NOMATCH;
305+
#endif
306+
300307
#endif
301308
}
302309

ixwebsocket/IXUrlParser.cpp

+6-4
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ namespace
180180
bHasUserName = true;
181181
break;
182182
}
183-
else if (*LocalString == '/')
183+
else if (*LocalString == '/' || *LocalString == '?')
184184
{
185185
// end of <host>:<port> specification
186186
bHasUserName = false;
@@ -242,7 +242,7 @@ namespace
242242
LocalString++;
243243
break;
244244
}
245-
else if (!bHasBracket && (*LocalString == ':' || *LocalString == '/'))
245+
else if (!bHasBracket && (*LocalString == ':' || *LocalString == '/' || *LocalString == '?'))
246246
{
247247
// port number is specified
248248
break;
@@ -280,12 +280,14 @@ namespace
280280
}
281281

282282
// skip '/'
283-
if (*CurrentString != '/')
283+
if (*CurrentString != '/' && *CurrentString != '?')
284284
{
285285
return clParseURL(LUrlParserError_NoSlash);
286286
}
287287

288-
CurrentString++;
288+
if (*CurrentString != '?') {
289+
CurrentString++;
290+
}
289291

290292
// parse the path
291293
LocalString = CurrentString;

ixwebsocket/IXWebSocketProxyServer.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ namespace ix
5757
server.setOnConnectionCallback(
5858
[remoteUrl, remoteUrlsMapping](std::weak_ptr<ix::WebSocket> webSocket,
5959
std::shared_ptr<ConnectionState> connectionState) {
60-
auto state = std::dynamic_pointer_cast<ProxyConnectionState>(connectionState);
60+
auto state = std::static_pointer_cast<ProxyConnectionState>(connectionState);
6161
auto remoteIp = connectionState->getRemoteIp();
6262

6363
// Server connection

ixwebsocket/IXWebSocketServer.cpp

+5-1
Original file line numberDiff line numberDiff line change
@@ -19,17 +19,20 @@ namespace ix
1919
{
2020
const int WebSocketServer::kDefaultHandShakeTimeoutSecs(3); // 3 seconds
2121
const bool WebSocketServer::kDefaultEnablePong(true);
22+
const int WebSocketServer::kPingIntervalSeconds(-1); // disable heartbeat
2223

2324
WebSocketServer::WebSocketServer(int port,
2425
const std::string& host,
2526
int backlog,
2627
size_t maxConnections,
2728
int handshakeTimeoutSecs,
28-
int addressFamily)
29+
int addressFamily,
30+
int pingIntervalSeconds)
2931
: SocketServer(port, host, backlog, maxConnections, addressFamily)
3032
, _handshakeTimeoutSecs(handshakeTimeoutSecs)
3133
, _enablePong(kDefaultEnablePong)
3234
, _enablePerMessageDeflate(true)
35+
, _pingIntervalSeconds(pingIntervalSeconds)
3336
{
3437
}
3538

@@ -93,6 +96,7 @@ namespace ix
9396
auto webSocket = std::make_shared<WebSocket>();
9497

9598
webSocket->setAutoThreadName(false);
99+
webSocket->setPingInterval(_pingIntervalSeconds);
96100

97101
if (_onConnectionCallback)
98102
{

ixwebsocket/IXWebSocketServer.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ namespace ix
3333
int backlog = SocketServer::kDefaultTcpBacklog,
3434
size_t maxConnections = SocketServer::kDefaultMaxConnections,
3535
int handshakeTimeoutSecs = WebSocketServer::kDefaultHandShakeTimeoutSecs,
36-
int addressFamily = SocketServer::kDefaultAddressFamily);
36+
int addressFamily = SocketServer::kDefaultAddressFamily,
37+
int pingIntervalSeconds = WebSocketServer::kPingIntervalSeconds);
3738
virtual ~WebSocketServer();
3839
virtual void stop() final;
3940

@@ -61,6 +62,7 @@ namespace ix
6162
int _handshakeTimeoutSecs;
6263
bool _enablePong;
6364
bool _enablePerMessageDeflate;
65+
int _pingIntervalSeconds;
6466

6567
OnConnectionCallback _onConnectionCallback;
6668
OnClientMessageCallback _onClientMessageCallback;
@@ -69,6 +71,7 @@ namespace ix
6971
std::set<std::shared_ptr<WebSocket>> _clients;
7072

7173
const static bool kDefaultEnablePong;
74+
const static int kPingIntervalSeconds;
7275

7376
// Methods
7477
virtual void handleConnection(std::unique_ptr<Socket> socket,

test/IXUrlParserTest.cpp

+34
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,40 @@ namespace ix
8484
REQUIRE(port == 443); // default port for wss
8585
}
8686

87+
SECTION("wss://google.com/?arg=value")
88+
{
89+
std::string url = "wss://google.com/?arg=value&arg2=value2";
90+
std::string protocol, host, path, query;
91+
int port;
92+
bool res;
93+
94+
res = UrlParser::parse(url, protocol, host, path, query, port);
95+
96+
REQUIRE(res);
97+
REQUIRE(protocol == "wss");
98+
REQUIRE(host == "google.com");
99+
REQUIRE(path == "/?arg=value&arg2=value2");
100+
REQUIRE(query == "arg=value&arg2=value2");
101+
REQUIRE(port == 443); // default port for wss
102+
}
103+
104+
SECTION("wss://google.com?arg=value")
105+
{
106+
std::string url = "wss://google.com?arg=value&arg2=value2";
107+
std::string protocol, host, path, query;
108+
int port;
109+
bool res;
110+
111+
res = UrlParser::parse(url, protocol, host, path, query, port);
112+
113+
REQUIRE(res);
114+
REQUIRE(protocol == "wss");
115+
REQUIRE(host == "google.com");
116+
REQUIRE(path == "/?arg=value&arg2=value2");
117+
REQUIRE(query == "arg=value&arg2=value2");
118+
REQUIRE(port == 443); // default port for wss
119+
}
120+
87121
SECTION("real test")
88122
{
89123
std::string url =

0 commit comments

Comments
 (0)